2018-11-15 22:35:25 +03:00
#!/bin/env python3
#
# Haiku build configuration tool
# Copyright 2002-2018, Haiku, Inc. All rights reserved.
#
import argparse
import os
import subprocess
import sys
2018-11-15 23:45:30 +03:00
import errno
2018-11-15 22:35:25 +03:00
from pprint import pprint
parser = argparse . ArgumentParser ( description = ' Configure a build of Haiku ' )
2018-11-16 01:32:22 +03:00
parser . add_argument ( ' --target-arch ' , nargs = 1 ,
help = ' Target architectures. First provided is primary. ' , type = str , action = ' append ' ,
2018-11-15 22:35:25 +03:00
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> ' ) )
2018-11-16 01:32:22 +03:00
parser . add_argument ( ' --use-gcc-toolchain ' , nargs = 1 ,
help = ' Assume cross compilation. Build using an existing gcc-based toolchain. ' ,
2018-11-15 22:35:25 +03:00
metavar = ( ' <prefix> ' ) )
2018-11-16 01:32:22 +03:00
parser . add_argument ( ' --use-clang ' , default = False , action = ' store_true ' , help = ' Assume native clang build ' )
2018-11-15 22:35:25 +03:00
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 ( ) )
2018-11-15 23:45:30 +03:00
### Global functions
2018-11-15 22:35:25 +03:00
2018-11-15 23:45:30 +03:00
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
2018-11-15 22:35:25 +03:00
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 )
2018-11-15 23:45:30 +03:00
### 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
2018-11-15 22:35:25 +03:00
# 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 } )
2018-11-15 23:45:30 +03:00
def write_build_config ( filename ) :
global buildConfig
with open ( filename , " w " ) as fh :
for i in buildConfig :
fh . write ( i [ " key " ] + " ?= " + str ( i [ " value " ] ) + " ; \n " )
2018-11-15 22:35:25 +03:00
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 )
2018-11-15 23:45:30 +03:00
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 )
2018-11-15 22:35:25 +03:00
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 "
2018-11-15 23:45:30 +03:00
set_build_config ( " HOST_PLATFORM " , platform_lookup ( host_sysname ) )
2018-11-15 22:35:25 +03:00
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 ( ) )
2018-11-15 23:45:30 +03:00
set_build_config ( " HOST_GCC_MACHINE " , cmdrun ( [ cc , " -dumpmachine " ] ) . strip ( ) )
set_build_config ( " HOST_GCC_RAW_VERSION " , cmdrun ( [ cc , " -dumpversion " ] ) . strip ( ) )
2018-11-15 22:35:25 +03:00
def setup_target_compiler ( arch ) :
cc = get_build_config ( " HOST_CC " )
2018-11-15 23:45:30 +03:00
triplet = triplet_lookup ( arch )
2018-11-15 22:35:25 +03:00
set_build_config ( " HAIKU_GCC_RAW_VERSION_ " + arch , cmdrun ( [ cc , " -dumpversion " ] ) . strip ( ) )
2018-11-15 23:45:30 +03:00
set_build_config ( " HAIKU_GCC_MACHINE_ " + arch , triplet )
2018-11-15 22:35:25 +03:00
set_build_config ( " HAIKU_CPU_ " + arch , arch )
if args [ " use_clang " ] :
2018-11-15 23:45:30 +03:00
set_build_config ( " HAIKU_CC_ " + arch , " clang -target " + triplet + " -B llvm- " )
2018-11-15 22:35:25 +03:00
2018-11-16 01:32:22 +03:00
def build_gcc_toolchain ( buildtools_dir , arch ) :
bok ( arch + " toolchain build complete! " )
2018-11-15 22:35:25 +03:00
### 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 :
2018-11-16 01:32:22 +03:00
berror ( " You need to specify at least one target architecture via --target-arch " )
2018-11-15 22:35:25 +03:00
exit ( 1 )
2018-11-16 01:32:22 +03:00
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 " )
2018-11-15 22:35:25 +03:00
exit ( 1 )
2018-11-16 01:32:22 +03:00
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 " )
2018-11-15 22:35:25 +03:00
# 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 )
2018-11-16 01:32:22 +03:00
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 ] )
2018-11-15 23:45:30 +03:00
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! " )