summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/android.py110
-rw-r--r--tools/ios.py74
-rw-r--r--tools/javascript.py45
-rw-r--r--tools/linux.py38
-rw-r--r--tools/my_spawn.py52
-rw-r--r--tools/osx.py50
-rw-r--r--tools/windows.py68
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++",
+ ]
+ )