460 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			460 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #!/usr/bin/env python
 | |
| 
 | |
| import errno
 | |
| import hashlib
 | |
| import fnmatch
 | |
| import os
 | |
| import platform
 | |
| import re
 | |
| import repo
 | |
| import subprocess
 | |
| import sys
 | |
| 
 | |
| from lldbbuild import *
 | |
| 
 | |
| #### SETTINGS ####
 | |
| 
 | |
| def LLVM_HASH_INCLUDES_DIFFS():
 | |
|     return False
 | |
| 
 | |
| # For use with Xcode-style builds
 | |
| 
 | |
| def process_vcs(vcs):
 | |
|     return {
 | |
|         "svn": VCS.svn,
 | |
|         "git": VCS.git
 | |
|     }[vcs]
 | |
| 
 | |
| def process_root(name):
 | |
|     return {
 | |
|         "llvm": llvm_source_path(),
 | |
|         "clang": clang_source_path(),
 | |
|         "ninja": ninja_source_path()
 | |
|     }[name]
 | |
| 
 | |
| def process_repo(r):
 | |
|     return {
 | |
|         'name': r["name"],
 | |
|         'vcs': process_vcs(r["vcs"]),
 | |
|         'root': process_root(r["name"]),
 | |
|         'url': r["url"],
 | |
|         'ref': r["ref"]
 | |
|     }
 | |
| 
 | |
| def fallback_repo(name):
 | |
|     return {
 | |
|         'name': name,
 | |
|         'vcs': None,
 | |
|         'root': process_root(name),
 | |
|         'url': None,
 | |
|         'ref': None
 | |
|     }
 | |
| 
 | |
| def dirs_exist(names):
 | |
|     for name in names:
 | |
|         if not os.path.isdir(process_root(name)):
 | |
|             return False
 | |
|     return True
 | |
| 
 | |
| def XCODE_REPOSITORIES():
 | |
|     names = ["llvm", "clang", "ninja"]
 | |
|     if dirs_exist(names):
 | |
|         return [fallback_repo(n) for n in names]
 | |
|     override = repo.get_override()
 | |
|     if override:
 | |
|         return [process_repo(r) for r in override]
 | |
|     identifier = repo.identifier()
 | |
|     if identifier == None:
 | |
|         identifier = "<invalid>" # repo.find will just use the fallback file
 | |
|     set = repo.find(identifier)
 | |
|     return [process_repo(r) for r in set]
 | |
| 
 | |
| 
 | |
| def get_c_compiler():
 | |
|     return subprocess.check_output([
 | |
|         'xcrun',
 | |
|         '--sdk', 'macosx',
 | |
|         '-find', 'clang'
 | |
|     ]).rstrip()
 | |
| 
 | |
| 
 | |
| def get_cxx_compiler():
 | |
|     return subprocess.check_output([
 | |
|         'xcrun',
 | |
|         '--sdk', 'macosx',
 | |
|         '-find', 'clang++'
 | |
|     ]).rstrip()
 | |
| 
 | |
| #                 CFLAGS="-isysroot $(xcrun --sdk macosx --show-sdk-path) -mmacosx-version-min=${DARWIN_DEPLOYMENT_VERSION_OSX}" \
 | |
| #                        LDFLAGS="-mmacosx-version-min=${DARWIN_DEPLOYMENT_VERSION_OSX}" \
 | |
| 
 | |
| 
 | |
| def get_deployment_target():
 | |
|     return os.environ.get('MACOSX_DEPLOYMENT_TARGET', None)
 | |
| 
 | |
| 
 | |
| def get_c_flags():
 | |
|     cflags = ''
 | |
|     # sdk_path = subprocess.check_output([
 | |
|     #     'xcrun',
 | |
|     #     '--sdk', 'macosx',
 | |
|     #     '--show-sdk-path']).rstrip()
 | |
|     # cflags += '-isysroot {}'.format(sdk_path)
 | |
