Shared object with CMake

Hi all,

I am currently trying to shift towards cmake and ran into some trouble

Up till now I used a Makefile to complie the code:

...
$(LIBMYLIB):        $(OBJMYLIB) 
	@echo "Linking $@ ..."
	$(CXX) -shared -o $@ `root-config --ldflags` $(CXXFLAGS) $(OBJMYLIB) $(LIBS)
...
mylib_dict.C:        $(MYLIBHEADER)
	@rm -f mylib_dict.C mylib_dict.h
	@echo "Generating dictionary ... $@"
	rootcint mylib_dict.C -c $(MYLIBHEADER) mylib_LinkDef.h
...

To use the lib in root I added

gSystem.Load("libmylib.so");

to the rootlogon file which works fine.

Now I want to include it in a cmake project.
For add a lib in the CMakeLists.txt I found :

add_library(mylib SHARED ${SRC})

I assume that the compile option need to be added either in the CMakeLists.txt or in the FindROOT.cmake file.

It would be great if I could get some advice on how to implement the library in the cmake project.

Thanks for your help.

Christian

Hi all,
I am still fighting with the transition from normal Makefile to CMake.

In order to clarify my questions I prepared two examples one using the conventional Makefile (used so far and working) and one showing my attemps to generate the same program with CMake.

The example inludes a shared library libMyUtilities.so with a class my_utilities and a function myReturn(Float_t) which returns the input Float_t. In addition there is a small main in the roottest directory which is calling myReturn.

Here the Makefile example:
rootDict_make.tar.gz (1.92 KB)
in order to make it work I added to my .bashrc

cd /home/christian/rootDict_make
source setup.sh  
# setup.sh set a few variables and adds the path with libMyUtilities.so to LD_LIBRARY_PATH

to use libMyUtilities.so from root I also added

gSystem.Load("libMyUtilities.so");

to my rootlogon file.
In the end I can use libMyUtilities.so with my compiled code and from within root.

Now I am trying to achive the same result with CMake
Here the CMake example:
rootDict_cmake.tar.gz (12.2 KB)

mkdir build
cd build
cmake ..

I get the message

-- Configuring done
CMake Error at my_util/CMakeLists.txt:31 (ADD_LIBRARY):
  Cannot find source file:

    /home/christian/rootDict_cmake/build/my_util/mylib_Dict.cxx

  Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
  .hxx .in .txx


-- Build files have been written to: /home/christian/rootDict_cmake/build

The file mylib_Dict.cxx can not be found as it should be greated by the function ROOT_GENERATE_DICTIONARY

I don’t see how to fix this issue.
Looking forward to receive some advice.

Thanks for the help.
Christian

Using ROOT from a CMake project should be very easy in principle (modulo some rough corners to be polished). The ROOT installation comes with the necessary FindROOT.cmake (for the classic configure/make build) or ROOTConfig.cmake (for the CMake build that is recommended). So, you do not need to have any /cmake directory with ROOT stuff.

At the top level you just need to find ROOT with find_package(ROOT …), which will define some ROOT variables which as ROOT_INCLUDE_DIRS, ROOT_LIBRARIES, ROOT_USE_FILE. So, your top level CMakeLists.txt file can be simply like this:

cmake_minimum_required(VERSION 2.8)
project(rootdict_cmake)

### where to put the libraries
set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/lib")
### where to put the executables
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin")

### add CERN ROOT
find_package(ROOT REQUIRED)
include(${ROOT_USE_FILE})

include_directories(${CMAKE_SOURCE_DIR}/my_util)

add_subdirectory(my_util)
add_subdirectory(roottest)

The macro ROOT_GENERATE_DICTIONARY(…) is provided to help users building dictionaries. The dictionary library CMakeLists.txt file be like this:

ROOT_GENERATE_DICTIONARY(mylib_Dict my_utilities.h LINKDEF my_utilities_LinkDef.h)
add_library(my SHARED my_utilities.cpp mylib_Dict.cxx)
target_link_libraries(my ${ROOT_LIBRARIES})

