Note
This dependency graph should be generated and updated by a CI pipeline.
add_library_with_dictionary(
LIBNAME # library name for the target
R3BLibName
LINKDEF # LinkDef file name for the ROOT dictionary
LibNameLinkDef.h
HEADERS # header file names used by the library
file1.h
file2.h
SRCS # source file names used by the library
file1.cxx
file2.cxx
INCLUDEDIRS # include directories of the target
${CMAKE_CURRENT_SOURCE_DIR} # the folder of the current CMakeLists.cxx
dir1 # any sub folders of ${CMAKE_CURRENT_SOURCE_DIR}
dir2
DEPENDENCIES # Dependencies
OtherLib # e.g. R3BSource, R3BTracking
)
PRIVATE
dependencies can be specified by PRIVATE_INCLUDEDIRS
and PRIVATE_DEPENDENCIES
.
CMake is the most popular build system for large C++ projects. Users can specify the build and linking options for C++ binaries using commands defined in CMakeLists.txt
files.
The most important conception of "modern" CMake is the so-called CMake target. A CMake target can either represent a library or an executable. However, what really makes the CMake target so useful is that a target can attach a library/executable with multiple "target properties", that can be propagated along the dependency chain. See this list for all available properties of CMake targets.
A target can be created either with add_library
or add_executable
. The dependencies between different targets can be specified by using target_link_libraries
:
# Creating a library as a target
add_library(mylib SHARED mylib.cxx others.cxx) # Same for add_executable
# Linking the library with other targets/libraries
target_link_libraries(mylib PUBLIC R3BSource PRIVATE R3BNeulandShared)
# add include directory to the target property
target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} dir1 PRIVATE dir2)
add_library
creates a library or an executable from a list of C++ source files. The header files, such as mylib.h
and others.h
, don't need to be added. The keyword SHARED
tells the target represents a dynamic library. If a static library is needed, use the keyword STATIC
.
target_link_libraries
specifies the dependencies of a library. If your library use any classes or functions defined in the library R3BSource
, you have to add the "R3BSource" either after PUBLIC
or PRIVATE
keywords. target_include_directories
specifies the include directories of a target. The include directories are a set of directory paths that C++ compiler will search when you use a include macro, such as #include<FileName.h>
. If FileName.h
doesn't exist in any include directories of the target, the compilation would fail.
The keywords "PUBLIC" and "PRIVATE" specifies whether the properties or dependencies can be propagated in the dependency chain. PUBLIC
means any libraries (or directories) linked to the current target are also linked to any other targets that link the current target. On the other hand, PRIVATE
means the dependencies and include directories are only for the current target.
For example, if the following dependency chain exists:
target_link_libraries(A PUBLIC B PRIVATE C)
target_link_libraries(D PUBLIC A)
the D
target can use all classes and functions defined in both A
and B
, but not in C
. The functions and classes from C
can only be used in the target A
.
Similarly, if the following exists:
target_include_directories(A PUBLIC dir1 PRIVATE dir2)
target_include_directories(B PUBLIC dir3)
target_link_libraries(B PUBLIC A)
the include directory of the target B
contains both dir3
and dir1
, but not dir2
.
Important
It's strongly recommended that PRIVATE
should always prioritized above PUBLIC
to reduce unnecessary dependencies. Clean dependencies can improve the compile time of the project.
From this ROOT official webpage, it can be found that a root dictionary can be generated directly from a target:
ROOT_GENERATE_DICTIONARY(myapp_dict myapp.h MODULE myapp LINKDEF LinkDef.h)
Thus, the implementation of the CMake function add_library_with_dictionary
utilize such the feature and create a target together with a root dictionary:
add_library(${LIBNAME} SHARED ${SRCS})
target_include_directories(
${LIBNAME}
PUBLIC ${INCLUDEDIRS}
PRIVATE ${PRIVATE_INCLUDEDIRS})
target_link_libraries(
${LIBNAME}
PUBLIC ${DEPENDENCIES}
PRIVATE ${PRIVATE_DEPENDENCIES})
root_generate_dictionary(${LIBNAME}_dict ${HEADERS} MODULE ${LIBNAME} LINKDEF
${LINKDEF})
NOTE: for the full detail of the CMake function, please visit the source file.