76392ecac7
Change-Id: I00110260efebf07aef81bc618d7e07c73aa07fa4
253 lines
8.6 KiB
Python
Executable File
253 lines
8.6 KiB
Python
Executable File
#!/bin/env python3
|
|
#
|
|
# Haiku build configuration tool
|
|
# Copyright 2002-2018, Haiku, Inc. All rights reserved.
|
|
#
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import errno
|
|
from pprint import pprint
|
|
|
|
parser = argparse.ArgumentParser(description='Configure a build of Haiku')
|
|
parser.add_argument('--target-arch', nargs=1,
|
|
help='Target architectures. First provided is primary.', type=str, action='append',
|
|
choices=('x86_gcc2', 'x86', 'x86_64', 'ppc', 'm68k', 'arm', 'arm64', 'riscv32', 'riscv64'))
|
|
parser.add_argument('--bootstrap', nargs=3,
|
|
help='Prepare for a bootstrap build. No pre-built packages will be used, instead they will be built from the sources (in several phases).',
|
|
metavar=('<haikuporter>','<haikuports.cross>', '<haikuports>'))
|
|
parser.add_argument('--build-gcc-toolchain', nargs=1,
|
|
help='Assume cross compilation. Build a gcc-based toolchain.',
|
|
metavar=('<buildtools dir>'))
|
|
parser.add_argument('--use-gcc-toolchain', nargs=1,
|
|
help='Assume cross compilation. Build using an existing gcc-based toolchain.',
|
|
metavar=('<prefix>'))
|
|
parser.add_argument('--use-clang', default=False, action='store_true', help='Assume native clang build')
|
|
parser.add_argument('--distro-compatibility', nargs=1,
|
|
help='The distribution\'s level of compatibility with the official Haiku distribution. The generated files will contain the respective trademarks accordingly.',
|
|
choices=('official', 'compatible', 'default'), default='default')
|
|
args = vars(parser.parse_args())
|
|
|
|
### Global functions
|
|
|
|
def mkdir_p(path):
|
|
try:
|
|
os.makedirs(path)
|
|
except OSError as exc:
|
|
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
|
pass
|
|
else:
|
|
raise
|
|
|
|
def bok(message):
|
|
start_color = ""
|
|
end_color = ""
|
|
if sys.stdout.isatty():
|
|
start_color = "\033[92m"
|
|
end_color = "\033[0m"
|
|
print(start_color + message + end_color)
|
|
|
|
def berror(message):
|
|
start_color = ""
|
|
end_color = ""
|
|
if sys.stdout.isatty():
|
|
start_color = "\033[91m"
|
|
end_color = "\033[0m"
|
|
print(start_color + message + end_color)
|
|
|
|
def binfo(message):
|
|
start_color = ""
|
|
end_color = ""
|
|
if sys.stdout.isatty():
|
|
start_color = "\033[94m"
|
|
end_color = "\033[0m"
|
|
print(start_color + message + end_color)
|
|
|
|
### Global Varables
|
|
|
|
(host_sysname, host_nodename, host_release, host_version, host_machine) = os.uname()
|
|
buildConfig = []
|
|
|
|
# TODO: Remove "../.." if this ever moves to the source root
|
|
sourceDir = os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + "/../..")
|
|
outputDir = os.getcwd()
|
|
|
|
# If run in our source dir, assume generated
|
|
if outputDir == sourceDir:
|
|
outputDir = sourceDir + "/generated"
|
|
mkdir_p(outputDir)
|
|
|
|
### Helper Functions
|
|
|
|
# Run a command, collect stdout into a string
|
|
def cmdrun(cmd):
|
|
return subprocess.check_output(cmd).decode(sys.stdout.encoding)
|
|
|
|
# Get a config key
|
|
def get_build_config(key):
|
|
global buildConfig
|
|
for i in buildConfig:
|
|
if i["key"] == key:
|
|
return i["value"]
|
|
return None
|
|
|
|
# Delete a config key
|
|
def drop_build_config(key):
|
|
global buildConfig
|
|
value = get_build_config(key)
|
|
if value != None:
|
|
buildConfig.remove({"key": key, "value": value})
|
|
|
|
# Set a config key
|
|
def set_build_config(key, value):
|
|
global buildConfig
|
|
if get_build_config(key) != None:
|
|
drop_build_config(key)
|
|
buildConfig.append({"key": key, "value": value})
|
|
|
|
def write_build_config(filename):
|
|
global buildConfig
|
|
with open(filename, "w") as fh:
|
|
fh.write("# -- WARNING --\n")
|
|
fh.write("# This file was AUTOMATICALLY GENERATED by configure, and will be completely\n")
|
|
fh.write("# overwritten the next time configure is run.\n\n")
|
|
for i in buildConfig:
|
|
fh.write(i["key"] + " ?= " + str(i["value"]) + " ;\n")
|
|
|
|
def triplet_lookup(arch):
|
|
if arch == "x86_gcc2":
|
|
return "i586-pc-haiku"
|
|
elif arch == "x86":
|
|
return "i586-pc-haiku"
|
|
elif arch == "x86_64":
|
|
return "x86_64-unknown-haiku"
|
|
elif arch == "ppc":
|
|
return "powerpc-apple-haiku"
|
|
elif arch == "m68k":
|
|
return "m68k-unknown-haiku"
|
|
elif arch == "arm":
|
|
return "arm-unknown-haiku"
|
|
elif arch == "riscv32":
|
|
return "riscv32-unknown-haiku"
|
|
elif arch == "riscv64":
|
|
return "riscv64-unknown-haiku"
|
|
else:
|
|
berror("Unsupported target architecture: " + arch)
|
|
exit(1)
|
|
|
|
def platform_lookup(sysname):
|
|
if sysname == "Darwin":
|
|
return "darwin"
|
|
elif sysname == "FreeBSD":
|
|
return "freebsd"
|
|
elif sysname == "Haiku":
|
|
return "haiku_host"
|
|
elif sysname == "Linux":
|
|
return "linux"
|
|
elif sysname == "OpenBSD":
|
|
return "openbsd"
|
|
elif sysname == "SunOS":
|
|
return "sunos"
|
|
else:
|
|
berror("Unknown platform: " + sysname)
|
|
exit(1)
|
|
|
|
def setup_bootstrap():
|
|
if args["bootstrap"] == None:
|
|
return
|
|
set_build_config("HOST_HAIKU_PORTER", os.path.abspath(args["bootstrap"][0]))
|
|
set_build_config("HAIKU_PORTS", os.path.abspath(args["bootstrap"][1]))
|
|
set_build_config("HAIKU_PORTS_CROSS", os.path.abspath(args["bootstrap"][2]))
|
|
|
|
def setup_host_tools():
|
|
set_build_config("HOST_SHA256", "sha256sum")
|
|
set_build_config("HOST_EXTENDED_REGEX_SED", "sed -r")
|
|
|
|
def setup_host_compiler():
|
|
cc = os.environ.get("CC")
|
|
if cc == None:
|
|
# We might want to step through each potential compiler here
|
|
cc = "gcc"
|
|
set_build_config("HOST_PLATFORM", platform_lookup(host_sysname))
|
|
set_build_config("HOST_CC", cc)
|
|
set_build_config("HOST_CC_LD", cmdrun([cc, "-print-prog-name=ld"]).strip())
|
|
set_build_config("HOST_CC_OBJCOPY", cmdrun([cc, "-print-prog-name=objcopy"]).strip())
|
|
set_build_config("HOST_GCC_MACHINE", cmdrun([cc, "-dumpmachine"]).strip())
|
|
set_build_config("HOST_GCC_RAW_VERSION", cmdrun([cc, "-dumpversion"]).strip())
|
|
|
|
def setup_target_compiler(arch):
|
|
cc = get_build_config("HOST_CC")
|
|
triplet = triplet_lookup(arch)
|
|
set_build_config("HAIKU_GCC_RAW_VERSION_" + arch, cmdrun([cc, "-dumpversion"]).strip())
|
|
set_build_config("HAIKU_GCC_MACHINE_" + arch, triplet)
|
|
set_build_config("HAIKU_CPU_" + arch, arch)
|
|
if args["use_clang"]:
|
|
set_build_config("HAIKU_CC_" + arch, "clang -target " + triplet + " -B llvm-")
|
|
|
|
def build_gcc_toolchain(buildtools_dir, arch):
|
|
bok(arch + " toolchain build complete!")
|
|
|
|
### Workflow
|
|
|
|
umask = os.umask(0)
|
|
os.umask(umask)
|
|
if umask > 22:
|
|
berror("Your umask is too restrictive (should be <= 0022; is actually " + str(umask) + ")")
|
|
print()
|
|
berror("Additionally, if the source tree was cloned with a too-restrictive umask,")
|
|
berror("you will need to run \"git checkout\" again to fix this.")
|
|
exit(1)
|
|
|
|
if args["target_arch"] == None:
|
|
berror("You need to specify at least one target architecture via --target-arch")
|
|
exit(1)
|
|
|
|
if args["use_clang"] == False and args["build_gcc_toolchain"] == None and args["use_gcc_toolchain"] == None:
|
|
berror("You need to pick a toolchain via --build-gcc-toolchain, --use-gcc-toolchain, or --use-clang")
|
|
exit(1)
|
|
elif args["use_clang"] == True:
|
|
bok("Using the host's clang toolchain with a haiku target.")
|
|
elif args["build_gcc_toolchain"] != None:
|
|
bok("Building a gcc cross-compiler.")
|
|
elif args["use_gcc_toolchain"] != None:
|
|
bok("Using the existing gcc toolchain at " + args["use_gcc_toolchain"][0])
|
|
|
|
mkdir_p(outputDir + "/build")
|
|
|
|
# Some Defaults
|
|
set_build_config("TARGET_PLATFORM", "haiku")
|
|
set_build_config("HAIKU_INCLUDE_SOURCES", 0)
|
|
set_build_config("HAIKU_USE_GCC_PIPE", 0)
|
|
set_build_config("HAIKU_HOST_USE_32BIT", 0)
|
|
set_build_config("HAIKU_HOST_USE_XATTR", "")
|
|
set_build_config("HAIKU_HOST_USE_XATTR_REF", "")
|
|
set_build_config("HAIKU_DISTRO_COMPATIBILITY", args["distro_compatibility"])
|
|
|
|
setup_bootstrap()
|
|
setup_host_tools()
|
|
setup_host_compiler()
|
|
|
|
binfo("Configuring a Haiku build at " + outputDir)
|
|
|
|
for arch in args["target_arch"]:
|
|
binfo("Configuring " + arch[0] + " architecture...")
|
|
setup_target_compiler(arch[0])
|
|
|
|
if args["build_gcc_toolchain"] != None:
|
|
build_gcc_toolchain(args["build_gcc_toolchain"][0], arch[0])
|
|
|
|
write_build_config(outputDir + "/build/BuildConfig")
|
|
|
|
# Write out an entry Jamfile in our build directory
|
|
with open(outputDir + "/Jamfile", "w") as fh:
|
|
fh.write("# -- WARNING --\n")
|
|
fh.write("# This file was AUTOMATICALLY GENERATED by configure, and will be completely\n")
|
|
fh.write("# overwritten the next time configure is run.\n\n")
|
|
fh.write("HAIKU_TOP = " + os.path.relpath(sourceDir, outputDir) + " ;\n")
|
|
fh.write("HAIKU_OUTPUT_DIR = " + os.path.relpath(outputDir, os.getcwd()) + " ;\n\n")
|
|
fh.write("include [ FDirName $(HAIKU_TOP) Jamfile ] ;\n")
|
|
|
|
bok("Configuration complete!")
|