How to build & install a simple ROOT library with cmake?

Hi,
I’m trying to learn to use cmake in order to build shared libraries of ROOT-based classes.
I have tried to copy & mix & match what I see in test/CMakeLists.txt and in the main ROOT
cmake build structure, e.g. hist/hist/CMakeLists.txt.
I am using the git branch v5-34-00-patches on Ubuntu 14.10 (gcc 4.9.1) with cmake v2.8.12.2

I have two simple classes, one derived from TObject, the other derives from the first,
in the following structure:

rootLib/
rootLib/CMakeLists.txt
rootLib/inc
rootLib/inc/LinkDef.h
rootLib/inc/RootClass2.h
rootLib/inc/RootClass1.h
rootLib/src
rootLib/src/RootClass1.cpp
rootLib/src/RootClass2.cpp

Here is the CMakeLists.txt file:

cmake_minimum_required(VERSION 2.6 FATAL_ERROR)

project(rootLib)
find_package(ROOT REQUIRED)
set(CMAKE_MODULE_PATH ${ROOT_DIR}/modules)
include(RootNewMacros)

include_directories(${ROOT_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)

ROOT_GENERATE_DICTIONARY(RootLibDict *.h LINKDEF LinkDef.h)
ROOT_LINKER_LIBRARY(RootLib *.cpp RootLibDict.cxx LIBRARIES Core)

This works fine:

ganp115:~/software/CMake/rootLib% mkdir build
ganp115:~/software/CMake/rootLib% cd build
ganp115:~/software/CMake/rootLib/build% mkdir destdir
ganp115:~/software/CMake/rootLib/build% cmake -DCMAKE_INSTALL_PREFIX=$PWD/destdir ..
-- The C compiler identification is GNU 4.9.1
-- The CXX compiler identification is GNU 4.9.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/john/software/CMake/rootLib/build
ganp115:~/software/CMake/rootLib/build% make
[ 25%] Generating RootLibDict.cxx, RootLibDict.h
Scanning dependencies of target RootLib
[ 50%] Building CXX object CMakeFiles/RootLib.dir/src/RootClass1.cpp.o
[ 75%] Building CXX object CMakeFiles/RootLib.dir/src/RootClass2.cpp.o
[100%] Building CXX object CMakeFiles/RootLib.dir/RootLibDict.cxx.o
Linking CXX shared library libRootLib.so
[100%] Built target RootLib

and produces the expected libRootLib.so in the build directory which I can load in ROOT and
play with my new classes. However, if I try to install:

ganp115:~/software/CMake/rootLib/build% make install
make: *** No rule to make target 'install'.  Stop.

Clearly I have missed something. Looking at e.g. hist/hist/CMakeLists.txt, it seems that I should
add ROOT_INSTALL_HEADERS() to the end of CMakeLists.txt, but when I do this I get an error that
I can’t understand:

CMake Error at /home/john/software/build/root-v5-34-00/cmake/modules/RootNewMacros.cmake:456 (install):
  install DIRECTORY given no DESTINATION!
Call Stack (most recent call first):
  CMakeLists.txt:14 (ROOT_INSTALL_HEADERS)

Also inspired by hist/hist/CMakeLists.txt, it seems that generating the rootmap file should be a piece of
cake too, so I modified in the following way:

ROOT_GENERATE_DICTIONARY(RootLibDict *.h LINKDEF LinkDef.h)
ROOT_GENERATE_ROOTMAP(RootLib LINKDEF LinkDef.h DEPENDENCIES Core)
ROOT_LINKER_LIBRARY(RootLib *.cpp RootLibDict.cxx LIBRARIES Core)

But again I clearly haven’t understood how to use the ROOT cmake modules (if they had explanatory comments in their source code it might be easier…) because I now get:

CMake Error at /home/john/software/build/root-v5-34-00/cmake/modules/RootNewMacros.cmake:443 (install):
  install FILES given no DESTINATION!
Call Stack (most recent call first):
  CMakeLists.txt:12 (ROOT_GENERATE_ROOTMAP)

I am sure I have missed something obvious, any help would be greatly appreciated.
Cheers
John

OK I’ve made some progress :slight_smile:
It seems that I have to add

set(CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/include)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_INSTALL_PREFIX}/lib)
set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib)

in order for it to work. This seems odd: shouldn’t these variables be set automatically by cmake???
I’m not entirely sure that the definitions that I have given to them would be as platform-independent as I would like…

Anyway, with this done I now get:

ganp115:~/software/CMake/rootLib/build% make
[ 20%] Generating RootLibDict.cxx, RootLibDict.h
Scanning dependencies of target RootLib
[ 40%] Building CXX object CMakeFiles/RootLib.dir/src/RootClass1.cpp.o
[ 60%] Building CXX object CMakeFiles/RootLib.dir/src/RootClass2.cpp.o
[ 80%] Building CXX object CMakeFiles/RootLib.dir/RootLibDict.cxx.o
Linking CXX shared library destdir/lib/libRootLib.so
[ 80%] Built target RootLib
Scanning dependencies of target libRootLib.rootmap
[100%] Generating destdir/lib/libRootLib.rootmap
[100%] Built target libRootLib.rootmap
ganp115:~/software/CMake/rootLib/build% make install
[ 80%] Built target RootLib
[100%] Built target libRootLib.rootmap
Install the project...
-- Install configuration: ""
-- Installing: /home/john/software/CMake/rootLib/build/destdir/include
-- Installing: /home/john/software/CMake/rootLib/build/destdir/include/RootClass2.h
-- Installing: /home/john/software/CMake/rootLib/build/destdir/include/RootClass1.h

