1535dbc13SAlexander von Gluck IV#!/bin/env python3
2535dbc13SAlexander von Gluck IV#
3535dbc13SAlexander von Gluck IV# Haiku build configuration tool
4535dbc13SAlexander von Gluck IV# Copyright 2002-2018, Haiku, Inc. All rights reserved.
5535dbc13SAlexander von Gluck IV#
6535dbc13SAlexander von Gluck IV
7535dbc13SAlexander von Gluck IVimport argparse
8535dbc13SAlexander von Gluck IVimport os
9535dbc13SAlexander von Gluck IVimport subprocess
10535dbc13SAlexander von Gluck IVimport sys
11cf62f22aSAlexander von Gluck IVimport errno
12535dbc13SAlexander von Gluck IVfrom pprint import pprint
13535dbc13SAlexander von Gluck IV
14535dbc13SAlexander von Gluck IVparser = argparse.ArgumentParser(description='Configure a build of Haiku')
154d182b9bSAlexander von Gluck IVparser.add_argument('--target-arch', nargs=1,
164d182b9bSAlexander von Gluck IV    help='Target architectures. First provided is primary.', type=str, action='append',
17c59cde3dSAlexander von Gluck IV    choices=('x86_gcc2', 'x86', 'x86_64', 'ppc', 'm68k', 'arm', 'arm64', 'riscv64'))
18535dbc13SAlexander von Gluck IVparser.add_argument('--bootstrap', nargs=3,
19535dbc13SAlexander von Gluck IV    help='Prepare for a bootstrap build. No pre-built packages will be used, instead they will be built from the sources (in several phases).',
20535dbc13SAlexander von Gluck IV    metavar=('<haikuporter>','<haikuports.cross>', '<haikuports>'))
21535dbc13SAlexander von Gluck IVparser.add_argument('--build-gcc-toolchain', nargs=1,
22535dbc13SAlexander von Gluck IV    help='Assume cross compilation. Build a gcc-based toolchain.',
23535dbc13SAlexander von Gluck IV    metavar=('<buildtools dir>'))
244d182b9bSAlexander von Gluck IVparser.add_argument('--use-gcc-toolchain', nargs=1,
254d182b9bSAlexander von Gluck IV    help='Assume cross compilation. Build using an existing gcc-based toolchain.',
26535dbc13SAlexander von Gluck IV    metavar=('<prefix>'))
274d182b9bSAlexander von Gluck IVparser.add_argument('--use-clang', default=False, action='store_true', help='Assume native clang build')
28535dbc13SAlexander von Gluck IVparser.add_argument('--distro-compatibility', nargs=1,
29535dbc13SAlexander von Gluck IV    help='The distribution\'s level of compatibility with the official Haiku distribution. The generated files will contain the respective trademarks accordingly.',
30535dbc13SAlexander von Gluck IV    choices=('official', 'compatible', 'default'), default='default')
31535dbc13SAlexander von Gluck IVargs = vars(parser.parse_args())
32535dbc13SAlexander von Gluck IV
33cf62f22aSAlexander von Gluck IV### Global functions
34535dbc13SAlexander von Gluck IV
35cf62f22aSAlexander von Gluck IVdef mkdir_p(path):
36cf62f22aSAlexander von Gluck IV    try:
37cf62f22aSAlexander von Gluck IV        os.makedirs(path)
38cf62f22aSAlexander von Gluck IV    except OSError as exc:
39cf62f22aSAlexander von Gluck IV        if exc.errno == errno.EEXIST and os.path.isdir(path):
40cf62f22aSAlexander von Gluck IV            pass
41cf62f22aSAlexander von Gluck IV        else:
42cf62f22aSAlexander von Gluck IV            raise
43535dbc13SAlexander von Gluck IV
44535dbc13SAlexander von Gluck IVdef bok(message):
45535dbc13SAlexander von Gluck IV    start_color = ""
46535dbc13SAlexander von Gluck IV    end_color = ""
47535dbc13SAlexander von Gluck IV    if sys.stdout.isatty():
48535dbc13SAlexander von Gluck IV        start_color = "\033[92m"
49535dbc13SAlexander von Gluck IV        end_color = "\033[0m"
50535dbc13SAlexander von Gluck IV    print(start_color + message + end_color)
51535dbc13SAlexander von Gluck IV
52535dbc13SAlexander von Gluck IVdef berror(message):
53535dbc13SAlexander von Gluck IV    start_color = ""
54535dbc13SAlexander von Gluck IV    end_color = ""
55535dbc13SAlexander von Gluck IV    if sys.stdout.isatty():
56535dbc13SAlexander von Gluck IV        start_color = "\033[91m"
57535dbc13SAlexander von Gluck IV        end_color = "\033[0m"
58535dbc13SAlexander von Gluck IV    print(start_color + message + end_color)
59535dbc13SAlexander von Gluck IV
60535dbc13SAlexander von Gluck IVdef binfo(message):
61535dbc13SAlexander von Gluck IV    start_color = ""
62535dbc13SAlexander von Gluck IV    end_color = ""
63535dbc13SAlexander von Gluck IV    if sys.stdout.isatty():
64535dbc13SAlexander von Gluck IV        start_color = "\033[94m"
65535dbc13SAlexander von Gluck IV        end_color = "\033[0m"
66535dbc13SAlexander von Gluck IV    print(start_color + message + end_color)
67535dbc13SAlexander von Gluck IV
68cf62f22aSAlexander von Gluck IV### Global Varables
69cf62f22aSAlexander von Gluck IV
70cf62f22aSAlexander von Gluck IV(host_sysname, host_nodename, host_release, host_version, host_machine) = os.uname()
71cf62f22aSAlexander von Gluck IVbuildConfig = []
72cf62f22aSAlexander von Gluck IV
73cf62f22aSAlexander von Gluck IV# TODO: Remove "../.." if this ever moves to the source root
74cf62f22aSAlexander von Gluck IVsourceDir = os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + "/../..")
75cf62f22aSAlexander von Gluck IVoutputDir = os.getcwd()
76cf62f22aSAlexander von Gluck IV
77cf62f22aSAlexander von Gluck IV# If run in our source dir, assume generated
78cf62f22aSAlexander von Gluck IVif outputDir == sourceDir:
79cf62f22aSAlexander von Gluck IV    outputDir = sourceDir + "/generated"
80cf62f22aSAlexander von Gluck IV    mkdir_p(outputDir)
81cf62f22aSAlexander von Gluck IV
82cf62f22aSAlexander von Gluck IV### Helper Functions
83cf62f22aSAlexander von Gluck IV
84535dbc13SAlexander von Gluck IV# Run a command, collect stdout into a string
85535dbc13SAlexander von Gluck IVdef cmdrun(cmd):
86535dbc13SAlexander von Gluck IV    return subprocess.check_output(cmd).decode(sys.stdout.encoding)
87535dbc13SAlexander von Gluck IV
88535dbc13SAlexander von Gluck IV# Get a config key
89535dbc13SAlexander von Gluck IVdef get_build_config(key):
90535dbc13SAlexander von Gluck IV    global buildConfig
91535dbc13SAlexander von Gluck IV    for i in buildConfig:
92535dbc13SAlexander von Gluck IV        if i["key"] == key:
93535dbc13SAlexander von Gluck IV            return i["value"]
94535dbc13SAlexander von Gluck IV    return None
95535dbc13SAlexander von Gluck IV
96535dbc13SAlexander von Gluck IV# Delete a config key
97535dbc13SAlexander von Gluck IVdef drop_build_config(key):
98535dbc13SAlexander von Gluck IV    global buildConfig
99535dbc13SAlexander von Gluck IV    value = get_build_config(key)
100535dbc13SAlexander von Gluck IV    if value != None:
101535dbc13SAlexander von Gluck IV        buildConfig.remove({"key": key, "value": value})
102535dbc13SAlexander von Gluck IV
103535dbc13SAlexander von Gluck IV# Set a config key
104535dbc13SAlexander von Gluck IVdef set_build_config(key, value):
105535dbc13SAlexander von Gluck IV    global buildConfig
106535dbc13SAlexander von Gluck IV    if get_build_config(key) != None:
107535dbc13SAlexander von Gluck IV        drop_build_config(key)
108535dbc13SAlexander von Gluck IV    buildConfig.append({"key": key, "value": value})
109535dbc13SAlexander von Gluck IV
110cf62f22aSAlexander von Gluck IVdef write_build_config(filename):
111cf62f22aSAlexander von Gluck IV    global buildConfig
112cf62f22aSAlexander von Gluck IV    with open(filename, "w") as fh:
11376392ecaSAlexander von Gluck IV        fh.write("# -- WARNING --\n")
11476392ecaSAlexander von Gluck IV        fh.write("# This file was AUTOMATICALLY GENERATED by configure, and will be completely\n")
11576392ecaSAlexander von Gluck IV        fh.write("# overwritten the next time configure is run.\n\n")
116cf62f22aSAlexander von Gluck IV        for i in buildConfig:
117cf62f22aSAlexander von Gluck IV            fh.write(i["key"] + " ?= " + str(i["value"]) + " ;\n")
118cf62f22aSAlexander von Gluck IV
119535dbc13SAlexander von Gluck IVdef triplet_lookup(arch):
120535dbc13SAlexander von Gluck IV    if arch == "x86_gcc2":
121535dbc13SAlexander von Gluck IV        return "i586-pc-haiku"
122535dbc13SAlexander von Gluck IV    elif arch == "x86":
123535dbc13SAlexander von Gluck IV        return "i586-pc-haiku"
124535dbc13SAlexander von Gluck IV    elif arch == "x86_64":
125535dbc13SAlexander von Gluck IV        return "x86_64-unknown-haiku"
126535dbc13SAlexander von Gluck IV    elif arch == "ppc":
127535dbc13SAlexander von Gluck IV        return "powerpc-apple-haiku"
128535dbc13SAlexander von Gluck IV    elif arch == "m68k":
129535dbc13SAlexander von Gluck IV        return "m68k-unknown-haiku"
130535dbc13SAlexander von Gluck IV    elif arch == "arm":
131535dbc13SAlexander von Gluck IV        return "arm-unknown-haiku"
132535dbc13SAlexander von Gluck IV    elif arch == "riscv64":
133535dbc13SAlexander von Gluck IV        return "riscv64-unknown-haiku"
134535dbc13SAlexander von Gluck IV    else:
135535dbc13SAlexander von Gluck IV        berror("Unsupported target architecture: " + arch)
136535dbc13SAlexander von Gluck IV        exit(1)
137535dbc13SAlexander von Gluck IV
138cf62f22aSAlexander von Gluck IVdef platform_lookup(sysname):
139cf62f22aSAlexander von Gluck IV    if sysname == "Darwin":
140cf62f22aSAlexander von Gluck IV        return "darwin"
141cf62f22aSAlexander von Gluck IV    elif sysname == "FreeBSD":
142cf62f22aSAlexander von Gluck IV        return "freebsd"
143cf62f22aSAlexander von Gluck IV    elif sysname == "Haiku":
144cf62f22aSAlexander von Gluck IV        return "haiku_host"
145cf62f22aSAlexander von Gluck IV    elif sysname == "Linux":
146cf62f22aSAlexander von Gluck IV        return "linux"
147cf62f22aSAlexander von Gluck IV    elif sysname == "OpenBSD":
148cf62f22aSAlexander von Gluck IV        return "openbsd"
149cf62f22aSAlexander von Gluck IV    elif sysname == "SunOS":
150cf62f22aSAlexander von Gluck IV        return "sunos"
151cf62f22aSAlexander von Gluck IV    else:
152cf62f22aSAlexander von Gluck IV        berror("Unknown platform: " + sysname)
153cf62f22aSAlexander von Gluck IV        exit(1)
154cf62f22aSAlexander von Gluck IV
155535dbc13SAlexander von Gluck IVdef setup_bootstrap():
156535dbc13SAlexander von Gluck IV    if args["bootstrap"] == None:
157535dbc13SAlexander von Gluck IV        return
158535dbc13SAlexander von Gluck IV    set_build_config("HOST_HAIKU_PORTER", os.path.abspath(args["bootstrap"][0]))
159535dbc13SAlexander von Gluck IV    set_build_config("HAIKU_PORTS", os.path.abspath(args["bootstrap"][1]))
160535dbc13SAlexander von Gluck IV    set_build_config("HAIKU_PORTS_CROSS", os.path.abspath(args["bootstrap"][2]))
161535dbc13SAlexander von Gluck IV
162535dbc13SAlexander von Gluck IVdef setup_host_tools():
163535dbc13SAlexander von Gluck IV    set_build_config("HOST_SHA256", "sha256sum")
164535dbc13SAlexander von Gluck IV    set_build_config("HOST_EXTENDED_REGEX_SED", "sed -r")
165535dbc13SAlexander von Gluck IV
166535dbc13SAlexander von Gluck IVdef setup_host_compiler():
167535dbc13SAlexander von Gluck IV    cc = os.environ.get("CC")
168535dbc13SAlexander von Gluck IV    if cc == None:
169535dbc13SAlexander von Gluck IV        # We might want to step through each potential compiler here
170535dbc13SAlexander von Gluck IV        cc = "gcc"
171cf62f22aSAlexander von Gluck IV    set_build_config("HOST_PLATFORM", platform_lookup(host_sysname))
172535dbc13SAlexander von Gluck IV    set_build_config("HOST_CC", cc)
173535dbc13SAlexander von Gluck IV    set_build_config("HOST_CC_LD", cmdrun([cc, "-print-prog-name=ld"]).strip())
174535dbc13SAlexander von Gluck IV    set_build_config("HOST_CC_OBJCOPY", cmdrun([cc, "-print-prog-name=objcopy"]).strip())
175cf62f22aSAlexander von Gluck IV    set_build_config("HOST_GCC_MACHINE", cmdrun([cc, "-dumpmachine"]).strip())
176cf62f22aSAlexander von Gluck IV    set_build_config("HOST_GCC_RAW_VERSION", cmdrun([cc, "-dumpversion"]).strip())
177535dbc13SAlexander von Gluck IV
178535dbc13SAlexander von Gluck IVdef setup_target_compiler(arch):
179535dbc13SAlexander von Gluck IV    cc = get_build_config("HOST_CC")
180cf62f22aSAlexander von Gluck IV    triplet = triplet_lookup(arch)
181535dbc13SAlexander von Gluck IV    set_build_config("HAIKU_GCC_RAW_VERSION_" + arch, cmdrun([cc, "-dumpversion"]).strip())
182cf62f22aSAlexander von Gluck IV    set_build_config("HAIKU_GCC_MACHINE_" + arch, triplet)
183535dbc13SAlexander von Gluck IV    set_build_config("HAIKU_CPU_" + arch, arch)
184535dbc13SAlexander von Gluck IV    if args["use_clang"]:
185cf62f22aSAlexander von Gluck IV        set_build_config("HAIKU_CC_" + arch, "clang -target " + triplet + " -B llvm-")
186535dbc13SAlexander von Gluck IV
1874d182b9bSAlexander von Gluck IVdef build_gcc_toolchain(buildtools_dir, arch):
1884d182b9bSAlexander von Gluck IV    bok(arch + " toolchain build complete!")
1894d182b9bSAlexander von Gluck IV
190535dbc13SAlexander von Gluck IV### Workflow
191535dbc13SAlexander von Gluck IV
192535dbc13SAlexander von Gluck IVumask = os.umask(0)
193535dbc13SAlexander von Gluck IVos.umask(umask)
194535dbc13SAlexander von Gluck IVif umask > 22:
195535dbc13SAlexander von Gluck IV    berror("Your umask is too restrictive (should be <= 0022; is actually " + str(umask) + ")")
196535dbc13SAlexander von Gluck IV    print()
197535dbc13SAlexander von Gluck IV    berror("Additionally, if the source tree was cloned with a too-restrictive umask,")
198535dbc13SAlexander von Gluck IV    berror("you will need to run \"git checkout\" again to fix this.")
199535dbc13SAlexander von Gluck IV    exit(1)
200535dbc13SAlexander von Gluck IV
201535dbc13SAlexander von Gluck IVif args["target_arch"] == None:
2024d182b9bSAlexander von Gluck IV    berror("You need to specify at least one target architecture via --target-arch")
203535dbc13SAlexander von Gluck IV    exit(1)
204535dbc13SAlexander von Gluck IV
2054d182b9bSAlexander von Gluck IVif args["use_clang"] == False and args["build_gcc_toolchain"] == None and args["use_gcc_toolchain"] == None:
2064d182b9bSAlexander von Gluck IV    berror("You need to pick a toolchain via --build-gcc-toolchain, --use-gcc-toolchain, or --use-clang")
207535dbc13SAlexander von Gluck IV    exit(1)
2084d182b9bSAlexander von Gluck IVelif args["use_clang"] == True:
2094d182b9bSAlexander von Gluck IV    bok("Using the host's clang toolchain with a haiku target.")
2104d182b9bSAlexander von Gluck IVelif args["build_gcc_toolchain"] != None:
2114d182b9bSAlexander von Gluck IV    bok("Building a gcc cross-compiler.")
2124d182b9bSAlexander von Gluck IVelif args["use_gcc_toolchain"] != None:
2134d182b9bSAlexander von Gluck IV    bok("Using the existing gcc toolchain at " + args["use_gcc_toolchain"][0])
2144d182b9bSAlexander von Gluck IV
2154d182b9bSAlexander von Gluck IVmkdir_p(outputDir + "/build")
216535dbc13SAlexander von Gluck IV
217535dbc13SAlexander von Gluck IV# Some Defaults
218535dbc13SAlexander von Gluck IVset_build_config("TARGET_PLATFORM", "haiku")
219535dbc13SAlexander von Gluck IVset_build_config("HAIKU_INCLUDE_SOURCES", 0)
220535dbc13SAlexander von Gluck IVset_build_config("HAIKU_USE_GCC_PIPE", 0)
221535dbc13SAlexander von Gluck IVset_build_config("HAIKU_HOST_USE_32BIT", 0)
222535dbc13SAlexander von Gluck IVset_build_config("HAIKU_HOST_USE_XATTR", "")
223535dbc13SAlexander von Gluck IVset_build_config("HAIKU_HOST_USE_XATTR_REF", "")
224535dbc13SAlexander von Gluck IVset_build_config("HAIKU_DISTRO_COMPATIBILITY", args["distro_compatibility"])
225535dbc13SAlexander von Gluck IV
226535dbc13SAlexander von Gluck IVsetup_bootstrap()
227535dbc13SAlexander von Gluck IVsetup_host_tools()
228535dbc13SAlexander von Gluck IVsetup_host_compiler()
229535dbc13SAlexander von Gluck IV
230535dbc13SAlexander von Gluck IVbinfo("Configuring a Haiku build at " + outputDir)
231535dbc13SAlexander von Gluck IV
2324d182b9bSAlexander von Gluck IVfor arch in args["target_arch"]:
2334d182b9bSAlexander von Gluck IV    binfo("Configuring " + arch[0] + " architecture...")
2344d182b9bSAlexander von Gluck IV    setup_target_compiler(arch[0])
2354d182b9bSAlexander von Gluck IV
2364d182b9bSAlexander von Gluck IV    if args["build_gcc_toolchain"] != None:
2374d182b9bSAlexander von Gluck IV        build_gcc_toolchain(args["build_gcc_toolchain"][0], arch[0])
2384d182b9bSAlexander von Gluck IV
239cf62f22aSAlexander von Gluck IVwrite_build_config(outputDir + "/build/BuildConfig")
240cf62f22aSAlexander von Gluck IV
241cf62f22aSAlexander von Gluck IV# Write out an entry Jamfile in our build directory
242cf62f22aSAlexander von Gluck IVwith open(outputDir + "/Jamfile", "w") as fh:
243cf62f22aSAlexander von Gluck IV    fh.write("# -- WARNING --\n")
244cf62f22aSAlexander von Gluck IV    fh.write("# This file was AUTOMATICALLY GENERATED by configure, and will be completely\n")
245cf62f22aSAlexander von Gluck IV    fh.write("# overwritten the next time configure is run.\n\n")
246cf62f22aSAlexander von Gluck IV    fh.write("HAIKU_TOP           = " + os.path.relpath(sourceDir, outputDir) + " ;\n")
247cf62f22aSAlexander von Gluck IV    fh.write("HAIKU_OUTPUT_DIR    = " + os.path.relpath(outputDir, os.getcwd()) + " ;\n\n")
248cf62f22aSAlexander von Gluck IV    fh.write("include [ FDirName $(HAIKU_TOP) Jamfile ] ;\n")
249cf62f22aSAlexander von Gluck IV
250cf62f22aSAlexander von Gluck IVbok("Configuration complete!")