1
0
mirror of synced 2024-11-05 04:28:54 +01:00

Updates for ROOT

This commit is contained in:
Henry Schreiner 2019-08-08 16:18:42 -04:00
parent f19057232c
commit 89c222da2c
8 changed files with 63 additions and 115 deletions

View File

@ -1,8 +1,9 @@
# ROOT
ROOT is a C++ Toolkit for High Energy Physics. It is huge. There are really a lot of ways to use it in CMake, though many/most of the examples you'll find are probably wrong. Here's my recommendation.
Most importantly, there are lots of improvements in CMake in more recent versions of ROOT - try to use 6.14+!
Most importantly, there are *lots of improvements* in CMake support in more recent versions of ROOT - Using 6.16+ is much, much easier! If you really must support 6.14 or earlier, see the section at the end.
## Finding ROOT
@ -14,7 +15,7 @@ to attempt to find ROOT. If you don't have your paths set up, you can pass `-DRO
## The too-simple way
ROOT [provides a utility](https://root.cern.ch/how/integrate-root-my-project-cmake) to set up a ROOT project, which you can activate using `include("${ROOT_USE_FILE}")`. This will automatically make ugly directory level and global variables for you. It will save you a little time setting up, and will waste massive amounts of time later if you try to do anything tricky. As long as you aren't making a library, it's probably fine for simple scripts. Includes and flags are set globally, but you'll still need to link to `${ROOT_LIBRARIES}` yourself, along with possibly `ROOT_EXE_LINKER_FLAGS` (You will have to `separate_arguments` first before linking or you will get an error if there are multiple flags, like on macOS).
ROOT [provides a utility](https://root.cern.ch/how/integrate-root-my-project-cmake) to set up a ROOT project, which you can activate using `include("${ROOT_USE_FILE}")`. This will automatically make ugly directory level and global variables for you. It will save you a little time setting up, and will waste massive amounts of time later if you try to do anything tricky. As long as you aren't making a library, it's probably fine for simple scripts. Includes and flags are set globally, but you'll still need to link to `${ROOT_LIBRARIES}` yourself, along with possibly `ROOT_EXE_LINKER_FLAGS` (You will have to `separate_arguments` first before linking or you will get an error if there are multiple flags, like on macOS). Also, before 6.16, you have to manually fix a bug in the spacing.
Here's what it would look like:
@ -22,27 +23,17 @@ Here's what it would look like:
## The right way (Targets)
ROOT 6.12 and earlier do not add the include directory for imported targets. ROOT 6.14+ has corrected this error. To fix this error for older ROOT versions, you'll need something like:
[import:'setup_includes', lang:'cmake'](../../examples/root-simple/CMakeLists.txt)
You will also often want the compile flags and definitions:
[import:'setup_flags', lang:'cmake'](../../examples/root-simple/CMakeLists.txt)
In CMake 3.11, you can replace that last function call with:
[import:'modern_fix', lang:'cmake'](../../examples/root-simple-3.11/CMakeLists.txt)
All the ROOT targets will require `ROOT::Core`, so this will be enough regardless of which ROOT targets you need.
ROOT 6.12 and earlier do not add the include directory for imported targets. ROOT 6.14+ has corrected this error, and required target properties have been getting better.
To link, just pick the libraries you want to use:
[import:'add_and_link', lang:'cmake'](../../examples/root-simple/CMakeLists.txt)
If you'd like to see the default list, run `root-config --libs` on the command line.
## Components
Find ROOT allows you to specify components. It will add anything you list to ${ROOT_LIBRARIES}, so you might want to build your own target using that to avoid listing the components twice. This does not solve dependencies though; so it is an error to list `RooFit` but not `RooFitCore`. If you link to `ROOT::RooFit` instead of `${ROOT_LIBRARIES}`, then `RooFitCore` is not required.
Find ROOT allows you to specify components. It will add anything you list to `${ROOT_LIBRARIES}`, so you might want to build your own target using that to avoid listing the components twice. This did not solve dependencies; it was an error to list `RooFit` but not `RooFitCore`. If you link to `ROOT::RooFit` instead of `${ROOT_LIBRARIES}`, then `RooFitCore` is not required.
## Dictionary generation
@ -58,7 +49,10 @@ To generate, you should include the following in your CMakeLists:
```cmake
include("${ROOT_DIR}/modules/RootNewMacros.cmake")
include_directories(ROOT_BUG)
# Uncomment for ROOT versions than 6.16
# They break if nothing is in the global include list!
# include_directories(ROOT_BUG)
```
The second line is due to a bug in the NewMacros file that causes dictionary generation to fail if there is not at least one global include directory or a `inc` folder. Here I'm including a non-existent directory just to make it work. There is no `ROOT_BUG` directory.
@ -79,3 +73,42 @@ The final two output files must sit next to the library output. This is done by
[linkdef-root]: https://root.cern.ch/selecting-dictionary-entries-linkdefh
---
# Using Old ROOT
If you really have to use older ROOT, you'll need something like this:
```cmake
# ROOT targets are missing includes and flags in ROOT 6.10 and 6.12
set_property(TARGET ROOT::Core PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "${ROOT_INCLUDE_DIRS}")
# Early ROOT does not include the flags required on targets
add_library(ROOT::Flags_CXX IMPORTED INTERFACE)
# ROOT 6.14 and earlier have a spacing bug in the linker flags
string(REPLACE "-L " "-L" ROOT_EXE_LINKER_FLAGS "${ROOT_EXE_LINKER_FLAGS}")
# Fix for ROOT_CXX_FLAGS not actually being a CMake list
separate_arguments(ROOT_CXX_FLAGS)
set_property(TARGET ROOT::Flags_CXX APPEND PROPERTY
INTERFACE_COMPILE_OPTIONS ${ROOT_CXX_FLAGS})
# Add definitions
separate_arguments(ROOT_DEFINITIONS)
foreach(_flag ${ROOT_EXE_LINKER_FLAG_LIST})
# Remove -D or /D if present
string(REGEX REPLACE [=[^[-//]D]=] "" _flag ${_flag})
set_property(TARGET ROOT::Flags APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_flag})
endforeach()
# This also fixes a bug in the linker flags
separate_arguments(ROOT_EXE_LINKER_FLAGS)
set_property(TARGET ROOT::Flags_CXX APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ${ROOT_EXE_LINKER_FLAGS})
# Make sure you link with ROOT::Flags_CXX too!
```

View File

@ -10,5 +10,4 @@ add_subdirectory(extended-project)
add_subdirectory(root-usefile)
add_subdirectory(root-simple)
add_subdirectory(root-simple-3.11)
add_subdirectory(root-dict)

View File

@ -1,6 +1,6 @@
## [main]
cmake_minimum_required(VERSION 3.4)
cmake_minimum_required(VERSION 3.4...3.15)
project(RootDictExample LANGUAGES CXX)
@ -9,21 +9,14 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_PLATFORM_INDEPENDENT_CODE ON)
find_package(Threads)
find_package(ROOT CONFIG REQUIRED)
include("${ROOT_DIR}/modules/RootNewMacros.cmake")
# We will set the flags ourselves
set_target_properties(ROOT::Core PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${ROOT_INCLUDE_DIRS}")
include_directories(ROOT_BUG)
root_generate_dictionary(G__DictExample DictExample.h LINKDEF DictLinkDef.h)
add_library(DictExample SHARED DictExample.cxx DictExample.h G__DictExample.cxx)
target_include_directories(DictExample PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(DictExample PUBLIC ROOT::Core Threads::Threads)
target_link_libraries(DictExample PUBLIC ROOT::Core)
## [main]

View File

@ -1,34 +0,0 @@
## [main]
cmake_minimum_required(VERSION 3.11)
project(RootSimpleExample311 LANGUAGES CXX)
find_package(ROOT CONFIG REQUIRED)
## [modern_fix]
target_include_directories(ROOT::Core INTERFACE "${ROOT_INCLUDE_DIRS}")
add_library(ROOT::Flags_CXX IMPORTED INTERFACE)
separate_arguments(ROOT_CXX_FLAGS)
target_compile_options(ROOT::Flags_CXX INTERFACE ${ROOT_CXX_FLAGS})
separate_arguments(ROOT_DEFINITIONS)
target_compile_definitions(ROOT::Flags_CXX INTERFACE ${ROOT_DEFINITIONS})
# This fixes a bug in the linker flags
string(REPLACE "-L " "-L" ROOT_EXE_LINKER_FLAGS "${ROOT_EXE_LINKER_FLAGS}")
separate_arguments(ROOT_EXE_LINKER_FLAGS)
# Stuck into using old property method due to separate -L and -l arguments
# (A full path to -l is better!)
set_property(TARGET ROOT::Flags_CXX PROPERTY
INTERFACE_LINK_LIBRARIES ${ROOT_EXE_LINKER_FLAGS})
## [modern_fix]
add_executable(RootSimpleExample311 SimpleExample.cxx)
target_link_libraries(RootSimpleExample311 PUBLIC ROOT::Physics ROOT::Flags_CXX)
## [main]
enable_testing()
add_test(NAME RootSimpleExample311 COMMAND RootSimpleExample311)

View File

@ -1,11 +0,0 @@
# A Simple ROOT Project (CMake 3.11)
This is a minimal example of a ROOT project using the target system and without a dictionary.
This uses the new support in CMake 3.11+ for adding interface properties on an imported interface target.
#### examples/root-simple-3.11/CMakeLists.txt
[import:'main', lang:'cmake'](CMakeLists.txt)
#### examples/root-simple-3.11/SimpleExample.cxx
[import](SimpleExample.cxx)

View File

@ -1,7 +0,0 @@
#include <TLorentzVector.h>
int main() {
TLorentzVector v(1,2,3,4);
v.Print();
return 0;
}

View File

@ -1,46 +1,19 @@
## [main]
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.1...3.15)
project(RootSimpleExample LANGUAGES CXX)
# Finding the ROOT package
## [find_package]
find_package(ROOT CONFIG REQUIRED)
find_package(ROOT 6.16 CONFIG REQUIRED)
## [find_package]
# ROOT targets are missing includes and flags
## [setup_includes]
set_property(TARGET ROOT::Core PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "${ROOT_INCLUDE_DIRS}")
## [setup_includes]
## [setup_flags]
add_library(ROOT::Flags_CXX IMPORTED INTERFACE)
# Fix for ROOT_CXX_FLAGS not actually being a CMake list
separate_arguments(ROOT_CXX_FLAGS)
set_property(TARGET ROOT::Flags_CXX APPEND PROPERTY
INTERFACE_COMPILE_OPTIONS ${ROOT_CXX_FLAGS})
# Add definitions
separate_arguments(ROOT_DEFINITIONS)
foreach(_flag ${ROOT_EXE_LINKER_FLAG_LIST})
# Remove -D or /D if present
string(REGEX REPLACE [=[^[-//]D]=] "" _flag ${_flag})
set_property(TARGET ROOT::Flags APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_flag})
endforeach()
# This also fixes a bug in the linker flags
string(REPLACE "-L " "-L" ROOT_EXE_LINKER_FLAGS "${ROOT_EXE_LINKER_FLAGS}")
separate_arguments(ROOT_EXE_LINKER_FLAGS)
set_property(TARGET ROOT::Flags_CXX APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ${ROOT_EXE_LINKER_FLAGS})
## [setup_flags]
# Adding an exectuable program and linking to needed ROOT libraries
# Adding an executable program and linking to needed ROOT libraries
## [add_and_link]
add_executable(RootSimpleExample SimpleExample.cxx)
target_link_libraries(RootSimpleExample PUBLIC ROOT::Physics ROOT::Flags_CXX)
target_link_libraries(RootSimpleExample PUBLIC ROOT::Physics)
## [add_and_link]
## [main]

View File

@ -1,16 +1,18 @@
## [main]
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.1...3.15)
project(RootUseFileExample LANGUAGES CXX)
find_package(ROOT CONFIG REQUIRED)
find_package(ROOT 6.16 CONFIG REQUIRED)
# Sets up global settings
include("${ROOT_USE_FILE}")
# This is required for ROOT < 6.16
# string(REPLACE "-L " "-L" ROOT_EXE_LINKER_FLAGS "${ROOT_EXE_LINKER_FLAGS}")
# This is required on if there is more than one flag (like on macOS)
# and this also fixes a bug in the linker flags
string(REPLACE "-L " "-L" ROOT_EXE_LINKER_FLAGS "${ROOT_EXE_LINKER_FLAGS}")
separate_arguments(ROOT_EXE_LINKER_FLAGS)
add_executable(RootUseFileExample SimpleExample.cxx)