Example for Integrating ROOT into CMake projects

I have a question about Integrating ROOT into CMake projects, I want a simple cmake example to use ROOT and it’s dictionary mechanism. I find an very nice example wrote by Enrico: with_cmake example
It has only 5 files:

  • readwrite_twoints.cpp
  • twoints.cpp
  • twoints.hpp
  • LinkDef.h
  • CMakeLists.txt

I can easily build and run it (with CMake3.24.0 and ROOT6.26/06 on Ubuntu18.04)

git clone https://github.com/eguiraud/root_dictionaries_tutorial
mkdir root_dictionaries_tutorial/with_cmake/build
cd root_dictionaries_tutorial/with_cmake/build
cmake ../
make -j4

But the question is, if I add an TVector3 object to class twoints in twoints.hpp:

// twoints.hpp
#pragma once
#include "TVector3.h"

class TwoInts {
   int _a;
   int _b;

   TVector3 r;
   TwoInts() {}
   TwoInts(int a, int b) : _a(a), _b(b) {}
   int GetA() const;
   int GetB() const;
   TwoInts& SetA(int a);
   TwoInts& SetB(int b);

But I get this error when I make it:

[100%] Linking CXX executable readwrite_twoints
CMakeFiles/readwrite_twoints.dir/readwrite_twoints.cpp.o: In function `TVector3::~TVector3()':
readwrite_twoints.cpp:(.text._ZN8TVector3D2Ev[_ZN8TVector3D5Ev]+0xf): undefined reference to `vtable for TVector3'
CMakeFiles/readwrite_twoints.dir/readwrite_twoints.cpp.o: In function `TVector3::TVector3()':
readwrite_twoints.cpp:(.text._ZN8TVector3C2Ev[_ZN8TVector3C5Ev]+0x1b): undefined reference to `vtable for TVector3'
collect2: error: ld returned 1 exit status
CMakeFiles/readwrite_twoints.dir/build.make:117: recipe for target 'readwrite_twoints' failed
make[2]: *** [readwrite_twoints] Error 1
CMakeFiles/Makefile2:84: recipe for target 'CMakeFiles/readwrite_twoints.dir/all' failed
make[1]: *** [CMakeFiles/readwrite_twoints.dir/all] Error 2
Makefile:90: recipe for target 'all' failed
make: *** [all] Error 2

I’m not familiar with root and cmake, especially the dictionary mechanism, any comment will be helpful for me, thanks!

For convenience, this is the content of the CMakeList.txt

cmake_minimum_required(VERSION 3.9)
project (readwrite_twoints CXX)

# Look for ROOT. As long as an installation is available in the environment, this should succeed.
message(STATUS "Looking for ROOT")
message(STATUS "ROOT ${ROOT_VERSION} found at ${ROOT_BINDIR}")

add_executable(readwrite_twoints readwrite_twoints.cpp twoints.cpp)
target_link_libraries(readwrite_twoints ROOT::RIO)

# attach dictionaries to the executable. first, tell it where to look for headers required by the dictionaries:
target_include_directories(readwrite_twoints PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
# then generate dictionaries and add them as a dependency of the executable (via the MODULE parameter):
ROOT_GENERATE_DICTIONARY(twoints_dict twoints.hpp MODULE readwrite_twoints LINKDEF LinkDef.h)

Add: ROOT::Physics

1 Like

It works, Thank you very much!

By the way I want to ask, where can I see all this options, like ROOT:RIO and ROOT::Physics, is this same as the output of root-config --libs. And how can I know which class in each library.

In the bottom of the TVector3” class reference web page, there is a “Libraries for TVector3” graph.

See also: How to dump modulemap “.pcm” files

1 Like

Thank you very much!