Handling PCM dependencies correctly in cmake

Dear ROOTers,

I found one problem in adapting our cmake build system to ROOT 6.

Our software is split into several libraries, and correspondingly incorporates several dictionaries /rootmaps / PCMs.
We use a slightly adapted version of the ROOTNewMacros-cmake macros (to adapt to our file naming conventions).

One case seems to be broken in dependency generation, and I believe it is also broken in ROOTNewMacros. Imagine the following situation:

  • A “base” library which incorporates something as basic as CBTObject (something inheriting TObject). It ends up in something like libcbbase.so, cbbaseDict_rdict.pcm, libcbbase.rootmap.
  • Several “addons” libraries, e.g. “tracking”, which include these basic headers and derive from such objects, so you get e.g. libbgotracking.so, bgotrackingDict_rdict.pcm, libbgotracking.rootmap.

Now, the PCM for the “base” only depends on the headers which go into the “base” library. This means it will only be rebuilt if e.g. “CBTObject.h” changes.

The PCM for “tracking” will be rebuilt ONLY if the headers taking part in the “clustering” library were changed.

Now, I observe something like the following sometimes (please ignore the strange markup, we have our own error-printer):

   <ERROR> 2015-11-23 15:05:02 <ROOT-TProtoClass::Fi>(not set )  data member with index 20 is not found in class BTAbstractTrackFitter 
   <ERROR> 2015-11-23 15:05:02 < ROOT-CreateRealData>(not set )  Cannot find data member # 20 of class BTAbstractTrackFitter for parent BTGFTrackFitting!

I investigated a bit and it seems to me that this happens if:

  • The datamembers of a basic class such as “CBTObject.h” are changed.
  • The PCM for “base” is regenerated, but the PCM e.g. for “tracking” is not recreated, since the direct headers for “tracking” did not change. Only headers included in headers which are part of the “tracking” library did change.
    Note this also holds for Class-version=0 classes.

So my question, finally, is: How do I express the PCM regeneration rule correctly?
Depending on the headers which go into the libraries is not correct, since “rootcling” is of course clever and also looks at the included headers. The PCM then remembers the data-layout of the base-classes, and is not recreated if the base-class layout changes, since cmake “does not parse the headers”.

I believe this is also wrong in ROOTNewMacros itself, but probably does not show up since TObject (or something else which is basic) is not changed significantly often.

Of course, possible solutions are:

  • “IMPLICIT_DEPENDS CXX” of cmake. This might work (I guess?), but is not ninja-compatible and a very recent feature (ROOT also does not use it).
  • Rerunning rootcling each time. This is slow, and I have also not yet figured out how to instruct cmake to always revisit a target even if the output files are still there.
  • Using “rootcling -m cbbaseDict_rdict.pcm” and so on, but I am unsure that this will help, and PCM-dependencies are unclear to cmake, and I also think “-m” is not even effective yet.

Any other suggestions on how to solve this?
At the moment I am still considering the option of always rerunning rootcling (i.e. forcibly deleting the in-build-tree PCMs) since that seems to be the only viable (but expensive) option.
It would already be helpful if ROOT / Cling could check at runtime whether the related PCMs are incompatible with the parsed headers in a more clear way than “data member with index 20 is not found in class BTAbstractTrackFitter”, then I could at least instruct the user in case this happens (or have a post-build PCM-checking functionality).

Cheers (and I am really looking forward to real C++ modules :slight_smile: ),
Oliver

Very nice problem analysis. Probably we are ‘lucky’ building ROOT because any change in any base class will trigger a rebuild of libCore and rootcling, and this will trigger the re-build of all PCM.

We started recently to use IMPLICIT_DEPENDS CXX to cope with the problem of ‘include’ dependencies of LinkDef.h. The macro on ‘master’ looks like:

add_custom_command(OUTPUT ${dictionary}.cxx ${pcm_name} ${rootmap_name}
                     COMMAND ${command} -f  ${dictionary}.cxx ${newargs} ${rootmapargs}
                                        ${ARG_OPTIONS} ${definitions} ${includedirs} ${rheaderfiles} ${_linkdef}
                     IMPLICIT_DEPENDS CXX ${_linkdef}
                     DEPENDS ${headerfiles} ${_linkdef} ${ROOTCINTDEP})

I was not aware that this would not work on Ninja. Then, perhaps the only option left is to depend on dependent PCMs. And this probably will need to be made explicit (like we do for libraries).

Hi,

rootcling / genreflex already “appreciate” to be passed the dependent PCMs as -m libcbbase_dict.pcm. The CMake macro should probably expose that (if not done already) and make use of that for dependency tracking. Note that the dependency is really on the dependent PCM, not on its headers.

Cheers, Axel.

Hi Axel, hi Pere,

thanks a lot for your replies!
In fact, the cmake-macro of ROOT master already exposes the functionality to pass dependent PCM files.

For us the main issue is (in the end) that we (in our software) still do not have explicit linking everywhere, but (for the libraries) rely on correct dependency generation via the underlying make tool (which uses things such as “g++ -m” to find out implicit dependencies).
As such, we do not have explicit dependencies of libraries and PCMs against “core” libraries, but rely on rootmap-based autoloading still (but in general, still load almost everything anyways). Since there are cross-dependencies between the libraries, explicit dependencies are almost impossible without a full restructuring of our software (which would be best, but…), so I’ll try to add explicit dependencies at least between the most-core parts (data-objects, interfaces etc.) and most user code.

Also I am unsure at one point in the “-m” documentation as shown by rootcling:

[quote]The flag -m must be followed by the name (absolute path or relative
to the current path) of a pcm file which will be loaded before any
header files.[/quote]
It remains unclear to me how is relocatability handled:
Will the dependent-PCM then, later at runtime, be loaded from the LD_LIBRARY_PATH, searching with these compile-time provided paths “stripped”?

Cheers and thanks!
Oliver

For reference, the cmake-bug concerning IMPLICIT_DEPENDS is:
https://cmake.org/Bug/view.php?id=13234, sadly very long-standing…

Hello again,

maybe I can answer myself, can you confirm?

[quote=“olifre”]It remains unclear to me how is relocatability handled:
Will the dependent-PCM then, later at runtime, be loaded from the LD_LIBRARY_PATH, searching with these compile-time provided paths “stripped”?[/quote]

From a quick look at the code, which I finally had today, I find in rootclingTCling.cxx:

dictFile.WriteObjectAny(&gAncestorPCMNames, "std::vector<std::string>", "__AncestorPCMNames");
It seems to me from a short grep’ping that “__AncestorPCMNames” is not read back (yet).
So probably I’m asking too early how relocatability is handled?

My assumption would be that I pass (via the cmake macro) “-m some/build/time/path/to/ancestor/pcm/some.pcm” to rootcling,
so that it can check which definitions are already inside the build-time generated ancestor PCM and remove them from the PCM it’s just creating, and later at runtime it would go and look for the (likely relocated) basename “some.pcm” in LD_LIBRARY_PATH.

Cheers and thanks!
Oliver

Hi,

Your assumption is correct :slight_smile: The logic is as follows:

Any libWhatever.so with dictionary is expected to have a libWhatever_dict.pcm. Thus the file name is sufficient (or rather must be sufficient) to uniquely identify the PCM.

And indeed this is currently not yet used, because we are still working on providing PCM support. But the information could be used to track build system dependencies.

Cheers, Axel.