| 
 | |
|     deployment_target = get_deployment_target()
 | |
|     if deployment_target:
 | |
|         # cflags += ' -mmacosx-version-min={}'.format(deployment_target)
 | |
|         pass
 | |
| 
 | |
|     return cflags
 | |
| 
 | |
| 
 | |
| def get_cxx_flags():
 | |
|     return get_c_flags()
 | |
| 
 | |
| 
 | |
| def get_common_linker_flags():
 | |
|     linker_flags = ""
 | |
|     deployment_target = get_deployment_target()
 | |
|     if deployment_target:
 | |
|         # if len(linker_flags) > 0:
 | |
|         #     linker_flags += ' '
 | |
|         # linker_flags += '-mmacosx-version-min={}'.format(deployment_target)
 | |
|         pass
 | |
| 
 | |
|     return linker_flags
 | |
| 
 | |
| 
 | |
| def get_exe_linker_flags():
 | |
|     return get_common_linker_flags()
 | |
| 
 | |
| 
 | |
| def get_shared_linker_flags():
 | |
|     return get_common_linker_flags()
 | |
| 
 | |
| 
 | |
| def CMAKE_FLAGS():
 | |
|     return {
 | |
|         "Debug": [
 | |
|             "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
 | |
|             "-DLLVM_ENABLE_ASSERTIONS=ON",
 | |
|         ],
 | |
|         "DebugClang": [
 | |
|             "-DCMAKE_BUILD_TYPE=Debug",
 | |
|             "-DLLVM_ENABLE_ASSERTIONS=ON",
 | |
|         ],
 | |
|         "Release": [
 | |
|             "-DCMAKE_BUILD_TYPE=Release",
 | |
|             "-DLLVM_ENABLE_ASSERTIONS=ON",
 | |
|         ],
 | |
|         "BuildAndIntegration": [
 | |
|             "-DCMAKE_BUILD_TYPE=Release",
 | |
|             "-DLLVM_ENABLE_ASSERTIONS=OFF",
 | |
|         ],
 | |
|     }
 | |
| 
 | |
| 
 | |
| def CMAKE_ENVIRONMENT():
 | |
|     return {
 | |
|     }
 | |
| 
 | |
| #### COLLECTING ALL ARCHIVES ####
 | |
| 
 | |
| 
 | |
| def collect_archives_in_path(path):
 | |
|     files = os.listdir(path)
 | |
|     # Only use libclang and libLLVM archives, and exclude libclang_rt
 | |
|     regexp = "^lib(clang[^_]|LLVM|gtest).*$"
 | |
|     return [
 | |
|         os.path.join(
 | |
|             path,
 | |
|             file) for file in files if file.endswith(".a") and re.match(
 | |
|             regexp,
 | |
|             file)]
 | |
| 
 | |
| 
 | |
| def archive_list():
 | |
|     paths = library_paths()
 | |
|     archive_lists = [collect_archives_in_path(path) for path in paths]
 | |
|     return [archive for archive_list in archive_lists for archive in archive_list]
 | |
| 
 | |
| 
 | |
| def write_archives_txt():
 | |
|     f = open(archives_txt(), 'w')
 | |
|     for archive in archive_list():
 | |
|         f.write(archive + "\n")
 | |
|     f.close()
 | |
| 
 | |
| #### COLLECTING REPOSITORY MD5S ####
 | |
| 
 | |
| 
 | |
| def source_control_status(spec):
 | |
|     vcs_for_spec = vcs(spec)
 | |
|     if LLVM_HASH_INCLUDES_DIFFS():
 | |
|         return vcs_for_spec.status() + vcs_for_spec.diff()
 | |
|     else:
 | |
|         return vcs_for_spec.status()
 | |
| 
 | |
| 
 | |
| def source_control_status_for_specs(specs):
 | |
|     statuses = [source_control_status(spec) for spec in specs]
 | |
