Browse Source

Merge pull request #759 from aaronfranke/scons-cpu-arch

Unify bits, android_arch, macos_arch ios_arch into arch, support non-x86 Linux
Fabio Alessandrelli 3 years ago
parent
commit
851ec2f923

+ 8 - 7
.github/workflows/ci.yml

@@ -13,26 +13,26 @@ jobs:
             os: ubuntu-18.04
             platform: linux
             artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
-            artifact-path: bin/libgodot-cpp.linux.release.64.a
+            artifact-path: bin/libgodot-cpp.linux.release.x86_64.a
 
           - name: 🐧 Linux (GCC, Double Precision)
             os: ubuntu-18.04
             platform: linux
             artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
-            artifact-path: bin/libgodot-cpp.linux.release.64.a
+            artifact-path: bin/libgodot-cpp.linux.release.x86_64.a
             flags: float=64
 
           - name: 🏁 Windows (x86_64, MSVC)
             os: windows-2019
             platform: windows
             artifact-name: godot-cpp-windows-msvc2019-x86_64-release
-            artifact-path: bin/libgodot-cpp.windows.release.64.lib
+            artifact-path: bin/libgodot-cpp.windows.release.x86_64.lib
 
           - name: 🏁 Windows (x86_64, MinGW)
             os: windows-2019
             platform: windows
             artifact-name: godot-cpp-linux-mingw-x86_64-release
-            artifact-path: bin/libgodot-cpp.windows.release.64.a
+            artifact-path: bin/libgodot-cpp.windows.release.x86_64.a
             flags: use_mingw=yes
 
           - name: 🍎 macOS (universal)
@@ -40,20 +40,21 @@ jobs:
             platform: osx
             artifact-name: godot-cpp-macos-universal-release
             artifact-path: bin/libgodot-cpp.osx.release.universal.a
-            flags: macos_arch=universal
+            flags: arch=universal
 
           - name: 🤖 Android (arm64)
             os: ubuntu-18.04
             platform: android
             artifact-name: godot-cpp-android-arm64-release
-            artifact-path: bin/libgodot-cpp.android.release.arm64v8.a
-            flags: android_arch=arm64v8
+            artifact-path: bin/libgodot-cpp.android.release.arm64.a
+            flags: arch=arm64
 
           - name: 🍏 iOS (arm64)
             os: macos-11
             platform: ios
             artifact-name: godot-cpp-ios-arm64-release
             artifact-path: bin/libgodot-cpp.ios.release.arm64.a
+            flags: arch=arm64
 
     steps:
       - name: Checkout

+ 14 - 9
README.md

@@ -42,12 +42,15 @@ so formatting is done before your changes are submitted.
 
 ## Getting Started
 
-It's a bit similar to what it was for 3.x but also a bit different. This new approach is much more akin to how core Godot modules are structured.
+It's a bit similar to what it was for 3.x but also a bit different.
+This new approach is much more akin to how core Godot modules are structured.
 
 Compiling this repository generates a static library to be linked with your shared lib,
 just like before.
 
-To use the shared lib in your Godot project you'll need a `.gdextension` file, which replaces what was the `.gdnlib` before. Follow the example:
+To use the shared lib in your Godot project you'll need a `.gdextension`
+file, which replaces what was the `.gdnlib` before.
+Follow [the example](test/demo/example.gdextension):
 
 ```ini
 [configuration]
@@ -56,15 +59,17 @@ entry_symbol = "example_library_init"
 
 [libraries]
 
-linux.64.debug = "bin/libgdexample.linux.debug.64.so"
-linux.64.release = "bin/libgdexample.linux.release.64.so"
-windows.64.debug = "bin/libgdexample.windows.debug.64.dll"
-windows.64.release = "bin/libgdexample.windows.release.64.dll"
-macos.debug = "bin/libgdexample.debug.framework"
-macos.release = "bin/libgdexample.release.framework"
+macos.debug = "bin/libgdexample.osx.debug.framework"
+macos.release = "bin/libgdexample.osx.release.framework"
+windows.debug.x86_64 = "bin/libgdexample.windows.debug.x86_64.dll"
+windows.release.x86_64 = "bin/libgdexample.windows.release.x86_64.dll"
+linux.debug.x86_64 = "bin/libgdexample.linux.debug.x86_64.so"
+linux.release.x86_64 = "bin/libgdexample.linux.release.x86_64.so"
+# Repeat for other architectures to support arm64, rv64, etc.
 ```
 
