-
Notifications
You must be signed in to change notification settings - Fork 60
/
podioMacros.cmake
393 lines (353 loc) · 17 KB
/
podioMacros.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#---------------------------------------------------------------------------------------------------
#---PODIO_GENERATE_DICTIONARY( dictionary headerfiles SELECTION selectionfile OPTIONS opt1 opt2 ...
# DEPENDS dependency1 dependency2 ...
# )
# if dictionary is a TARGET (e.g., created with add_library), we inherit the INCLUDE_DIRECTORES and
# COMPILE_DEFINITIONS properties
#
# This is a copy from RELFEX_GENERATE_DICTIONARY from the RootMacros in Root v6.22
# Copied here to allow creating dictionaries based on targer properties
#---------------------------------------------------------------------------------------------------
function(PODIO_GENERATE_DICTIONARY dictionary)
CMAKE_PARSE_ARGUMENTS(ARG "" "SELECTION" "OPTIONS;DEPENDS" ${ARGN})
#---Get List of header files---------------
set(headerfiles)
foreach(fp ${ARG_UNPARSED_ARGUMENTS})
file(GLOB files inc/${fp})
if(files)
foreach(f ${files})
if(NOT f MATCHES LinkDef)
set(headerfiles ${headerfiles} ${f})
endif()
endforeach()
elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${fp})
set(headerfiles ${headerfiles} ${CMAKE_CURRENT_SOURCE_DIR}/${fp})
else()
set(headerfiles ${headerfiles} ${fp})
endif()
endforeach()
#---Get Selection file------------------------------------
if(IS_ABSOLUTE ${ARG_SELECTION})
set(selectionfile ${ARG_SELECTION})
else()
set(selectionfile ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_SELECTION})
endif()
set(gensrcdict ${dictionary}.cxx)
#---roottest compability---------------------------------
if(CMAKE_ROOTTEST_NOROOTMAP)
set(rootmapname )
set(rootmapopts )
elseif(DEFINED CMAKE_ROOTTEST_NOROOTMAP) # Follow the roottest dictionary library naming
set(rootmapname ${dictionary}.rootmap)
set(rootmapopts --rootmap=${rootmapname} --rootmap-lib=${libprefix}${dictionary}_dictrflx)
else()
set(rootmapname ${dictionary}Dict.rootmap)
set(rootmapopts --rootmap=${rootmapname} --rootmap-lib=${libprefix}${dictionary}Dict)
endif()
set(include_dirs ${CMAKE_CURRENT_SOURCE_DIR})
get_directory_property(incdirs INCLUDE_DIRECTORIES)
foreach(d ${incdirs})
if(NOT "${d}" MATCHES "^(AFTER|BEFORE|INTERFACE|PRIVATE|PUBLIC|SYSTEM)$")
list(APPEND include_dirs ${d})
endif()
endforeach()
get_directory_property(defs COMPILE_DEFINITIONS)
foreach( d ${defs})
list(APPEND definitions ${d})
endforeach()
IF(TARGET ${dictionary})
LIST(APPEND include_dirs $<TARGET_PROPERTY:${dictionary},INCLUDE_DIRECTORIES>)
LIST(APPEND definitions $<TARGET_PROPERTY:${dictionary},COMPILE_DEFINITIONS>)
ENDIF()
add_custom_command(
OUTPUT ${gensrcdict} ${rootmapname}
COMMAND ${ROOT_genreflex_CMD}
ARGS ${headerfiles} -o ${gensrcdict} ${rootmapopts} --select=${selectionfile}
--gccxmlpath=${GCCXML_home}/bin ${ARG_OPTIONS}
"-I$<JOIN:${include_dirs},;-I>"
"$<$<BOOL:$<JOIN:${definitions},>>:-D$<JOIN:${definitions},;-D>>"
DEPENDS ${headerfiles} ${selectionfile} ${ARG_DEPENDS}
COMMAND_EXPAND_LISTS
)
IF(TARGET ${dictionary})
target_sources(${dictionary} PRIVATE ${gensrcdict})
ENDIF()
set(gensrcdict ${dictionary}.cxx PARENT_SCOPE)
set_source_files_properties(${gensrcdict}
PROPERTIES
GENERATED TRUE
COMPILE_FLAGS "-Wno-overlength-strings"
)
#---roottest compability---------------------------------
if(CMAKE_ROOTTEST_DICT)
ROOTTEST_TARGETNAME_FROM_FILE(targetname ${dictionary})
set(targetname "${targetname}-dictgen")
add_custom_target(${targetname} DEPENDS ${gensrcdict} ${ROOT_LIBRARIES})
else()
set(targetname "${dictionary}-dictgen")
# Creating this target at ALL level enables the possibility to generate dictionaries (genreflex step)
# well before the dependent libraries of the dictionary are build
add_custom_target(${targetname} ALL DEPENDS ${gensrcdict})
endif()
# We are not going to be able to fix these in any case, so disable clang-tidy
# for the generated dictionaries
set_target_properties(${dictionary} PROPERTIES CXX_CLANG_TIDY "")
endfunction()
set(PODIO_USE_CLANG_FORMAT AUTO CACHE STRING "Try to use clang-format to format the code generated by podio")
set_property(CACHE PODIO_USE_CLANG_FORMAT PROPERTY STRINGS AUTO ON OFF)
#---------------------------------------------------------------------------------------------------
#---PODIO_GENERATE_DATAMODEL( datamodel YAML_FILE RETURN_HEADERS RETURN_SOURCES
# OUTPUT_FOLDER output_directory
# IO_BACKEND_HANDLERS io_handlers
# )
#
# Arguments:
# datamodel Name of the datamodel to be created. a TARGET "create${datamodel}" will be created
# YAML_FILE The path to the yaml file describing the datamodel
# RETURN_HEADERS variable that will be filled with the list of created headers files: ${datamodel}/*.h
# RETURN_SOURCES variable that will be filled with the list of created source files : src/*.cc
# Parameters:
# OLD_DESCRIPTION OPTIONAL: The path to the yaml file describing a previous datamodel version
# OUTPUT_FOLDER OPTIONAL: The folder in which the output files should be placed
# Default is ${CMAKE_CURRENT_SOURCE_DIR}
# UPSTREAM_EDM OPTIONAL: The upstream edm and its package name that are passed to the
# generator via --upstream-edm
# IO_BACKEND_HANDLERS OPTIONAL: The I/O backend handlers that should be generated. The list is
# passed directly to podio_class_generator.py and validated there
# Default is ROOT
# SCHEMA_EVOLUTION OPTIONAL: The path to the yaml file declaring the necessary schema evolution
# )
#
# Note that the create_${datamodel} target will always be called, but if the YAML_FILE has not changed
# this is essentially a no-op, and should not cause re-compilation.
#---------------------------------------------------------------------------------------------------
function(PODIO_GENERATE_DATAMODEL datamodel YAML_FILE RETURN_HEADERS RETURN_SOURCES)
CMAKE_PARSE_ARGUMENTS(ARG "" "OLD_DESCRIPTION;OUTPUT_FOLDER;UPSTREAM_EDM;SCHEMA_EVOLUTION" "IO_BACKEND_HANDLERS" ${ARGN})
IF(NOT ARG_OUTPUT_FOLDER)
SET(ARG_OUTPUT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
SET(UPSTREAM_EDM_ARG "")
IF (ARG_UPSTREAM_EDM)
SET(UPSTREAM_EDM_ARG "--upstream-edm=${ARG_UPSTREAM_EDM}")
ENDIF()
SET(OLD_DESCRIPTION_ARG "")
IF (ARG_OLD_DESCRIPTION)
SET(OLD_DESCRIPTION_ARG "--old-description=${ARG_OLD_DESCRIPTION}")
ENDIF()
IF(NOT ARG_IO_BACKEND_HANDLERS)
# At least build the ROOT selection.xml by default for now
SET(ARG_IO_BACKEND_HANDLERS "ROOT")
ENDIF()
SET(SCHEMA_EVOLUTION_ARG "")
IF (ARG_SCHEMA_EVOLUTION)
SET(SCHEMA_EVOLUTION_ARG "--evolution_file=${ARG_SCHEMA_EVOLUTION}")
ENDIF()
set(CLANG_FORMAT_ARG "")
if (PODIO_USE_CLANG_FORMAT STREQUAL AUTO OR PODIO_USE_CLANG_FORMAT)
find_program(CLANG_FORMAT_EXE NAMES "clang-format")
find_file(CLANG_FORMAT_FILE .clang-format PATH ${PROJECT_SOURCE_DIR} NO_DEFAULT_PATH)
# only newer versions of clang-format know about fallback-style.
execute_process(COMMAND ${CLANG_FORMAT_EXE} --fallback-style OUTPUT_VARIABLE CLANG_FALLBACK_STYLE ERROR_VARIABLE CLANG_FALLBACK_STYLE_ERR)
if(CLANG_FORMAT_EXE AND CLANG_FORMAT_FILE
AND NOT ${CLANG_FALLBACK_STYLE_ERR} MATCHES "Unknown")
message(STATUS "Found .clang-format file and clang-format executable. Will pass it to podio class generator")
set(CLANG_FORMAT_ARG "--clangformat")
else()
if(NOT CLANG_FORMAT_EXE)
message(STATUS "Could not find clang-format executable!")
endif()
if(NOT CLANG_FORMAT_FILE)
message(STATUS "Could not find .clang-format file!")
endif()
if(${CLANG_FALLBACK_STYLE_ERR} MATCHES "Unknown")
message(STATUS "Newer version of clang-format required - cannot run with --fallback-style!")
endif()
if(PODIO_USE_CLANG_FORMAT STREQUAL AUTO)
message(STATUS "Skip formatting of generated code files.")
elseif(PODIO_USE_CLANG_FORMAT)
message(FATAL_ERROR "Could not run clang-format on generated code files!")
endif()
endif()
endif()
# Make sure that we re run the generation process everytime either the
# templates or the yaml file changes.
include(${podio_PYTHON_DIR}/templates/CMakeLists.txt)
set_property(
DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
${YAML_FILE}
${PODIO_TEMPLATES}
${podio_PYTHON_DIR}/podio_class_generator.py
${podio_PYTHON_DIR}/podio/generator_utils.py
${podio_PYTHON_DIR}/podio/podio_config_reader.py
)
message(STATUS "Creating '${datamodel}' datamodel")
# we need to boostrap the data model, so this has to be executed in the cmake run
execute_process(
COMMAND ${Python_EXECUTABLE} ${podio_PYTHON_DIR}/podio_class_generator.py ${CLANG_FORMAT_ARG} ${OLD_DESCRIPTION_ARG} ${SCHEMA_EVOLUTION_ARG} ${UPSTREAM_EDM_ARG} ${YAML_FILE} ${ARG_OUTPUT_FOLDER} ${datamodel} ${ARG_IO_BACKEND_HANDLERS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE podio_generate_command_retval
)
IF(NOT ${podio_generate_command_retval} EQUAL 0)
message(FATAL_ERROR "Could not generate datamodel '${datamodel}'. Check your definition in '${YAML_FILE}'")
ENDIF()
# Get the generated headers and source files
include(${ARG_OUTPUT_FOLDER}/podio_generated_files.cmake)
set (${RETURN_HEADERS} ${headers} PARENT_SCOPE)
set (${RETURN_SOURCES} ${sources} PARENT_SCOPE)
endfunction()
#---------------------------------------------------------------------------------------------------
#---PODIO_ADD_DATAMODEL_CORE_LIB( lib_name HEADERS SOURCES
# OUTPUT_FOLDER output_directory
# )
#
# Add the core datamodel library linking only to the core podio::podio library
# without any I/O backend specific dependencies.
#
# Arguments:
# lib_name Name of the library
# HEADERS The list of all header files created by PODIO_GENERATE_DATAMODEL
# SOURCES The list of all source files created by PODIO_GENERATE_DATAMODEL
#
# Parameters:
# OUTPUT_FOLDER OPTIONAL: The folder in which the output files have been placed by PODIO_GENERATE_DATAMODEL. Defaults to ${CMAKE_CURRENT_SOURCE_DIR}
#---------------------------------------------------------------------------------------------------
function(PODIO_ADD_DATAMODEL_CORE_LIB lib_name HEADERS SOURCES)
CMAKE_PARSE_ARGUMENTS(ARG "" "OUTPUT_FOLDER" "" ${ARGN})
IF(NOT ARG_OUTPUT_FOLDER)
SET(ARG_OUTPUT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
# Filter out anything I/O backend related to build the core library
LIST(FILTER HEADERS EXCLUDE REGEX .*SIOBlock.h)
LIST(FILTER SOURCES EXCLUDE REGEX .*SIOBlock.cc)
add_library(${lib_name} SHARED ${SOURCES} ${HEADERS})
target_link_libraries(${lib_name} PUBLIC podio::podio)
target_include_directories(${lib_name} PUBLIC
$<BUILD_INTERFACE:${ARG_OUTPUT_FOLDER}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
set_target_properties(${lib_name} PROPERTIES
PUBLIC_HEADER "${HEADERS}"
CXX_CLANG_TIDY "" # Do not run clang-tidy on generated sources
# TODO: Update generation to generate compliant code already
)
endfunction()
#---------------------------------------------------------------------------------------------------
#---PODIO_ADD_ROOT_IO_DICT( dict_name CORE_LIB HEADERS SELECTION_XML
# OUTPUT_FOLDER output_directory
# )
#
# Conditionally add the ROOT dictionary to the targets if the corresponding
# selection xml has been generated by PODIO_GENERATE_DATAMODEL.
#
# Arguments:
# dict_name Name of the dictionary
# CORE_LIB The core datamodel library (e.g. from PODIO_ADD_DATAMODEL_CORE_LIB)
# HEADERS The list of all header files generated by PODIO_GENERATE_DATAMODEL
# SELECTION_XML The selection.xml file genertaed by PODIO_GENERATE_DATAMODEL (either an absolute path or relative to OUTPUT_FOLDER)
#
# Parameters:
# OUTPUT_FOLDER OPTIONAL: The folder in which the output files have been placed by PODIO_GENERATE_DATAMODEL. Defaults to ${CMAKE_CURRENT_SOURCE_DIR}
#---------------------------------------------------------------------------------------------------
function(PODIO_ADD_ROOT_IO_DICT dict_name CORE_LIB HEADERS SELECTION_XML)
CMAKE_PARSE_ARGUMENTS(ARG "" "OUTPUT_FOLDER" "" ${ARGN})
IF(NOT ARG_OUTPUT_FOLDER)
SET(ARG_OUTPUT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
IF(IS_ABSOLUTE ${SELECTION_XML})
set(selectionfile ${SELECTION_XML})
ELSE()
set(selectionfile ${ARG_OUTPUT_FOLDER}/${SELECTION_XML})
ENDIF()
IF (NOT EXISTS ${selectionfile})
message(STATUS "Not adding the ROOT dictionaries for ${CORE_LIB}, because \'${selectionfile}\' does not exist")
RETURN()
ENDIF()
# Filter out anything I/O backend related from the generated headers as ROOT only needs
# the core headers
LIST(FILTER HEADERS EXCLUDE REGEX .*SIOBlock.h)
add_library(${dict_name} SHARED)
target_link_libraries(${dict_name} PUBLIC
${CORE_LIB}
podio::podio
ROOT::Core
)
target_include_directories(${dict_name} PUBLIC
$<BUILD_INTERFACE:${ARG_OUTPUT_FOLDER}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
PODIO_GENERATE_DICTIONARY(${dict_name} ${HEADERS} SELECTION ${selectionfile}
OPTIONS --library ${CMAKE_SHARED_LIBRARY_PREFIX}${dict_name}${CMAKE_SHARED_LIBRARY_SUFFIX}
)
set_target_properties(${dict_name}-dictgen PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_dependencies(${dict_name} ${CORE_LIB})
endfunction()
#---------------------------------------------------------------------------------------------------
#---PODIO_ADD_SIO_IO_BLOCKS( CORE_LIB HEADERS SOURCES
# OUTPUT_FOLDER output_directory
# )
#
# Conditionally add the SIOBlocks library to the targets if the corresponding
# SIOBlocks code has been generated by PODIO_GENERATE_DATAMODEL. Since the
# runtime loading of the SIOBlocks library follows a naming convention, the name
# of the library cannot be chosen freely, but is instead determined from the
# name of the core datamodel library.
#
# Arguments:
# CORE_LIB The name of the core datamodel library. The name of the SIO Block library target will be ${CORE_LIB}SioBlocks
# HEADERS The list of all header files created by PODIO_GENERATE_DATAMODEL
# SOURCES The list of all source files created by PODIO_GENERATE_DATAMODEL
#
# Parameters:
# OUTPUT_FOLDER OPTIONAL: The folder in which the output files have been placed by PODIO_GENERATE_DATAMODEL. Defaults to ${CMAKE_CURRENT_SOURCE_DIR}
#---------------------------------------------------------------------------------------------------
function(PODIO_ADD_SIO_IO_BLOCKS CORE_LIB HEADERS SOURCES)
CMAKE_PARSE_ARGUMENTS(ARG "" "OUTPUT_FOLDER" "" ${ARGN})
IF(NOT ARG_OUTPUT_FOLDER)
SET(ARG_OUTPUT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
# Only get the SIOBlock handlers
LIST(FILTER HEADERS INCLUDE REGEX .*SIOBlock.h)
LIST(FILTER SOURCES INCLUDE REGEX .*SIOBlock.cc)
IF(NOT HEADERS)
MESSAGE(STATUS "Not adding the SIO Blocks library to the targets because the corresponding c++ sources have not been generated")
RETURN()
ENDIF()
add_library(${CORE_LIB}SioBlocks SHARED ${SOURCES} ${HEADERS})
target_link_libraries(${CORE_LIB}SioBlocks PUBLIC ${CORE_LIB} podio::podio podio::podioSioIO SIO::sio)
target_include_directories(${CORE_LIB}SioBlocks PUBLIC
$<BUILD_INTERFACE:${ARG_OUTPUT_FOLDER}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
# Disable clang-tidy on generated sources
set_target_properties(${CORE_LIB}SioBlocks PROPERTIES CXX_CLANG_TIDY "")
endfunction()
#---------------------------------------------------------------------------------------------------
function(PODIO_CHECK_CPP_FS FS_LIBS)
SET(have_filesystem FALSE)
MESSAGE(STATUS "Checking for filesystem library support of compiler")
# GNU implementation prior to 9.1 requires linking with -lstdc++fs and LLVM
# implementation prior to LLVM 9.0 requires linking with -lc++fs
# After that it should be built-in
FOREACH(FS_LIB_NAME "" stdc++fs c++fs)
# MESSAGE(STATUS "Linking against ${FS_LIB_NAME}")
try_compile(have_filesystem ${PROJECT_BINARY_DIR}/try ${PROJECT_SOURCE_DIR}/cmake/try_filesystem.cpp
CXX_STANDARD ${CMAKE_CXX_STANDARD}
CXX_EXTENSIONS False
OUTPUT_VARIABLE HAVE_FS_OUTPUT
LINK_LIBRARIES ${FS_LIB_NAME}
)
# MESSAGE(STATUS "-----> " ${HAVE_FS_OUTPUT})
IF(have_filesystem)
MESSAGE(STATUS "Compiler supports filesystem when linking against '${FS_LIB_NAME}'")
SET(${FS_LIBS} ${FS_LIB_NAME} PARENT_SCOPE)
RETURN()
ENDIF()
MESSAGE(STATUS "Compiler not compatible when linking against '${FS_LIB_NAME}'")
ENDFOREACH()
MESSAGE(STATUS "Compiler does not have filesystem support, falling back to boost::filesystem")
find_package(Boost REQUIRED COMPONENTS filesystem system)
SET(${FS_LIBS} Boost::filesystem Boost::system PARENT_SCOPE)
SET_TARGET_PROPERTIES(Boost::filesystem
PROPERTIES
INTERFACE_COMPILE_DEFINITIONS USE_BOOST_FILESYSTEM
)
endfunction()