class Stage1Builder(base_builders.LLVMBuilder): name: str = 'stage1' install_dir: Path = paths.OUT_DIR / 'stage1-install' build_android_targets: bool = False config_list: List[configs.Config] = [configs.host_config()] @property def llvm_targets(self) -> Set[str]: if self.build_android_targets: return constants.HOST_TARGETS | constants.ANDROID_TARGETS else: return constants.HOST_TARGETS @property def llvm_projects(self) -> Set[str]: proj = {'clang', 'lld', 'libcxxabi', 'libcxx', 'compiler-rt'} if self.build_lldb: proj.add('lldb') return proj @property def ldflags(self) -> List[str]: ldflags = super().ldflags # Use -static-libstdc++ to statically link the c++ runtime [1]. This # avoids specifying self.toolchain.lib_dir in rpath to find libc++ at # runtime. # [1] libc++ in our case, despite the flag saying -static-libstdc++. ldflags.append('-static-libstdc++') return ldflags @property def cmake_defines(self) -> Dict[str, str]: defines = super().cmake_defines defines['CLANG_ENABLE_ARCMT'] = 'OFF' defines['CLANG_ENABLE_STATIC_ANALYZER'] = 'OFF' defines['LLVM_BUILD_TOOLS'] = 'ON' # Make libc++.so a symlink to libc++.so.x instead of a linker script that # also adds -lc++abi. Statically link libc++abi to libc++ so it is not # necessary to pass -lc++abi explicitly. This is needed only for Linux. if self._config.target_os.is_linux: defines['LIBCXX_ENABLE_ABI_LINKER_SCRIPT'] = 'OFF' defines['LIBCXX_ENABLE_STATIC_ABI_LIBRARY'] = 'ON' # Do not build compiler-rt for Darwin. We don't ship host (or any # prebuilt) runtimes for Darwin anyway. Attempting to build these will # fail compilation of lib/builtins/atomic_*.c that only get built for # Darwin and fail compilation due to us using the bionic version of # stdatomic.h. if self._config.target_os.is_darwin: defines['LLVM_BUILD_EXTERNAL_COMPILER_RT'] = 'ON' # Don't build libfuzzer as part of the first stage build. defines['COMPILER_RT_BUILD_LIBFUZZER'] = 'OFF' return defines
class LibNcursesBuilder(base_builders.AutoconfBuilder, base_builders.LibInfo): name: str = 'libncurses' src_dir: Path = paths.LIBNCURSES_SRC_DIR config_list: List[configs.Config] = [configs.host_config()] lib_version: str = '6' @property def config_flags(self) -> List[str]: return super().config_flags + [ '--with-shared', ] @property def _lib_names(self) -> List[str]: return ['libncurses', 'libform', 'libpanel']
class LibEditBuilder(base_builders.AutoconfBuilder): name: str = 'libedit' src_dir: Path = paths.LIBEDIT_SRC_DIR config_list: List[configs.Config] = [configs.host_config()] def install(self) -> None: super().install() if self._config.target_os.is_darwin: # Updates LC_ID_DYLIB so that users of libedit won't link with absolute path. libedit_path = paths.get_libedit_lib(self.install_dir, self._config.target_os) cmd = [ 'install_name_tool', '-id', f'@rpath/{libedit_path.name}', str(libedit_path) ] utils.check_call(cmd)
class LibXml2Builder(base_builders.CMakeBuilder, base_builders.LibInfo): name: str = 'libxml2' src_dir: Path = paths.LIBXML2_SRC_DIR config_list: List[configs.Config] = [configs.host_config()] lib_version: str = '2.9.10' @contextlib.contextmanager def _backup_file(self, file_to_backup: Path) -> Iterator[None]: backup_file = file_to_backup.parent / (file_to_backup.name + '.bak') if file_to_backup.exists(): file_to_backup.rename(backup_file) try: yield finally: if backup_file.exists(): backup_file.rename(file_to_backup) def build(self) -> None: # The src dir contains configure files for Android platform. Rename them # so that they will not be used during our build. # We don't delete them here because the same libxml2 may be used to build # Android platform later. with self._backup_file(self.src_dir / 'include' / 'libxml' / 'xmlversion.h'): with self._backup_file(self.src_dir / 'config.h'): super().build() @property def cmake_defines(self) -> Dict[str, str]: defines = super().cmake_defines defines['LIBXML2_WITH_PYTHON'] = 'OFF' defines['LIBXML2_WITH_PROGRAMS'] = 'OFF' defines['LIBXML2_WITH_LZMA'] = 'OFF' defines['LIBXML2_WITH_ICONV'] = 'OFF' defines['LIBXML2_WITH_ZLIB'] = 'OFF' return defines @property def include_dir(self) -> Path: return self.install_dir / 'include' / 'libxml2' @property def symlinks(self) -> List[Path]: if self._config.target_os.is_windows: return [] ext = 'so' if self._config.target_os.is_linux else 'dylib' return [self.install_dir / 'lib' / f'libxml2.{ext}']
class SwigBuilder(base_builders.AutoconfBuilder): name: str = 'swig' src_dir: Path = paths.SWIG_SRC_DIR config_list: List[configs.Config] = [configs.host_config()] @property def config_flags(self) -> List[str]: flags = super().config_flags flags.append('--without-pcre') return flags @property def ldflags(self) -> List[str]: ldflags = super().ldflags # Point to the libc++.so from the toolchain. ldflags.append(f'-Wl,-rpath,{self.toolchain.lib_dir}') return ldflags
class LibEditBuilder(base_builders.AutoconfBuilder, base_builders.LibInfo): name: str = 'libedit' src_dir: Path = paths.LIBEDIT_SRC_DIR config_list: List[configs.Config] = [configs.host_config()] libncurses: base_builders.LibInfo lib_version: str = '0' @property def ldflags(self) -> List[str]: return [ f'-L{self.libncurses.link_libraries[0].parent}', ] + super().ldflags @property def cflags(self) -> List[str]: flags = [] flags.append('-I' + str(self.libncurses.include_dir)) flags.append('-I' + str(self.libncurses.include_dir / 'ncurses')) return flags + super().cflags def build(self) -> None: files: List[Path] = [] super().build()
class XzBuilder(base_builders.CMakeBuilder, base_builders.LibInfo): name: str = 'liblzma' src_dir: Path = paths.XZ_SRC_DIR config_list: List[configs.Config] = [configs.host_config()] static_lib: bool = True
class Stage2Builder(base_builders.LLVMBuilder): name: str = 'stage2' install_dir: Path = paths.OUT_DIR / 'stage2-install' config_list: List[configs.Config] = [configs.host_config()] remove_install_dir: bool = True debug_build: bool = False build_instrumented: bool = False profdata_file: Optional[Path] = None lto: bool = True @property def llvm_targets(self) -> Set[str]: return constants.ANDROID_TARGETS @property def llvm_projects(self) -> Set[str]: proj = { 'clang', 'lld', 'libcxxabi', 'libcxx', 'compiler-rt', 'clang-tools-extra', 'openmp', 'polly' } if self.build_lldb: proj.add('lldb') return proj @property def env(self) -> Dict[str, str]: env = super().env # Point CMake to the libc++ from stage1. It is possible that once built, # the newly-built libc++ may override this because of the rpath pointing to # $ORIGIN/../lib64. That'd be fine because both libraries are built from # the same sources. env['LD_LIBRARY_PATH'] = str(self.toolchain.lib_dir) return env @property def ldflags(self) -> List[str]: ldflags = super().ldflags if self.build_instrumented: # Building libcxx, libcxxabi with instrumentation causes linker errors # because these are built with -nodefaultlibs and prevent libc symbols # needed by libclang_rt.profile from being resolved. Manually adding # the libclang_rt.profile to linker flags fixes the issue. resource_dir = self.toolchain.resource_dir ldflags.append(str(resource_dir / 'libclang_rt.profile-x86_64.a')) return ldflags @property def cflags(self) -> List[str]: cflags = super().cflags if self.profdata_file: cflags.append('-Wno-profile-instr-out-of-date') cflags.append('-Wno-profile-instr-unprofiled') return cflags @property def cmake_defines(self) -> Dict[str, str]: defines = super().cmake_defines defines['SANITIZER_ALLOW_CXXABI'] = 'OFF' defines['OPENMP_ENABLE_OMPT_TOOLS'] = 'FALSE' defines['LIBOMP_ENABLE_SHARED'] = 'FALSE' defines['CLANG_PYTHON_BINDINGS_VERSIONS'] = '3' if (self.lto and not self._config.target_os.is_darwin and not self.build_instrumented and not self.debug_build): defines['LLVM_ENABLE_LTO'] = 'Thin' # Build libFuzzer here to be exported for the host fuzzer builds. libFuzzer # is not currently supported on Darwin. if self._config.target_os.is_darwin: defines['COMPILER_RT_BUILD_LIBFUZZER'] = 'OFF' else: defines['COMPILER_RT_BUILD_LIBFUZZER'] = 'ON' if self.debug_build: defines['CMAKE_BUILD_TYPE'] = 'Debug' if self.build_instrumented: defines['LLVM_BUILD_INSTRUMENTED'] = 'ON' # llvm-profdata is only needed to finish CMake configuration # (tools/clang/utils/perf-training/CMakeLists.txt) and not needed for # build llvm_profdata = self.toolchain.path / 'bin' / 'llvm-profdata' defines['LLVM_PROFDATA'] = str(llvm_profdata) elif self.profdata_file: defines['LLVM_PROFDATA_FILE'] = str(self.profdata_file) # Make libc++.so a symlink to libc++.so.x instead of a linker script that # also adds -lc++abi. Statically link libc++abi to libc++ so it is not # necessary to pass -lc++abi explicitly. This is needed only for Linux. if self._config.target_os.is_linux: defines['LIBCXX_ENABLE_STATIC_ABI_LIBRARY'] = 'ON' defines['LIBCXX_ENABLE_ABI_LINKER_SCRIPT'] = 'OFF' # Do not build compiler-rt for Darwin. We don't ship host (or any # prebuilt) runtimes for Darwin anyway. Attempting to build these will # fail compilation of lib/builtins/atomic_*.c that only get built for # Darwin and fail compilation due to us using the bionic version of # stdatomic.h. if self._config.target_os.is_darwin: defines['LLVM_BUILD_EXTERNAL_COMPILER_RT'] = 'ON' return defines def install_config(self) -> None: super().install_config() lldb_wrapper_path = self.install_dir / 'bin' / 'lldb.sh' lib_path_env = 'LD_LIBRARY_PATH' if self._config.target_os.is_linux else 'DYLD_LIBRARY_PATH' lldb_wrapper_path.write_text( textwrap.dedent(f"""\ #!/bin/bash CURDIR=$(cd $(dirname $0) && pwd) export PYTHONHOME="$CURDIR/../python3" export {lib_path_env}="$CURDIR/../python3/lib:${lib_path_env}" "$CURDIR/lldb" "$@" """)) lldb_wrapper_path.chmod(0o755)
class Stage1Builder(base_builders.LLVMBuilder): name: str = 'stage1' toolchain_name: str = 'prebuilt' install_dir: Path = paths.OUT_DIR / 'stage1-install' build_llvm_tools: bool = False build_android_targets: bool = False config_list: List[configs.Config] = [configs.host_config()] use_goma_for_stage1: bool = False @property def llvm_targets(self) -> Set[str]: if self.build_android_targets: return constants.HOST_TARGETS | constants.ANDROID_TARGETS else: return constants.HOST_TARGETS @property def llvm_projects(self) -> Set[str]: proj = {'clang', 'lld', 'libcxxabi', 'libcxx', 'compiler-rt'} if self.build_llvm_tools: # For lldb-tblgen. It will be used to build lldb-server and # windows lldb. proj.add('lldb') return proj @property def ldflags(self) -> List[str]: ldflags = super().ldflags # Point CMake to the libc++.so from the prebuilts. Install an rpath # to prevent linking with the newly-built libc++.so ldflags.append(f'-Wl,-rpath,{self.toolchain.lib_dir}') return ldflags def set_lldb_flags(self, target: hosts.Host, defines: Dict[str, str]) -> None: # Disable dependencies because we only need lldb-tblgen to be built. defines['LLDB_ENABLE_PYTHON'] = 'OFF' defines['LLDB_ENABLE_LIBEDIT'] = 'OFF' @property def cmake_defines(self) -> Dict[str, str]: defines = super().cmake_defines defines['CLANG_ENABLE_ARCMT'] = 'OFF' defines['CLANG_ENABLE_STATIC_ANALYZER'] = 'OFF' if self.build_llvm_tools: defines['LLVM_BUILD_TOOLS'] = 'ON' else: defines['LLVM_BUILD_TOOLS'] = 'OFF' # Make libc++.so a symlink to libc++.so.x instead of a linker script that # also adds -lc++abi. Statically link libc++abi to libc++ so it is not # necessary to pass -lc++abi explicitly. This is needed only for Linux. if self._config.target_os.is_linux: defines['LIBCXX_ENABLE_ABI_LINKER_SCRIPT'] = 'OFF' defines['LIBCXX_ENABLE_STATIC_ABI_LIBRARY'] = 'ON' # Do not build compiler-rt for Darwin. We don't ship host (or any # prebuilt) runtimes for Darwin anyway. Attempting to build these will # fail compilation of lib/builtins/atomic_*.c that only get built for # Darwin and fail compilation due to us using the bionic version of # stdatomic.h. if self._config.target_os.is_darwin: defines['LLVM_BUILD_EXTERNAL_COMPILER_RT'] = 'ON' # Don't build libfuzzer as part of the first stage build. defines['COMPILER_RT_BUILD_LIBFUZZER'] = 'OFF' return defines @property def env(self) -> Dict[str, str]: env = super().env if self.use_goma_for_stage1: env['USE_GOMA'] = 'true' return env