|     return "".join(statuses)
 | |
| 
 | |
| 
 | |
| def all_source_control_status():
 | |
|     return source_control_status_for_specs(XCODE_REPOSITORIES())
 | |
| 
 | |
| 
 | |
| def md5(string):
 | |
|     m = hashlib.md5()
 | |
|     m.update(string)
 | |
|     return m.hexdigest()
 | |
| 
 | |
| 
 | |
| def all_source_control_status_md5():
 | |
|     return md5(all_source_control_status())
 | |
| 
 | |
| #### CHECKING OUT AND BUILDING LLVM ####
 | |
| 
 | |
| 
 | |
| def apply_patches(spec):
 | |
|     files = os.listdir(os.path.join(lldb_source_path(), 'scripts'))
 | |
|     patches = [
 | |
|         f for f in files if fnmatch.fnmatch(
 | |
|             f, spec['name'] + '.*.diff')]
 | |
|     for p in patches:
 | |
|         run_in_directory(["patch",
 | |
|                           "-p0",
 | |
|                           "-i",
 | |
|                           os.path.join(lldb_source_path(),
 | |
|                                        'scripts',
 | |
|                                        p)],
 | |
|                          spec['root'])
 | |
| 
 | |
| 
 | |
| def check_out_if_needed(spec):
 | |
|     if not os.path.isdir(spec['root']):
 | |
|         vcs(spec).check_out()
 | |
|         apply_patches(spec)
 | |
| 
 | |
| 
 | |
| def all_check_out_if_needed():
 | |
|     map(check_out_if_needed, XCODE_REPOSITORIES())
 | |
| 
 | |
| 
 | |
| def should_build_llvm():
 | |
|     if build_type() == BuildType.Xcode:
 | |
|         # TODO use md5 sums
 | |
|         return True
 | |
| 
 | |
| 
 | |
| def do_symlink(source_path, link_path):
 | |
|     print "Symlinking " + source_path + " to " + link_path
 | |
|     if os.path.islink(link_path):
 | |
|         os.remove(link_path)
 | |
|     if not os.path.exists(link_path):
 | |
|         os.symlink(source_path, link_path)
 | |
| 
 | |
| 
 | |
| def setup_source_symlink(repo):
 | |
|     source_path = repo["root"]
 | |
|     link_path = os.path.join(lldb_source_path(), os.path.basename(source_path))
 | |
|     do_symlink(source_path, link_path)
 | |
| 
 | |
| 
 | |
| def setup_source_symlinks():
 | |
|     map(setup_source_symlink, XCODE_REPOSITORIES())
 | |
| 
 | |
| 
 | |
| def setup_build_symlink():
 | |
|     # We don't use the build symlinks in llvm.org Xcode-based builds.
 | |
|     if build_type() != BuildType.Xcode:
 | |
|         source_path = package_build_path()
 | |
|         link_path = expected_package_build_path()
 | |
|         do_symlink(source_path, link_path)
 | |
| 
 | |
| 
 | |
| def should_run_cmake(cmake_build_dir):
 | |
|     # We need to run cmake if our llvm build directory doesn't yet exist.
 | |
|     if not os.path.exists(cmake_build_dir):
 | |
|         return True
 | |
| 
 | |
|     # Wee also need to run cmake if for some reason we don't have a ninja
 | |
|     # build file.  (Perhaps the cmake invocation failed, which this current
 | |
|     # build may have fixed).
 | |
|     ninja_path = os.path.join(cmake_build_dir, "build.ninja")
 | |
|     return not os.path.exists(ninja_path)
 | |
| 
 | |
| 
 | |
| def cmake_environment():
 | |
|     cmake_env = join_dicts(os.environ, CMAKE_ENVIRONMENT())
 | |
|     return cmake_env
 | |
| 
 | |
| 
 | |
| def is_executable(path):
 | |
