-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmeson.build
More file actions
418 lines (380 loc) · 17.8 KB
/
Copy pathmeson.build
File metadata and controls
418 lines (380 loc) · 17.8 KB
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
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# Notice: if both static and dynamic libraries are present, the dynamic library will be used
# Forcing suffix lib instead of variants like lib64
project('gemc', 'cpp',
default_options : [
'default_library=static',
'default_both_libraries=static',
'libdir=lib'
],
version : run_command('ci/gemc_version.sh', check : true).stdout().strip(),
meson_version : '>= 1.10.1'
)
project_description = 'GEMC (GEant Monte-Carlo) is a program based on Geant4 to simulate the passage of particles through matter. '
# additional debug options useful for profiling
if get_option('buildtype') == 'debug'
add_project_arguments('-fno-omit-frame-pointer', language : 'cpp')
add_project_arguments('-fno-optimize-sibling-calls', language : 'cpp')
add_project_arguments('-O2', language : 'cpp')
endif
# Do not to write .pyc bytecode cache files
test_env = environment()
test_env.set('PYTHONDONTWRITEBYTECODE', '1')
# init lists
############
LD = []
all_libs = []
all_pkgconfig_libs = []
# Kept as plain (root-relative) path strings rather than include_directories() objects so the list
# can be resolved into a single location-independent object below (gemc_includes) for the bin/
# executable. '.' = source root, which resolves <gemc/module/header.h> → src/gemc/module/header.h.
all_includes = ['.']
empty_dict = { 'na' : [''] }
lib_target_maps = {}
subdir('meson')
# Fill dictionary
#################
subdir('gemc/guts')
subdir('gemc/goptions')
subdir('gemc/glogging')
subdir('gemc/gbase')
subdir('gemc/gfactory')
subdir('gemc/textProgressBar')
subdir('gemc/gtouchable')
subdir('gemc/ghit')
subdir('gemc/gtranslationTable')
subdir('gemc/gdata')
subdir('gemc/ganalysis')
subdir('gemc/gboard')
subdir('gemc/gdynamicDigitization')
subdir('gemc/gsystem') # uses api for testing
subdir('gemc/gstreamer')
subdir('gemc/eventDispenser')
subdir('gemc/gqtbuttonswidget')
subdir('gemc/g4display')
subdir('gemc/g4dialog')
subdir('gemc/g4system')
subdir('gemc/gparticle')
subdir('gemc/gphysics')
subdir('gemc/gsplash')
subdir('gemc/gsd') # TODO: example
subdir('gemc/gfields')
subdir('gemc/gdetector')
subdir('gemc/dbselect')
subdir('gemc/gtree')
subdir('gemc/pmaker')
subdir('gemc/gui')
subdir('gemc/actions')
subdir('gemc/utilities')
# Set up Python environment via pygemc subproject.
# The subproject creates a build-tree venv so configure works even when the
# install prefix does not exist yet (ci/build.sh does 'rm -rf $GEMC' first).
# venv_bin points at that build-tree venv for tests.
# At install time, ci/install_python_env.py creates a fresh venv at the prefix.
pygemc_sub = subproject('pygemc')
venv_bin = pygemc_sub.get_variable('venv_bin')
python_exe = import('python').find_installation(venv_bin / 'python3')
pygemc_src = meson.project_source_root() / 'subprojects' / 'pygemc'
#meson.add_install_script(find_program('python3'), 'ci/install_python_env.py', pygemc_src)
meson.add_install_script(find_program('python3'), files('ci/install_python_env.py'), pygemc_src)
# compilation loop
foreach L : LD
this_lib_name = L['name'] # key name must be present
sources = L.get('sources', [''])
headers = L.get('headers', [''])
examples = L.get('examples', empty_dict)
example_internal_dependencies = L.get('example_internal_dependencies', empty_dict)
geo_build = L.get('geo_build', empty_dict)
this_deps = L.get('dependencies', [])
this_internal_libs = L.get('internal_dependencies', [])
plugins = L.get('plugins', empty_dict)
plugin_dependencies = L.get('plugin_dependencies', empty_dict)
additional_includes = L.get('additional_includes', [''])
moc_headers = L.get('moc_headers', [''])
moc_sources = []
qrc_sources = L.get('qrc_sources', [''])
qrc_examples_sources = L.get('qrc_examples_sources', [''])
qrc_compiled_sources = []
qrc_examples_compiled_sources = []
if not moc_headers.contains('')
moc_sources = qt6.compile_moc(headers : moc_headers,
dependencies : this_deps)
endif
# Resolve internal library deps before building the library so shared objects
# record their NEEDED entries and RTTI/vtable symbols are resolvable at load time.
internal_link_with = []
foreach this_link_with : this_internal_libs
if lib_target_maps.has_key(this_link_with)
internal_link_with += [lib_target_maps[this_link_with]]
endif
endforeach
if not sources.contains('')
if not qrc_sources.contains('')
qrc_compiled_sources += qt6.compile_resources(name : this_lib_name + '_qtresources', sources : qrc_sources)
endif
this_library = library(
this_lib_name,
sources + moc_sources + qrc_compiled_sources,
install : true,
dependencies : this_deps,
include_directories : all_includes + additional_includes,
link_with : internal_link_with
)
if not all_libs.contains(this_library)
all_libs += this_library
all_pkgconfig_libs += ['${libdir}/lib' + this_lib_name + '.a']
lib_target_maps += { this_lib_name : this_library }
endif
endif
# header files
if not headers.contains('')
install_headers(headers, subdir : 'gemc' / this_lib_name, preserve_path : true)
endif
this_library_link_with = []
# todo: this produces duplicates ROOT libraries
if not sources.contains('')
this_library_link_with += this_library
endif
foreach this_link_with : this_internal_libs
if lib_target_maps.has_key(this_link_with)
this_library_link_with += [lib_target_maps[this_link_with]]
endif
endforeach
if plugins != empty_dict
# Same rationale as the example executables: a STATIC module library
# (link_with) propagates this_deps' link args, so pass only their
# compile/include part to the plugins to avoid duplicate -l flags; zlib is
# linked once explicitly. With shared module libraries (use_sharedl, e.g. the
# sanitizer build) the .so is self-contained and does not forward those link
# args, so the full this_deps must be passed instead.
# (computed here, before 'sources' is rebound by the plugin loop below.)
if sources.contains('') or use_sharedl
plugin_base_deps = [this_deps, zlib_dep]
else
plugin_base_deps = [declare_dependency(dependencies : this_deps).partial_dependency(compile_args : true, includes : true), zlib_dep]
endif
foreach name, sources : plugins
this_plugin_dependencies = plugin_base_deps
if plugin_dependencies.has_key(name)
this_plugin_dependencies += plugin_dependencies[name]
endif
shared_library(
name,
sources[0],
install : sources[1],
dependencies : this_plugin_dependencies,
include_directories : all_includes + ('gemc' / this_lib_name) + additional_includes,
link_with : this_library_link_with,
name_suffix : 'gplugin',
name_prefix : '',
# Forces any static libraries that get built as part of the Meson project to be built with PIC
# so they can be linked into a shared module
override_options : ['b_staticpic=true']
)
endforeach
endif
# examples
if examples != empty_dict
# geometry, higher priority so it is run before the test
if geo_build != empty_dict
foreach name, geo_python_script : geo_build
install_examples_dir = get_option('prefix') + '/test/' + this_lib_name
test_examples_dir = meson.project_build_root() + '/test/' + this_lib_name
run_command('mkdir', '-p', test_examples_dir, check : true)
source_subdir = 'gemc' / this_lib_name / 'examples'
install_subdir(source_subdir,
install_dir : install_examples_dir,
strip_directory : true,
follow_symlinks : true)
test(name,
python_exe,
args : [geo_python_script],
workdir : test_examples_dir,
is_parallel : false,
env : test_env,
priority : 20)
endforeach
endif
# example executables, lower priority so it's executed after build geometry
if not qrc_examples_sources.contains('')
qrc_examples_compiled_sources = qt6.compile_resources(name : this_lib_name + '_qtresources', sources : qrc_examples_sources)
endif
foreach name, sources_and_arguments : examples
# concatenate the items in sources_and_arguments[1] to a string
example_sources = sources_and_arguments[0] + qrc_examples_compiled_sources
arguments = sources_and_arguments[1]
example_link_with = this_library_link_with
if example_internal_dependencies.has_key(name)
foreach example_internal_lib : example_internal_dependencies[name]
if lib_target_maps.has_key(example_internal_lib)
example_link_with += [lib_target_maps[example_internal_lib]]
endif
endforeach
endif
# A STATIC module library (link_with) already propagates the link args of
# this_deps, so only the compile/include part is needed here. Re-passing
# the full deps duplicates -l flags and makes ld warn "ignoring duplicate
# libraries: -lsqlite3". expat/zlib are geant4's static-link needs and are
# not module deps, so they are linked here exactly once.
# With shared module libraries (use_sharedl, e.g. the sanitizer build) the
# .so is self-contained and does NOT forward those link args, so symbols an
# example uses but the module library does not (e.g. gboard_example.cc's
# G4VisExecutive) would be unresolved; pass the full this_deps in that case.
if sources.contains('') or use_sharedl
example_deps = this_deps + [expat_dep, zlib_dep]
else
example_compile_deps = declare_dependency(dependencies : this_deps).partial_dependency(compile_args : true, includes : true)
example_deps = [example_compile_deps, expat_dep, zlib_dep]
endif
exe = executable(
name,
example_sources,
install : true,
dependencies : example_deps,
include_directories : all_includes + ('gemc' / this_lib_name) + additional_includes,
link_with : example_link_with,
# Builds the executable as a PIE (position-independent executable).
override_options : ['b_pie=true']
)
test(name,
exe,
env : project_test_env,
args : arguments,
is_parallel : false,
priority : -20)
endforeach
endif
foreach include_dir : additional_includes
if not all_includes.contains(include_dir)
all_includes += include_dir
endif
endforeach
if not all_includes.contains('gemc' / this_lib_name) and not (sources.contains('') and headers.contains(''))
all_includes += 'gemc' / this_lib_name
endif
endforeach
# compile gemc
qrc_gemc_sources = qt6.compile_resources(sources : 'qtresources.qrc')
# Use files() so the source paths resolve from the project root rather than from bin/, where the
# executable() target is declared (see bin/meson.build).
gemc_sources = files('gemc.cc', 'gemc_options.cc')
# Resolve the root-relative include path strings in all_includes into a single, location-independent
# include_directories() object here (in the project-root scope) so it can be used from bin/meson.build,
# where bare path strings would otherwise be resolved relative to bin/ and fail (e.g. "Include dir
# gemc/guts does not exist"). Drop the empty-string default entry that '.' already covers.
gemc_include_dirs = []
foreach inc : all_includes
if inc != ''
gemc_include_dirs += inc
endif
endforeach
gemc_includes = include_directories(gemc_include_dirs)
# The gemc executable is declared in bin/meson.build so that its build output lands at
# build/bin/gemc. Declaring it here with a 'bin/gemc' target name instead triggers a Meson warning
# ("Target has a path separator in its name ... will become a hard error"), and naming it just
# 'gemc' would collide with the build/gemc/ directory created by the subdir('gemc/...') calls above.
subdir('bin')
pkg = import('pkgconfig')
pkgconfig_prog = find_program('pkg-config', 'pkgconf', required : true)
gemc_pkgconfig_env = environment()
gemc_pkgconfig_env.prepend('PKG_CONFIG_PATH', geant4_pc_path)
gemc_pkgconfig_env.prepend('PKG_CONFIG_PATH', clhep_deps.get_variable(pkgconfig : 'libdir') / 'pkgconfig')
clhep_pkgconfig_includedir = run_command(
pkgconfig_prog, '--variable=includedir', 'clhep',
env : gemc_pkgconfig_env,
check : true,
).stdout().strip()
geant4_pkgconfig_includedir = run_command(
pkgconfig_prog, '--variable=includedir', 'geant4_core',
env : gemc_pkgconfig_env,
check : true,
).stdout().strip()
gemc_pkgconfig_cflags = [
'-I' + clhep_pkgconfig_includedir,
'-I' + geant4_pkgconfig_includedir / 'Geant4',
]
gemc_pkgconfig_private_libs = []
foreach private_pkg : ['clhep', 'geant4_core', 'expat', 'zlib', 'sqlite3']
gemc_pkgconfig_private_libs += run_command(
pkgconfig_prog, '--libs', '--static', private_pkg,
env : gemc_pkgconfig_env,
check : true,
).stdout().strip().split()
endforeach
gemc_pkgconfig_variables = ['plugin_link_args=']
if host_machine.system() == 'darwin'
gemc_pkgconfig_variables = ['plugin_link_args=-Wl,-undefined,dynamic_lookup']
endif
pkg.generate(
name : 'gemc',
filebase : 'gemc',
description : project_description,
version : meson.project_version(),
libraries : all_pkgconfig_libs,
libraries_private : [yaml_cpp_dep, assimp_dep] + gemc_pkgconfig_private_libs,
extra_cflags : gemc_pkgconfig_cflags,
variables : gemc_pkgconfig_variables,
)
# test gemc options. Adjust root to fit the geometry
examples_dir = get_option('prefix') + '/examples'
dbhost = ['-sql=' + examples_dir + '/gemc.db']
# TODO: change system with a custom with magnetic field, or use upcoming assign_field option
# If I put b2 here we need to add the diole definitions
gsystem = ['-gsystem="[{name: b2}]"']
general_gemc = ['-verbosity.gemc=2', '-debug.gemc=true', '-check_overlaps=2',
'-verbosity.gaction=2', '-debug.gaction=true',
'-verbosity.grunaction=2', '-debug.grunaction=true',
'-verbosity.grun=2', '-debug.grun=true',
'-verbosity.geventaction=2', '-debug.geventaction=true',
'-nthreads=4', '-n=8',
'-root="G4Box 25*cm 24*cm 40*cm G4_AIR"',
'-gmultipoles="[{name: dipole, pole_number: 2, strength: 2, rotaxis: Z, longitudinal: true}]"',
'-verbosity.eventdispenser=2', '-debug.eventdispenser=true']
root = ['-gstreamer="[{format: root, filename: out}]"']
ascii = ['-gstreamer="[{format: ascii, filename: out}]"']
gstreamer_test = ascii
if root_dep.found()
gstreamer_test = ['-gstreamer="[{format: root, filename: out}, {format: ascii, filename: out} ]"']
endif
gemc_test_sqlite = dbhost + gsystem + general_gemc
test_options = [
{ 'default' : [''] },
{ 'show_phys' : ['-showPhysics'] },
{ 'phys_verbose' : ['-verbosity.gphysics=2', '-debug.gphysics=true'] },
{ 'gui_verbose' : ['-verbosity.dbselect=2', '-debug.dbselect=true',
'-verbosity.gsplash=2', '-debug.gsplash=true'] },
{ 'detector_verbose' : ['-verbosity.gdetector=2', '-debug.gdetector=true',
'-verbosity.gsystem=2', '-debug.gsystem=true',
'-verbosity.g4system=2', '-debug.g4system=true'] },
{ 'gdigitization_verbose' : ['-verbosity.gdigitization=2', '-debug.gdigitization=true',
'-verbosity.plugins=2', '-debug.plugins=true',
'-verbosity.gtranslationtable=2', '-debug.gtranslationtable=true',
'-verbosity.gsd=2', '-debug.gsd=true',
'-verbosity.gdetector=2', '-debug.gdetector=true',
'-verbosity.gtouchable=2', '-debug.gtouchable=true'] },
{ 'gstreamer_verbose' : ['-verbosity.digitized_data=2', '-debug.digitized_data=true',
'-verbosity.gstreamer=2', '-debug.gstreamer=true',
'-verbosity.true_data=2', '-debug.true_data=true'] + gstreamer_test },
{ 'gfield_verbose' : ['-verbosity.gfield=1', '-debug.gfield=true',
'-gmultipoles="[{name: dipole, pole_number: 2, strength: 2, rotaxis: Z, longitudinal: true}]"',
'-global_field=dipole', '-max_field_step=5*mm',
'-gparticle="[{name: e-, p: 2300, theta: 23.0}]"'] }
]
foreach opt_dict : test_options
foreach key, value : opt_dict # each dict has exactly one entry
test_name = 'gemc_' + key # => gemc_default, gemc_show_pys
test_arguments = value
test(
test_name,
gemc,
args : test_arguments + gemc_test_sqlite,
# suite : 'gemc',
is_parallel : false,
timeout : 60, # adjust as needed
priority : -20
)
endforeach
endforeach
subdir('examples')
meson.add_install_script(find_program('python3'), files('ci/install_examples_db.py'))
subdir('tests')
post_install = run_command('echo', 'Installation completed!', check : true)