#!python import os, sys, platform, json, subprocess 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 add_sources(sources, dirpath, extension): for f in os.listdir(dirpath): if f.endswith("." + extension): sources.append(dirpath + "/" + f) def gen_gdnative_lib(target, source, env): for t in target: with open(t.srcnode().path, "w") as w: w.write( decode_utf8(source[0].get_contents()) .replace("{GDNATIVE_PATH}", os.path.splitext(t.name)[0]) .replace("{TARGET}", env["target"]) ) env = Environment() target_arch = ARGUMENTS.get("b", ARGUMENTS.get("bits", "64")) target_platform = ARGUMENTS.get("p", ARGUMENTS.get("platform", "linux")) if target_platform == "windows": # This makes sure to keep the session environment variables on windows, # that way you can run scons in a vs 2017 prompt and it will find all the required tools if target_arch == "64": env = Environment(ENV=os.environ, TARGET_ARCH="amd64") else: env = Environment(ENV=os.environ, TARGET_ARCH="x86") env.Append(BUILDERS={"GDNativeLibBuilder": Builder(action=gen_gdnative_lib)}) customs = ["custom.py"] opts = Variables(customs, ARGUMENTS) opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler", False)) opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release"))) opts.Add(EnumVariable("android_arch", "Target Android architecture", "armv7", ["armv7", "arm64v8", "x86", "x86_64"])) opts.Add( "android_api_level", "Target Android API level", "18" if ARGUMENTS.get("android_arch", "armv7") in ["armv7", "x86"] 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), ) opts.Add(EnumVariable("ios_arch", "Target iOS architecture", "arm64", ["armv7", "arm64", "x86_64"])) opts.Add(BoolVariable("ios_simulator", "Target iOS Simulator", False)) opts.Add( "IPHONEPATH", "Path to iPhone toolchain", "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain", ) # Update environment (parse options) opts.Update(env) target = env["target"] if target_platform == "android": target_arch = env["android_arch"] elif target_platform == "ios": target_arch = env["ios_arch"] host_platform = platform.system() # Local dependency paths, adapt them to your setup godot_headers = ARGUMENTS.get("headers", "godot-cpp/godot-headers") godot_cpp_headers = ARGUMENTS.get("godot_cpp_headers", "godot-cpp/include") godot_cpp_lib_dir = ARGUMENTS.get("godot_cpp_lib_dir", "godot-cpp/bin") result_path = os.path.join("bin", "webrtc" if env["target"] == "release" else "webrtc_debug", "lib") lib_prefix = "" # Convenience check to enforce the use_llvm overrides when CXX is clang(++) if "CXX" in env and "clang" in os.path.basename(env["CXX"]): env["use_llvm"] = True if target_platform == "linux": env["CXX"] = "g++" # LLVM if env["use_llvm"]: if "clang++" not in os.path.basename(env["CXX"]): env["CC"] = "clang" env["CXX"] = "clang++" env["LINK"] = "clang++" if env["target"] == "debug": env.Prepend(CCFLAGS=["-g3"]) env.Append(LINKFLAGS=["-rdynamic"]) else: env.Prepend(CCFLAGS=["-O3"]) env.Append(CCFLAGS=["-fPIC", "-std=c++14"]) if target_arch == "32": env.Append(CCFLAGS=["-m32"]) env.Append(LINKFLAGS=["-m32"]) elif target_arch == "64": env.Append(CCFLAGS=["-m64"]) env.Append(LINKFLAGS=["-m64"]) # i386 does not like static libstdc++ env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) elif target_platform == "windows": if host_platform == "Windows": lib_prefix = "lib" env.Append(LINKFLAGS=["/WX"]) if target == "debug": env.Append(CCFLAGS=["/EHsc", "/D_DEBUG", "/MDd"]) else: env.Append(CCFLAGS=["/O2", "/EHsc", "/DNDEBUG", "/MD"]) else: if target_arch == "32": env["CXX"] = "i686-w64-mingw32-g++" elif target_arch == "64": env["CXX"] = "x86_64-w64-mingw32-g++" if env["target"] == "debug": env.Append(CCFLAGS=["-Og", "-g"]) elif env["target"] == "release": env.Append(CCFLAGS=["-O3"]) env.Append(CCFLAGS=["-std=c++14", "-Wwrite-strings"]) env.Append(LINKFLAGS=["--static", "-Wl,--no-undefined", "-static-libgcc", "-static-libstdc++"]) elif target_platform == "osx": if env["use_llvm"]: env["CXX"] = "clang++" # Only 64-bits is supported for OS X target_arch = "64" env.Append(CCFLAGS=["-std=c++14", "-arch", "x86_64"]) env.Append(LINKFLAGS=["-arch", "x86_64", "-framework", "Cocoa", "-Wl,-undefined,dynamic_lookup"]) if env["target"] == "debug": env.Append(CCFLAGS=["-Og", "-g"]) elif env["target"] == "release": env.Append(CCFLAGS=["-O3"]) elif target_platform == "ios": if env["ios_simulator"]: sdk_name = "iphonesimulator" env.Append(CCFLAGS=["-mios-simulator-version-min=10.0"]) env["LIBSUFFIX"] = ".simulator" + env["LIBSUFFIX"] 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.Append(CCFLAGS=["-std=c++14", "-arch", env["ios_arch"], "-isysroot", sdk_path]) env.Append( LINKFLAGS=["-arch", env["ios_arch"], "-Wl,-undefined,dynamic_lookup", "-isysroot", sdk_path, "-F" + sdk_path] ) if env["target"] == "debug": env.Append(CCFLAGS=["-Og", "-g"]) elif env["target"] == "release": env.Append(CCFLAGS=["-O3"]) elif target_platform == "android": # Verify NDK root if not "ANDROID_NDK_ROOT" in env: 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." ) # Validate API level api_level = int(env["android_api_level"]) if target_arch in ["arm64v8", "x86_64"] 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 host_platform == "Windows": toolchain += "windows" import platform as pltfm if pltfm.machine().endswith("64"): toolchain += "-x86_64" elif host_platform == "Linux": toolchain += "linux-x86_64" elif host_platform == "Darwin": toolchain += "darwin-x86_64" # Get architecture info arch_info_table = { "armv7": { "march": "armv7-a", "target": "armv7a-linux-androideabi", "tool_path": "arm-linux-androideabi", "compiler_path": "armv7a-linux-androideabi", "ccflags": ["-mfpu=neon"], }, "arm64v8": { "march": "armv8-a", "target": "aarch64-linux-android", "tool_path": "aarch64-linux-android", "compiler_path": "aarch64-linux-android", "ccflags": [], }, "x86": { "march": "i686", "target": "i686-linux-android", "tool_path": "i686-linux-android", "compiler_path": "i686-linux-android", "ccflags": ["-mstackrealign"], }, "x86_64": { "march": "x86-64", "target": "x86_64-linux-android", "tool_path": "x86_64-linux-android", "compiler_path": "x86_64-linux-android", "ccflags": [], }, } arch_info = arch_info_table[target_arch] # Setup tools env["CC"] = toolchain + "/bin/clang" env["CXX"] = toolchain + "/bin/clang++" env.Append( CCFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"], "-fPIC"] ) 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"]) else: print("No valid target platform selected.") sys.exit(1) # Godot CPP bindings env.Append(CPPPATH=[godot_headers]) env.Append(CPPPATH=[godot_cpp_headers, godot_cpp_headers + "/core", godot_cpp_headers + "/gen"]) env.Append(LIBPATH=[godot_cpp_lib_dir]) env.Append( LIBS=[ "%sgodot-cpp.%s.%s.%s%s" % (lib_prefix, target_platform, target, target_arch, ".simulator" if env["ios_simulator"] else "") ] ) # WebRTC stuff webrtc_dir = "webrtc" lib_name = "libwebrtc_full" lib_path = os.path.join(webrtc_dir, target_platform) lib_path += { "32": "/x86", "64": "/x64", "armv7": "/arm", "arm64v8": "/arm64", "arm64": "/arm64", "x86": "/x86", "x86_64": "/x64", }[target_arch] if target == "debug": lib_path += "/Debug" else: lib_path += "/Release" env.Append(CPPPATH=[webrtc_dir + "/include", webrtc_dir + "/include/third_party/abseil-cpp"]) if target_platform == "linux": env.Append(LIBS=[lib_name, "atomic"]) env.Append(LIBPATH=[lib_path]) # env.Append(CCFLAGS=["-std=c++11"]) env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX"]) env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"]) elif target_platform == "windows": # Mostly VisualStudio if env["CC"] == "cl": env.Append(CCFLAGS=["/DWEBRTC_WIN", "/DWIN32_LEAN_AND_MEAN", "/DNOMINMAX", "/DRTC_UNUSED=", "/DNO_RETURN="]) env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", "advapi32", "winmm", lib_name]]) env.Append(LIBPATH=[lib_path]) # Mostly "gcc" else: env.Append( CCFLAGS=[ "-DWINVER=0x0603", "-D_WIN32_WINNT=0x0603", "-DWEBRTC_WIN", "-DWIN32_LEAN_AND_MEAN", "-DNOMINMAX", "-DRTC_UNUSED=", "-DNO_RETURN=", ] ) env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", "advapi32", "winmm", lib_name]]) env.Append(LIBPATH=[lib_path]) elif target_platform == "osx": env.Append(LIBS=[lib_name]) env.Append(LIBPATH=[lib_path]) env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC"]) env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"]) elif target_platform == "ios": env.Append(LIBS=[lib_name]) env.Append(LIBPATH=[lib_path]) env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC", "-DWEBRTC_IOS"]) env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"]) elif target_platform == "android": env.Append(LIBS=["log"]) env.Append(LIBS=[lib_name]) env.Append(LIBPATH=[lib_path]) env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX", "-DWEBRTC_ANDROID"]) env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"]) if target_arch == "arm64v8": env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM64", "-DWEBRTC_HAS_NEON"]) elif target_arch == "armv7": env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM", "-DWEBRTC_ARCH_ARM_V7", "-DWEBRTC_HAS_NEON"]) # Our includes and sources env.Append(CPPPATH=["src/"]) sources = [] add_sources(sources, "src/", "cpp") add_sources(sources, "src/net/", "cpp") # Suffix suffix = ".%s.%s" % (target, target_arch) env["SHOBJSUFFIX"] = suffix + env["SHOBJSUFFIX"] # Make the shared library result_name = "webrtc_native.%s.%s.%s" % (target_platform, target, target_arch) + env["SHLIBSUFFIX"] library = env.SharedLibrary(target=os.path.join(result_path, result_name), source=sources) Default(library) # GDNativeLibrary gdnlib = "webrtc" if target != "release": gdnlib += "_debug" Default(env.GDNativeLibBuilder([os.path.join("bin", gdnlib, gdnlib + ".tres")], ["misc/gdnlib.tres"]))