[SCons] Move toolchains logic to tools folder.

This commit is contained in:
Fabio Alessandrelli
2022-06-06 15:09:32 +02:00
parent a0fcd8a735
commit 93f2091185
8 changed files with 461 additions and 393 deletions

110
tools/android.py Normal file
View File

@@ -0,0 +1,110 @@
import os
import sys
import my_spawn
from SCons.Script import ARGUMENTS
def options(opts):
opts.Add(
"android_api_level",
"Target Android API level",
"18" if "32" in ARGUMENTS.get("arch", "arm64") else "21",
)
opts.Add(
"ANDROID_NDK_ROOT",
"Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.",
os.environ.get("ANDROID_NDK_ROOT", None),
)
def exists(env):
if not "ANDROID_NDK_ROOT" in os.environ:
return False
return True
def generate(env):
if not "ANDROID_NDK_ROOT" in os.environ:
raise ValueError(
"To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation."
)
env["ANDROID_NDK_ROOT"] = os.environ["ANDROID_NDK_ROOT"]
if env["arch"] not in ("arm64", "x86_64", "arm32", "x86_32"):
print("Only arm64, x86_64, arm32, and x86_32 are supported on Android. Exiting.")
Exit()
if sys.platform == "win32" or sys.platform == "msys":
my_spawn.configure(env)
# Validate API level
api_level = int(env["android_api_level"])
if "64" in env["arch"] and api_level < 21:
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
env["android_api_level"] = "21"
api_level = 21
# Setup toolchain
toolchain = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/"
if sys.platform == "win32" or sys.platform == "msys":
toolchain += "windows"
import platform as pltfm
if pltfm.machine().endswith("64"):
toolchain += "-x86_64"
elif sys.platform.startswith("linux"):
toolchain += "linux-x86_64"
elif sys.platform == "darwin":
toolchain += "darwin-x86_64"
env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
# Get architecture info
arch_info_table = {
"arm32": {
"march": "armv7-a",
"target": "armv7a-linux-androideabi",
"compiler_path": "armv7a-linux-androideabi",
"ccflags": ["-mfpu=neon"],
},
"arm64": {
"march": "armv8-a",
"target": "aarch64-linux-android",
"compiler_path": "aarch64-linux-android",
"ccflags": [],
},
"x86_32": {
"march": "i686",
"target": "i686-linux-android",
"compiler_path": "i686-linux-android",
"ccflags": ["-mstackrealign"],
},
"x86_64": {
"march": "x86-64",
"target": "x86_64-linux-android",
"compiler_path": "x86_64-linux-android",
"ccflags": [],
},
}
arch_info = arch_info_table[env["arch"]]
# Setup tools
env["CC"] = toolchain + "/bin/clang"
env["CXX"] = toolchain + "/bin/clang++"
env["LINK"] = toolchain + "/bin/clang++"
env["AR"] = toolchain + "/bin/llvm-ar"
env["AS"] = toolchain + "/bin/llvm-as"
env["STRIP"] = toolchain + "/bin/llvm-strip"
env["RANLIB"] = toolchain + "/bin/llvm-ranlib"
env["SHLIBSUFFIX"] = ".so"
env.Append(
CCFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"], "-fPIC"]
) # , '-fPIE', '-fno-addrsig', '-Oz'])
env.Append(CCFLAGS=arch_info["ccflags"])
env.Append(LINKFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"]])
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])

74
tools/ios.py Normal file
View File

