#!/usr/bin/env python3 import os import subprocess import shutil import argparse import sys def get_build_config(build_type): """Return build configuration based on build type""" configs = { 'debug': { 'build_dir': 'build-debug', 'install_dir': './build-debug-install', 'build_type': 'Debug', 'sanitizer': 'Address', 'shared_libs': True }, 'thread': { 'build_dir': 'build-thread', 'install_dir': './build-thread-install', 'build_type': 'Debug', 'sanitizer': 'Thread', 'shared_libs': True }, 'release': { 'build_dir': 'build-release', 'install_dir': './build-release-install', 'build_type': 'Release', 'sanitizer': None, 'shared_libs': False } } if build_type not in configs: print(f"Error: Unsupported build type '{build_type}'") print(f"Supported build types: {', '.join(configs.keys())}") sys.exit(1) return configs[build_type] def build_llvm(config): """Execute LLVM build process""" print(f"Starting LLVM build ({config['build_type']} mode)") # Build CMake command config_args = [ "cmake", "-G", "Ninja", "-S", "./llvm", "-B", config['build_dir'], "-DLLVM_USE_LINKER=lld", "-DCMAKE_C_COMPILER=clang", "-DCMAKE_CXX_COMPILER=clang++", "-DCMAKE_BUILD_TYPE=" + config['build_type'], # Only build native to speed up building llvm. "-DLLVM_TARGETS_TO_BUILD=Native", "-DLLVM_ENABLE_PROJECTS=clang", "-DCMAKE_INSTALL_PREFIX=" + config['install_dir'], ] # Add optional configurations # Build shared lib to reduce binary size and speed up linking if config['shared_libs']: config_args.append("-DBUILD_SHARED_LIBS=ON") if config['sanitizer']: config_args.append(f"-DLLVM_USE_SANITIZER={config['sanitizer']}") # CMake build command list cmake_commands = [ config_args, ["cmake", "--build", config['build_dir']], ["cmake", "--install", config['build_dir']] ] # Execute CMake commands for i, command in enumerate(cmake_commands): print(f"Executing command {i+1}/{len(cmake_commands)}: {' '.join(command)}") try: subprocess.run(command, check=True) except subprocess.CalledProcessError as e: print(f"Build failed: {e}") sys.exit(1) def copy_header_files(config): """Copy header files to installation directory""" print("Copying header files...") src = "./clang/lib/Sema/" dst = os.path.join(config['install_dir'], "include/clang/Sema/") files = ["CoroutineStmtBuilder.h", "TypeLocBuilder.h", "TreeTransform.h"] # Ensure target directory exists os.makedirs(dst, exist_ok=True) for file in files: src_file = os.path.join(src, file) dst_file = os.path.join(dst, file) if os.path.exists(src_file): print(f"Copying {src_file} to {dst_file}") shutil.copy(src_file, dst_file) else: print(f"Warning: Source file does not exist {src_file}") def main(): parser = argparse.ArgumentParser( description="Build LLVM libraries with different build configurations", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Build type descriptions: debug - Debug mode with Address Sanitizer, builds shared libraries thread - Debug mode with Thread Sanitizer, builds shared libraries release - Release mode without sanitizer, builds static libraries Examples: python build-llvm-libs.py debug python build-llvm-libs.py thread python build-llvm-libs.py release """ ) parser.add_argument( 'build_type', choices=['debug', 'thread', 'release'], help='Build type (debug/thread/release)' ) parser.add_argument( '--skip-copy', action='store_true', help='Skip header file copying step' ) args = parser.parse_args() # Get build configuration config = get_build_config(args.build_type) print(f"=== LLVM Build Configuration ===") print(f"Build type: {args.build_type}") print(f"Build directory: {config['build_dir']}") print(f"Install directory: {config['install_dir']}") print(f"CMake build type: {config['build_type']}") if config['sanitizer']: print(f"Sanitizer: {config['sanitizer']}") print(f"Shared libraries: {config['shared_libs']}") print("=" * 30) # Execute build build_llvm(config) # Copy header files (unless skipped) if not args.skip_copy: copy_header_files(config) print(f"\n✅ LLVM {args.build_type} build completed!") print(f"Install directory: {config['install_dir']}") if __name__ == "__main__": main()