-The `entry_symbol` is the name of the function that initializes your library. It should be similar to following layout:
+The `entry_symbol` is the name of the function that initializes
+your library. It should be similar to following layout:
 
 ```cpp
 extern "C" {

+ 102 - 49
SConstruct

@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 
 import os
+import platform
 import sys
 import subprocess
 from binding_generator import scons_generate_bindings, scons_emit_files
@@ -82,15 +83,6 @@ else:
 
 env = Environment(ENV=os.environ)
 
-is64 = sys.maxsize > 2**32
-if (
-    env["TARGET_ARCH"] == "amd64"
-    or env["TARGET_ARCH"] == "emt64"
-    or env["TARGET_ARCH"] == "x86_64"
-    or env["TARGET_ARCH"] == "arm64-v8a"
-):
-    is64 = True
-
 opts = Variables([], ARGUMENTS)
 opts.Add(
     EnumVariable(
@@ -101,7 +93,7 @@ opts.Add(
         ignorecase=2,
     )
 )
-opts.Add(EnumVariable("bits", "Target platform bits", "64" if is64 else "32", ("32", "64")))
+
 opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler - only effective when targeting Linux or FreeBSD", False))
 opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False))
 # Must be the same setting as used for cpp_bindings
@@ -115,11 +107,8 @@ opts.Add(PathVariable("custom_api_file", "Path to a custom JSON API file", None,
 opts.Add(
     BoolVariable("generate_bindings", "Force GDExtension API bindings generation. Auto-detected by default.", False)
 )
-opts.Add(EnumVariable("android_arch", "Target Android architecture", "armv7", ["armv7", "arm64v8", "x86", "x86_64"]))
 opts.Add("macos_deployment_target", "macOS deployment target", "default")
 opts.Add("macos_sdk_path", "macOS SDK path", "")
-opts.Add(EnumVariable("macos_arch", "Target macOS architecture", "universal", ["universal", "x86_64", "arm64"]))
-opts.Add(EnumVariable("ios_arch", "Target iOS architecture", "arm64", ["universal", "arm64", "x86_64"]))
 opts.Add(BoolVariable("ios_simulator", "Target iOS Simulator", False))
 opts.Add(
     "IPHONEPATH",
@@ -129,7 +118,7 @@ opts.Add(
 opts.Add(
     "android_api_level",
     "Target Android API level",
-    "18" if ARGUMENTS.get("android_arch", "armv7") in ["armv7", "x86"] else "21",
+    "18" if "32" in ARGUMENTS.get("arch", "arm64") else "21",
 )
 opts.Add(
     "ANDROID_NDK_ROOT",
@@ -141,9 +130,54 @@ opts.Add(BoolVariable("generate_template_get_node", "Generate a template version
 opts.Add(BoolVariable("build_library", "Build the godot-cpp library.", True))
 opts.Add(EnumVariable("float", "Floating-point precision", "32", ("32", "64")))
 
+# CPU architecture options.
+architecture_array = ["", "universal", "x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32"]
+architecture_aliases = {
+    "x64": "x86_64",
+    "amd64": "x86_64",
+    "armv7": "arm32",
+    "armv8": "arm64",
+    "arm64v8": "arm64",
+    "aarch64": "arm64",
+    "rv": "rv64",
+    "riscv": "rv64",
+    "riscv64": "rv64",
+    "ppcle": "ppc32",
+    "ppc": "ppc32",
+    "ppc64le": "ppc64",
+}
+opts.Add(EnumVariable("arch", "CPU architecture", "", architecture_array, architecture_aliases))
+
 opts.Update(env)
 Help(opts.GenerateHelpText(env))
 
+# Process CPU architecture argument.
+if env["arch"] == "":
+    # No architecture specified. Default to arm64 if building for Android,
+    # universal if building for macOS or iOS, wasm32 if building for web,
+    # otherwise default to the host architecture.
+    if env["platform"] in ["osx", "ios"]:
+        env["arch"] = "universal"
+    elif env["platform"] == "android":
+        env["arch"] = "arm64"
+    elif env["platform"] == "javascript":
+        env["arch"] = "wasm32"
+    else:
+        host_machine = platform.machine().lower()
+        if host_machine in architecture_array:
+            env["arch"] = host_machine
+        elif host_machine in architecture_aliases.keys():
+            env["arch"] = architecture_aliases[host_machine]
+        elif "86" in host_machine:
+            # Catches x86, i386, i486, i586, i686, etc.
+            env["arch"] = "x86_32"
+        else:
+            print("Unsupported CPU architecture: " + host_machine)
+            Exit()
+
+# We use this to re-set env["arch"] anytime we call opts.Update(env).
+env_arch = env["arch"]
+
 # Detect and print a warning listing unknown SCons variables to ease troubleshooting.
 unknown = opts.UnknownVariables()
 if unknown:
@@ -151,16 +185,19 @@ if unknown:
     for item in unknown.items():
         print("    " + item[0] + "=" + item[1])
 
+print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
+
 # This makes sure to keep the session environment variables on Windows.
 # This way, you can run SCons in a Visual Studio 2017 prompt and it will find
 # all the required tools
 if host_platform == "windows" and env["platform"] != "android":
-    if env["bits"] == "64":
+    if env["arch"] == "x86_64":
         env = Environment(TARGET_ARCH="amd64")
-    elif env["bits"] == "32":
+    elif env["arch"] == "x86_32":
         env = Environment(TARGET_ARCH="x86")
 
     opts.Update(env)
+    env["arch"] = env_arch
 
 # Require C++17
 if host_platform == "windows" and env["platform"] == "windows" and not env["use_mingw"]:
@@ -187,26 +224,35 @@ if env["platform"] == "linux" or env["platform"] == "freebsd":
     elif env["target"] == "release":
         env.Append(CCFLAGS=["-O3"])
 
-    if env["bits"] == "64":
-        env.Append(CCFLAGS=["-m64"])
-        env.Append(LINKFLAGS=["-m64"])
-    elif env["bits"] == "32":
-        env.Append(CCFLAGS=["-m32"])
-        env.Append(LINKFLAGS=["-m32"])
+    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"])
 
 elif env["platform"] == "osx":
+    if env["arch"] not in ("universal", "arm64", "x86_64"):
+        print("Only universal, arm64, and x86_64 are supported on macOS. Exiting.")
+        Exit()
+
     # Use Clang on macOS by default
     env["CXX"] = "clang++"
 
-    if env["bits"] == "32":
-        raise ValueError("Only 64-bit builds are supported for the macOS target.")
-
-    if env["macos_arch"] == "universal":
+    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["macos_arch"]])
-        env.Append(CCFLAGS=["-arch", env["macos_arch"]])
+        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"]])
@@ -230,6 +276,10 @@ elif env["platform"] == "osx":
         env.Append(CCFLAGS=["-O3"])
 
 elif env["platform"] == "ios":
+    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"])
@@ -251,7 +301,7 @@ elif env["platform"] == "ios":
     env["RANLIB"] = compiler_path + "ranlib"
     env["SHLIBSUFFIX"] = ".dylib"
 
-    if env["ios_arch"] == "universal":
+    if env["arch"] == "universal":
         if env["ios_simulator"]:
             env.Append(LINKFLAGS=["-arch", "x86_64", "-arch", "arm64"])
             env.Append(CCFLAGS=["-arch", "x86_64", "-arch", "arm64"])
@@ -259,8 +309,8 @@ elif env["platform"] == "ios":
             env.Append(LINKFLAGS=["-arch", "arm64"])
             env.Append(CCFLAGS=["-arch", "arm64"])
     else:
-        env.Append(LINKFLAGS=["-arch", env["ios_arch"]])
-        env.Append(CCFLAGS=["-arch", env["ios_arch"]])
+        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])
@@ -282,12 +332,12 @@ elif env["platform"] == "windows":
 
     elif host_platform == "linux" or host_platform == "freebsd" or host_platform == "osx":
         # Cross-compilation using MinGW
-        if env["bits"] == "64":
+        if env["arch"] == "x86_64":
             env["CXX"] = "x86_64-w64-mingw32-g++"
             env["AR"] = "x86_64-w64-mingw32-ar"
             env["RANLIB"] = "x86_64-w64-mingw32-ranlib"
             env["LINK"] = "x86_64-w64-mingw32-g++"
-        elif env["bits"] == "32":
+        elif env["arch"] == "x86_32":
             env["CXX"] = "i686-w64-mingw32-g++"
             env["AR"] = "i686-w64-mingw32-ar"
             env["RANLIB"] = "i686-w64-mingw32-ranlib"
@@ -297,6 +347,7 @@ elif env["platform"] == "windows":
         # Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff.
         env = Environment(ENV=os.environ, tools=["mingw"])
         opts.Update(env)
+        env["arch"] = env_arch
 
         # Still need to use C++17.
         env.Append(CCFLAGS=["-std=c++17"])
@@ -322,10 +373,15 @@ elif env["platform"] == "windows":
         )
 
 elif env["platform"] == "android":
+    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 host_platform == "windows":
         # Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff.
         env = Environment(ENV=os.environ, tools=["mingw"])
         opts.Update(env)
+        env["arch"] = env_arch
 
         # Long line hack. Use custom spawn, quick AR append (to avoid files with the same names to override each other).
         env["SPAWN"] = mySpawn
@@ -339,7 +395,7 @@ elif env["platform"] == "android":
 
     # Validate API level
     api_level = int(env["android_api_level"])
-    if env["android_arch"] in ["x86_64", "arm64v8"] and api_level < 21:
+    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
@@ -360,21 +416,21 @@ elif env["platform"] == "android":
 
     # Get architecture info
     arch_info_table = {
-        "armv7": {
+        "arm32": {
             "march": "armv7-a",
             "target": "armv7a-linux-androideabi",
             "tool_path": "arm-linux-androideabi",
             "compiler_path": "armv7a-linux-androideabi",
             "ccflags": ["-mfpu=neon"],
         },
-        "arm64v8": {
+        "arm64": {
             "march": "armv8-a",
             "target": "aarch64-linux-android",
             "tool_path": "aarch64-linux-android",
             "compiler_path": "aarch64-linux-android",
             "ccflags": [],
         },
-        "x86": {
+        "x86_32": {
             "march": "i686",
             "target": "i686-linux-android",
             "tool_path": "i686-linux-android",
@@ -389,7 +445,7 @@ elif env["platform"] == "android":
             "ccflags": [],
         },
     }
-    arch_info = arch_info_table[env["android_arch"]]
+    arch_info = arch_info_table[env["arch"]]
 
     # Setup tools
     env["CC"] = toolchain + "/bin/clang"
@@ -409,9 +465,14 @@ elif env["platform"] == "android":
         env.Append(CCFLAGS=["-O3"])
 
 elif env["platform"] == "javascript":
+    if env["arch"] not in ("wasm32"):
+        print("Only wasm32 supported on web. Exiting.")
+        Exit()
+
     if host_platform == "windows":
         env = Environment(ENV=os.environ, tools=["cc", "c++", "ar", "link", "textfile", "zip"])
         opts.Update(env)
+        env["arch"] = env_arch
     else:
         env["ENV"] = os.environ
 
@@ -474,17 +535,9 @@ add_sources(sources, "src/core", "cpp")
 add_sources(sources, "src/variant", "cpp")
 sources.extend([f for f in bindings if str(f).endswith(".cpp")])
 
-env["arch_suffix"] = env["bits"]
-if env["platform"] == "android":
-    env["arch_suffix"] = env["android_arch"]
-elif env["platform"] == "ios":
-    env["arch_suffix"] = env["ios_arch"]
-    if env["ios_simulator"]:
-        env["arch_suffix"] += ".simulator"
-elif env["platform"] == "javascript":
-    env["arch_suffix"] = "wasm"
-elif env["platform"] == "osx":
-    env["arch_suffix"] = env["macos_arch"]
+env["arch_suffix"] = env["arch"]
+if env["ios_simulator"]:
+    env["arch_suffix"] += ".simulator"
 
 library = None
 env["OBJSUFFIX"] = ".{}.{}.{}{}".format(env["platform"], env["target"], env["arch_suffix"], env["OBJSUFFIX"])

+ 1 - 1
binding_generator.py

@@ -67,7 +67,7 @@ def scons_generate_bindings(target, source, env):
     generate_bindings(
         str(source[0]),
         env["generate_template_get_node"],
-        env["bits"],
+        "32" if "32" in env["arch"] else "64",
         "double" if (env["float"] == "64") else "float",
         target[0].abspath,
     )

+ 8 - 4
test/demo/example.gdextension

@@ -4,9 +4,13 @@ entry_symbol = "example_library_init"
 
 [libraries]
 
-linux.64.debug = "bin/libgdexample.linux.debug.64.so"
-linux.64.release = "bin/libgdexample.linux.release.64.so"
-windows.64.debug = "bin/libgdexample.windows.debug.64.dll"
-windows.64.release = "bin/libgdexample.windows.release.64.dll"
 macos.debug = "bin/libgdexample.osx.debug.framework"
 macos.release = "bin/libgdexample.osx.release.framework"
+windows.debug.x86_64 = "bin/libgdexample.windows.debug.x86_64.dll"
+windows.release.x86_64 = "bin/libgdexample.windows.release.x86_64.dll"
+linux.debug.x86_64 = "bin/libgdexample.linux.debug.x86_64.so"
+linux.release.x86_64 = "bin/libgdexample.linux.release.x86_64.so"
+linux.debug.arm64 = "bin/libgdexample.linux.debug.arm64.so"
+linux.release.arm64 = "bin/libgdexample.linux.release.arm64.so"
+linux.debug.rv64 = "bin/libgdexample.linux.debug.rv64.so"
+linux.release.rv64 = "bin/libgdexample.linux.release.rv64.so"

+ 5 - 6
test/demo/icon.png.import

@@ -1,9 +1,9 @@
 [remap]
 
 importer="texture"
-type="StreamTexture2D"
+type="CompressedTexture2D"
 uid="uid://cswr8vy4lt7dt"
-path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
+path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
 metadata={
 "vram_texture": false
 }
@@ -11,7 +11,7 @@ metadata={
 [deps]
 
 source_file="res://icon.png"
-dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"]
+dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
 
 [params]
 
@@ -21,7 +21,6 @@ compress/hdr_compression=1
 compress/bptc_ldr=0
 compress/normal_map=0
 compress/channel_pack=0
-compress/streamed=false
 mipmaps/generate=false
 mipmaps/limit=-1
 roughness/mode=0
@@ -29,7 +28,7 @@ roughness/src_normal=""
 process/fix_alpha_border=true
 process/premult_alpha=false
 process/normal_map_invert_y=false
-process/HDR_as_SRGB=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
 process/size_limit=0
 detect_3d/compress_to=1
-svg/scale=1.0

+ 2 - 2
test/demo/main.gd

@@ -46,5 +46,5 @@ func _ready():
 	prints("  ANSWER_TO_EVERYTHING", $Example.ANSWER_TO_EVERYTHING)
 	prints("  CONSTANT_WITHOUT_ENUM", $Example.CONSTANT_WITHOUT_ENUM)
 
-func _on_Example_custom_signal(name, value):
-	prints("Example emitted:", name, value)
+func _on_Example_custom_signal(signal_name, value):
+	prints("Example emitted:", signal_name, value)

+ 0 - 6
test/demo/main.tscn

@@ -12,16 +12,10 @@ offset_left = 194.0
 offset_top = -2.0
 offset_right = 234.0
 offset_bottom = 21.0
-__meta__ = {
-"_edit_use_anchors_": false
-}
 
 [node name="Button" type="Button" parent="."]
 offset_right = 79.0
 offset_bottom = 29.0
 text = "Click me!"
-__meta__ = {
-"_edit_use_anchors_": false
-}
 
 [connection signal="custom_signal" from="Example" to="." method="_on_Example_custom_signal"]

+ 2 - 1
test/demo/project.godot

@@ -6,13 +6,14 @@
 ;   [section] ; section goes between []
 ;   param=value ; assign values to parameters
 
-config_version=4
+config_version=5
 
 [application]
 
 config/name="GDExtension Test Project"
 run/main_scene="res://main.tscn"
 config/icon="res://icon.png"
+config/features=PackedStringArray("4.0")
 
 [native_extensions]