|     return os.path.isfile(path) and os.access(path, os.X_OK)
 | |
| 
 | |
| 
 | |
| def find_executable_in_paths(program, paths_to_check):
 | |
|     program_dir, program_name = os.path.split(program)
 | |
|     if program_dir:
 | |
|         if is_executable(program):
 | |
|             return program
 | |
|     else:
 | |
|         for path_dir in paths_to_check:
 | |
|             path_dir = path_dir.strip('"')
 | |
|             executable_file = os.path.join(path_dir, program)
 | |
|             if is_executable(executable_file):
 | |
|                 return executable_file
 | |
|     return None
 | |
| 
 | |
| 
 | |
| def find_cmake():
 | |
|     # First check the system PATH env var for cmake
 | |
|     cmake_binary = find_executable_in_paths(
 | |
|         "cmake", os.environ["PATH"].split(os.pathsep))
 | |
|     if cmake_binary:
 | |
|         # We found it there, use it.
 | |
|         return cmake_binary
 | |
| 
 | |
|     # Check a few more common spots.  Xcode launched from Finder
 | |
|     # will have the default environment, and may not have
 | |
|     # all the normal places present.
 | |
|     extra_cmake_dirs = [
 | |
|         "/usr/local/bin",
 | |
|         "/opt/local/bin",
 | |
|         os.path.join(os.path.expanduser("~"), "bin")
 | |
|     ]
 | |
| 
 | |
|     if platform.system() == "Darwin":
 | |
|         # Add locations where an official CMake.app package may be installed.
 | |
|         extra_cmake_dirs.extend([
 | |
|             os.path.join(
 | |
|                 os.path.expanduser("~"),
 | |
|                 "Applications",
 | |
|                 "CMake.app",
 | |
|                 "Contents",
 | |
|                 "bin"),
 | |
|             os.path.join(
 | |
|                 os.sep,
 | |
|                 "Applications",
 | |
|                 "CMake.app",
 | |
|                 "Contents",
 | |
|                 "bin")])
 | |
| 
 | |
|     cmake_binary = find_executable_in_paths("cmake", extra_cmake_dirs)
 | |
|     if cmake_binary:
 | |
|         # We found it in one of the usual places.  Use that.
 | |
|         return cmake_binary
 | |
| 
 | |
|     # We couldn't find cmake.  Tell the user what to do.
 | |
|     raise Exception(
 | |
|         "could not find cmake in PATH ({}) or in any of these locations ({}), "
 | |
|         "please install cmake or add a link to it in one of those locations".format(
 | |
|             os.environ["PATH"], extra_cmake_dirs))
 | |
| 
 | |
| 
 | |
| def cmake_flags():
 | |
|     cmake_flags = CMAKE_FLAGS()[lldb_configuration()]
 | |
|     cmake_flags += ["-GNinja",
 | |
|                     "-DCMAKE_C_COMPILER={}".format(get_c_compiler()),
 | |
|                     "-DCMAKE_CXX_COMPILER={}".format(get_cxx_compiler()),
 | |
|                     "-DCMAKE_INSTALL_PREFIX={}".format(expected_package_build_path_for("llvm")),
 | |
|                     "-DCMAKE_C_FLAGS={}".format(get_c_flags()),
 | |
|                     "-DCMAKE_CXX_FLAGS={}".format(get_cxx_flags()),
 | |
|                     "-DCMAKE_EXE_LINKER_FLAGS={}".format(get_exe_linker_flags()),
 | |
|                     "-DCMAKE_SHARED_LINKER_FLAGS={}".format(get_shared_linker_flags()),
 | |
|                     "-DHAVE_CRASHREPORTER_INFO=1"]
 | |
|     deployment_target = get_deployment_target()
 | |
|     if deployment_target:
 | |
|         cmake_flags.append(
 | |
|             "-DCMAKE_OSX_DEPLOYMENT_TARGET={}".format(deployment_target))
 | |
