forked from OSchip/llvm-project
344 lines
10 KiB
Python
344 lines
10 KiB
Python
|
#!/usr/bin/env python
|
||
|
|
||
|
import errno
|
||
|
import hashlib
|
||
|
import os
|
||
|
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",
|
||
|
],
|
||
|
}
|
||
|
|
||
|
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 check_out_if_needed(spec):
|
||
|
if not os.path.isdir(spec['root']):
|
||
|
vcs(spec).check_out()
|
||
|
|
||
|
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")
|
||
|
]
|
||
|
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(
|
||
|
"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)
|