@@ -0,0 +1,74 @@
import os
import sys
import subprocess
from SCons.Variables import *
if sys.version_info < (3,):
def decode_utf8(x):
return x
else:
import codecs
def decode_utf8(x):
return codecs.utf_8_decode(x)[0]
def options(opts):
opts.Add(BoolVariable("ios_simulator", "Target iOS Simulator", False))
opts.Add(
"IPHONEPATH",
"Path to iPhone toolchain",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain",
)
def exists(env):
return sys.platform == "darwin"
def generate(env):
if env["arch"] not in ("universal", "arm64", "x86_64"):
print("Only universal, arm64, and x86_64 are supported on iOS. Exiting.")
Exit()
if env["ios_simulator"]:
sdk_name = "iphonesimulator"
env.Append(CCFLAGS=["-mios-simulator-version-min=10.0"])
else:
sdk_name = "iphoneos"
env.Append(CCFLAGS=["-miphoneos-version-min=10.0"])
try:
sdk_path = decode_utf8(subprocess.check_output(["xcrun", "--sdk", sdk_name, "--show-sdk-path"]).strip())
except (subprocess.CalledProcessError, OSError):
raise ValueError("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
compiler_path = env["IPHONEPATH"] + "/usr/bin/"
env["ENV"]["PATH"] = env["IPHONEPATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"]
env["CC"] = compiler_path + "clang"
env["CXX"] = compiler_path + "clang++"
env["AR"] = compiler_path + "ar"
env["RANLIB"] = compiler_path + "ranlib"
env["SHLIBSUFFIX"] = ".dylib"
if env["arch"] == "universal":
if env["ios_simulator"]:
env.Append(LINKFLAGS=["-arch", "x86_64", "-arch", "arm64"])
env.Append(CCFLAGS=["-arch", "x86_64", "-arch", "arm64"])
else:
env.Append(LINKFLAGS=["-arch", "arm64"])
env.Append(CCFLAGS=["-arch", "arm64"])
else:
env.Append(LINKFLAGS=["-arch", env["arch"]])
env.Append(CCFLAGS=["-arch", env["arch"]])
env.Append(CCFLAGS=["-isysroot", sdk_path])
env.Append(LINKFLAGS=["-isysroot", sdk_path, "-F" + sdk_path])
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])

45
tools/javascript.py Normal file
View File

@@ -0,0 +1,45 @@
import os
def exists(env):
return "EM_CONFIG" in os.environ
def generate(env):
if env["arch"] not in ("wasm32"):
print("Only wasm32 supported on web. Exiting.")
Exit()
if "EM_CONFIG" in os.environ:
env["ENV"] = os.environ
env["CC"] = "emcc"
env["CXX"] = "em++"
env["AR"] = "emar"
env["RANLIB"] = "emranlib"
env.Append(CPPFLAGS=["-s", "SIDE_MODULE=1"])
env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"])
env["SHOBJSUFFIX"] = ".bc"
env["SHLIBSUFFIX"] = ".wasm"
# Use TempFileMunge since some AR invocations are too long for cmd.exe.
# Use POSIX-style paths, required with TempFileMunge.
env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
# All intermediate files are just LLVM bitcode.
env["OBJPREFIX"] = ""
env["OBJSUFFIX"] = ".bc"
env["PROGPREFIX"] = ""
# Program() output consists of multiple files, so specify suffixes manually at builder.
env["PROGSUFFIX"] = ""
env["LIBPREFIX"] = "lib"
env["LIBSUFFIX"] = ".a"
env["LIBPREFIXES"] = ["$LIBPREFIX"]
env["LIBSUFFIXES"] = ["$LIBSUFFIX"]
env.Replace(SHLINKFLAGS="$LINKFLAGS")
env.Replace(SHLINKFLAGS="$LINKFLAGS")
if env["target"] == "debug":
env.Append(CCFLAGS=["-O0", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])

38
tools/linux.py Normal file
View File

@@ -0,0 +1,38 @@
from SCons.Variables import *
def options(opts):
opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler - only effective when targeting Linux", False))
def exists(env):
return True
def generate(env):
if env["use_llvm"]:
base = env.Tool("clang")
base.generate(env)
env.Append(CCFLAGS=["-fPIC", "-Wwrite-strings"])
env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"])
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])
if env["arch"] == "x86_64":
# -m64 and -m32 are x86-specific already, but it doesn't hurt to
# be clear and also specify -march=x86-64. Similar with 32-bit.
env.Append(CCFLAGS=["-m64", "-march=x86-64"])
env.Append(LINKFLAGS=["-m64", "-march=x86-64"])
elif env["arch"] == "x86_32":
env.Append(CCFLAGS=["-m32", "-march=i686"])
env.Append(LINKFLAGS=["-m32", "-march=i686"])
elif env["arch"] == "arm64":
env.Append(CCFLAGS=["-march=armv8-a"])
env.Append(LINKFLAGS=["-march=armv8-a"])
elif env["arch"] == "rv64":
env.Append(CCFLAGS=["-march=rv64gc"])
env.Append(LINKFLAGS=["-march=rv64gc"])

52
tools/my_spawn.py Normal file
View File

