Skip to content

Commit b280629

Browse files
authored
Support Ubuntu 24.04 and LLVM 14.0.5; automatically select LLVM version based on compiler version (#309)
1 parent f19f558 commit b280629

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

build-and-run-tests.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def main(args):
3333
parser.add_argument('--binder', default='', help='Path to Binder tool. If none is given then download, build and install binder into main/source/build. Use "--binder-debug" to control which mode of binder (debug/release) is used.')
3434
parser.add_argument("--binder-debug", action="store_true", help="Run binder tool in debug mode (only relevant if no '--binder' option was specified)")
3535
parser.add_argument('--pybind11', default='', help='Path to pybind11 source tree')
36+
parser.add_argument('--llvm-version', default=None, choices=['6.0.1', '13.0.0', '14.0.5'], help='Manually specify LLVM version to install')
3637
parser.add_argument('--annotate-includes', action="store_true", help='Annotate includes in generated source files')
3738
parser.add_argument('--trace', action="store_true", help='Binder will add trace output to to generated source files')
3839
parser.add_argument('--gcc-install-prefix', default=None, help='Path to GCC install prefix which will be used to determent location of libstdc++ for Binder build. Default is: auto-detected. Use this option if you would like to build Binder with compiler that was side-installed and which LLVM build system failed to identify. To see what path Binder uses for libstdc++ run `binder -- -xc++ -E -v`.')
@@ -42,7 +43,7 @@ def main(args):
4243

4344
source_path = os.path.abspath('.')
4445

45-
if not Options.binder: Options.binder = build.install_llvm_tool('binder', source_path+'/source', source_path + '/build', Options.binder_debug, jobs=Options.jobs, gcc_install_prefix=Options.gcc_install_prefix, compiler=Options.compiler)
46+
if not Options.binder: Options.binder = build.install_llvm_tool('binder', source_path+'/source', source_path + '/build', Options.binder_debug, jobs=Options.jobs, gcc_install_prefix=Options.gcc_install_prefix, compiler=Options.compiler, llvm_version=Options.llvm_version)
4647

4748
if not Options.pybind11: Options.pybind11 = build.install_pybind11(source_path + '/build')
4849

build.py

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,52 @@ def get_cmake_compiler_options(compiler):
8989
return ''
9090

9191

92-
def install_llvm_tool(name, source_location, prefix_root, debug, compiler, jobs, gcc_install_prefix, clean=True):
92+
def install_llvm_tool(name, source_location, prefix_root, debug, compiler, jobs, gcc_install_prefix, clean=True, llvm_version=None):
9393
''' Install and update (if needed) custom LLVM tool at given prefix (from config).
9494
Return absolute path to executable on success and terminate with error on failure
9595
'''
9696
if not os.path.isdir(prefix_root): os.makedirs(prefix_root)
9797

98-
# llvm_version='9.0.0' # v8 and v9 can not be build with Clang-3.4, we if need upgrade to v > 7 then we should probably dynamicly change LLVM version based on complier versions
99-
# llvm_version='7.1.0' # compiling v7.* on clang-3.4 lead to lockup while compiling tools/clang/lib/Sema/SemaChecking.cpp
100-
llvm_version, headers = ('13.0.0', 'tools/clang/lib/Headers/clang-resource-headers clang') if Platform == 'macos' and platform.machine() == 'arm64' else ('6.0.1', 'tools/clang/lib/Headers/clang-headers')
101-
#llvm_version, headers = ('13.0.0', 'tools/clang/lib/Headers/clang-resource-headers clang') if Platform == 'macos' else ('6.0.1', 'tools/clang/lib/Headers/clang-headers')
102-
#llvm_version, headers = ('13.0.0', 'tools/clang/lib/Headers/clang-resource-headers clang')
103-
#if Platform == 'macos': headers += ' clang'
98+
if compiler in ('clang', 'gcc'):
99+
# Both Clang and GCC have a -dumpversion flag
100+
compiler_version = int(subprocess.check_output([compiler, "-dumpversion"]).decode('utf-8').split('.')[0])
101+
else:
102+
# cl doesn't.
103+
compiler_version = None
104+
105+
if llvm_version is None:
106+
# We need to select an LLVM version to build.
107+
108+
# compiling v7.* on clang-3.4 lead to lockup while compiling
109+
# tools/clang/lib/Sema/SemaChecking.cpp v8 and v9 can not be built with
110+
# Clang-3.4. So we need to dynamicly change LLVM version based on
111+
# complier versions
112+
113+
if compiler == 'gcc' and compiler_version >= 13:
114+
# GCC13's STL no longer works with LLVM 6, it has features that
115+
# require e.g.
116+
# <https://github.com/llvm/llvm-project/commit/add16a8da9ccd07eabda2dffd0d32188f07da09c>
117+
# released in LLVM 9.
118+
# Also, LLVM 13 has a bug with not actually including the headers it
119+
# needs <https://github.com/llvm/llvm-project/issues/55711>, which
120+
# wasn't fixed until 14.0.5.
121+
llvm_version = '14.0.5'
122+
elif Platform == 'macos' and platform.machine() == 'arm64':
123+
# ARM Mac also requires a newer LLVM version
124+
llvm_version = '13.0.0'
125+
else:
126+
# We keep the default version back as far as we can for compatibility
127+
# with old system compilers.
128+
llvm_version = '6.0.1'
129+
130+
headers = {
131+
'14.0.5': 'tools/clang/lib/Headers/clang-resource-headers',
132+
'13.0.0': 'tools/clang/lib/Headers/clang-resource-headers',
133+
'6.0.1': 'tools/clang/lib/Headers/clang-headers'
134+
}[llvm_version]
135+
136+
if Platform == 'macos':
137+
headers += ' clang'
104138

105139
prefix = prefix_root + '/llvm-' + llvm_version
106140

@@ -129,15 +163,26 @@ def install_llvm_tool(name, source_location, prefix_root, debug, compiler, jobs,
129163
llvm_url, clang_url = {
130164
'6.0.1' : ('https://releases.llvm.org/6.0.1/llvm-6.0.1.src.tar.xz', 'https://releases.llvm.org/6.0.1/cfe-6.0.1.src.tar.xz'),
131165
'13.0.0' : ('https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/llvm-13.0.0.src.tar.xz', 'https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang-13.0.0.src.tar.xz'),
166+
'14.0.5' : ('https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.5/llvm-14.0.5.src.tar.xz', 'https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.5/clang-14.0.5.src.tar.xz')
132167
}[llvm_version]
133168

134-
if not os.path.isfile(prefix + '/CMakeLists.txt'):
169+
# The LLVM tarballs may include a "cmake" directory that needs to be
170+
# sibling to the main source directories in order for the build to
171+
# work. That path can't depend on the LLVM version, so we track that ourselves.
172+
cmake_path = os.path.join(prefix_root, "cmake")
173+
cmake_version_path = os.path.join(cmake_path, "llvm_version.txt")
174+
175+
if not os.path.isfile(prefix + '/CMakeLists.txt') or not os.path.isfile(cmake_version_path) or open(cmake_version_path).read() != llvm_version:
135176
#execute('Download LLVM source...', 'cd {prefix_root} && curl https://releases.llvm.org/{llvm_version}/llvm-{llvm_version}.src.tar.xz | tar -Jxom && mv llvm-{llvm_version}.src {prefix}'.format(**locals()) )
136-
execute('Download LLVM source...', 'cd {prefix_root} && mkdir llvm-{llvm_version}.src && curl -LJ {llvm_url} | tar --strip-components=1 -Jxom -C llvm-{llvm_version}.src && mv llvm-{llvm_version}.src {prefix}'.format(**locals()) )
177+
if os.path.isdir(prefix): shutil.rmtree(prefix)
178+
execute('Download LLVM source...', 'cd {prefix_root} && curl -LJ {llvm_url} | tar -Jxom && mv llvm-{llvm_version}.src {prefix}'.format(**locals()) )
179+
os.makedirs(cmake_path, exist_ok=True)
180+
open(cmake_version_path, 'w').write(llvm_version)
137181

138182
if not os.path.isdir(clang_path):
139183
#execute('Download Clang source...', 'cd {prefix_root} && curl https://releases.llvm.org/{llvm_version}/cfe-{llvm_version}.src.tar.xz | tar -Jxom && mv cfe-{llvm_version}.src {clang_path}'.format(**locals()) )
140-
execute('Download Clang source...', 'cd {prefix_root} && mkdir clang-{llvm_version}.src && curl -LJ {clang_url} | tar --strip-components=1 -Jxom -C clang-{llvm_version}.src && mv clang-{llvm_version}.src {clang_path}'.format(**locals()) )
184+
clang_name = 'cfe' if llvm_version == '6.0.1' else 'clang'
185+
execute('Download Clang source...', 'cd {prefix_root} && curl -LJ {clang_url} | tar -Jxom && mv {clang_name}-{llvm_version}.src {clang_path}'.format(**locals()) )
141186

142187
if not os.path.isdir(prefix+'/tools/clang/tools/extra'): os.makedirs(prefix+'/tools/clang/tools/extra')
143188

@@ -180,7 +225,7 @@ def install_llvm_tool(name, source_location, prefix_root, debug, compiler, jobs,
180225
if not os.path.isdir(build_dir): os.makedirs(build_dir)
181226
execute(
182227
'Building tool: {}...'.format(name), # -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=1
183-
'cd {build_dir} && cmake -G Ninja {config} -DLLVM_ENABLE_EH=1 -DLLVM_ENABLE_RTTI=ON {gcc_install_prefix} .. && ninja binder {headers} {jobs}'.format( # was 'binder clang', we need to build Clang so lib/clang/<version>/include is also built
228+
'cd {build_dir} && cmake -G Ninja {config} -DLLVM_ENABLE_EH=1 -DLLVM_ENABLE_RTTI=ON -DLLVM_INCLUDE_BENCHMARKS=OFF {gcc_install_prefix} .. && ninja binder {headers} {jobs}'.format( # was 'binder clang', we need to build Clang so lib/clang/<version>/include is also built
184229
build_dir=build_dir, config=config,
185230
jobs=f'-j{jobs}' if jobs else '',
186231
gcc_install_prefix='-DGCC_INSTALL_PREFIX='+gcc_install_prefix if gcc_install_prefix else '',
@@ -230,6 +275,7 @@ def main(args):
230275
parser.add_argument('--binder', default='', help='Path to Binder tool. If none is given then download, build and install binder into build/ directory. Use "--binder-debug" to control which mode of binder (debug/release) is used.')
231276
parser.add_argument("--binder-debug", action="store_true", help="Run binder tool in debug mode (only relevant if no '--binder' option was specified)")
232277
parser.add_argument('--pybind11', default='', help='Path to pybind11 source tree')
278+
parser.add_argument('--llvm-version', default=None, choices=['6.0.1', '13.0.0', '14.0.5'], help='Manually specify LLVM version to install')
233279
parser.add_argument('--annotate-includes', action="store_true", help='Annotate includes in generated source files')
234280
parser.add_argument('--trace', action="store_true", help='Binder will add trace output to to generated source files')
235281

@@ -238,7 +284,7 @@ def main(args):
238284

239285
source_path = os.path.abspath('.')
240286

241-
if not Options.binder: Options.binder = install_llvm_tool('binder', source_path+'/source', source_path + '/build', debug=Options.binder_debug, compiler=Options.compiler, jobs=Options.jobs, gcc_install_prefix=None)
287+
if not Options.binder: Options.binder = install_llvm_tool('binder', source_path+'/source', source_path + '/build', debug=Options.binder_debug, compiler=Options.compiler, jobs=Options.jobs, gcc_install_prefix=None, llvm_version=Options.llvm_version)
242288

243289
if not Options.pybind11: Options.pybind11 = install_pybind11(source_path + '/build')
244290

0 commit comments

Comments
 (0)