diff options
Diffstat (limited to 'scripts/Xcode')
-rwxr-xr-x | scripts/Xcode/build-llvm.py | 373 | ||||
-rw-r--r-- | scripts/Xcode/lldbbuild.py | 135 | ||||
-rw-r--r-- | scripts/Xcode/package-clang-headers.py | 82 |
3 files changed, 590 insertions, 0 deletions
diff --git a/scripts/Xcode/build-llvm.py b/scripts/Xcode/build-llvm.py new file mode 100755 index 0000000000000..b594a8cfe17b6 --- /dev/null +++ b/scripts/Xcode/build-llvm.py @@ -0,0 +1,373 @@ +#!/usr/bin/env python + +import errno +import hashlib +import fnmatch +import os +import platform +import subprocess +import sys + +from lldbbuild import * + +#### SETTINGS #### + +def LLVM_HASH_INCLUDES_DIFFS (): + return False + +# The use of "x = "..."; return x" here is important because tooling looks for +# it with regexps. Only change how this works if you know what you are doing. + +def LLVM_REF (): + llvm_ref = "master" + return llvm_ref + +def CLANG_REF (): + clang_ref = "master" + return clang_ref + +# For use with Xcode-style builds + +def XCODE_REPOSITORIES (): + return [ + { 'name': "llvm", + 'vcs': VCS.git, + 'root': llvm_source_path(), + 'url': "http://llvm.org/git/llvm.git", + 'ref': LLVM_REF() }, + + { 'name': "clang", + 'vcs': VCS.git, + 'root': clang_source_path(), + 'url': "http://llvm.org/git/clang.git", + 'ref': CLANG_REF() }, + + { 'name': "ninja", + 'vcs': VCS.git, + 'root': ninja_source_path(), + 'url': "https://github.com/ninja-build/ninja.git", + 'ref': "master" } + ] + +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) + return [os.path.join(path, file) for file in files if file.endswith(".a")] + +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 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()) + ] + 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 #### + +all_check_out_if_needed() +build_llvm_if_needed() +write_archives_txt() + +sys.exit(0) diff --git a/scripts/Xcode/lldbbuild.py b/scripts/Xcode/lldbbuild.py new file mode 100644 index 0000000000000..bb43315dc29de --- /dev/null +++ b/scripts/Xcode/lldbbuild.py @@ -0,0 +1,135 @@ +import os +import subprocess + +#### UTILITIES #### + +def enum (*sequential, **named): + enums = dict(zip(sequential, range(len(sequential))), **named) + return type('Enum', (), enums) + +#### SETTINGS #### + +#### INTERFACE TO THE XCODEPROJ #### + +def lldb_source_path (): + return os.environ.get('SRCROOT') + +def expected_llvm_build_path (): + if build_type() == BuildType.Xcode: + return package_build_path() + else: + return os.path.join(os.environ.get('LLDB_PATH_TO_LLVM_BUILD'), package_build_dir_name("llvm")) + +def archives_txt (): + return os.path.join(expected_package_build_path(), "archives.txt") + +def expected_package_build_path (): + return os.path.abspath(os.path.join(expected_llvm_build_path(), "..")) + +def architecture (): + platform_name = os.environ.get('RC_PLATFORM_NAME') + if not platform_name: + platform_name = os.environ.get('PLATFORM_NAME') + platform_arch = os.environ.get('ARCHS').split()[-1] + return platform_name + "-" + platform_arch + +def lldb_configuration (): + return os.environ.get('CONFIGURATION') + +def llvm_configuration (): + return os.environ.get('LLVM_CONFIGURATION') + +def llvm_build_dirtree (): + return os.environ.get('LLVM_BUILD_DIRTREE') + +# Edit the code below when adding build styles. + +BuildType = enum('Xcode') # (Debug,DebugClang,Release) + +def build_type (): + return BuildType.Xcode + +#### VCS UTILITIES #### + +VCS = enum('git', + 'svn') + +def run_in_directory(args, path): + return subprocess.check_output(args, cwd=path) + +class Git: + def __init__ (self, spec): + self.spec = spec + def status (self): + return run_in_directory(["git", "branch", "-v"], self.spec['root']) + def diff (self): + return run_in_directory(["git", "diff"], self.spec['root']) + def check_out (self): + run_in_directory(["git", "clone", "--depth=1", self.spec['url'], self.spec['root']], lldb_source_path()) + run_in_directory(["git", "fetch", "--all"], self.spec['root']) + run_in_directory(["git", "checkout", self.spec['ref']], self.spec['root']) + +class SVN: + def __init__ (self, spec): + self.spec = spec + def status (self): + return run_in_directory(["svn", "info"], self.spec['root']) + def diff (self): + return run_in_directory(["svn", "diff"], self.spec['root']) + # TODO implement check_out + +def vcs (spec): + if spec['vcs'] == VCS.git: + return Git(spec) + elif spec['vcs'] == VCS.svn: + return SVN(spec) + else: + return None + +#### SOURCE PATHS #### + +def llvm_source_path (): + if build_type() == BuildType.Xcode: + return os.path.join(lldb_source_path(), "llvm") + +def clang_source_path (): + if build_type() == BuildType.Xcode: + return os.path.join(llvm_source_path(), "tools", "clang") + +def ninja_source_path (): + if build_type() == BuildType.Xcode: + return os.path.join(lldb_source_path(), "ninja") + +#### BUILD PATHS #### + +def packages (): + return ["llvm"] + +def package_build_dir_name (package): + return package + "-" + architecture() + +def expected_package_build_path_for (package): + if build_type() == BuildType.Xcode: + if package != "llvm": + raise("On Xcode build, we only support the llvm package: requested {}".format(package)) + return package_build_path() + return os.path.join(expected_package_build_path(), package_build_dir_name(package)) + +def expected_package_build_paths (): + return [expected_package_build_path_for(package) for package in packages()] + +def library_path (build_path): + return build_path + "/lib" + +def library_paths (): + if build_type() == BuildType.Xcode: + package_build_paths = [package_build_path()] + else: + package_build_paths = expected_package_build_paths() + return [library_path(build_path) for build_path in package_build_paths] + +def package_build_path (): + return os.path.join( + llvm_build_dirtree(), + os.environ["LLVM_CONFIGURATION"], + os.environ["CURRENT_ARCH"]) diff --git a/scripts/Xcode/package-clang-headers.py b/scripts/Xcode/package-clang-headers.py new file mode 100644 index 0000000000000..55ecc90d357b8 --- /dev/null +++ b/scripts/Xcode/package-clang-headers.py @@ -0,0 +1,82 @@ +#! /usr/bin/env python + +# package-clang-headers.py +# +# The Clang module loader depends on built-in headers for the Clang compiler. +# We grab these from the Clang build and move them into the LLDB module. + +# TARGET_DIR is where the lldb framework/shared library gets put. +# LLVM_BUILD_DIR is where LLVM and Clang got built +# LLVM_BUILD_DIR/lib/clang should exist and contain headers + +import os +import re +import shutil +import sys + +import lldbbuild + +if len(sys.argv) != 3: + print "usage: " + sys.argv[0] + " TARGET_DIR LLVM_BUILD_DIR" + sys.exit(1) + +target_dir = sys.argv[1] +llvm_build_dir = lldbbuild.expected_package_build_path_for("llvm") + +if not os.path.isdir(target_dir): + print target_dir + " doesn't exist" + sys.exit(1) + +if not os.path.isdir(llvm_build_dir): + llvm_build_dir = re.sub ("-macosx-", "-iphoneos-", llvm_build_dir) + +if not os.path.isdir(llvm_build_dir): + llvm_build_dir = re.sub ("-iphoneos-", "-appletvos-", llvm_build_dir) + +if not os.path.isdir(llvm_build_dir): + llvm_build_dir = re.sub ("-appletvos-", "-watchos-", llvm_build_dir) + +if not os.path.isdir(llvm_build_dir): + print llvm_build_dir + " doesn't exist" + sys.exit(1) + +resources = os.path.join(target_dir, "LLDB.framework", "Resources") + +if not os.path.isdir(resources): + print resources + " must exist" + sys.exit(1) + +clang_dir = os.path.join(llvm_build_dir, "lib", "clang") + +if not os.path.isdir(clang_dir): + print clang_dir + " must exist" + sys.exit(1) + +version_dir = None + +for subdir in os.listdir(clang_dir): + if (re.match("^[0-9]+(\.[0-9]+)*$", subdir)): + version_dir = os.path.join(clang_dir, subdir) + break + +if version_dir == None: + print "Couldn't find a subdirectory of the form #(.#)... in " + clang_dir + sys.exit(1) + +if not os.path.isdir(version_dir): + print version_dir + " is not a directory" + sys.exit(1) + +# Just checking... we're actually going to copy all of version_dir +include_dir = os.path.join(version_dir, "include") + +if not os.path.isdir(include_dir): + print version_dir + " is not a directory" + sys.exit(1) + +clang_resources = os.path.join(resources, "Clang") + +if os.path.isdir(clang_resources): + shutil.rmtree(clang_resources) + +shutil.copytree(version_dir, clang_resources) |