Project

General

Profile

Creating an art module which saves the build time and version of your package

One of the most useful pieces of information one can have about a datafile concerns the conditions of the software used to produce it. Particularly during the development phase of a DAQ system, when studying output physics data it's crucial to know the circumstances under which it was produced: what build version of the DAQ system was used? When was it built? What about the same information for packages on which it depended (most notably, artdaq itself)? Fortunately, it's quite easy to create an EDProducer Art module which will save this information for each run in an artdaq-based DAQ system, and artdaq-demo provides an instructive example on this point.

We'll start off by looking at a struct artdaq-demo defines which will provide its users with build information about artdaq-demo, and use it to create a similar structure for your own artdaq-based DAQ package. If you take a look at the artdaq-demo/BuildInfo directory, you'll see three files: GetPackageBuildInfo.hh, GetPackageBuildInfo.cc.in, and CMakeLists.txt. These files define a struct called "GetPackageBuildInfo" within the artdaq-demo package's namespace, "demo"; this struct contains a function, "getPackageBuildInfo" (note the lower-case g), which will return an instance of artdaq's PackageBuildInfo struct. Instances of PackageBuildInfo will contain getter functions providing a package's build time and release version.

As a starting point, you can copy BuildInfo/ over to your own package; if you wish to compile the code in this directory during a build, you'll want to edit the CMakeLists.txt file in the parent directory of your new BuildInfo directory so that it includes the following line:

add_subdirectory(BuildInfo)

If you don't add this, the build system will ignore the directory you just added. To make this code part of your own package, a few minor tweaks will be needed, which we'll step through. To begin with, we look at the GetPackageBuildInfo.hh file:


#ifndef artdaq_demo_BuildInfo_GetPackageBuildInfo_hh
#define artdaq_demo_BuildInfo_GetPackageBuildInfo_hh

#include "artdaq-core/Data/PackageBuildInfo.hh" 

#include <string>

namespace demo {

  struct GetPackageBuildInfo {

    static artdaq::PackageBuildInfo getPackageBuildInfo();
  };

}

#endif /* artdaq_demo_BuildInfo_GetPackageBuildInfo_hh */

Here, there are two things you would want to change: the label "artdaq_demo_BuildInfo_GetPackageBuildInfo_hh", replacing "artdaq_demo" with the name of your package (substituting "_" for "-"), and the namespace of the GetPackageBuildInfo struct, from "demo" into the namespace your package uses.

Next, we modify GetPackageBuildInfo.cc.in :


#include "artdaq-demo/BuildInfo/GetPackageBuildInfo.hh" 

#include <string>

namespace demo {

  artdaq::PackageBuildInfo GetPackageBuildInfo::getPackageBuildInfo() {

    artdaq::PackageBuildInfo pkg;

    pkg.setPackageName("artdaq-demo");
    pkg.setPackageVersion("@version@");
    pkg.setBuildTimestamp("@utcDateTime@");

    return pkg;
  }

}

In this file -- not technically a C++ source file, but rather a template file whose "version" and "utcDateTime" tokens will be substituted with the package's version and build time (in Universal Time Coordinates) as it's converted into a source file during your build -- there are three changes to be made. You'll want to replace the "#include" at the top of the file with the path to your own GetPackageBuildInfo.hh file, not artdaq-demo's ; you'll want to replace artdaq-demo's "demo" namespace with your own; and finally, you'll of course want to change the argument to "pkg.setPackageName()".

Finally, although the CMakeLists.txt file appears fairly complicated due to the token-subsititution logic, the change you'll need to make to it is fairly simple. The only change you would need to make to the source below would be any necessary changes to the argument list of include_directories() so that your #includes in GetPackageBuildInfo.cc.in are found during compilation. In other words: make sure the parent directory of the parent directory of BuildInfo/ is in the include_directories() list.

# JCF, 1/14/15

# The "include_directories()" macro below is not strictly necessary
# from an artdaq-demo perspective, but if users of other packages wish
# to implement their own BuildInfo-style modules they can copy this
# CMakeLists.txt file and easily use "include_directories()" to set
# their include path(s)

# PROJECT_SOURCE_DIR contains the full path to the root of your
# project source directory, i.e. to the nearest directory where
# CMakeLists.txt contains the PROJECT() command

# Uncomment the MESSAGE() macro to actually see what
# PROJECT_SOURCE_DIR is set to during the build

# MESSAGE( STATUS "PROJECT_SOURCE_DIR:         " ${PROJECT_SOURCE_DIR} )

include_directories( ${PROJECT_SOURCE_DIR} )

# the utcDateTime variable is used by the GetPackageBuildInfo code
# to report the build datetime
execute_process( COMMAND "date" "-u" "+%d-%b-%Y %H:%M:%S %Z" OUTPUT_VARIABLE rawUTCDate )
string( STRIP ${rawUTCDate} utcDateTime )

configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/GetPackageBuildInfo.cc.in
  ${CMAKE_CURRENT_BINARY_DIR}/GetPackageBuildInfo.cc @ONLY )