It seems a little strange that now the library & rootmap are directly created in the installation
directory, and not installed by ‘make install’. All the same, everything seems to work, adding
$PWD/destdir/lib to LD_LIBRARY_PATH before launching ROOT I have tested that the classes are
automatically loaded as they should be.

However, one final strange behaviour: if I now do ‘make clean’ in the build directory, the library and rootmap are deleted from the installation directory!!! Surely not the desired result?

Hi,

Why don’t you use cmake commands for build & install like this?

cmake_minimum_require(VERSION 2.8)

project(rootLib)

set(CMAKE_INSTALL_PREFIX /your-install-dir)

set(CMAKE_MODULE_PATH $ENV{ROOTSYS}/etc/cmake)

find_package(ROOT)

include_directories(${ROOT_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/inc)

root_generate_dictionary(RootLibDict inc/RootClass1.h inc/RootClass2.h LINKDEF inc/LinkDef.h)

add_library(RootLib SHARED src/RootClass1.cpp src/RootClass2.cpp RootLibDict)

target_link_libraries(RootLib ${ROOT_LIBRARIES})

install(TARGETS RootLib LIBRARY DESTINATION lib)
install(FILES inc/RootClass1.h inc/RootClass2.h DESTINATION include)

Hi Hokim

Several answers to your question:
(1) I’m a relative newcomer to cmake;
(2) I reasoned that if ROOT comes with lots of predefined macros to do the hard work,
it’s better to use them instead of trying to reinvent the wheel;
(3) The proposed solution in the FAQ on the website (“Can I integrate ROOT into my CMake build?”)
doesn’t work (i.e. I downloaded the event.tgz file from http://root.cern.ch/drupal/faq#n657,
did the following):

ganp115:~/software/CMake/event% ll
total 68K
-rw-r--r-- 1 john john 4.2K Apr 14  2009 CMakeLists.txt
-rw-rw-r-- 1 john john  13K Nov 14 17:38 CMakeLists.txt.user
-rw-r--r-- 1 john john  15K Apr 14  2009 Event.cxx
-rw-r--r-- 1 john john 7.8K Apr 14  2009 Event.h
-rw-r--r-- 1 john john  259 Apr 14  2009 EventLinkDef.h
-rw-r--r-- 1 john john 9.4K Apr 14  2009 FindROOT.cmake

ganp115:~/software/CMake/event% mkdir build && cd build && mkdir tmp
ganp115:~/software/CMake/event/build% cmake .. -DCMAKE_INSTALL_PREFIX=$PWD/tmp
-- The C compiler identification is GNU 4.9.1
-- The CXX compiler identification is GNU 4.9.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Looking for Root...
-- Looking for Root... - found /home/john/software/build/root-v5-34-00/bin/root
-- Looking for Root... - version 5.34/23 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/john/software/CMake/event/build
ganp115:~/software/CMake/event/build% make
[ 33%] Generating EventDict.cxx, EventDict.h
Error: cannot open file "Event.h"  :0:
!!!Removing /home/john/software/CMake/event/build/EventDict.cxx /home/john/software/CMake/event/build/EventDict.h !!!
Error: /home/john/software/build/root-v5-34-00/bin/rootcint: error loading headers...
CMakeFiles/Event.dir/build.make:57: recipe for target 'EventDict.cxx' failed
make[2]: *** [EventDict.cxx] Error 1
CMakeFiles/Makefile2:63: recipe for target 'CMakeFiles/Event.dir/all' failed
make[1]: *** [CMakeFiles/Event.dir/all] Error 2
Makefile:116: recipe for target 'all' failed
make: *** [all] Error 2

OK I seem to have found a solution which works (with ROOT v5.34/23):

cmake_minimum_required(VERSION 2.6 FATAL_ERROR)

project(rootLib)

find_package(ROOT REQUIRED)
include(StandaloneBuild)
include(RootInstallDirs)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)

ROOT_STANDARD_LIBRARY_PACKAGE(rootLib DEPENDENCIES ${ROOT_LIBRARIES})

as long as the source files end in ‘.cxx’ (pity there isn’t an option to change the default extension).
Now I’ll try the exact same with ROOT v6.02…

Improved finished version which works with both 5.34 & 6.02 branches:

cmake_minimum_required(VERSION 2.6 FATAL_ERROR)

set(libName rootLib)

project(${libName})

#---ROOT libraries/modules needed by our classes
set(rootLibsToLink Hist RIO Tree MathCore Gpad Gui)

#---specify needed libraries so they are added to ${ROOT_LIBRARIES}
find_package(ROOT REQUIRED ${rootLibsToLink})

include(${ROOT_USE_FILE})
if(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif()
link_directories(${ROOT_LIBRARY_DIRS})
include(RootInstallDirs)
# needed for v6: sets cxx11 options (perhaps always needed?)
set(CMAKE_CXX_FLAGS ${ROOT_CXX_FLAGS})

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)

ROOT_STANDARD_LIBRARY_PACKAGE(${libName} DEPENDENCIES ${ROOT_LIBRARIES})