diff options
author | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2022-06-06 15:09:32 +0200 |
---|---|---|
committer | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2022-06-27 20:44:12 +0200 |
commit | 93f2091185ff4390ca8fc8901ebc68ebc35a218f (patch) | |
tree | c69f995ae6b3e20995747861c595ca1a8fef9942 /tools | |
parent | a0fcd8a7353ab692d864d3807974a93c097fb362 (diff) | |
download | redot-cpp-93f2091185ff4390ca8fc8901ebc68ebc35a218f.tar.gz |
[SCons] Move toolchains logic to tools folder.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/android.py | 110 | ||||
-rw-r--r-- | tools/ios.py | 74 | ||||
-rw-r--r-- | tools/javascript.py | 45 | ||||
-rw-r--r-- | tools/linux.py | 38 | ||||
-rw-r--r-- | tools/my_spawn.py | 52 | ||||
-rw-r--r-- | tools/osx.py | 50 | ||||
-rw-r--r-- | tools/windows.py | 68 |
7 files changed, 437 insertions, 0 deletions
diff --git a/tools/android.py b/tools/android.py new file mode 100644 index 0000000..98c3b3f --- /dev/null +++ b/tools/android.py @@ -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"]) diff --git a/tools/ios.py b/tools/ios.py new file mode 100644 index 0000000..1101d47 --- /dev/null +++ b/tools/ios.py @@ -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"]) diff --git a/tools/javascript.py b/tools/javascript.py new file mode 100644 index 0000000..5a93584 --- /dev/null +++ b/tools/javascript.py @@ -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"]) diff --git a/tools/linux.py b/tools/linux.py new file mode 100644 index 0000000..6f89d81 --- /dev/null +++ b/tools/linux.py @@ -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"]) diff --git a/tools/my_spawn.py b/tools/my_spawn.py new file mode 100644 index 0000000..0b21419 --- /dev/null +++ b/tools/my_spawn.py @@ -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"]) diff --git a/tools/osx.py b/tools/osx.py new file mode 100644 index 0000000..1130f83 --- /dev/null +++ b/tools/osx.py @@ -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"]) diff --git a/tools/windows.py b/tools/windows.py new file mode 100644 index 0000000..40d7712 --- /dev/null +++ b/tools/windows.py @@ -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++", + ] + ) |