art_make_library( LIBRARY_NAME artdaq-demo_BuildInfo
                  SOURCE
                  ${CMAKE_CURRENT_BINARY_DIR}/GetPackageBuildInfo.cc
                 )

install_headers()
install_source()

That's it -- our "traits class" is complete. Once you have it, it's now quite simple to create an Art module which will store the information from the PackageBuildInfo struct for each run. Again, we copy from artdaq-demo; simply copy the file "ArtdaqDemoBuildInfo_module.cc" from artdaq-demo/ArtModules to the ArtModules directory in your own package (or create this directory if you don't already have it, remembering to add the line "add_subdirectory(ArtModules)" to the CMakeLists.txt file in ArtModules' parent directory). Rename the file to reflect your own package's name. The file looks like the following:

#include "artdaq-core/ArtModules/BuildInfo_module.hh" 

#include "artdaq/BuildInfo/GetPackageBuildInfo.hh" 
#include "artdaq-core/BuildInfo/GetPackageBuildInfo.hh" 
#include "artdaq-core-demo/BuildInfo/GetPackageBuildInfo.hh" 
#include "artdaq-demo/BuildInfo/GetPackageBuildInfo.hh" 

#include <string>

namespace demo {

  static std::string instanceName = "ArtdaqDemoBuildInfo";
  typedef artdaq::BuildInfo< &instanceName, artdaqcore::GetPackageBuildInfo, artdaq::GetPackageBuildInfo, coredemo::GetPackageBuildInfo, demo::GetPackageBuildInfo> ArtdaqDemoBuildInfo;

  DEFINE_ART_MODULE(ArtdaqDemoBuildInfo)
}

Most of the implementation details you won't need to worry about; they occur in the artdaq-core package's BuildInfo template code, located in its BuildInfo_module.hh file. All you need to worry about is what to call your module (replace "ArtdaqDemoBuildInfo" with its name) and then the packages whose info you'd want your module to save (most likely, this will include your DAQ package, artdaq (which it depends on) and artdaq-core (which artdaq depends on). Note that for a package's info to be added to your module, that package will need traits information such as we made for your package above. Once you've decided what you want in your module, make sure to include each packages' traits class (best practice is for it always to be called GetPackageBuildInfo, made unique from the other packages' versions of GetPackageBuildInfo by the package-specific namespace in which it's contained). For artdaq-demo, four such traits classes are used, for artdaq-core, artdaq, artdaq-core-demo, and artdaq-demo; you may have other requirements. Change the namespace from "demo" to be that of your own package as well. Finally, a note on the "instanceName" parameter: this will serve both as the name of the FHiCL parameter which allows you to define the name of your module's product instance, and the default product instance name if you don't specifically define this.

Once you've written the code for your BuildInfo module, make sure the build system knows how to compile it; go to the CMakeLists.txt file in your ArtModules directory and add something like the following:

simple_plugin(ArtdaqDemoBuildInfo "module" 
  artdaq_DAQdata
  artdaq_BuildInfo
  artdaq-core_BuildInfo
  artdaq-demo_BuildInfo
  artdaq-core-demo_BuildInfo
  ${MF_MESSAGELOGGER}
  ${FHICLCPP}
  ${CETLIB}
)

The only difference with the above code is that you'll want to use a different set of BuildInfo shared object libraries, of course.

Once all of this has been compiled, you can test out your new module. In the producers block of a FHiCL document, you simply need to specify that you're using it; an example of this with the artdaq-demo BuildInfo module is:

artdaqDemoBuildInfo:
{
   module_type: ArtdaqDemoBuildInfo

   ArtdaqDemoBuildInfo: myInstanceName
}

…where here, the default instance name of "ArtdaqDemoBuildInfo" has been overridden with "myInstanceName". Once you've specified your buildinfo module, remember to put it into an output path. After a product from a buildinfo module has been stored, you can take a look at it via artdaq-core's PrintBuildInfo module, which you should specify in the analyzers block of your FHiCL document:

     printBuildInfo: {
    module_type: PrintBuildInfo

        buildinfo_module_label: artdaqDemoBuildInfo
        buildinfo_instance_label: myInstanceName
     }

…where again, you'll want to remember to put this module in your output path. The PrintBuildInfo module serves to create a table containing all the info of each package which was specified in the construction of a given buildinfo module.

To see this in action, you can use the FHiCL documents already supplied with artdaq-demo. If you have its environment set up, simply run

driver -c driver.fcl

and among other things, a root file called "driver.root" will be created which will contain the build info product created by ArtdaqDemoBuildInfo. To see the contents of this product, you can run art directly on the driver.root file using the readRoot.fcl script:

art -s driver.root -c readRoot.fcl

At the top of your output, you should see something like the following:

--------------------------------------------------------------
Package             |Version             |Timestamp           
artdaq-core         |v1_04_00            |17-Sep-2014 20:29:38 UTC
artdaq              |v1_12_02            |17-Sep-2014 20:31:14 UTC
artdaq-core-demo    |v0_00_02            |17-Sep-2014 21:11:56 UTC
artdaq-demo         |v2_02_00            |17-Sep-2014 21:21:03 UTC
--------------------------------------------------------------