forked from easybuilders/easybuild-easyblocks
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllvm.py
More file actions
1555 lines (1339 loc) · 74.6 KB
/
Copy pathllvm.py
File metadata and controls
1555 lines (1339 loc) · 74.6 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
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
##
# Copyright 2020-2025 Ghent University
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# https://github.com/easybuilders/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for building and installing LLVM, implemented as an easyblock
@author: Dmitri Gribenko (National Technical University of Ukraine "KPI")
@author: Ward Poelmans (Ghent University)
@author: Alan O'Cais (Juelich Supercomputing Centre)
@author: Maxime Boissonneault (Digital Research Alliance of Canada, Universite Laval)
@author: Simon Branford (University of Birmingham)
@author: Kenneth Hoste (Ghent University)
@author: Davide Grassano (CECAM HQ - Lausanne)
"""
import contextlib
import glob
import os
import re
import stat
from easybuild.framework.easyconfig import CUSTOM
from easybuild.toolchains.compiler.clang import Clang
from easybuild.tools import LooseVersion
from easybuild.tools.utilities import trace_msg
from easybuild.tools.build_log import EasyBuildError, print_msg, print_warning
from easybuild.tools.config import ERROR, IGNORE, SEARCH_PATH_LIB_DIRS, build_option
from easybuild.tools.environment import setvar
from easybuild.tools.filetools import apply_regex_substitutions, change_dir, copy_dir, adjust_permissions
from easybuild.tools.filetools import mkdir, remove_file, symlink, which, write_file, remove_dir
from easybuild.tools.modules import MODULE_LOAD_ENV_HEADERS, get_software_root, get_software_version
from easybuild.tools.run import run_shell_cmd, EasyBuildExit
from easybuild.tools.systemtools import AARCH32, AARCH64, POWER, RISCV64, X86_64, POWER_LE
from easybuild.tools.systemtools import get_cpu_architecture, get_cpu_family, get_shared_lib_ext
from easybuild.easyblocks.generic.cmakemake import CMakeMake, get_cmake_python_config_dict
BUILD_TARGET_AMDGPU = 'AMDGPU'
BUILD_TARGET_NVPTX = 'NVPTX'
LLVM_TARGETS = [
'AArch64', BUILD_TARGET_AMDGPU, 'ARM', 'AVR', 'BPF', 'Hexagon', 'Lanai', 'LoongArch', 'Mips', 'MSP430',
BUILD_TARGET_NVPTX, 'PowerPC', 'RISCV', 'Sparc', 'SPIRV', 'SystemZ', 'VE', 'WebAssembly', 'X86', 'XCore',
'all'
]
LLVM_EXPERIMENTAL_TARGETS = [
'ARC', 'CSKY', 'DirectX', 'M68k', 'Xtensa',
]
ALL_TARGETS = LLVM_TARGETS + LLVM_EXPERIMENTAL_TARGETS
DEFAULT_TARGETS_MAP = {
AARCH32: ['ARM'],
AARCH64: ['AArch64'],
POWER: ['PowerPC'],
RISCV64: ['RISCV'],
X86_64: ['X86'],
}
AVAILABLE_OFFLOAD_DLOPEN_PLUGIN_OPTIONS = [
'cuda',
'amdgpu'
]
GCC_DEPENDENCY_OPTS_DEFAULT = {
'CLANG_DEFAULT_CXX_STDLIB': 'libc++',
'CLANG_DEFAULT_RTLIB': 'compiler-rt',
# Moved to general_opts for ease of building with openmp offload (or other multi-stage builds)
# 'CLANG_DEFAULT_LINKER': 'lld',
'CLANG_DEFAULT_UNWINDLIB': 'libunwind',
'COMPILER_RT_BUILD_GWP_ASAN': 'Off',
'COMPILER_RT_ENABLE_INTERNAL_SYMBOLIZER': 'On',
'COMPILER_RT_ENABLE_STATIC_UNWINDER': 'On', # https://lists.llvm.org/pipermail/llvm-bugs/2016-July/048424.html
'COMPILER_RT_USE_BUILTINS_LIBRARY': 'On',
'COMPILER_RT_USE_LIBCXX': 'On',
'COMPILER_RT_USE_LLVM_UNWINDER': 'On',
'LIBCXX_CXX_ABI': 'libcxxabi',
'LIBCXX_DEFAULT_ABI_LIBRARY': 'libcxxabi',
# Needed as libatomic could not be present on the system (compilation and tests will succeed because of the
# GCCcore builddep, but usage/sanity check will fail due to missing libatomic)
'LIBCXX_HAS_ATOMIC_LIB': 'NO',
'LIBCXX_HAS_GCC_S_LIB': 'Off',
'LIBCXX_USE_COMPILER_RT': 'On',
'LIBCXXABI_HAS_GCC_S_LIB': 'Off',
'LIBCXXABI_USE_LLVM_UNWINDER': 'On',
'LIBCXXABI_USE_COMPILER_RT': 'On',
'LIBUNWIND_HAS_GCC_S_LIB': 'Off',
'LIBUNWIND_USE_COMPILER_RT': 'On',
# Libxml2 from system gets automatically detected and linked in bringing dependencies from stdc++, gcc_s, icuuc, etc
# Moved to a check at the configure step. See https://github.com/easybuilders/easybuild-easyconfigs/issues/22491
# 'LLVM_ENABLE_LIBXML2': 'Off',
'SANITIZER_USE_STATIC_LLVM_UNWINDER': 'On',
}
DISABLE_WERROR_OPTS = {
'BENCHMARK_ENABLE_WERROR': 'Off',
'COMPILER_RT_ENABLE_WERROR': 'Off',
'FLANG_ENABLE_WERROR': 'Off',
'LIBC_WNO_ERROR': 'On',
'LIBCXX_ENABLE_WERROR': 'Off',
'LIBUNWIND_ENABLE_WERROR': 'Off',
'LLVM_ENABLE_WERROR': 'Off',
'OPENMP_ENABLE_WERROR': 'Off',
}
GENERAL_OPTS = {
'CMAKE_VERBOSE_MAKEFILE': 'ON',
'LLVM_INCLUDE_BENCHMARKS': 'OFF',
'LLVM_INSTALL_UTILS': 'ON',
# If EB is launched from a venv, avoid giving priority to the venv's python
'Python3_FIND_VIRTUALENV': 'STANDARD',
}
@contextlib.contextmanager
def _wrap_env(path="", ld_path=""):
"""Wrap the environment with $PATH and $LD_LIBRARY_PATH."""
orig_path = os.getenv('PATH', '')
orig_ld_library_path = os.getenv('LD_LIBRARY_PATH', '')
path = ':'.join(filter(None, [path, orig_path]))
ld_path = ':'.join(filter(None, [ld_path, orig_ld_library_path]))
setvar('PATH', path)
setvar('LD_LIBRARY_PATH', ld_path)
try:
yield
finally:
setvar('PATH', orig_path)
setvar('LD_LIBRARY_PATH', orig_ld_library_path)
def get_arch_prefix():
"""Return the architecture prefix"""
arch = get_cpu_architecture()
if arch == POWER:
if get_cpu_family() == POWER_LE:
return 'powerpc64le'
else:
return 'powerpc64'
else:
return arch.lower()
class EB_LLVM(CMakeMake):
"""
Support for building and installing LLVM
"""
minimal_conflicts = [
'build_bolt',
'build_clang_extras',
'build_lld',
'build_lldb',
'build_openmp',
'build_openmp_tools',
'build_runtimes',
'bootstrap',
'full_llvm',
'python_bindings',
'use_polly',
]
# Create symlink between equivalent host triples, useful so that other build processes that relies on older
# triple names can still work when passing the old name to --target
symlink_lst = [
('x86_64-unknown-linux-gnu', 'x86_64-pc-linux'),
('x86_64-unknown-linux-gnu', 'x86_64-pc-linux-gnu'),
]
# From LLVM 19, GCC_INSTALL_PREFIX is not supported anymore to hardcode the GCC installation path into the binaries;
# Now every compilers needs a .cfg file with the --gcc-install-dir option
# This list tells which compilers need to have a .cfg file created
# NOTE: flang is the expected name also for the 'flang-new' compiler
cfg_compilers = ['clang', 'clang++', 'flang']
@staticmethod
def extra_options():
extra_vars = CMakeMake.extra_options()
extra_vars.update({
'amd_gfx_list': [None, "List of AMDGPU targets to build for.", CUSTOM],
'assertions': [False, "Enable assertions. Helps to catch bugs in Clang.", CUSTOM],
'bootstrap': [True, "Build LLVM-Clang using itself", CUSTOM],
'build_bolt': [False, "Build the LLVM bolt binary optimizer", CUSTOM],
'build_clang_extras': [False, "Build the LLVM Clang extra tools", CUSTOM],
'build_lld': [False, "Build the LLVM lld linker", CUSTOM],
'build_lldb': [False, "Build the LLVM lldb debugger", CUSTOM],
'build_openmp': [True, "Build the LLVM OpenMP runtime", CUSTOM],
'build_openmp_offload': [True, "Build the LLVM OpenMP offload runtime", CUSTOM],
'build_openmp_tools': [True, "Build the LLVM OpenMP tools interface", CUSTOM],
'build_runtimes': [False, "Build the LLVM runtimes (compiler-rt, libunwind, libcxx, libcxxabi)", CUSTOM],
'build_targets': [None, "Build targets for LLVM (host architecture if None). Possible values: " +
', '.join(ALL_TARGETS), CUSTOM],
'debug_tests': [True, "Enable verbose output for tests", CUSTOM],
'disable_werror': [False, "Disable -Werror for all projects", CUSTOM],
'enable_rtti': [True, "Enable RTTI", CUSTOM],
'full_llvm': [False, "Build LLVM without any dependency", CUSTOM],
'minimal': [False, "Build LLVM only", CUSTOM],
'python_bindings': [False, "Install python bindings", CUSTOM],
'skip_all_tests': [False, "Skip running of tests", CUSTOM],
'skip_sanitizer_tests': [True, "Do not run the sanitizer tests", CUSTOM],
'test_suite_ignore_patterns': [None, "List of test to ignore (if the string matches)", CUSTOM],
'test_suite_max_failed': [0, "Maximum number of failing tests (does not count allowed failures)", CUSTOM],
'test_suite_timeout_single': [None, "Timeout for each individual test in the test suite", CUSTOM],
'test_suite_timeout_total': [None, "Timeout for total running time of the testsuite", CUSTOM],
'use_pic': [True, "Build with Position Independent Code (PIC)", CUSTOM],
'usepolly': [None, "DEPRECATED, alias for 'use_polly'", CUSTOM],
'use_polly': [None, "Build Clang with polly, disabled by default", CUSTOM],
})
return extra_vars
def __init__(self, *args, **kwargs):
"""Initialize LLVM-specific variables."""
super().__init__(*args, **kwargs)
if self.cfg['usepolly'] is not None:
self.log.deprecated("Use of easyconfig parameter 'usepolly', replace by 'use_polly'", '6.0')
if self.cfg['use_polly'] is None:
self.cfg['use_polly'] = self.cfg['usepolly']
else:
# Do not overwrite value set via the new name
print_warning("Both 'usepolly' and 'use_polly' are set, please use only 'use_polly'")
self.llvm_obj_dir_stage1 = None
self.llvm_obj_dir_stage2 = None
self.llvm_obj_dir_stage3 = None
self.intermediate_projects = ['llvm', 'clang']
self.intermediate_runtimes = ['compiler-rt', 'libunwind', 'libcxx', 'libcxxabi']
if not self.cfg['minimal']:
self.final_projects = ['llvm', 'mlir', 'clang', 'flang']
else:
self.final_projects = ['llvm']
self.final_runtimes = []
self.gcc_prefix = None
self.runtimes_cmake_args = {
'CMAKE_C_COMPILER': [],
'CMAKE_C_FLAGS': [],
'CMAKE_CXX_COMPILER': [],
'CMAKE_CXX_FLAGS': [],
'CMAKE_EXE_LINKER_FLAGS': [],
}
self.offload_targets = ['host']
self.host_triple = None
self.dynamic_linker = None
# Shared
off_opts, on_opts = [], []
self.build_shared = self.cfg.get('build_shared_libs', False)
if self.build_shared:
self.cfg['build_shared_libs'] = None
on_opts.extend(['LLVM_BUILD_LLVM_DYLIB', 'LLVM_LINK_LLVM_DYLIB', 'LIBCXX_ENABLE_SHARED',
'LIBCXXABI_ENABLE_SHARED', 'LIBUNWIND_ENABLE_SHARED'])
else:
off_opts.extend(['LIBCXX_ENABLE_ABI_LINKER_SCRIPT', 'LIBCXX_ENABLE_SHARED', 'LIBCXXABI_ENABLE_SHARED',
'LIBUNWIND_ENABLE_SHARED', 'LLVM_BUILD_LLVM_DYLIB', 'LLVM_LINK_LLVM_DYLIB'])
on_opts.extend(['LIBCXX_ENABLE_STATIC', 'LIBCXX_ENABLE_STATIC_ABI_LIBRARY', 'LIBCXXABI_ENABLE_STATIC',
'LIBUNWIND_ENABLE_STATIC'])
# RTTI
if self.cfg['enable_rtti']:
on_opts.extend(['LLVM_ENABLE_RTTI', 'LLVM_REQUIRES_RTTI'])
# Does not work yet with Flang
# on_opts.append('LLVM_ENABLE_EH')
if self.cfg['use_pic']:
on_opts.append('CMAKE_POSITION_INDEPENDENT_CODE')
self.general_opts = GENERAL_OPTS.copy()
for opt in on_opts:
self.general_opts[opt] = 'ON'
for opt in off_opts:
self.general_opts[opt] = 'OFF'
self.full_llvm = self.cfg['full_llvm']
if self.cfg['minimal']:
conflicts = [_ for _ in self.minimal_conflicts if self.cfg[_]]
if conflicts:
raise EasyBuildError("Minimal build conflicts with '%s'", ', '.join(conflicts))
# Other custom options
if self.full_llvm:
if not self.cfg['bootstrap']:
raise EasyBuildError("Full LLVM build requires bootstrap build")
if not self.cfg['build_lld']:
raise EasyBuildError("Full LLVM build requires building lld")
if not self.cfg['build_runtimes']:
raise EasyBuildError("Full LLVM build requires building runtimes")
self.log.info("Building LLVM without any GCC dependency")
if self.cfg['disable_werror']:
self.general_opts.update(DISABLE_WERROR_OPTS)
if self.cfg['build_runtimes']:
self.final_runtimes += ['compiler-rt', 'libunwind', 'libcxx', 'libcxxabi']
if self.cfg['build_openmp']:
self.final_projects.append('openmp')
if self.cfg['build_openmp_offload']:
if not self.cfg['build_openmp']:
raise EasyBuildError("Building OpenMP offload requires building OpenMP runtime")
# LLVM 19 added a new runtime target for explicit offloading
# https://discourse.llvm.org/t/llvm-19-1-0-no-library-libomptarget-nvptx-sm-80-bc-found/81343
if LooseVersion(self.version) >= LooseVersion('19'):
self.log.debug("Explicitly enabling OpenMP offloading for LLVM >= 19")
self.final_runtimes.append('offload')
else:
self.log.warning("OpenMP offloading is included with the OpenMP runtime for LLVM < 19")
if self.cfg['build_openmp_tools']:
if not self.cfg['build_openmp']:
raise EasyBuildError("Building OpenMP tools requires building OpenMP runtime")
if self.cfg['use_polly']:
self.final_projects.append('polly')
if self.cfg['build_clang_extras']:
self.final_projects.append('clang-tools-extra')
if self.cfg['build_lld']:
self.intermediate_projects.append('lld')
self.final_projects.append('lld')
# This should be the default to make offload multi-stage compilations easier
self.general_opts['CLANG_DEFAULT_LINKER'] = 'lld'
self.general_opts['FLANG_DEFAULT_LINKER'] = 'lld'
self.remove_gcc_dependency_opts = GCC_DEPENDENCY_OPTS_DEFAULT.copy()
if self.cfg['build_lldb']:
self.final_projects.append('lldb')
if self.full_llvm:
self.remove_gcc_dependency_opts['LLDB_ENABLE_LIBXML2'] = 'Off'
self.remove_gcc_dependency_opts['LLDB_ENABLE_LZMA'] = 'Off'
self.remove_gcc_dependency_opts['LLDB_ENABLE_PYTHON'] = 'Off'
if self.cfg['build_bolt']:
self.final_projects.append('bolt')
# Fix for https://github.com/easybuilders/easybuild-easyblocks/issues/3689
if LooseVersion(self.version) < LooseVersion('16'):
self.general_opts['LLVM_INCLUDE_GO_TESTS'] = 'OFF'
self.log.info("Final projects to build: %s", ', '.join(self.final_projects))
self.log.info("Final runtimes to build: %s", ', '.join(self.final_runtimes))
self._cmakeopts = {}
self._cfgopts = list(filter(None, self.cfg.get('configopts', '').split()))
@property
def llvm_src_dir(self):
"""Return root source directory of LLVM (containing all components)"""
# LLVM is the first source so we already have this in start_dir. Might be changed later
return self.start_dir
def _configure_build_targets(self):
# list of CUDA compute capabilities to use can be specifed in two ways (where (2) overrules (1)):
# (1) in the easyconfig file, via the custom cuda_compute_capabilities;
# (2) in the EasyBuild configuration, via --cuda-compute-capabilities configuration option;
cuda_cc_list = build_option('cuda_compute_capabilities') or self.cfg['cuda_compute_capabilities'] or []
cuda_toolchain = hasattr(self.toolchain, 'COMPILER_CUDA_FAMILY')
amd_gfx_list = self.cfg['amd_gfx_list'] or []
# List of (lower-case) dependencies
self.deps = [dep['name'].lower() for dep in self.cfg.dependencies()]
# Build targets
build_targets = self.cfg['build_targets'] or []
if not build_targets:
self.log.debug("No build targets specified, using default detection")
arch = get_cpu_architecture()
if arch not in DEFAULT_TARGETS_MAP:
raise EasyBuildError("No default build targets defined for CPU architecture %s.", arch)
build_targets += DEFAULT_TARGETS_MAP[arch]
# If CUDA is included as a dep, add NVPTX as a target
# There are (old) toolchains with CUDA as part of the toolchain
if 'cuda' in self.deps or cuda_toolchain:
self.log.info("CUDA dependency detected, adding NVPTX as a target")
build_targets.append(BUILD_TARGET_NVPTX)
elif cuda_cc_list:
self.log.info("CUDA compute capabilities specified, adding NVPTX as a target")
build_targets.append(BUILD_TARGET_NVPTX)
# For AMDGPU support during runtime we need ROCR-Runtime and ROCT-Thunk-Interface. While split into
# separate packages pre ROCm 6.2, it is now combined into ROCR-Runtime. As ROCR-Thunk-Interface was a
# dependency for ROCR-Runtime before, checking for ROCR-Runtime as a dependency is sufficient.
# Generally, ROCR-Runtime is not a hard dependency for LLVM. If not found, LLVM can still build
# an offload-capable compiler runtime, and will try to dlopen the required libraries at runtime.
# Therefore, also allow the build without ROCR-Runtime, with only the desired architecture list being set.
# https://openmp.llvm.org/SupportAndFAQ.html#q-how-to-build-an-openmp-amdgpu-offload-capable-compiler
if 'rocr-runtime' in self.deps:
self.log.info("ROCR-Runtime dependency detected, adding AMDGPU as a target")
build_targets.append(BUILD_TARGET_AMDGPU)
elif amd_gfx_list:
self.log.info("AMD GPU list specified, adding AMDGPU as a target")
build_targets.append(BUILD_TARGET_AMDGPU)
self.cfg['build_targets'] = build_targets
self.log.debug("Using %s as default build targets for CPU architecture %s.", build_targets, arch)
unknown_targets = set(build_targets) - set(ALL_TARGETS)
if unknown_targets:
raise EasyBuildError("Some of the chosen build targets (%s) are not in %s.",
', '.join(unknown_targets), ', '.join(ALL_TARGETS))
exp_targets = set(build_targets) & set(LLVM_EXPERIMENTAL_TARGETS)
if exp_targets:
self.log.warning("Experimental targets %s are being used.", ', '.join(exp_targets))
all_target_cond = 'all' in build_targets
self.nvptx_target_cond = (BUILD_TARGET_NVPTX in build_targets) or all_target_cond
self.amdgpu_target_cond = (BUILD_TARGET_AMDGPU in build_targets) or all_target_cond
if ('cuda' in self.deps or cuda_toolchain) and not self.nvptx_target_cond:
raise EasyBuildError("CUDA dependency detected, but NVPTX not in manually specified build targets")
if cuda_cc_list and not self.nvptx_target_cond:
raise EasyBuildError(
"CUDA compute capabilities specified, but NVPTX not in manually specified build targets"
)
if 'rocr-runtime' in self.deps and not self.amdgpu_target_cond:
raise EasyBuildError(
"ROCR-Runtime dependency detected, but AMDGPU not in manually specified build targets"
)
if amd_gfx_list and not self.amdgpu_target_cond:
raise EasyBuildError("AMD GPU list specified, but AMDGPU not in manually specified build targets")
self.build_targets = build_targets or []
# Enable offload targets for LLVM >= 18
self.cuda_cc = []
self.amd_gfx = []
if self.cfg['build_openmp_offload'] and LooseVersion(self.version) >= LooseVersion('18'):
if self.nvptx_target_cond:
if LooseVersion(self.version) < LooseVersion('20') and not cuda_cc_list:
raise EasyBuildError(
f"LLVM < 20 requires 'cuda_compute_capabilities' to build with {BUILD_TARGET_NVPTX}"
)
self.cuda_cc = [cc.replace('.', '') for cc in cuda_cc_list]
self.offload_targets += ['cuda']
self.log.debug("Enabling `cuda` offload target")
if self.amdgpu_target_cond:
if LooseVersion(self.version) < LooseVersion('20') and not amd_gfx_list:
raise EasyBuildError(f"LLVM < 20 requires 'amd_gfx_list' to build with {BUILD_TARGET_AMDGPU}")
self.amd_gfx = amd_gfx_list
self.offload_targets += ['amdgpu'] # Used for LLVM >= 19
self.log.debug("Enabling `amdgpu` offload target")
self.general_opts['CMAKE_BUILD_TYPE'] = self.build_type
self.general_opts['LLVM_TARGETS_TO_BUILD'] = self.list_to_cmake_arg(build_targets)
self._cmakeopts = {}
self._cfgopts = list(filter(None, self.cfg.get('configopts', '').split()))
def prepare_step(self, *args, **kwargs):
"""Prepare step, modified to ensure install dir is deleted before building"""
super().prepare_step(*args, **kwargs)
# re-create installation dir (deletes old installation),
# Needed to ensure hardcoded rpath do not point to old installation during runtime builds and testing
self.make_installdir()
def _add_cmake_runtime_args(self):
"""Generate the value for 'RUNTIMES_CMAKE_ARGS' and add it to the cmake options."""
args = []
for key, val in self.runtimes_cmake_args.items():
if isinstance(val, list):
val = ' '.join(val)
if val:
args.append(f'-D{key}={val}')
if args:
self._cmakeopts['RUNTIMES_CMAKE_ARGS'] = self.list_to_cmake_arg(args)
def _configure_general_build(self):
"""General configuration step for LLVM."""
self._cmakeopts.update(self.general_opts)
self._add_cmake_runtime_args()
def _configure_intermediate_build(self):
"""Configure the intermediate stages of the build."""
self._cmakeopts['LLVM_ENABLE_PROJECTS'] = self.list_to_cmake_arg(self.intermediate_projects)
self._cmakeopts['LLVM_ENABLE_RUNTIMES'] = self.list_to_cmake_arg(self.intermediate_runtimes)
def _configure_final_build(self):
"""Configure the final stage of the build."""
self._cmakeopts['LLVM_ENABLE_PROJECTS'] = self.list_to_cmake_arg(self.final_projects)
self._cmakeopts['LLVM_ENABLE_RUNTIMES'] = self.list_to_cmake_arg(self.final_runtimes)
hwloc_root = get_software_root('hwloc')
if hwloc_root:
self.log.info("Using %s as hwloc root", hwloc_root)
self._cmakeopts['LIBOMP_USE_HWLOC'] = 'ON'
self._cmakeopts['LIBOMP_HWLOC_INSTALL_DIR'] = hwloc_root
if 'openmp' in self.final_projects:
if self.cfg['build_openmp_offload']:
# Force dlopen of the GPU libraries at runtime, not using existing libraries
if LooseVersion(self.version) >= LooseVersion('19'):
self.runtimes_cmake_args['LIBOMPTARGET_PLUGINS_TO_BUILD'] = '%s' % '|'.join(self.offload_targets)
dlopen_plugins = set(self.offload_targets) & set(AVAILABLE_OFFLOAD_DLOPEN_PLUGIN_OPTIONS)
if dlopen_plugins:
self._cmakeopts['LIBOMPTARGET_DLOPEN_PLUGINS'] = self.list_to_cmake_arg(dlopen_plugins)
else:
if self.amdgpu_target_cond:
self._cmakeopts['LIBOMPTARGET_FORCE_DLOPEN_LIBHSA'] = 'ON'
if self.nvptx_target_cond:
self._cmakeopts['LIBOMPTARGET_FORCE_DLOPEN_LIBCUDA'] = 'ON'
self._cmakeopts['OPENMP_ENABLE_LIBOMPTARGET'] = 'ON'
self._cmakeopts['LIBOMP_INSTALL_ALIASES'] = 'OFF'
if not self.cfg['build_openmp_tools']:
self._cmakeopts['OPENMP_ENABLE_OMPT_TOOLS'] = 'OFF'
# Make sure tests are not running with more than 'parallel' tasks
parallel = self.cfg.parallel
if not build_option('mpi_tests'):
parallel = 1
lit_args = [f'-j {parallel}']
if self.cfg['debug_tests']:
lit_args += ['-v']
timeout_single = self.cfg['test_suite_timeout_single']
if timeout_single:
lit_args += ['--timeout', str(timeout_single)]
timeout_total = self.cfg['test_suite_timeout_total']
if timeout_total:
lit_args += ['--max-time', str(timeout_total)]
self._cmakeopts['LLVM_LIT_ARGS'] = '"%s"' % ' '.join(lit_args)
if self.cfg['use_polly']:
self._cmakeopts['LLVM_POLLY_LINK_INTO_TOOLS'] = 'ON'
if not self.cfg['skip_all_tests']:
self._cmakeopts['LLVM_INCLUDE_TESTS'] = 'ON'
self._cmakeopts['LLVM_BUILD_TESTS'] = 'ON'
@staticmethod
def _get_gcc_prefix():
"""Get the GCC prefix for the build."""
arch = get_arch_prefix()
gcc_root = get_software_root('GCCcore')
gcc_version = get_software_version('GCCcore')
# If that doesn't work, try with GCC
if gcc_root is None:
gcc_root = get_software_root('GCC')
gcc_version = get_software_version('GCC')
# If that doesn't work either, print error and exit
if gcc_root is None:
raise EasyBuildError("Can't find GCC or GCCcore to use")
pattern = os.path.join(gcc_root, 'lib', 'gcc', f'{arch}-*', gcc_version)
matches = glob.glob(pattern)
if not matches:
raise EasyBuildError("Can't find GCC version %s for architecture %s in %s", gcc_version, arch, pattern)
gcc_prefix = os.path.abspath(matches[0])
return gcc_root, gcc_prefix
@staticmethod
def _get_gcc_libpath(strict=False):
"""Get the GCC library path for the build."""
gcc_root = get_software_root('GCCcore')
if gcc_root is None:
gcc_root = get_software_root('GCC')
if gcc_root is None:
if strict:
raise EasyBuildError("Can't find GCC or GCCcore to use")
else:
print_msg("Can't find GCC or GCCcore to use, skipping setting of GCC library path", level=IGNORE)
return ''
return os.path.join(gcc_root, 'lib64')
def _set_gcc_prefix(self):
"""Set the GCC prefix for the build."""
if self.gcc_prefix is None:
gcc_root, gcc_prefix = self._get_gcc_prefix()
# --gcc-toolchain and --gcc-install-dir for flang are not supported before LLVM 19
# https://github.com/llvm/llvm-project/pull/87360
if LooseVersion(self.version) < LooseVersion('19'):
self.log.debug("Using GCC_INSTALL_PREFIX")
self.general_opts['GCC_INSTALL_PREFIX'] = gcc_root
else:
# See https://github.com/llvm/llvm-project/pull/85891#issuecomment-2021370667
self.log.debug("Using '--gcc-install-dir' in CMAKE_C_FLAGS and CMAKE_CXX_FLAGS")
self.runtimes_cmake_args['CMAKE_C_FLAGS'] += ['--gcc-install-dir=%s' % gcc_prefix]
self.runtimes_cmake_args['CMAKE_CXX_FLAGS'] += ['--gcc-install-dir=%s' % gcc_prefix]
self.gcc_prefix = gcc_prefix
self.log.debug("Using %s as the gcc install location", self.gcc_prefix)
def _set_dynamic_linker(self):
"""Set the dynamic linker for the build if not the default one."""
if self.sysroot:
linkers = glob.glob(os.path.join(self.sysroot, '**', 'ld-*.so*'))
for linker in linkers:
if os.path.isfile(linker) and not os.path.islink(linker):
self.log.info("Using linker %s from sysroot", linker)
self.dynamic_linker = linker
break
else:
msg = f"No linker found in sysroot {self.sysroot}, using default linker"
trace_msg(msg)
self.log.warning(msg)
def _update_test_ignore_patterns(self):
"""Update the ignore patterns based on known ignorable test failures when running with specific LLVM versions
or with specific dependencies/options."""
self.ignore_patterns = self.cfg['test_suite_ignore_patterns'] or []
new_ignore_patterns = []
if self.sysroot:
# Some tests will run a FileCheck on the output of `clang -v` for `-internal-externc-isystem /usr/include`
# where the path is hardcoded. If sysroot is set we replace that path by prepending the sysroot to it.
# The changes needed varies from file to file and are not the same across versions.
# Since this seems to be more of a problem with the test-suite settings than using the compilers
# we can probably safely ignore these tests.
known_driver_files = [
'baremetal.cpp', 'csky-toolchain.c', 'freebsd-include-paths.c',
'haiku.c', 'hexagon-toolchain-elf.c', 'hexagon-toolchain-linux.c',
'mips-cs.cpp', 'mips-fsf.cpp', 'mips-img-v2.cpp', 'mips-img.cpp',
'riscv32-toolchain-extra.c', 'riscv64-toolchain-extra.c',
'rocm-detect.hip',
]
known_frontend_files = [
'warning-poison-system-directories.c'
]
for file in known_driver_files:
new_ignore_patterns.append(f'Clang :: Driver/{file}')
for file in known_frontend_files:
new_ignore_patterns.append(f'Clang :: Frontend/{file}')
# Test related to config files, can fail due to overriding the default config file that we set to
# ensure correct working with sysroot builds
new_ignore_patterns.append('Flang :: Driver/config-file.f90')
# See https://github.com/easybuilders/easybuild-easyblocks/pull/3741#issuecomment-2944852391
# System-related failures due to /etc/timezone behavior
new_ignore_patterns.append('llvm-libc++-shared.cfg.in :: std/time/time.zone/')
# Can give different behavior based on system Scrt1.o
new_ignore_patterns.append('Flang :: Driver/missing-input.f90')
# See https://github.com/llvm/llvm-project/issues/140024
if LooseVersion(self.version) <= LooseVersion('20.1.5'):
new_ignore_patterns.append('LLVM :: CodeGen/Hexagon/isel/pfalse-v4i1.ll')
self.ignore_patterns += new_ignore_patterns
self.log.info(f"Ignore patterns added due to known and ignorable test failures: {new_ignore_patterns}")
def configure_step(self):
"""
Install extra tools in bin/; enable zlib if it is a dep; optionally enable rtti; and set the build target
"""
# Allow running with older versions of LLVM for minimal builds in order to replace EB_LLVM easyblock
if not self.cfg['minimal'] and LooseVersion(self.version) < LooseVersion('18.1.6'):
raise EasyBuildError("LLVM version %s is not supported, please use version 18.1.6 or newer", self.version)
# Allow running with older versions of LLVM for minimal builds in order to replace EB_LLVM easyblock
gcc_version = get_software_version('GCCcore')
if not self.cfg['minimal'] and LooseVersion(gcc_version) < LooseVersion('13'):
raise EasyBuildError("LLVM %s requires GCC 13 or newer, found %s", self.version, gcc_version)
# Lit is needed for running tests-suite
lit_root = get_software_root('lit')
if not lit_root:
if not self.cfg['skip_all_tests']:
raise EasyBuildError("Can't find 'lit', needed for running tests-suite")
timeouts = self.cfg['test_suite_timeout_single'] or self.cfg['test_suite_timeout_total']
if not self.cfg['skip_all_tests'] and timeouts:
psutil_root = get_software_root('psutil')
if not psutil_root:
raise EasyBuildError("Can't find 'psutil', needed for running tests-suite with timeout")
# Parallel build
self.make_parallel_opts = ""
if self.cfg.parallel:
self.make_parallel_opts = f"-j {self.cfg.parallel}"
self._configure_build_targets()
# Sysroot
self.sysroot = build_option('sysroot')
if self.sysroot:
if LooseVersion(self.version) < LooseVersion('19'):
raise EasyBuildError("Using sysroot is not supported by EasyBuild for LLVM < 19")
self.general_opts['DEFAULT_SYSROOT'] = self.sysroot
self.general_opts['CMAKE_SYSROOT'] = self.sysroot
self._set_dynamic_linker()
trace_msg(f"Using '{self.dynamic_linker}' as dynamic linker from sysroot {self.sysroot}")
# CMAKE_INSTALL_PREFIX and LLVM start directory are set here instead of in __init__ to
# ensure this easyblock can be used as a Bundle component, see
# https://github.com/easybuilders/easybuild-easyblocks/issues/3680
self.general_opts['CMAKE_INSTALL_PREFIX'] = self.installdir
# Bootstrap
self.llvm_obj_dir_stage1 = os.path.join(self.builddir, 'llvm.obj.1')
if self.cfg['bootstrap']:
self.log.info("Initialising for bootstrap build.")
self.llvm_obj_dir_stage2 = os.path.join(self.builddir, 'llvm.obj.2')
self.llvm_obj_dir_stage3 = os.path.join(self.builddir, 'llvm.obj.3')
self.final_dir = self.llvm_obj_dir_stage3
mkdir(self.llvm_obj_dir_stage2)
mkdir(self.llvm_obj_dir_stage3)
else:
self.log.info("Initialising for single stage build.")
self.final_dir = self.llvm_obj_dir_stage1
self.general_opts['LLVM_ENABLE_ASSERTIONS'] = 'ON' if self.cfg['assertions'] else 'OFF'
# Dependencies based persistent options (should be reused across stages)
# Libxml2
xml2_root = get_software_root('libxml2')
# Explicitly disable libxml2 if not found to avoid linking against system libxml2
if xml2_root:
if self.full_llvm:
self.log.warning("LLVM is being built in 'full_llvm' mode, libxml2 will not be used")
self.general_opts['LLVM_ENABLE_LIBXML2'] = 'OFF'
else:
self.general_opts['LLVM_ENABLE_LIBXML2'] = 'ON'
else:
self.general_opts['LLVM_ENABLE_LIBXML2'] = 'OFF'
# If 'ON', risk finding a system zlib or zstd leading to including /usr/include as -isystem that can lead
# to errors during compilation of 'offload.tools.kernelreplay' due to the inclusion of LLVMSupport (19.x)
self.general_opts['LLVM_ENABLE_ZLIB'] = 'ON' if get_software_root('zlib') else 'OFF'
self.general_opts['LLVM_ENABLE_ZSTD'] = 'ON' if get_software_root('zstd') else 'OFF'
# Should not use system SWIG if present
self.general_opts['LLDB_ENABLE_SWIG'] = 'ON' if get_software_root('SWIG') else 'OFF'
# Avoid using system `gdb` in case it is not provided as a dependency
# This could cause the wrong sysroot/dynamic linker being picked up in a sysroot build causing tests to fail
self.general_opts['LIBOMP_OMPD_GDB_SUPPORT'] = 'ON' if get_software_root('GDB') else 'OFF'
z3_root = get_software_root("Z3")
if z3_root:
self.log.info("Using %s as Z3 root", z3_root)
self.general_opts['LLVM_ENABLE_Z3_SOLVER'] = 'ON'
self.general_opts['LLVM_Z3_INSTALL_DIR'] = z3_root
else:
self.general_opts['LLVM_ENABLE_Z3_SOLVER'] = 'OFF'
# update ignore patterns for ignorable test failures
self._update_test_ignore_patterns()
python_opts = get_cmake_python_config_dict()
self.general_opts.update(python_opts)
self.runtimes_cmake_args.update(python_opts)
if self.cfg['bootstrap']:
self._configure_intermediate_build()
else:
self._configure_final_build()
if self.cfg['skip_sanitizer_tests'] and build_option('strict') != ERROR:
self.log.info("Disabling the sanitizer tests")
self.disable_sanitizer_tests()
# Remove python bindings tests causing uncaught exception in the build
cmakelists_tests = os.path.join(self.start_dir, 'clang', 'CMakeLists.txt')
regex_subs = []
regex_subs.append((r'add_subdirectory\(bindings/python/tests\)', ''))
apply_regex_substitutions(cmakelists_tests, regex_subs)
# Remove flags disabling the use of configuration files during compiler-rt tests as we in general rely on them
# (see https://github.com/easybuilders/easybuild-easyblocks/pull/3741#issuecomment-2939404304)
lit_cfg_file = os.path.join(self.start_dir, 'compiler-rt', 'test', 'lit.common.cfg.py')
regex_subs = [
(r'^if config.has_no_default_config_flag:', ''),
(r'^\s*config.environment\["CLANG_NO_DEFAULT_CONFIG"\] = "1"', '')
]
apply_regex_substitutions(lit_cfg_file, regex_subs)
self._set_gcc_prefix()
# If we don't want to build with CUDA (not in dependencies) trick CMakes FindCUDA module into not finding it by
# using the environment variable which is used as-is and later checked for a falsy value when determining
# whether CUDA was found
if not get_software_root('CUDA'):
setvar('CUDA_NVCC_EXECUTABLE', 'IGNORE')
if self.cfg['build_openmp_offload'] and LooseVersion('19') <= LooseVersion(self.version) < LooseVersion('20'):
gpu_archs = []
gpu_archs += ['sm_%s' % cc for cc in self.cuda_cc]
gpu_archs += self.amd_gfx
if gpu_archs:
self._cmakeopts['LIBOMPTARGET_DEVICE_ARCHITECTURES'] = self.list_to_cmake_arg(gpu_archs)
self._configure_general_build()
self.add_cmake_opts()
src_dir = os.path.join(self.start_dir, 'llvm')
output = super().configure_step(builddir=self.llvm_obj_dir_stage1, srcdir=src_dir)
# Get LLVM_HOST_TRIPLE (e.g. x86_64-unknown-linux-gnu) from the output
for line in output.splitlines():
if 'llvm host triple' in line.lower():
self.host_triple = line.split(':')[1].strip()
break
else:
# LLVM_HOST_TRIPLE needs to be set when building runtimes or bootstrapping.
if self.cfg['build_runtimes'] or self.cfg['bootstrap']:
raise EasyBuildError("`LLVM_HOST_TRIPLE` not found in the output of the configure step")
# Otherwise it can be inferred a posteriori from the install directory
else:
self.log.warning("`LLVM_HOST_TRIPLE` not found in the output of the configure step")
if not self.cfg['bootstrap']:
if build_option('rpath') and self._cmakeopts['LLVM_ENABLE_RUNTIMES'] != '""':
# Ensure RPATH wrappers are used for the runtimes also at the first stage
# Call configure again now that the host triple is known from the previous configure call
remove_dir(self.llvm_obj_dir_stage1)
self._prepare_runtimes_rpath_wrappers(self.llvm_obj_dir_stage1)
self.add_cmake_opts()
trace_msg("Reconfiguring LLVM to use the RPATH wrappers for the runtimes")
super().configure_step(builddir=self.llvm_obj_dir_stage1, srcdir=src_dir)
# Pre-create the CFG files in the `build_stage/bin` directory to enforce using the correct dynamic
# linker in case of sysroot builds, and to ensure the correct GCC installation is used also for the
# runtimes (which would otherwise use the system default dynamic linker)
self._create_compiler_config_file(self.llvm_obj_dir_stage1)
def disable_sanitizer_tests(self):
"""Disable the tests of all the sanitizers by removing the test directories from the build system"""
cmakelists_tests = os.path.join(self.start_dir, 'compiler-rt', 'test', 'CMakeLists.txt')
regex_subs = [(r'compiler_rt_test_runtime.*san.*', '')]
apply_regex_substitutions(cmakelists_tests, regex_subs)
def add_cmake_opts(self):
"""Add LLVM-specific CMake options."""
base_opts = self._cfgopts.copy()
for k, v in self._cmakeopts.items():
base_opts.append('-D%s=%s' % (k, v))
self.cfg['configopts'] = ' '.join(base_opts)
def configure_step2(self):
"""Configure the second stage of the bootstrap."""
self._cmakeopts = {}
self._configure_general_build()
self._configure_intermediate_build()
if self.full_llvm:
self._cmakeopts.update(self.remove_gcc_dependency_opts)
def configure_step3(self):
"""Configure the third stage of the bootstrap."""
self._cmakeopts = {}
self._configure_general_build()
self._configure_final_build()
# Update runtime CMake arguments, as they might have
# changed when configuring the final build arguments
self._add_cmake_runtime_args()
if self.full_llvm:
self._cmakeopts.update(self.remove_gcc_dependency_opts)
def _create_compiler_config_file(self, installdir):
"""Create a config file for the compiler to point to the correct GCC installation."""
self._set_gcc_prefix()
# This is only needed for LLVM >= 19, as the --gcc-install-dir option was introduced then
if LooseVersion(self.version) < LooseVersion('19'):
return
bin_dir = os.path.join(installdir, 'bin')
opts = [f'--gcc-install-dir={self.gcc_prefix}']
if self.dynamic_linker:
opts.append(f'-Wl,-dynamic-linker,{self.dynamic_linker}')
# The --dyld-prefix flag exists, but beside being poorly documented it is also not supported by flang
# https://reviews.llvm.org/D851
# prefix = self.sysroot.rstrip('/')
# opts.append(f'--dyld-prefix={prefix}')
# Check, for a non `full_llvm` build, if GCCcore is in the LIBRARY_PATH, and if not add it;
# This is needed as the runtimes tests will not add the -L option to the linker command line for GCCcore
# otherwise
if not self.full_llvm:
gcc_lib = self._get_gcc_libpath(strict=True)
lib_path = os.getenv('LIBRARY_PATH', '')
if gcc_lib not in lib_path:
self.log.info("Adding GCCcore libraries location `%s` the config files", gcc_lib)
opts.append(f'-L{gcc_lib}')
for comp in self.cfg_compilers:
write_file(os.path.join(bin_dir, f'{comp}.cfg'), ' '.join(opts))
def build_with_prev_stage(self, prev_dir, stage_dir):
"""Build LLVM using the previous stage."""
curdir = os.getcwd()
bin_dir = os.path.join(prev_dir, 'bin')
lib_dir_runtime = self.get_runtime_lib_path(prev_dir)
# Give priority to the libraries in the current stage if compiled to avoid failures due to undefined symbols
# e.g. when calling the compiled clang-ast-dump for stage 3
lib_path = ':'.join(filter(None, [
os.path.join(stage_dir, lib_dir_runtime),
os.path.join(prev_dir, lib_dir_runtime),
]))
if build_option('rpath'):
self._prepare_runtimes_rpath_wrappers(stage_dir)
# Needed for passing the variables to the build command
with _wrap_env(bin_dir, lib_path):
# If building with rpath, create RPATH wrappers for the Clang compilers for stage 2 and 3
if build_option('rpath'):
# !!! Should be replaced with ClangFlang (or correct naming) toolchain once available
# as this will only create rpath wrappers for Clang and not Flang
my_toolchain = Clang(name='Clang', version='1')
my_toolchain.prepare_rpath_wrappers(
rpath_include_dirs=[
os.path.join(self.installdir, 'lib'),
os.path.join(self.installdir, 'lib64'),
os.path.join(self.installdir, lib_dir_runtime),
]
)
self.log.info("Prepared rpath wrappers")
# add symlink for 'opt' to wrapper dir, since Clang expects it in the same directory
# see https://github.com/easybuilders/easybuild-easyblocks/issues/3075
clang_wrapper_dir = os.path.dirname(which('clang'))
symlink(os.path.join(prev_dir, 'opt'), os.path.join(clang_wrapper_dir, 'opt'))
# RPATH wrappers add -Wl,rpath arguments to all command lines, including when it is just compiling
# Clang by default warns about that, and then some configure tests use -Werror which turns those
# warnings into errors. As a result, those configure tests fail, even though the compiler supports the
# requested functionality (e.g. the test that checks if -fPIC is supported would fail, and it compiles
# without resulting in relocation errors).
# See https://github.com/easybuilders/easybuild-easyblocks/pull/2799#issuecomment-1270621100
# Here, we add -Wno-unused-command-line-argument to CXXFLAGS to avoid these warnings alltogether
cflags = os.getenv('CFLAGS', '')
cxxflags = os.getenv('CXXFLAGS', '')
setvar('CFLAGS', "%s %s" % (cflags, '-Wno-unused-command-line-argument'))
setvar('CXXFLAGS', "%s %s" % (cxxflags, '-Wno-unused-command-line-argument'))
if self.full_llvm:
# See https://github.com/llvm/llvm-project/issues/111667
to_add = '--unwindlib=none'
# for flags in ['CMAKE_C_FLAGS', 'CMAKE_CXX_FLAGS']:
for flags in ['CMAKE_EXE_LINKER_FLAGS']:
ptr = self.runtimes_cmake_args[flags]
if to_add not in ptr:
ptr.append(to_add)
self._add_cmake_runtime_args()
# determine full path to clang/clang++ (which may be wrapper scripts in case of RPATH linking)
clang = which('clang')
clangxx = which('clang++')
self._cmakeopts['CMAKE_C_COMPILER'] = clang
self._cmakeopts['CMAKE_CXX_COMPILER'] = clangxx
self._cmakeopts['CMAKE_ASM_COMPILER'] = clang
self._cmakeopts['CMAKE_ASM_COMPILER_ID'] = 'Clang'
self._create_compiler_config_file(prev_dir)
# also pre-create the CFG files in the `build_stage/bin` directory to enforce using the correct dynamic
# linker in case of sysroot builds, and to ensure the correct GCC installation is used also for the
# runtimes (which would otherwise use the system default dynamic linker)
self._create_compiler_config_file(stage_dir)
self.add_cmake_opts()
change_dir(stage_dir)
self.log.debug("Configuring %s", stage_dir)
cmd = ' '.join(['cmake', self.cfg['configopts'], os.path.join(self.start_dir, 'llvm')])
run_shell_cmd(cmd)
self.log.debug("Building %s", stage_dir)
cmd = f"make {self.make_parallel_opts} VERBOSE=1"
res = run_shell_cmd(cmd, fail_on_error=False)
# Observed in 20.1.0, the build of the offloading tools can fail due to 'cstdint' file not found
# But will succeed if executed again with -j 1 (possible missing dependency in the CMake logic?)
# See https://github.com/llvm/llvm-project/issues/130783
if res.exit_code != EasyBuildExit.SUCCESS: