def CopyLibstdcpp(args, build_dir): if not args.gcc_toolchain: return # Find libstdc++.so.6 libstdcpp = subprocess.check_output([ os.path.join(args.gcc_toolchain, 'bin', 'g++'), '-print-file-name=libstdc++.so.6' ]).rstrip() # Copy libstdc++.so.6 into the build dir so that the built binaries can find # it. Binaries get their rpath set to $origin/../lib/. For clang, lld, # etc. that live in the bin/ directory, this means they expect to find the .so # in their neighbouring lib/ dir. For other tools however, this doesn't work # since those exeuctables are spread out into different directories. # TODO(hans): Unit tests don't get rpath set at all, unittests/ copying # below doesn't help at the moment. for d in [ 'lib', 'test/tools/llvm-isel-fuzzer/lib', 'test/tools/llvm-opt-fuzzer/lib', 'unittests/CodeGen/lib', 'unittests/DebugInfo/lib', 'unittests/ExecutionEngine/lib', 'unittests/Support/lib', 'unittests/Target/lib', 'unittests/Transforms/lib', 'unittests/lib', 'unittests/tools/lib', 'unittests/tools/llvm-exegesis/lib' ]: EnsureDirExists(os.path.join(build_dir, d)) CopyFile(libstdcpp, os.path.join(build_dir, d))
def CopyDirectoryContents(src, dst): """Copy the files from directory src to dst.""" dst = os.path.realpath(dst) # realpath() in case dst ends in /.. EnsureDirExists(dst) for f in os.listdir(src): CopyFile(os.path.join(src, f), dst)
def main(): parser = argparse.ArgumentParser(description='Build Clang.') parser.add_argument('--bootstrap', action='store_true', help='first build clang with CC, then with itself.') parser.add_argument('--disable-asserts', action='store_true', help='build with asserts disabled') parser.add_argument('--gcc-toolchain', help='what gcc toolchain to use for ' 'building; --gcc-toolchain=/opt/foo picks ' '/opt/foo/bin/gcc') parser.add_argument('--lto-lld', action='store_true', help='build lld with LTO (only applies on Linux)') parser.add_argument('--pgo', action='store_true', help='build with PGO') parser.add_argument('--llvm-force-head-revision', action='store_true', help='build the latest revision') parser.add_argument('--run-tests', action='store_true', help='run tests after building') parser.add_argument('--skip-build', action='store_true', help='do not build anything') parser.add_argument('--skip-checkout', action='store_true', help='do not create or update any checkouts') parser.add_argument('--extra-tools', nargs='*', default=[], help='select additional chrome tools to build') parser.add_argument('--use-system-cmake', action='store_true', help='use the cmake from PATH instead of downloading ' 'and using prebuilt cmake binaries') parser.add_argument('--with-android', type=gn_arg, nargs='?', const=True, help='build the Android ASan runtime (linux only)', default=sys.platform.startswith('linux')) parser.add_argument('--without-android', action='store_false', help='don\'t build Android ASan runtime (linux only)', dest='with_android') parser.add_argument( '--without-fuchsia', action='store_false', help='don\'t build Fuchsia clang_rt runtime (linux/mac)', dest='with_fuchsia', default=sys.platform in ('linux2', 'darwin')) args = parser.parse_args() if args.lto_lld and not args.bootstrap: print('--lto-lld requires --bootstrap') return 1 if args.lto_lld and not sys.platform.startswith('linux'): # TODO(hans): Use it on Windows too. print('--lto-lld is only effective on Linux. Ignoring the option.') args.lto_lld = False if args.pgo and not args.bootstrap: print('--pgo requires --bootstrap') return 1 if args.with_android and not os.path.exists(ANDROID_NDK_DIR): print('Android NDK not found at ' + ANDROID_NDK_DIR) print( 'The Android NDK is needed to build a Clang whose -fsanitize=address' ) print('works on Android. See ') print( 'https://www.chromium.org/developers/how-tos/android-build-instructions' ) print('for how to install the NDK, or pass --without-android.') return 1 if args.llvm_force_head_revision: # Don't build fuchsia runtime on ToT bots at all. args.with_fuchsia = False if args.with_fuchsia and not os.path.exists(FUCHSIA_SDK_DIR): print('Fuchsia SDK not found at ' + FUCHSIA_SDK_DIR) print('The Fuchsia SDK is needed to build libclang_rt for Fuchsia.') print('Install the Fuchsia SDK by adding fuchsia to the ') print('target_os section in your .gclient and running hooks, ') print('or pass --without-fuchsia.') print( 'https://chromium.googlesource.com/chromium/src/+/master/docs/fuchsia_build_instructions.md' ) print('for general Fuchsia build instructions.') return 1 # Don't buffer stdout, so that print statements are immediately flushed. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) # The gnuwin package also includes curl, which is needed to interact with the # github API below. # TODO(crbug.com/965937): Use urllib once our Python is recent enough, and # move this down to where we fetch other build tools. AddGnuWinToPath() # TODO(crbug.com/929645): Remove once we build on host systems with a modern # enough GCC to build Clang. MaybeDownloadHostGcc(args) global CLANG_REVISION, PACKAGE_VERSION if args.llvm_force_head_revision: CLANG_REVISION = GetLatestLLVMCommit() if not args.skip_checkout: CheckoutLLVM(CLANG_REVISION, LLVM_DIR) if args.llvm_force_head_revision: PACKAGE_VERSION = 'n%s-%s-0' % (GetCommitCount(CLANG_REVISION), CLANG_REVISION[:8]) print('Locally building clang %s...' % PACKAGE_VERSION) WriteStampFile('', STAMP_FILE) WriteStampFile('', FORCE_HEAD_REVISION_FILE) AddCMakeToPath(args) DeleteChromeToolsShim() if args.skip_build: return 0 # The variable "lld" is only used on Windows because only there does setting # CMAKE_LINKER have an effect: On Windows, the linker is called directly, # while elsewhere it's called through the compiler driver, and we pass # -fuse-ld=lld there to make the compiler driver call the linker (by setting # LLVM_ENABLE_LLD). cc, cxx, lld = None, None, None if args.gcc_toolchain: # Use the specified gcc installation for building. cc = os.path.join(args.gcc_toolchain, 'bin', 'gcc') cxx = os.path.join(args.gcc_toolchain, 'bin', 'g++') if not os.access(cc, os.X_OK): print('Invalid --gcc-toolchain: ' + args.gcc_toolchain) return 1 cflags = [] cxxflags = [] ldflags = [] targets = 'AArch64;ARM;Mips;PowerPC;SystemZ;WebAssembly;X86' projects = 'clang;compiler-rt;lld;chrometools' if sys.platform == 'darwin': # clang needs libc++, else -stdlib=libc++ won't find includes # (this is needed for bootstrap builds and for building the fuchsia runtime) projects += ';libcxx' base_cmake_args = [ '-GNinja', '-DCMAKE_BUILD_TYPE=Release', '-DLLVM_ENABLE_ASSERTIONS=%s' % ('OFF' if args.disable_asserts else 'ON'), '-DLLVM_ENABLE_PROJECTS=' + projects, '-DLLVM_TARGETS_TO_BUILD=' + targets, '-DLLVM_ENABLE_PIC=OFF', '-DLLVM_ENABLE_UNWIND_TABLES=OFF', '-DLLVM_ENABLE_TERMINFO=OFF', '-DCLANG_PLUGIN_SUPPORT=OFF', '-DCLANG_ENABLE_STATIC_ANALYZER=OFF', '-DCLANG_ENABLE_ARCMT=OFF', '-DBUG_REPORT_URL=' + BUG_REPORT_URL, # See PR41956: Don't link libcxx into libfuzzer. '-DCOMPILER_RT_USE_LIBCXX=NO', # Don't run Go bindings tests; PGO makes them confused. '-DLLVM_INCLUDE_GO_TESTS=OFF', ] if args.gcc_toolchain: # Don't use the custom gcc toolchain when building compiler-rt tests; those # tests are built with the just-built Clang, and target both i386 and x86_64 # for example, so should ust the system's libstdc++. base_cmake_args.append( '-DCOMPILER_RT_TEST_COMPILER_CFLAGS=--gcc-toolchain=') if sys.platform == 'win32': base_cmake_args.append('-DLLVM_USE_CRT_RELEASE=MT') if sys.platform == 'darwin': # Use the system libc++abi. # TODO(hans): use https://reviews.llvm.org/D62060 instead base_cmake_args.append('-DLIBCXX_CXX_ABI=libcxxabi') base_cmake_args.append('-DLIBCXX_CXX_ABI_SYSTEM=1') if sys.platform != 'win32': # libxml2 is required by the Win manifest merging tool used in cross-builds. base_cmake_args.append('-DLLVM_ENABLE_LIBXML2=FORCE_ON') if args.bootstrap: print('Building bootstrap compiler') if os.path.exists(LLVM_BOOTSTRAP_DIR): RmTree(LLVM_BOOTSTRAP_DIR) EnsureDirExists(LLVM_BOOTSTRAP_DIR) os.chdir(LLVM_BOOTSTRAP_DIR) projects = 'clang' if args.pgo: # Need libclang_rt.profile projects += ';compiler-rt' if sys.platform != 'darwin' or args.lto_lld: projects += ';lld' if sys.platform == 'darwin': # Need libc++ and compiler-rt for the bootstrap compiler on mac. projects += ';libcxx;compiler-rt' bootstrap_targets = 'X86' if sys.platform == 'darwin': # Need ARM and AArch64 for building the ios clang_rt. bootstrap_targets += ';ARM;AArch64' bootstrap_args = base_cmake_args + [ '-DLLVM_TARGETS_TO_BUILD=' + bootstrap_targets, '-DLLVM_ENABLE_PROJECTS=' + projects, '-DCMAKE_INSTALL_PREFIX=' + LLVM_BOOTSTRAP_INSTALL_DIR, '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), # Ignore args.disable_asserts for the bootstrap compiler. '-DLLVM_ENABLE_ASSERTIONS=ON', ] if sys.platform == 'darwin': # On macOS, the bootstrap toolchain needs to have compiler-rt because # dsymutil's link needs libclang_rt.osx.a. Only the x86_64 osx # libraries are needed though, and only libclang_rt (i.e. # COMPILER_RT_BUILD_BUILTINS). bootstrap_args.extend([ '-DDARWIN_osx_ARCHS=x86_64', '-DCOMPILER_RT_BUILD_BUILTINS=ON', '-DCOMPILER_RT_BUILD_CRT=OFF', '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF', '-DCOMPILER_RT_BUILD_SANITIZERS=OFF', '-DCOMPILER_RT_BUILD_XRAY=OFF', '-DCOMPILER_RT_ENABLE_IOS=OFF', '-DCOMPILER_RT_ENABLE_WATCHOS=OFF', '-DCOMPILER_RT_ENABLE_TVOS=OFF', ]) elif args.pgo: # PGO needs libclang_rt.profile but none of the other compiler-rt stuff. bootstrap_args.extend([ '-DCOMPILER_RT_BUILD_BUILTINS=OFF', '-DCOMPILER_RT_BUILD_CRT=OFF', '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF', '-DCOMPILER_RT_BUILD_PROFILE=ON', '-DCOMPILER_RT_BUILD_SANITIZERS=OFF', '-DCOMPILER_RT_BUILD_XRAY=OFF', ]) if cc is not None: bootstrap_args.append('-DCMAKE_C_COMPILER=' + cc) if cxx is not None: bootstrap_args.append('-DCMAKE_CXX_COMPILER=' + cxx) if lld is not None: bootstrap_args.append('-DCMAKE_LINKER=' + lld) RunCommand(['cmake'] + bootstrap_args + [os.path.join(LLVM_DIR, 'llvm')], msvc_arch='x64') CopyLibstdcpp(args, LLVM_BOOTSTRAP_DIR) CopyLibstdcpp(args, LLVM_BOOTSTRAP_INSTALL_DIR) RunCommand(['ninja'], msvc_arch='x64') if args.run_tests: test_targets = ['check-all'] if sys.platform == 'darwin': # TODO(crbug.com/731375): Run check-all on Darwin too. test_targets = ['check-llvm', 'check-clang', 'check-builtins'] if sys.platform == 'win32': CopyDiaDllTo(os.path.join(LLVM_BOOTSTRAP_DIR, 'bin')) RunCommand(['ninja'] + test_targets, msvc_arch='x64') RunCommand(['ninja', 'install'], msvc_arch='x64') if sys.platform == 'win32': cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe') cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe') lld = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'lld-link.exe') # CMake has a hard time with backslashes in compiler paths: # https://stackoverflow.com/questions/13050827 cc = cc.replace('\\', '/') cxx = cxx.replace('\\', '/') lld = lld.replace('\\', '/') else: cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang') cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang++') if sys.platform.startswith('linux'): base_cmake_args.append('-DLLVM_ENABLE_LLD=ON') if args.gcc_toolchain: # Tell the bootstrap compiler where to find the standard library headers # and shared object files. cflags.append('--gcc-toolchain=' + args.gcc_toolchain) cxxflags.append('--gcc-toolchain=' + args.gcc_toolchain) print('Bootstrap compiler installed.') if args.pgo: print('Building instrumented compiler') if os.path.exists(LLVM_INSTRUMENTED_DIR): RmTree(LLVM_INSTRUMENTED_DIR) EnsureDirExists(LLVM_INSTRUMENTED_DIR) os.chdir(LLVM_INSTRUMENTED_DIR) projects = 'clang' if sys.platform == 'darwin': projects += ';libcxx;compiler-rt' instrument_args = base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DLLVM_ENABLE_PROJECTS=' + projects, '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), # Build with instrumentation. '-DLLVM_BUILD_INSTRUMENTED=IR', ] # Build with the bootstrap compiler. if cc is not None: instrument_args.append('-DCMAKE_C_COMPILER=' + cc) if cxx is not None: instrument_args.append('-DCMAKE_CXX_COMPILER=' + cxx) if lld is not None: instrument_args.append('-DCMAKE_LINKER=' + lld) RunCommand(['cmake'] + instrument_args + [os.path.join(LLVM_DIR, 'llvm')], msvc_arch='x64') CopyLibstdcpp(args, LLVM_INSTRUMENTED_DIR) RunCommand(['ninja'], msvc_arch='x64') print('Instrumented compiler built.') # Train by building some C++ code. # # pgo_training-1.ii is a preprocessed (on Linux) version of # src/third_party/blink/renderer/core/layout/layout_object.cc, selected # because it's a large translation unit in Blink, which is normally the # slowest part of Chromium to compile. Using this, we get ~20% shorter # build times for Linux, Android, and Mac, which is also what we got when # training by actually building a target in Chromium. (For comparison, a # C++-y "Hello World" program only resulted in 14% faster builds.) # See https://crbug.com/966403#c16 for all numbers. # # TODO(hans): Enhance the training, perhaps by including preprocessed code # from more platforms, and by doing some linking so that lld can benefit # from PGO as well. Perhaps the training could be done asynchronously by # dedicated buildbots that upload profiles to the cloud. training_source = 'pgo_training-1.ii' with open(training_source, 'w') as f: DownloadUrl(CDS_URL + '/' + training_source, f) train_cmd = [ os.path.join(LLVM_INSTRUMENTED_DIR, 'bin', 'clang++'), '-target', 'x86_64-unknown-unknown', '-O2', '-g', '-std=c++14', '-fno-exceptions', '-fno-rtti', '-w', '-c', training_source ] if sys.platform == 'darwin': train_cmd.extend([ '-stdlib=libc++', '-isysroot', subprocess.check_output(['xcrun', '--show-sdk-path']).rstrip() ]) RunCommand(train_cmd, msvc_arch='x64') # Merge profiles. profdata = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-profdata') RunCommand( [profdata, 'merge', '-output=' + LLVM_PROFDATA_FILE] + glob.glob( os.path.join(LLVM_INSTRUMENTED_DIR, 'profiles', '*.profraw')), msvc_arch='x64') print('Profile generated.') compiler_rt_args = [ '-DCOMPILER_RT_BUILD_CRT=OFF', '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF', '-DCOMPILER_RT_BUILD_PROFILE=ON', '-DCOMPILER_RT_BUILD_SANITIZERS=ON', '-DCOMPILER_RT_BUILD_XRAY=OFF', ] if sys.platform == 'darwin': compiler_rt_args.extend([ '-DCOMPILER_RT_BUILD_BUILTINS=ON', '-DCOMPILER_RT_ENABLE_IOS=ON', '-DCOMPILER_RT_ENABLE_WATCHOS=OFF', '-DCOMPILER_RT_ENABLE_TVOS=OFF', # armv7 is A5 and earlier, armv7s is A6+ (2012 and later, before 64-bit # iPhones). armv7k is Apple Watch, which we don't need. '-DDARWIN_ios_ARCHS=armv7;armv7s;arm64', '-DDARWIN_iossim_ARCHS=i386;x86_64', # We don't need 32-bit intel support for macOS, we only ship 64-bit. '-DDARWIN_osx_ARCHS=x86_64', ]) else: compiler_rt_args.append('-DCOMPILER_RT_BUILD_BUILTINS=OFF') # LLVM uses C++11 starting in llvm 3.5. On Linux, this means libstdc++4.7+ is # needed, on OS X it requires libc++. clang only automatically links to libc++ # when targeting OS X 10.9+, so add stdlib=libc++ explicitly so clang can run # on OS X versions as old as 10.7. deployment_target = '' if sys.platform == 'darwin' and args.bootstrap: # When building on 10.9, /usr/include usually doesn't exist, and while # Xcode's clang automatically sets a sysroot, self-built clangs don't. cflags = [ '-isysroot', subprocess.check_output(['xcrun', '--show-sdk-path']).rstrip() ] cxxflags = ['-stdlib=libc++'] + cflags ldflags += ['-stdlib=libc++'] deployment_target = '10.7' # If building at head, define a macro that plugins can use for #ifdefing # out code that builds at head, but not at CLANG_REVISION or vice versa. if args.llvm_force_head_revision: cflags += ['-DLLVM_FORCE_HEAD_REVISION'] cxxflags += ['-DLLVM_FORCE_HEAD_REVISION'] # Build PDBs for archival on Windows. Don't use RelWithDebInfo since it # has different optimization defaults than Release. # Also disable stack cookies (/GS-) for performance. if sys.platform == 'win32': cflags += ['/Zi', '/GS-'] cxxflags += ['/Zi', '/GS-'] ldflags += ['/DEBUG', '/OPT:REF', '/OPT:ICF'] deployment_env = None if deployment_target: deployment_env = os.environ.copy() deployment_env['MACOSX_DEPLOYMENT_TARGET'] = deployment_target # Build lld and code coverage tools. This is done separately from the rest of # the build because these tools require threading support. print('Building thread-enabled tools.') tools_with_threading = ['dsymutil', 'lld', 'llvm-cov', 'llvm-profdata'] print('Building the following tools with threading support: %s' % str(tools_with_threading)) if os.path.exists(THREADS_ENABLED_BUILD_DIR): RmTree(THREADS_ENABLED_BUILD_DIR) EnsureDirExists(THREADS_ENABLED_BUILD_DIR) os.chdir(THREADS_ENABLED_BUILD_DIR) threads_enabled_cmake_args = base_cmake_args + [ '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags) ] if cc is not None: threads_enabled_cmake_args.append('-DCMAKE_C_COMPILER=' + cc) if cxx is not None: threads_enabled_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx) if lld is not None: threads_enabled_cmake_args.append('-DCMAKE_LINKER=' + lld) if args.lto_lld: # Build lld with LTO. That speeds up the linker by ~10%. # We only use LTO for Linux now. # # The linker expects all archive members to have symbol tables, so the # archiver needs to be able to create symbol tables for bitcode files. # GNU ar and ranlib don't understand bitcode files, but llvm-ar and # llvm-ranlib do, so use them. ar = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ar') ranlib = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ranlib') threads_enabled_cmake_args += [ '-DCMAKE_AR=' + ar, '-DCMAKE_RANLIB=' + ranlib, '-DLLVM_ENABLE_LTO=thin', ] RunCommand(['cmake'] + threads_enabled_cmake_args + [os.path.join(LLVM_DIR, 'llvm')], msvc_arch='x64', env=deployment_env) CopyLibstdcpp(args, THREADS_ENABLED_BUILD_DIR) RunCommand(['ninja'] + tools_with_threading, msvc_arch='x64') print('Building final compiler.') default_tools = ['plugins', 'blink_gc_plugin', 'translation_unit'] chrome_tools = list(set(default_tools + args.extra_tools)) if cc is not None: base_cmake_args.append('-DCMAKE_C_COMPILER=' + cc) if cxx is not None: base_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx) if lld is not None: base_cmake_args.append('-DCMAKE_LINKER=' + lld) cmake_args = base_cmake_args + compiler_rt_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_INSTALL_PREFIX=' + LLVM_BUILD_DIR, '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(CHROMIUM_DIR, 'tools', 'clang'), '-DCHROMIUM_TOOLS=%s' % ';'.join(chrome_tools) ] if args.pgo: cmake_args.append('-DLLVM_PROFDATA_FILE=' + LLVM_PROFDATA_FILE) if sys.platform == 'darwin': cmake_args += [ '-DCOMPILER_RT_ENABLE_IOS=ON', '-DSANITIZER_MIN_OSX_VERSION=10.7' ] # TODO(crbug.com/962988): Use -DLLVM_EXTERNAL_PROJECTS instead. CreateChromeToolsShim() if os.path.exists(LLVM_BUILD_DIR): RmTree(LLVM_BUILD_DIR) EnsureDirExists(LLVM_BUILD_DIR) os.chdir(LLVM_BUILD_DIR) RunCommand(['cmake'] + cmake_args + [os.path.join(LLVM_DIR, 'llvm')], msvc_arch='x64', env=deployment_env) CopyLibstdcpp(args, LLVM_BUILD_DIR) RunCommand(['ninja'], msvc_arch='x64') # Copy in the threaded versions of lld and other tools. if sys.platform == 'win32': CopyFile( os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld-link.exe'), os.path.join(LLVM_BUILD_DIR, 'bin')) CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld.pdb'), os.path.join(LLVM_BUILD_DIR, 'bin')) else: for tool in tools_with_threading: CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', tool), os.path.join(LLVM_BUILD_DIR, 'bin')) if chrome_tools: # If any Chromium tools were built, install those now. RunCommand(['ninja', 'cr-install'], msvc_arch='x64') VerifyVersionOfBuiltClangMatchesVERSION() if sys.platform == 'win32': platform = 'windows' elif sys.platform == 'darwin': platform = 'darwin' else: assert sys.platform.startswith('linux') platform = 'linux' rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION, 'lib', platform) # Do an out-of-tree build of compiler-rt for 32-bit Win clang_rt.profile.lib. if sys.platform == 'win32': if os.path.isdir(COMPILER_RT_BUILD_DIR): RmTree(COMPILER_RT_BUILD_DIR) os.makedirs(COMPILER_RT_BUILD_DIR) os.chdir(COMPILER_RT_BUILD_DIR) if args.bootstrap: # The bootstrap compiler produces 64-bit binaries by default. cflags += ['-m32'] cxxflags += ['-m32'] compiler_rt_args = base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), '-DCOMPILER_RT_BUILD_BUILTINS=OFF', '-DCOMPILER_RT_BUILD_CRT=OFF', '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF', '-DCOMPILER_RT_BUILD_PROFILE=ON', '-DCOMPILER_RT_BUILD_SANITIZERS=OFF', '-DCOMPILER_RT_BUILD_XRAY=OFF', ] RunCommand(['cmake'] + compiler_rt_args + [os.path.join(LLVM_DIR, 'llvm')], msvc_arch='x86', env=deployment_env) RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86') # Copy select output to the main tree. rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION, 'lib', platform) # Static and dynamic libraries: CopyDirectoryContents(rt_lib_src_dir, rt_lib_dst_dir) if args.with_android: make_toolchain = os.path.join(ANDROID_NDK_DIR, 'build', 'tools', 'make_standalone_toolchain.py') # TODO(thakis): Now that the NDK uses clang, try to build all archs in # one LLVM build instead of making 3 different toolchains and building # 3 times. for target_arch in ['aarch64', 'arm', 'i686']: # Make standalone Android toolchain for target_arch. toolchain_dir = os.path.join(LLVM_BUILD_DIR, 'android-toolchain-' + target_arch) api_level = '21' if target_arch == 'aarch64' else '19' RunCommand([ make_toolchain, '--api=' + api_level, '--force', '--install-dir=%s' % toolchain_dir, '--stl=libc++', '--arch=' + { 'aarch64': 'arm64', 'arm': 'arm', 'i686': 'x86', }[target_arch] ]) # Build compiler-rt runtimes needed for Android in a separate build tree. build_dir = os.path.join(LLVM_BUILD_DIR, 'android-' + target_arch) if not os.path.exists(build_dir): os.mkdir(os.path.join(build_dir)) os.chdir(build_dir) target_triple = target_arch if target_arch == 'arm': target_triple = 'armv7' target_triple += '-linux-android' + api_level cflags = [ '--target=%s' % target_triple, '--sysroot=%s/sysroot' % toolchain_dir, '-B%s' % toolchain_dir ] android_args = base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'), '-DCMAKE_CXX_COMPILER=' + os.path.join( LLVM_BUILD_DIR, 'bin/clang++'), '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'), '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), '-DCMAKE_ASM_FLAGS=' + ' '.join(cflags), '-DCOMPILER_RT_BUILD_BUILTINS=OFF', '-DCOMPILER_RT_BUILD_CRT=OFF', '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF', '-DCOMPILER_RT_BUILD_PROFILE=ON', '-DCOMPILER_RT_BUILD_SANITIZERS=ON', '-DCOMPILER_RT_BUILD_XRAY=OFF', '-DSANITIZER_CXX_ABI=libcxxabi', '-DCMAKE_SHARED_LINKER_FLAGS=-Wl,-u__cxa_demangle', '-DANDROID=1' ] RunCommand(['cmake'] + android_args + [COMPILER_RT_DIR]) # We use ASan i686 build for fuzzing. libs_want = ['lib/linux/libclang_rt.asan-{0}-android.so'] if target_arch in ['aarch64', 'arm']: libs_want += [ 'lib/linux/libclang_rt.ubsan_standalone-{0}-android.so', 'lib/linux/libclang_rt.profile-{0}-android.a', ] if target_arch == 'aarch64': libs_want += ['lib/linux/libclang_rt.hwasan-{0}-android.so'] libs_want = [lib.format(target_arch) for lib in libs_want] RunCommand(['ninja'] + libs_want) # And copy them into the main build tree. for p in libs_want: shutil.copy(p, rt_lib_dst_dir) if args.with_fuchsia: # Fuchsia links against libclang_rt.builtins-<arch>.a instead of libgcc.a. for target_arch in ['aarch64', 'x86_64']: fuchsia_arch_name = { 'aarch64': 'arm64', 'x86_64': 'x64' }[target_arch] toolchain_dir = os.path.join(FUCHSIA_SDK_DIR, 'arch', fuchsia_arch_name, 'sysroot') # Build clang_rt runtime for Fuchsia in a separate build tree. build_dir = os.path.join(LLVM_BUILD_DIR, 'fuchsia-' + target_arch) if not os.path.exists(build_dir): os.mkdir(os.path.join(build_dir)) os.chdir(build_dir) target_spec = target_arch + '-fuchsia' # TODO(thakis): Might have to pass -B here once sysroot contains # binaries (e.g. gas for arm64?) fuchsia_args = base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'), '-DCMAKE_CXX_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang++'), '-DCMAKE_LINKER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'), '-DCMAKE_AR=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-ar'), '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'), '-DCMAKE_SYSTEM_NAME=Fuchsia', '-DCMAKE_C_COMPILER_TARGET=%s-fuchsia' % target_arch, '-DCMAKE_ASM_COMPILER_TARGET=%s-fuchsia' % target_arch, '-DCOMPILER_RT_BUILD_BUILTINS=ON', '-DCOMPILER_RT_BUILD_CRT=OFF', '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF', '-DCOMPILER_RT_BUILD_PROFILE=OFF', '-DCOMPILER_RT_BUILD_SANITIZERS=OFF', '-DCOMPILER_RT_BUILD_XRAY=OFF', '-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON', '-DCMAKE_SYSROOT=%s' % toolchain_dir, # TODO(thakis|scottmg): Use PER_TARGET_RUNTIME_DIR for all platforms. # https://crbug.com/882485. '-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON', # These are necessary because otherwise CMake tries to build an # executable to test to see if the compiler is working, but in doing so, # it links against the builtins.a that we're about to build. '-DCMAKE_C_COMPILER_WORKS=ON', '-DCMAKE_ASM_COMPILER_WORKS=ON', ] RunCommand(['cmake'] + fuchsia_args + [os.path.join(COMPILER_RT_DIR, 'lib', 'builtins')]) builtins_a = 'libclang_rt.builtins.a' RunCommand(['ninja', builtins_a]) # And copy it into the main build tree. fuchsia_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION, 'lib', target_spec) if not os.path.exists(fuchsia_lib_dst_dir): os.makedirs(fuchsia_lib_dst_dir) CopyFile(os.path.join(build_dir, 'lib', target_spec, builtins_a), fuchsia_lib_dst_dir) # Run tests. if args.run_tests or args.llvm_force_head_revision: RunCommand(['ninja', '-C', LLVM_BUILD_DIR, 'cr-check-all'], msvc_arch='x64') if args.run_tests: if sys.platform == 'win32': CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin')) test_targets = ['check-all'] if sys.platform == 'darwin': # TODO(thakis): Run check-all on Darwin too, https://crbug.com/959361 test_targets = ['check-llvm', 'check-clang', 'check-lld'] RunCommand(['ninja', '-C', LLVM_BUILD_DIR] + test_targets, msvc_arch='x64') if sys.platform == 'darwin': for dylib in glob.glob(os.path.join(rt_lib_dst_dir, '*.dylib')): # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to # @executable_path. # Has to happen after running tests. # TODO(glider): this is transitional. We'll need to fix the dylib # name either in our build system, or in Clang. See also # http://crbug.com/344836. subprocess.call([ 'install_name_tool', '-id', '@executable_path/' + os.path.basename(dylib), dylib ]) WriteStampFile(PACKAGE_VERSION, STAMP_FILE) WriteStampFile(PACKAGE_VERSION, FORCE_HEAD_REVISION_FILE) print('Clang build was successful.') return 0
def main(): parser = argparse.ArgumentParser(description='Build Clang.') parser.add_argument('--bootstrap', action='store_true', help='first build clang with CC, then with itself.') parser.add_argument('--disable-asserts', action='store_true', help='build with asserts disabled') parser.add_argument('--gcc-toolchain', help='(no longer used)') parser.add_argument('--lto-lld', action='store_true', help='build lld with LTO') parser.add_argument('--llvm-force-head-revision', action='store_true', help='build the latest revision') parser.add_argument('--run-tests', action='store_true', help='run tests after building') parser.add_argument('--skip-build', action='store_true', help='do not build anything') parser.add_argument('--skip-checkout', action='store_true', help='do not create or update any checkouts') parser.add_argument('--extra-tools', nargs='*', default=[], help='select additional chrome tools to build') parser.add_argument('--use-system-cmake', action='store_true', help='use the cmake from PATH instead of downloading ' 'and using prebuilt cmake binaries') parser.add_argument('--with-android', type=gn_arg, nargs='?', const=True, help='build the Android ASan runtime (linux only)', default=sys.platform.startswith('linux')) parser.add_argument('--without-android', action='store_false', help='don\'t build Android ASan runtime (linux only)', dest='with_android') parser.add_argument( '--without-fuchsia', action='store_false', help='don\'t build Fuchsia clang_rt runtime (linux/mac)', dest='with_fuchsia', default=sys.platform in ('linux2', 'darwin')) args = parser.parse_args() if args.lto_lld and not args.bootstrap: print('--lto-lld requires --bootstrap') return 1 if args.lto_lld and not sys.platform.startswith('linux'): print('--lto-lld is only effective on Linux. Ignoring the option.') args.lto_lld = False if args.with_android and not os.path.exists(ANDROID_NDK_DIR): print('Android NDK not found at ' + ANDROID_NDK_DIR) print( 'The Android NDK is needed to build a Clang whose -fsanitize=address' ) print('works on Android. See ') print( 'https://www.chromium.org/developers/how-tos/android-build-instructions' ) print('for how to install the NDK, or pass --without-android.') return 1 if args.llvm_force_head_revision: # Don't build fuchsia runtime on ToT bots at all. args.with_fuchsia = False if args.with_fuchsia and not os.path.exists(FUCHSIA_SDK_DIR): print('Fuchsia SDK not found at ' + FUCHSIA_SDK_DIR) print('The Fuchsia SDK is needed to build libclang_rt for Fuchsia.') print('Install the Fuchsia SDK by adding fuchsia to the ') print('target_os section in your .gclient and running hooks, ') print('or pass --without-fuchsia.') print( 'https://chromium.googlesource.com/chromium/src/+/master/docs/fuchsia_build_instructions.md' ) print('for general Fuchsia build instructions.') return 1 # DEVELOPER_DIR needs to be set when Xcode isn't in a standard location # and xcode-select wasn't run. This is needed for running clang and ld # for the build done by this script, but it's also needed for running # macOS system svn, so this needs to happen before calling functions using # svn. SetMacXcodePath() AddSvnToPathOnWin() global CLANG_REVISION, PACKAGE_VERSION if args.llvm_force_head_revision: CLANG_REVISION = GetSvnRevision(LLVM_REPO_URL) PACKAGE_VERSION = CLANG_REVISION + '-0' # Don't buffer stdout, so that print statements are immediately flushed. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) print('Locally building clang %s...' % PACKAGE_VERSION) WriteStampFile('', STAMP_FILE) WriteStampFile('', FORCE_HEAD_REVISION_FILE) AddCMakeToPath(args) AddGnuWinToPath() DeleteChromeToolsShim() CheckoutRepos(args) if args.skip_build: return cc, cxx = None, None cflags = [] cxxflags = [] ldflags = [] targets = 'AArch64;ARM;Mips;PowerPC;SystemZ;WebAssembly;X86' base_cmake_args = [ '-GNinja', '-DCMAKE_BUILD_TYPE=Release', '-DLLVM_ENABLE_ASSERTIONS=%s' % ('OFF' if args.disable_asserts else 'ON'), '-DLLVM_ENABLE_PIC=OFF', '-DLLVM_ENABLE_TERMINFO=OFF', '-DLLVM_TARGETS_TO_BUILD=' + targets, # Statically link MSVCRT to avoid DLL dependencies. '-DLLVM_USE_CRT_RELEASE=MT', '-DCLANG_PLUGIN_SUPPORT=OFF', '-DCLANG_ENABLE_STATIC_ANALYZER=OFF', '-DCLANG_ENABLE_ARCMT=OFF', # TODO(crbug.com/929645): Use newer toolchain to host. '-DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON', '-DBUG_REPORT_URL=' + BUG_REPORT_URL, ] if sys.platform != 'win32': # libxml2 is required by the Win manifest merging tool used in cross-builds. base_cmake_args.append('-DLLVM_ENABLE_LIBXML2=FORCE_ON') if args.bootstrap: print('Building bootstrap compiler') EnsureDirExists(LLVM_BOOTSTRAP_DIR) os.chdir(LLVM_BOOTSTRAP_DIR) bootstrap_args = base_cmake_args + [ '-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64', '-DCMAKE_INSTALL_PREFIX=' + LLVM_BOOTSTRAP_INSTALL_DIR, '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), # Ignore args.disable_asserts for the bootstrap compiler. '-DLLVM_ENABLE_ASSERTIONS=ON', ] if cc is not None: bootstrap_args.append('-DCMAKE_C_COMPILER=' + cc) if cxx is not None: bootstrap_args.append('-DCMAKE_CXX_COMPILER=' + cxx) RmCmakeCache('.') RunCommand(['cmake'] + bootstrap_args + [LLVM_DIR], msvc_arch='x64') RunCommand(['ninja'], msvc_arch='x64') if args.run_tests: if sys.platform == 'win32': CopyDiaDllTo(os.path.join(LLVM_BOOTSTRAP_DIR, 'bin')) RunCommand(['ninja', 'check-all'], msvc_arch='x64') RunCommand(['ninja', 'install'], msvc_arch='x64') if sys.platform == 'win32': cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe') cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe') # CMake has a hard time with backslashes in compiler paths: # https://stackoverflow.com/questions/13050827 cc = cc.replace('\\', '/') cxx = cxx.replace('\\', '/') else: cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang') cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang++') print('Building final compiler') # LLVM uses C++11 starting in llvm 3.5. On Linux, this means libstdc++4.7+ is # needed, on OS X it requires libc++. clang only automatically links to libc++ # when targeting OS X 10.9+, so add stdlib=libc++ explicitly so clang can run # on OS X versions as old as 10.7. deployment_target = '' if sys.platform == 'darwin' and args.bootstrap: # When building on 10.9, /usr/include usually doesn't exist, and while # Xcode's clang automatically sets a sysroot, self-built clangs don't. cflags = [ '-isysroot', subprocess.check_output(['xcrun', '--show-sdk-path']).rstrip() ] cxxflags = ['-stdlib=libc++'] + cflags ldflags += ['-stdlib=libc++'] deployment_target = '10.7' # Running libc++ tests takes a long time. Since it was only needed for # the install step above, don't build it as part of the main build. # This makes running package.py over 10% faster (30 min instead of 34 min) RmTree(LIBCXX_DIR) # If building at head, define a macro that plugins can use for #ifdefing # out code that builds at head, but not at CLANG_REVISION or vice versa. if args.llvm_force_head_revision: cflags += ['-DLLVM_FORCE_HEAD_REVISION'] cxxflags += ['-DLLVM_FORCE_HEAD_REVISION'] # Build PDBs for archival on Windows. Don't use RelWithDebInfo since it # has different optimization defaults than Release. # Also disable stack cookies (/GS-) for performance. if sys.platform == 'win32': cflags += ['/Zi', '/GS-'] cxxflags += ['/Zi', '/GS-'] ldflags += ['/DEBUG', '/OPT:REF', '/OPT:ICF'] deployment_env = None if deployment_target: deployment_env = os.environ.copy() deployment_env['MACOSX_DEPLOYMENT_TARGET'] = deployment_target # Build lld and code coverage tools. This is done separately from the rest of # the build because these tools require threading support. tools_with_threading = ['dsymutil', 'lld', 'llvm-cov', 'llvm-profdata'] print('Building the following tools with threading support: %s' % str(tools_with_threading)) if os.path.exists(THREADS_ENABLED_BUILD_DIR): RmTree(THREADS_ENABLED_BUILD_DIR) EnsureDirExists(THREADS_ENABLED_BUILD_DIR) os.chdir(THREADS_ENABLED_BUILD_DIR) threads_enabled_cmake_args = base_cmake_args + [ '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags) ] if cc is not None: threads_enabled_cmake_args.append('-DCMAKE_C_COMPILER=' + cc) if cxx is not None: threads_enabled_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx) if args.lto_lld: # Build lld with LTO. That speeds up the linker by ~10%. # We only use LTO for Linux now. # # The linker expects all archive members to have symbol tables, so the # archiver needs to be able to create symbol tables for bitcode files. # GNU ar and ranlib don't understand bitcode files, but llvm-ar and # llvm-ranlib do, so use them. ar = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ar') ranlib = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ranlib') threads_enabled_cmake_args += [ '-DCMAKE_AR=' + ar, '-DCMAKE_RANLIB=' + ranlib, '-DLLVM_ENABLE_LTO=thin', '-DLLVM_USE_LINKER=lld' ] RmCmakeCache('.') RunCommand(['cmake'] + threads_enabled_cmake_args + [LLVM_DIR], msvc_arch='x64', env=deployment_env) RunCommand(['ninja'] + tools_with_threading, msvc_arch='x64') # Build clang and other tools. CreateChromeToolsShim() cmake_args = [] # TODO(thakis): Unconditionally append this to base_cmake_args instead once # compiler-rt can build with clang-cl on Windows (http://llvm.org/PR23698) cc_args = base_cmake_args if sys.platform != 'win32' else cmake_args if cc is not None: cc_args.append('-DCMAKE_C_COMPILER=' + cc) if cxx is not None: cc_args.append('-DCMAKE_CXX_COMPILER=' + cxx) default_tools = ['plugins', 'blink_gc_plugin', 'translation_unit'] chrome_tools = list(set(default_tools + args.extra_tools)) cmake_args += base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_INSTALL_PREFIX=' + LLVM_BUILD_DIR, '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(CHROMIUM_DIR, 'tools', 'clang'), '-DCHROMIUM_TOOLS=%s' % ';'.join(chrome_tools) ] EnsureDirExists(LLVM_BUILD_DIR) os.chdir(LLVM_BUILD_DIR) RmCmakeCache('.') RunCommand(['cmake'] + cmake_args + [LLVM_DIR], msvc_arch='x64', env=deployment_env) RunCommand(['ninja'], msvc_arch='x64') # Copy in the threaded versions of lld and other tools. if sys.platform == 'win32': CopyFile( os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld-link.exe'), os.path.join(LLVM_BUILD_DIR, 'bin')) CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld.pdb'), os.path.join(LLVM_BUILD_DIR, 'bin')) else: for tool in tools_with_threading: CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', tool), os.path.join(LLVM_BUILD_DIR, 'bin')) if chrome_tools: # If any Chromium tools were built, install those now. RunCommand(['ninja', 'cr-install'], msvc_arch='x64') VerifyVersionOfBuiltClangMatchesVERSION() # Do an out-of-tree build of compiler-rt. # On Windows, this is used to get the 32-bit ASan run-time. # TODO(hans): Remove once the regular build above produces this. # On Mac and Linux, this is used to get the regular 64-bit run-time. # Do a clobbered build due to cmake changes. if os.path.isdir(COMPILER_RT_BUILD_DIR): RmTree(COMPILER_RT_BUILD_DIR) os.makedirs(COMPILER_RT_BUILD_DIR) os.chdir(COMPILER_RT_BUILD_DIR) # TODO(thakis): Add this once compiler-rt can build with clang-cl (see # above). #if args.bootstrap and sys.platform == 'win32': # The bootstrap compiler produces 64-bit binaries by default. #cflags += ['-m32'] #cxxflags += ['-m32'] compiler_rt_args = base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags) ] if sys.platform == 'darwin': compiler_rt_args += ['-DCOMPILER_RT_ENABLE_IOS=ON'] if sys.platform != 'win32': compiler_rt_args += [ '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-config'), '-DSANITIZER_MIN_OSX_VERSION="10.7"' ] # compiler-rt is part of the llvm checkout on Windows but a stand-alone # directory elsewhere, see the TODO above COMPILER_RT_DIR. RmCmakeCache('.') RunCommand(['cmake'] + compiler_rt_args + [LLVM_DIR if sys.platform == 'win32' else COMPILER_RT_DIR], msvc_arch='x86', env=deployment_env) RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86') if sys.platform != 'win32': RunCommand(['ninja', 'fuzzer']) # Copy select output to the main tree. # TODO(hans): Make this (and the .gypi and .isolate files) version number # independent. if sys.platform == 'win32': platform = 'windows' elif sys.platform == 'darwin': platform = 'darwin' else: assert sys.platform.startswith('linux') platform = 'linux' rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', platform) if sys.platform == 'win32': # TODO(thakis): This too is due to compiler-rt being part of the checkout # on Windows, see TODO above COMPILER_RT_DIR. rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION, 'lib', platform) rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION, 'lib', platform) # Blacklists: CopyDirectoryContents(os.path.join(rt_lib_src_dir, '..', '..', 'share'), os.path.join(rt_lib_dst_dir, '..', '..', 'share')) # Headers: if sys.platform != 'win32': CopyDirectoryContents( os.path.join(COMPILER_RT_BUILD_DIR, 'include/sanitizer'), os.path.join(LLVM_BUILD_DIR, 'lib/clang', RELEASE_VERSION, 'include/sanitizer')) # Static and dynamic libraries: CopyDirectoryContents(rt_lib_src_dir, rt_lib_dst_dir) if sys.platform == 'darwin': for dylib in glob.glob(os.path.join(rt_lib_dst_dir, '*.dylib')): # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to # @executable_path. # TODO(glider): this is transitional. We'll need to fix the dylib # name either in our build system, or in Clang. See also # http://crbug.com/344836. subprocess.call([ 'install_name_tool', '-id', '@executable_path/' + os.path.basename(dylib), dylib ]) if args.with_android: make_toolchain = os.path.join(ANDROID_NDK_DIR, 'build', 'tools', 'make_standalone_toolchain.py') for target_arch in ['aarch64', 'arm', 'i686']: # Make standalone Android toolchain for target_arch. toolchain_dir = os.path.join(LLVM_BUILD_DIR, 'android-toolchain-' + target_arch) api_level = '21' if target_arch == 'aarch64' else '19' RunCommand([ make_toolchain, '--api=' + api_level, '--force', '--install-dir=%s' % toolchain_dir, '--stl=libc++', '--arch=' + { 'aarch64': 'arm64', 'arm': 'arm', 'i686': 'x86', }[target_arch] ]) # NDK r16 "helpfully" installs libc++ as libstdc++ "so the compiler will # pick it up by default". Only these days, the compiler tries to find # libc++ instead. See https://crbug.com/902270. shutil.copy( os.path.join(toolchain_dir, 'sysroot/usr/lib/libstdc++.a'), os.path.join(toolchain_dir, 'sysroot/usr/lib/libc++.a')) shutil.copy( os.path.join(toolchain_dir, 'sysroot/usr/lib/libstdc++.so'), os.path.join(toolchain_dir, 'sysroot/usr/lib/libc++.so')) # Build compiler-rt runtimes needed for Android in a separate build tree. build_dir = os.path.join(LLVM_BUILD_DIR, 'android-' + target_arch) if not os.path.exists(build_dir): os.mkdir(os.path.join(build_dir)) os.chdir(build_dir) target_triple = target_arch if target_arch == 'arm': target_triple = 'armv7' target_triple += '-linux-android' + api_level cflags = [ '--target=%s' % target_triple, '--sysroot=%s/sysroot' % toolchain_dir, '-B%s' % toolchain_dir ] android_args = base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'), '-DCMAKE_CXX_COMPILER=' + os.path.join( LLVM_BUILD_DIR, 'bin/clang++'), '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'), '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), '-DCMAKE_ASM_FLAGS=' + ' '.join(cflags), '-DSANITIZER_CXX_ABI=libcxxabi', '-DCMAKE_SHARED_LINKER_FLAGS=-Wl,-u__cxa_demangle', '-DANDROID=1' ] RmCmakeCache('.') RunCommand(['cmake'] + android_args + [COMPILER_RT_DIR]) # We use ASan i686 build for fuzzing. libs_want = ['lib/linux/libclang_rt.asan-{0}-android.so'] if target_arch in ['aarch64', 'arm']: libs_want += [ 'lib/linux/libclang_rt.ubsan_standalone-{0}-android.so', 'lib/linux/libclang_rt.profile-{0}-android.a', ] if target_arch == 'aarch64': libs_want += ['lib/linux/libclang_rt.hwasan-{0}-android.so'] libs_want = [lib.format(target_arch) for lib in libs_want] RunCommand(['ninja'] + libs_want) # And copy them into the main build tree. for p in libs_want: shutil.copy(p, rt_lib_dst_dir) if args.with_fuchsia: # Fuchsia links against libclang_rt.builtins-<arch>.a instead of libgcc.a. for target_arch in ['aarch64', 'x86_64']: fuchsia_arch_name = { 'aarch64': 'arm64', 'x86_64': 'x64' }[target_arch] toolchain_dir = os.path.join(FUCHSIA_SDK_DIR, 'arch', fuchsia_arch_name, 'sysroot') # Build clang_rt runtime for Fuchsia in a separate build tree. build_dir = os.path.join(LLVM_BUILD_DIR, 'fuchsia-' + target_arch) if not os.path.exists(build_dir): os.mkdir(os.path.join(build_dir)) os.chdir(build_dir) target_spec = target_arch + '-fuchsia' # TODO(thakis): Might have to pass -B here once sysroot contains # binaries (e.g. gas for arm64?) fuchsia_args = base_cmake_args + [ '-DLLVM_ENABLE_THREADS=OFF', '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'), '-DCMAKE_CXX_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang++'), '-DCMAKE_LINKER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'), '-DCMAKE_AR=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-ar'), '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'), '-DCMAKE_SYSTEM_NAME=Fuchsia', '-DCMAKE_C_COMPILER_TARGET=%s-fuchsia' % target_arch, '-DCMAKE_ASM_COMPILER_TARGET=%s-fuchsia' % target_arch, '-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON', '-DCMAKE_SYSROOT=%s' % toolchain_dir, # TODO(thakis|scottmg): Use PER_TARGET_RUNTIME_DIR for all platforms. # https://crbug.com/882485. '-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON', # These are necessary because otherwise CMake tries to build an # executable to test to see if the compiler is working, but in doing so, # it links against the builtins.a that we're about to build. '-DCMAKE_C_COMPILER_WORKS=ON', '-DCMAKE_ASM_COMPILER_WORKS=ON', ] RmCmakeCache('.') RunCommand(['cmake'] + fuchsia_args + [os.path.join(COMPILER_RT_DIR, 'lib', 'builtins')]) builtins_a = 'libclang_rt.builtins.a' RunCommand(['ninja', builtins_a]) # And copy it into the main build tree. fuchsia_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION, target_spec, 'lib') if not os.path.exists(fuchsia_lib_dst_dir): os.makedirs(fuchsia_lib_dst_dir) CopyFile(os.path.join(build_dir, target_spec, 'lib', builtins_a), fuchsia_lib_dst_dir) # Run tests. if args.run_tests or args.llvm_force_head_revision: os.chdir(LLVM_BUILD_DIR) RunCommand(['ninja', 'cr-check-all'], msvc_arch='x64') if args.run_tests: if sys.platform == 'win32': CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin')) os.chdir(LLVM_BUILD_DIR) RunCommand(['ninja', 'check-all'], msvc_arch='x64') WriteStampFile(PACKAGE_VERSION, STAMP_FILE) WriteStampFile(PACKAGE_VERSION, FORCE_HEAD_REVISION_FILE) print('Clang build was successful.') return 0