|     return cmake_flags
 | |
| 
 | |
| 
 | |
| def run_cmake(cmake_build_dir, ninja_binary_path):
 | |
|     cmake_binary = find_cmake()
 | |
|     print "found cmake binary: using \"{}\"".format(cmake_binary)
 | |
| 
 | |
|     command_line = [cmake_binary] + cmake_flags() + [
 | |
|         "-DCMAKE_MAKE_PROGRAM={}".format(ninja_binary_path),
 | |
|         llvm_source_path()]
 | |
|     print "running cmake like so: ({}) in dir ({})".format(command_line, cmake_build_dir)
 | |
| 
 | |
|     subprocess.check_call(
 | |
|         command_line,
 | |
|         cwd=cmake_build_dir,
 | |
|         env=cmake_environment())
 | |
| 
 | |
| 
 | |
| def create_directories_as_needed(path):
 | |
|     try:
 | |
|         os.makedirs(path)
 | |
|     except OSError as error:
 | |
|         # An error indicating that the directory exists already is fine.
 | |
|         # Anything else should be passed along.
 | |
|         if error.errno != errno.EEXIST:
 | |
|             raise error
 | |
| 
 | |
| 
 | |
| def run_cmake_if_needed(ninja_binary_path):
 | |
|     cmake_build_dir = package_build_path()
 | |
|     if should_run_cmake(cmake_build_dir):
 | |
|         # Create the build directory as needed
 | |
|         create_directories_as_needed(cmake_build_dir)
 | |
|         run_cmake(cmake_build_dir, ninja_binary_path)
 | |
| 
 | |
| 
 | |
| def build_ninja_if_needed():
 | |
|     # First check if ninja is in our path.  If so, there's nothing to do.
 | |
|     ninja_binary_path = find_executable_in_paths(
 | |
|         "ninja", os.environ["PATH"].split(os.pathsep))
 | |
|     if ninja_binary_path:
 | |
|         # It's on the path.  cmake will find it.  We're good.
 | |
|         print "found ninja here: \"{}\"".format(ninja_binary_path)
 | |
|         return ninja_binary_path
 | |
| 
 | |
|     # Figure out if we need to build it.
 | |
|     ninja_build_dir = ninja_source_path()
 | |
|     ninja_binary_path = os.path.join(ninja_build_dir, "ninja")
 | |
|     if not is_executable(ninja_binary_path):
 | |
|         # Build ninja
 | |
|         command_line = ["python", "configure.py", "--bootstrap"]
 | |
|         print "building ninja like so: ({}) in dir ({})".format(command_line, ninja_build_dir)
 | |
|         subprocess.check_call(
 | |
|             command_line,
 | |
|             cwd=ninja_build_dir,
 | |
|             env=os.environ)
 | |
| 
 | |
|     return ninja_binary_path
 | |
| 
 | |
| 
 | |
| def join_dicts(dict1, dict2):
 | |
|     d = dict1.copy()
 | |
|     d.update(dict2)
 | |
|     return d
 | |
| 
 | |
| 
 | |
| def build_llvm(ninja_binary_path):
 | |
|     cmake_build_dir = package_build_path()
 | |
|     subprocess.check_call(
 | |
|         [ninja_binary_path],
 | |
|         cwd=cmake_build_dir,
 | |
|         env=cmake_environment())
 | |
| 
 | |
| 
 | |
| def build_llvm_if_needed():
 | |
|     if should_build_llvm():
 | |
|         ninja_binary_path = build_ninja_if_needed()
 | |
|         run_cmake_if_needed(ninja_binary_path)
 | |
|         build_llvm(ninja_binary_path)
 | |
|         setup_build_symlink()
 | |
| 
 | |
| #### MAIN LOGIC ####
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     all_check_out_if_needed()
 | |
|     build_llvm_if_needed()
 | |
|     write_archives_txt()
 | |
|     sys.exit(0)
 |