@@ -0,0 +1,52 @@
import os
def exists(env):
return os.name == "nt"
# Workaround for MinGW. See:
# http://www.scons.org/wiki/LongCmdLinesOnWin32
def configure(env):
import subprocess
def mySubProcess(cmdline, env):
# print "SPAWNED : " + cmdline
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
proc = subprocess.Popen(
cmdline,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
startupinfo=startupinfo,
shell=False,
env=env,
)
data, err = proc.communicate()
rv = proc.wait()
if rv:
print("=====")
print(err.decode("utf-8"))
print("=====")
return rv
def mySpawn(sh, escape, cmd, args, env):
newargs = " ".join(args[1:])
cmdline = cmd + " " + newargs
rv = 0
if len(cmdline) > 32000 and cmd.endswith("ar"):
cmdline = cmd + " " + args[1] + " " + args[2] + " "
for i in range(3, len(args)):
rv = mySubProcess(cmdline + args[i], env)
if rv:
break
else:
rv = mySubProcess(cmdline, env)
return rv
env["SPAWN"] = mySpawn
env.Replace(ARFLAGS=["q"])

50
tools/osx.py Normal file
View File

@@ -0,0 +1,50 @@
import os
import sys
def options(opts):
opts.Add("macos_deployment_target", "macOS deployment target", "default")
opts.Add("macos_sdk_path", "macOS SDK path", "")
def exists(env):
return sys.platform == "darwin"
def generate(env):
if env["arch"] not in ("universal", "arm64", "x86_64"):
print("Only universal, arm64, and x86_64 are supported on macOS. Exiting.")
Exit()
if sys.platform == "darwin":
# Use clang on macOS by default
env["CXX"] = "clang++"
env["CC"] = "clang"
if env["arch"] == "universal":
env.Append(LINKFLAGS=["-arch", "x86_64", "-arch", "arm64"])
env.Append(CCFLAGS=["-arch", "x86_64", "-arch", "arm64"])
else:
env.Append(LINKFLAGS=["-arch", env["arch"]])
env.Append(CCFLAGS=["-arch", env["arch"]])
if env["macos_deployment_target"] != "default":
env.Append(CCFLAGS=["-mmacosx-version-min=" + env["macos_deployment_target"]])
env.Append(LINKFLAGS=["-mmacosx-version-min=" + env["macos_deployment_target"]])
if env["macos_sdk_path"]:
env.Append(CCFLAGS=["-isysroot", env["macos_sdk_path"]])
env.Append(LINKFLAGS=["-isysroot", env["macos_sdk_path"]])
env.Append(
LINKFLAGS=[
"-framework",
"Cocoa",
"-Wl,-undefined,dynamic_lookup",
]
)
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])

68
tools/windows.py Normal file
View File

@@ -0,0 +1,68 @@
import sys
import my_spawn
from SCons.Tool.MSCommon import msvc_exists
from SCons.Variables import *
def options(opts):
opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False))
def exists(env):
return True
def generate(env):
base = None
if not env["use_mingw"] and msvc_exists(env):
base = env.Tool("msvc")
env["is_msvc"] = True
if env["arch"] == "x86_64":
env["TARGET_ARCH"] = "amd64"
elif env["arch"] == "x86_32":
env["TARGET_ARCH"] = "x86"
base.generate(env)
env.Append(CPPDEFINES=["TYPED_METHOD_BIND"])
env.Append(LINKFLAGS=["/WX"])
if env["target"] == "debug":
env.Append(CCFLAGS=["/Z7", "/Od", "/EHsc", "/D_DEBUG", "/MDd"])
elif env["target"] == "release":
env.Append(CCFLAGS=["/O2", "/EHsc", "/DNDEBUG", "/MD"])
elif sys.platform == "win32" or sys.platform == "msys":
env["use_mingw"] = True
base = env.Tool("mingw")
base.generate(env)
# Still need to use C++17.
env.Append(CCFLAGS=["-std=c++17"])
# Don't want lib prefixes
env["IMPLIBPREFIX"] = ""
env["SHLIBPREFIX"] = ""
# Want dll suffix
env["SHLIBSUFFIX"] = ".dll"
# Long line hack. Use custom spawn, quick AR append (to avoid files with the same names to override each other).
my_spawn.configure(env)
else:
env["use_mingw"] = True
# Cross-compilation using MinGW
prefix = "i686" if env["arch"] == "x86_32" else env["arch"]
env["CXX"] = prefix + "-w64-mingw32-g++"
env["CC"] = prefix + "-w64-mingw32-gcc"
env["AR"] = prefix + "-w64-mingw32-ar"
env["RANLIB"] = prefix + "-w64-mingw32-ranlib"
env["LINK"] = prefix + "-w64-mingw32-g++"
# Want dll suffix
env["SHLIBSUFFIX"] = ".dll"
# These options are for a release build even using target=debug
env.Append(CCFLAGS=["-O3", "-Wwrite-strings"])
env.Append(
LINKFLAGS=[
"--static",
"-Wl,--no-undefined",
"-static-libgcc",
"-static-libstdc++",
]
)