diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7e566d2..f7ff1fb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,56 @@ name: Continuous integration on: [push, pull_request] jobs: - linux: - name: Build (Linux, GCC) - runs-on: ubuntu-18.04 + build: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - name: 🐧 Linux (GCC) + 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 + godot_zip: Godot_v3.4-stable_linux_server.64.zip + executable: Godot_v3.4-stable_linux_server.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 + + - 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 + flags: use_mingw=yes + + - name: 🍎 macOS (universal) + os: macos-11 + platform: osx + artifact-name: godot-cpp-macos-universal-release + artifact-path: bin/libgodot-cpp.osx.release.64.a + flags: macos_arch=universal + godot_zip: Godot_v3.4-stable_osx.universal.zip + executable: Godot.app/Contents/MacOS/Godot + + - 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 + + - name: 🍏 iOS (arm64) + os: macos-11 + platform: ios + artifact-name: godot-cpp-ios-arm64-release + artifact-path: bin/libgodot-cpp.ios.release.arm64.a + steps: - name: Checkout uses: actions/checkout@v2 @@ -16,132 +63,47 @@ jobs: with: python-version: '3.x' - - name: Install dependencies + - name: Linux dependencies + if: ${{ matrix.platform == 'linux' }} run: | sudo apt-get update -qq sudo apt-get install -qqq build-essential pkg-config - python -m pip install scons - curl -LO https://downloads.tuxfamily.org/godotengine/3.4/Godot_v3.4-stable_linux_server.64.zip - unzip Godot_v3.4-stable_linux_server.64.zip - - name: Build godot-cpp - run: | - scons target=release generate_bindings=yes -j $(nproc) - - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: godot-cpp-linux-glibc2.27-x86_64-release - path: bin/libgodot-cpp.linux.release.64.a - if-no-files-found: error - - - name: Build test GDNative library - run: | - scons target=release platform=linux bits=64 -j $(nproc) -C test - - - name: Run test GDNative library - run: | - ./Godot_v3.4-stable_linux_server.64 --path test -s script.gd - - windows-msvc: - name: Build (Windows, MSVC) - runs-on: windows-2019 - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: recursive - - - name: Set up Python (for SCons) - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - - name: Install dependencies + - name: Install scons run: | python -m pip install scons - - name: Build godot-cpp - run: | - scons target=release generate_bindings=yes -j $env:NUMBER_OF_PROCESSORS - - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: godot-cpp-windows-msvc2019-x86_64-release - path: bin/libgodot-cpp.windows.release.64.lib - if-no-files-found: error - - windows-mingw: - name: Build (Windows, MinGW) - runs-on: windows-2019 - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: recursive - - - name: Set up Python (for SCons) - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - - name: Install dependencies - run: | - python -m pip install scons - - - name: Setup MinGW for Windows/MinGW build + - name: Windows dependency (MinGW) + if: ${{ matrix.platform == 'windows' }} uses: egor-tensin/setup-mingw@v2 - - name: Build godot-cpp + - name: Build godot-cpp (debug) run: | - scons target=release generate_bindings=yes use_mingw=yes -j $env:NUMBER_OF_PROCESSORS + scons platform=${{ matrix.platform }} target=debug generate_bindings=yes ${{ matrix.flags }} -j2 - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: godot-cpp-linux-mingw-x86_64-release - path: bin/libgodot-cpp.windows.release.64.a - if-no-files-found: error - - macos: - name: Build (macOS, Clang) - runs-on: macos-11 - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: recursive - - - name: Set up Python (for SCons) - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - - name: Install dependencies + - name: Build test without rebuilding godot-cpp (debug) run: | - python -m pip install scons - curl -LO https://downloads.tuxfamily.org/godotengine/3.4/Godot_v3.4-stable_osx.universal.zip - unzip Godot_v3.4-stable_osx.universal.zip + cd test + scons platform=${{ matrix.platform }} target=debug ${{ matrix.flags }} build_library=no -j2 - - name: Build godot-cpp + - name: Build test and godot-cpp (release) run: | - scons target=release generate_bindings=yes -j $(sysctl -n hw.logicalcpu) - - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: godot-cpp-macos-universal-release - path: bin/libgodot-cpp.osx.release.64.a - if-no-files-found: error - - - name: Build test GDNative library - run: | - scons target=release platform=osx bits=64 macos_arch=universal -j $(sysctl -n hw.logicalcpu) -C test + cd test + scons platform=${{ matrix.platform }} target=release ${{ matrix.flags }} -j2 - name: Run test GDNative library + if: ${{ matrix.platform == 'linux' || matrix.platform == 'osx' }} run: | - ./Godot.app/Contents/MacOS/Godot --path test -s script.gd + curl -LO https://downloads.tuxfamily.org/godotengine/3.4/${{ matrix.godot_zip }} + unzip ${{ matrix.godot_zip }} + ./${{ matrix.executable }} --path test -s script.gd + + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.artifact-name }} + path: ${{ matrix.artifact-path }} + if-no-files-found: error static-checks: name: Static Checks (clang-format) diff --git a/SConstruct b/SConstruct index 95815e21..8343fa0f 100644 --- a/SConstruct +++ b/SConstruct @@ -159,6 +159,8 @@ opts.Add( ) ) +opts.Add(BoolVariable("build_library", "Build the godot-cpp library.", True)) + opts.Update(env) Help(opts.GenerateHelpText(env)) @@ -173,11 +175,18 @@ if host_platform == "windows" and env["platform"] != "android": opts.Update(env) +# Require C++14 +if host_platform == "windows" and env["platform"] == "windows" and not env["use_mingw"]: + # MSVC + env.Append(CCFLAGS=["/std:c++14"]) +else: + env.Append(CCFLAGS=["-std=c++14"]) + if env["platform"] == "linux" or env["platform"] == "freebsd": if env["use_llvm"]: env["CXX"] = "clang++" - env.Append(CCFLAGS=["-fPIC", "-std=c++14", "-Wwrite-strings"]) + env.Append(CCFLAGS=["-fPIC", "-Wwrite-strings"]) env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"]) if env["target"] == "debug": @@ -206,8 +215,6 @@ elif env["platform"] == "osx": env.Append(LINKFLAGS=["-arch", env["macos_arch"]]) env.Append(CCFLAGS=["-arch", env["macos_arch"]]) - env.Append(CCFLAGS=["-std=c++14"]) - 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"]]) @@ -216,13 +223,7 @@ elif env["platform"] == "osx": 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", - ] - ) + env.Append(LINKFLAGS=["-Wl,-undefined,dynamic_lookup"]) if env["target"] == "debug": env.Append(CCFLAGS=["-Og", "-g"]) @@ -233,7 +234,6 @@ elif env["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"]) @@ -250,14 +250,13 @@ elif env["platform"] == "ios": env["CXX"] = compiler_path + "clang++" env["AR"] = compiler_path + "ar" env["RANLIB"] = compiler_path + "ranlib" + env["SHLIBSUFFIX"] = ".dylib" - env.Append(CCFLAGS=["-std=c++14", "-arch", env["ios_arch"], "-isysroot", sdk_path]) + env.Append(CCFLAGS=["-arch", env["ios_arch"], "-isysroot", sdk_path]) env.Append( LINKFLAGS=[ "-arch", env["ios_arch"], - "-framework", - "Cocoa", "-Wl,-undefined,dynamic_lookup", "-isysroot", sdk_path, @@ -296,14 +295,20 @@ 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 = env.Clone(tools=['mingw']) + + # Still need to use C++14. + env.Append(CCFLAGS=["-std=c++14"]) + # Don't want lib prefixes + env["IMPLIBPREFIX"] = "" + env["SHLIBPREFIX"] = "" env["SPAWN"] = mySpawn + env.Replace(ARFLAGS=["q"]) # Native or cross-compilation using MinGW if host_platform == "linux" or host_platform == "freebsd" or host_platform == "osx" or env["use_mingw"]: # These options are for a release build even using target=debug - env.Append(CCFLAGS=["-O3", "-std=c++14", "-Wwrite-strings"]) + env.Append(CCFLAGS=["-O3", "-Wwrite-strings"]) env.Append( LINKFLAGS=[ "--static", @@ -318,9 +323,10 @@ elif env["platform"] == "android": # Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff. env = Environment(ENV=os.environ, tools=["mingw"]) opts.Update(env) - # env = env.Clone(tools=['mingw']) + # Long line hack. Use custom spawn, quick AR append (to avoid files with the same names to override each other). env["SPAWN"] = mySpawn + env.Replace(ARFLAGS=["q"]) # Verify NDK root if not "ANDROID_NDK_ROOT" in env: @@ -385,11 +391,12 @@ elif env["platform"] == "android": # Setup tools env["CC"] = toolchain + "/bin/clang" env["CXX"] = toolchain + "/bin/clang++" - env["AR"] = toolchain + "/bin/" + arch_info["tool_path"] + "-ar" - env["AS"] = toolchain + "/bin/" + arch_info["tool_path"] + "-as" - env["LD"] = toolchain + "/bin/" + arch_info["tool_path"] + "-ld" - env["STRIP"] = toolchain + "/bin/" + arch_info["tool_path"] + "-strip" - env["RANLIB"] = toolchain + "/bin/" + arch_info["tool_path"] + "-ranlib" + env["AR"] = toolchain + "/bin/llvm-ar" + env["AS"] = toolchain + "/bin/llvm-as" + env["LD"] = toolchain + "/bin/llvm-ld" + env["STRIP"] = toolchain + "/bin/llvm-strip" + env["RANLIB"] = toolchain + "/bin/llvm-ranlib" + env["SHLIBSUFFIX"] = ".so" env.Append( CCFLAGS=[ @@ -399,6 +406,7 @@ elif env["platform"] == "android": ] ) 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"]) @@ -478,14 +486,25 @@ if env["platform"] == "android": arch_suffix = env["android_arch"] elif env["platform"] == "ios": arch_suffix = env["ios_arch"] + if env["ios_simulator"]: + arch_suffix += ".simulator" elif env["platform"] == "osx": if env["macos_arch"] != "universal": arch_suffix = env["macos_arch"] elif env["platform"] == "javascript": arch_suffix = "wasm" +# Expose it to projects that import this env. +env["arch_suffix"] = arch_suffix -library = env.StaticLibrary( - target="bin/" + "libgodot-cpp.{}.{}.{}{}".format(env["platform"], env["target"], arch_suffix, env["LIBSUFFIX"]), - source=sources, -) -Default(library) +library = None +env["OBJSUFFIX"] = ".{}.{}.{}{}".format(env["platform"], env["target"], arch_suffix, env["OBJSUFFIX"]) +library_name = "libgodot-cpp.{}.{}.{}{}".format(env["platform"], env["target"], arch_suffix, env["LIBSUFFIX"]) + +if env["build_library"]: + library = env.StaticLibrary(target=env.File("bin/%s" % library_name), source=sources) + Default(library) + +env.Append(CPPPATH=[env.Dir(f) for f in [env["headers_dir"], "include", "include/gen", "include/core"]]) +env.Append(LIBPATH=[env.Dir("bin")]) +env.Append(LIBS=library_name) +Return("env") diff --git a/test/SConstruct b/test/SConstruct index 63f219c3..9bfd43dc 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,146 +1,16 @@ #!/usr/bin/env python -import os -import sys -# Try to detect the host platform automatically. -# This is used if no `platform` argument is passed -if sys.platform.startswith("linux"): - host_platform = "linux" -elif sys.platform == "darwin": - host_platform = "osx" -elif sys.platform == "win32" or sys.platform == "msys": - host_platform = "windows" -else: - raise ValueError("Could not detect platform automatically, please specify with platform=") - -env = Environment(ENV=os.environ) - -opts = Variables([], ARGUMENTS) - -# Define our options -opts.Add(EnumVariable("target", "Compilation target", "debug", ["d", "debug", "r", "release"])) -opts.Add(EnumVariable("platform", "Compilation platform", host_platform, ["", "windows", "x11", "linux", "osx"])) -opts.Add( - EnumVariable( - "p", - "Compilation target, alias for 'platform'", - host_platform, - ["", "windows", "x11", "linux", "osx"], - ) -) -opts.Add(EnumVariable("bits", "Target platform bits", "64", ("32", "64"))) -opts.Add(BoolVariable("use_llvm", "Use the LLVM / Clang compiler", "no")) -opts.Add(PathVariable("target_path", "The path where the lib is installed.", "bin/", PathVariable.PathAccept)) -opts.Add(PathVariable("target_name", "The library name.", "libgdexample", PathVariable.PathAccept)) - -# Local dependency paths, adapt them to your setup -godot_headers_path = "../godot-headers/" -cpp_bindings_path = "../" -cpp_library = "libgodot-cpp" - -# only support 64 at this time.. -bits = 64 - -# Updates the environment with the option variables. -opts.Update(env) -# Generates help for the -h scons option. -Help(opts.GenerateHelpText(env)) - -# 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": - env = Environment(TARGET_ARCH="amd64") - elif env["bits"] == "32": - env = Environment(TARGET_ARCH="x86") - - opts.Update(env) - -# Process some arguments -if env["use_llvm"]: - env["CC"] = "clang" - env["CXX"] = "clang++" - -if env["p"] != "": - env["platform"] = env["p"] - -if env["platform"] == "": - print("No valid target platform selected.") - quit() - -# For the reference: -# - CCFLAGS are compilation flags shared between C and C++ -# - CFLAGS are for C-specific compilation flags -# - CXXFLAGS are for C++-specific compilation flags -# - CPPFLAGS are for pre-processor flags -# - CPPDEFINES are for pre-processor defines -# - LINKFLAGS are for linking flags - -# Check our platform specifics -if env["platform"] == "osx": - env["target_path"] += "osx/" - cpp_library += ".osx" - env.Append(CCFLAGS=["-arch", "x86_64"]) - env.Append(CXXFLAGS=["-std=c++17"]) - env.Append(LINKFLAGS=["-arch", "x86_64"]) - if env["target"] in ("debug", "d"): - env.Append(CCFLAGS=["-g", "-O2"]) - else: - env.Append(CCFLAGS=["-g", "-O3"]) - -elif env["platform"] in ("x11", "linux"): - env["target_path"] += "x11/" - cpp_library += ".linux" - env.Append(CCFLAGS=["-fPIC"]) - env.Append(CXXFLAGS=["-std=c++17"]) - if env["target"] in ("debug", "d"): - env.Append(CCFLAGS=["-g3", "-Og"]) - else: - env.Append(CCFLAGS=["-g", "-O3"]) - -elif env["platform"] == "windows": - env["target_path"] += "win64/" - cpp_library += ".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 - env.Append(ENV=os.environ) - - env.Append(CPPDEFINES=["WIN32", "_WIN32", "_WINDOWS", "_CRT_SECURE_NO_WARNINGS"]) - env.Append(CCFLAGS=["-W3", "-GR"]) - env.Append(CXXFLAGS=["-std:c++17"]) - if env["target"] in ("debug", "d"): - env.Append(CPPDEFINES=["_DEBUG"]) - env.Append(CCFLAGS=["-EHsc", "-MDd", "-ZI"]) - env.Append(LINKFLAGS=["-DEBUG"]) - else: - env.Append(CPPDEFINES=["NDEBUG"]) - env.Append(CCFLAGS=["-O2", "-EHsc", "-MD"]) - -if env["target"] in ("debug", "d"): - cpp_library += ".debug" -else: - cpp_library += ".release" - -cpp_library += "." + str(bits) - -# make sure our binding library is properly includes -env.Append( - CPPPATH=[ - ".", - godot_headers_path, - cpp_bindings_path + "include/", - cpp_bindings_path + "include/core/", - cpp_bindings_path + "include/gen/", - ] -) -env.Append(LIBPATH=[cpp_bindings_path + "bin/"]) -env.Append(LIBS=[cpp_library]) +env = SConscript("../SConstruct") # tweak this if you want to use different folders, or more folders, to store your source code in. -env.Append(CPPPATH=["src/"]) -sources = Glob("src/*.cpp") +env.Append(CPPPATH=['src/']) +sources = Glob('src/*.cpp') -library = env.SharedLibrary(target=env["target_path"] + env["target_name"], source=sources) +library = env.SharedLibrary( + "bin/libgdexample.{}.{}.{}{}".format( + env["platform"], env["target"], env["arch_suffix"], env["SHLIBSUFFIX"] + ), + source=sources, +) Default(library) diff --git a/test/gdexample.gdnlib b/test/gdexample.gdnlib index 260b4eab..9744b98e 100644 --- a/test/gdexample.gdnlib +++ b/test/gdexample.gdnlib @@ -7,10 +7,10 @@ reloadable=false [entry] -X11.64="res://bin/x11/libgdexample.so" -Server.64="res://bin/x11/libgdexample.so" -Windows.64="res://bin/win64/libgdexample.dll" -OSX.64="res://bin/osx/libgdexample.dylib" +X11.64="res://bin/libgdexample.linux.release.64.so" +Server.64="res://bin/libgdexample.linux.release.64.so" +Windows.64="res://bin/libgdexample.windows.release.64.dll" +OSX.64="res://bin/libgdexample.osx.release.64.dylib" [dependencies]