Notice that the dictionary file generated is called mylib_Dict.cxx and is added to the sources of library “my”.
Finally, a test executable can be produced with the following file:

add_executable(roottest main.cpp)
target_link_libraries(roottest my ${ROOT_LIBRARIES})

The complete example (modified to be minimalistic) has been uploaded.
rootDict_cmake.zip (8.15 KB)

Dear mato,
thanks for looking into that and providing your minimalistic example.

The good news first: I made it work. The library is accessible form root and also from the executable.
Unfortunately I had to make a few changes to make it work which are not clear to me and maybe you could comment on this.

All changes are in the top level CMakeLists.txt.
The first error said that it could not find the FindRoot.cmake. As I used your example there was no cmake/ directory thus no FindRoot.cmake with it.
To work around I added:

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} /home/christian/Desktop/Software/root_v5.34.24/etc/cmake/)

It seems to me that this is not the most elegant solution as this line needs to be modified for each installation.
After that I got a second error saying: include called with wrong number of arguments. Include only takes one
This came from include(${ROOT_USE_FILE}) which I had to replace with include_directories(${ROOT_INCLUDE_DIR}) file.
What I found is that ${ROOT_USE_FILE} is set in ROOTConfig.cmake which is not included in CMakeList.txt thus can not be found.

Again, after adding the changes everything is working but the changes seem to me not very practical if you want to install the code on different machines.
It would be great if you could comment on that.

Thanks again for your help. It is very much appreciated.
Cheers,
Christian

My instructions work with these two assumptions (which I forgot to mention :frowning:)

  1. you did build ROOT with CMake
  2. you have setup the environment with “source /bin/thisroot.sh”

Building ROOT with CMake creates the file ROOTconfig.cmake, which is [almost] equivalent to FindROOT.cmake. The cmake system locates it making use of the environment. You can help cmake by setting CMAKE_PREFIX_PATH to of your installation. The file ROOTconfig.cmake defines ROOT_USE_FILE and therefore it will find it and define the necessary stuff.

If you build with the classic configure/make (not recommended from now on) you need to specify as you did the
CMAKE_MODULE_PATH to the location of FindROOT.cmake (or copy it into your area if you wish). Then the rest is more of less what you just did.

Dear mato,
thanks again for the help.
Indeed root was not installed with cmake but with configure/make.
I reinstalled root with cmake instead following the instruction:
root.cern.ch/drupal/content/building-root-cmake

cd build
cmake ..
make

The installation works fine and I can open root as I am used to.
While I was trying to install the minimalistic example I got the following error message.

In file included from /home/christian/Desktop/mySoftware/root_v5.34.25/core/meta/inc/TClass.h:42:0,
                 from /home/christian/Desktop/rootDict_cmake/build/my_util/mylib_Dict.cxx:19:
/home/christian/Desktop/mySoftware/root_v5.34.25/core/thread/inc/ThreadLocalStorage.h:48:24: fatal error: RConfigure.h: No such file or directory
 #include "RConfigure.h"
compilation terminated.

Compiling the code with the original code example using the Makefile still workes.

As the two dict.cxx files generated in both cases look identical I don’t see where this error is comming from.
Please let me know if you have any idea

I think I understand. This is probably one rough edge to be polished. You are using ROOT from the build area, your problem will be solved if you install it and used from there.

cd build
cmake -DCMAKE_INSTALL_PREFIX=../install  ..
make
make install
source ../install/bin/thisroot.sh

Dear mato,
thanks a lot for the help.
It works like a charm.
I had some troubles figuring out how to add additional root libraries for my real project.
In the end I manged to make it work.
Just for completeness:

find_package(ROOT REQUIRED Graf Gpad Hist RIO Tree)
include(${ROOT_USE_FILE})

Thanks again,
Christian