diff --git a/.gitmodules b/.gitmodules index 9118248..b00992b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ [submodule "thirdparty/ssh2/libssh2"] path = thirdparty/ssh2/libssh2 url = https://github.com/libssh2/libssh2 +[submodule "thirdparty/openssl"] + path = thirdparty/openssl + url = https://github.com/openssl/openssl diff --git a/SConstruct b/SConstruct index 2047cdf..d0b78ec 100644 --- a/SConstruct +++ b/SConstruct @@ -14,16 +14,6 @@ opts.Add(PathVariable("target_path", "The path where the lib is installed.", "demo/addons/godot-git-plugin/")) opts.Add(PathVariable("target_name", "The library name.", "libgit_plugin", PathVariable.PathAccept)) -opts.Add(PathVariable("macos_openssl", "Path to OpenSSL library root - only used in macOS builds.", - "/usr/local/opt/openssl@1.1/", PathVariable.PathAccept)) # TODO: Find a way to configure this to use the cloned OpenSSL source code, based on `macos_arch`. -opts.Add(PathVariable("macos_openssl_static_ssl", "Path to OpenSSL libssl.a library - only used in macOS builds.", - os.path.join(os.path.abspath(os.getcwd()), "thirdparty/openssl/libssl.a"), PathVariable.PathAccept)) -opts.Add(PathVariable("macos_openssl_static_crypto", "Path to OpenSSL libcrypto.a library - only used in macOS builds.", - os.path.join(os.path.abspath(os.getcwd()), "thirdparty/openssl/libcrypto.a"), PathVariable.PathAccept)) -opts.Add(PathVariable("linux_openssl_static_ssl", "Path to OpenSSL libssl.a library - only used in Linux builds.", - "/usr/lib/x86_64-linux-gnu/libssl.a", PathVariable.PathAccept)) -opts.Add(PathVariable("linux_openssl_static_crypto", "Path to OpenSSL libcrypto.a library - only used in Linux builds.", - "/usr/lib/x86_64-linux-gnu/libcrypto.a", PathVariable.PathAccept)) # Updates the environment with the option variables. opts.Update(env) @@ -33,8 +23,18 @@ if ARGUMENTS.get("custom_api_file", "") != "": ARGUMENTS["target"] = "editor" env = SConscript("godot-cpp/SConstruct").Clone() + +# OpenSSL Builder +env.Tool("openssl", toolpath=["tools"]) + opts.Update(env) +if env["platform"] != "windows": # Windows does not need OpenSSL + ssl = env.OpenSSL() +else: + ssl = [] + +Export("ssl") Export("env") SConscript("thirdparty/SCsub") @@ -42,4 +42,4 @@ SConscript("thirdparty/SCsub") SConscript("godot-git-plugin/SCsub") # Generates help for the -h scons option. -Help(opts.GenerateHelpText(env)) +Help(env["options"].GenerateHelpText(env)) diff --git a/THIRDPARTY.md b/THIRDPARTY.md index 837488f..b9b8b52 100644 --- a/THIRDPARTY.md +++ b/THIRDPARTY.md @@ -5,10 +5,7 @@ The Godot Git Plugin source code uses the following third-party source code: 1. godotengine/godot-cpp - MIT License - https://github.com/godotengine/godot-cpp/tree/02336831735fd6affbe0a6fa252ec98d3e78120c 2. libgit2/libgit2 - GPLv2 with a special Linking Exception - https://github.com/libgit2/libgit2/tree/b7bad55e4bb0a285b073ba5e02b01d3f522fc95d 3. libssh2/libssh2 - BSD-3-Clause License - https://github.com/libssh2/libssh2/tree/635caa90787220ac3773c1d5ba11f1236c22eae8 - -We also link to these third-party libraries (only in the compiled binary form): - -1. OpenSSL - Only on Linux and MacOS - OpenSSL License - http://www.openssl.org/source/openssl-1.1.1s.tar.gz +4. openssl (only on Linux and MacOS) - OpenSSL License - https://github.com/openssl/openssl/tree/26baecb28ce461696966dac9ac889629db0b3b96 ## License Texts diff --git a/godot-git-plugin/SCsub b/godot-git-plugin/SCsub index 796cc97..6a20748 100644 --- a/godot-git-plugin/SCsub +++ b/godot-git-plugin/SCsub @@ -4,6 +4,7 @@ import os env = {} Import("env") +Import("ssl") # Process some arguments if env["use_llvm"]: @@ -24,8 +25,6 @@ if env["platform"] == "macos": env["target_path"] += "macos/" # Force static linkage (https://stackoverflow.com/a/2995999/7370948) - env.Append(LIBS=[File(env["macos_openssl_static_ssl"]), - File(env["macos_openssl_static_crypto"])]) if env["macos_deployment_target"] != "default": env.Append(CCFLAGS=["-mmacosx-version-min=" + @@ -35,8 +34,6 @@ if env["platform"] == "macos": elif env["platform"] == "linux": env["target_path"] += "linux/" - env.Append(LIBS=[File(env["linux_openssl_static_ssl"]), - File(env["linux_openssl_static_crypto"])]) elif env["platform"] == "windows": env["target_path"] += "win64/" @@ -50,9 +47,11 @@ env.Append(CPPPATH=["../thirdparty/git2/libgit2/include/"]) env.Append(LIBPATH=["../thirdparty/bin/"]) env.Prepend(LIBS=["git2", "ssh2"]) +lib_sources = Glob("src/*.cpp") +env.Depends(lib_sources, ssl) library = env.SharedLibrary( target=env["target_path"] + "{}{}{}".format(env["target_name"], env["suffix"], env["SHLIBSUFFIX"]), - source=Glob("src/*.cpp") + source=lib_sources ) Default(library) diff --git a/thirdparty/git2/SCsub b/thirdparty/git2/SCsub index 3f75044..1bfbc08 100644 --- a/thirdparty/git2/SCsub +++ b/thirdparty/git2/SCsub @@ -3,6 +3,7 @@ # Adopted from https://github.com/goostengine/goost/blob/20d8ce4c7d74c26832d69283305b25a72165784a/modules/git/SCsub Import("env") +Import("ssl") env_git = env.Clone() @@ -125,11 +126,6 @@ if env_git["platform"] in ["linux", "macos"]: "UNICODE_BUILTIN" ] ) - -if env_git["platform"] == "macos": - env_git.Prepend(CPPPATH=[env_git["macos_openssl"] + "include/"]) - static_ssl = File(env_git["macos_openssl_static_ssl"]) - static_crypto = File(env_git["macos_openssl_static_crypto"]) - env_git.Append(LIBS=[static_ssl, static_crypto]) + env_git.Depends(libgit2_sources, ssl) env_git.StaticLibrary(target="../bin/" + "git2", source=libgit2_sources) diff --git a/thirdparty/openssl b/thirdparty/openssl new file mode 160000 index 0000000..2cf4e90 --- /dev/null +++ b/thirdparty/openssl @@ -0,0 +1 @@ +Subproject commit 2cf4e90eaaf7402bf038b158dbdacd0a15561fb7 diff --git a/thirdparty/openssl/libcrypto.a b/thirdparty/openssl/libcrypto.a deleted file mode 100644 index 8189ef1..0000000 Binary files a/thirdparty/openssl/libcrypto.a and /dev/null differ diff --git a/thirdparty/openssl/libssl.a b/thirdparty/openssl/libssl.a deleted file mode 100644 index 5e73808..0000000 Binary files a/thirdparty/openssl/libssl.a and /dev/null differ diff --git a/thirdparty/ssh2/SCsub b/thirdparty/ssh2/SCsub index ed27565..ec1306b 100644 --- a/thirdparty/ssh2/SCsub +++ b/thirdparty/ssh2/SCsub @@ -3,6 +3,7 @@ # Adopted from https://github.com/nodegit/nodegit/blob/4561dcb7c120474a4553baa27e4c4c2f4be23a2b/vendor/libgit2.gyp Import("env") +Import("ssl") env_ssh2 = env.Clone() @@ -104,11 +105,6 @@ if env_ssh2["platform"] in ["linux", "macos"]: ("STDC_HEADERS", 1) ] ) - -if env_ssh2["platform"] == "macos": - env_ssh2.Append(CPPPATH=[env_ssh2["macos_openssl"] + "include/"]) - static_ssl = File(env_ssh2["macos_openssl_static_ssl"]) - static_crypto = File(env_ssh2["macos_openssl_static_crypto"]) - env_ssh2.Append(LIBS=[static_ssl, static_crypto]) + env_ssh2.Depends(libssh2_sources, ssl) env_ssh2.StaticLibrary(target="../bin/" + "ssh2", source=libssh2_sources) diff --git a/tools/openssl.py b/tools/openssl.py new file mode 100644 index 0000000..52bce1e --- /dev/null +++ b/tools/openssl.py @@ -0,0 +1,175 @@ +import os, sys +from SCons.Defaults import Mkdir +from SCons.Variables import PathVariable, BoolVariable + + +def ssl_emitter(target, source, env): + env.Depends(env["SSL_LIBS"], env.File(__file__)) + return env["SSL_LIBS"], [env.Dir(env["SSL_SOURCE"]), env.File(env["SSL_SOURCE"] + "/VERSION.dat")] + + +def ssl_action(target, source, env): + build_dir = env["SSL_BUILD"] + source_dir = env["SSL_SOURCE"] + install_dir = env["SSL_INSTALL"] + + ssl_env = env.Clone() + args = [ + "no-ssl2", + "no-ssl3", + "no-weak-ssl-ciphers", + "no-legacy", + "no-shared", + "no-tests", + "--prefix=%s" % install_dir, + "--openssldir=%s" % install_dir, + ] + if env["openssl_debug"]: + args.append("-d") + + if env["platform"] == "linux": + if env["arch"] == "x86_32": + args.extend(["linux-x86"]) + else: + args.extend(["linux-x86_64"]) + + elif env["platform"] == "android": + api = env["android_api_level"] if int(env["android_api_level"]) > 28 else "28" + args.extend( + [ + { + "arm64": "android-arm64", + "arm32": "android-arm", + "x86_32": "android-x86", + "x86_64": "android-x86_64", + }[env["arch"]], + "-D__ANDROID_API__=%s" % api, + ] + ) + # Setup toolchain path. + ssl_env.PrependENVPath("PATH", os.path.dirname(env["CC"])) + ssl_env["ENV"]["ANDROID_NDK_ROOT"] = os.environ.get("ANDROID_NDK_ROOT", "") + + elif env["platform"] == "macos": + if env["arch"] == "x86_64": + args.extend(["darwin64-x86_64"]) + elif env["arch"] == "arm64": + args.extend(["darwin64-arm64"]) + else: + raise ValueError("macOS architecture not supported: %s" % env["arch"]) + + if sys.platform != "darwin" and "OSXCROSS_ROOT" in os.environ: + args.extend( + ["CC=" + env["CC"], "CXX=" + env["CXX"], "AR=" + env["AR"], "AS=" + env["AS"], "RANLIB=" + env["RANLIB"]] + ) + + elif env["platform"] == "ios": + if env["ios_simulator"]: + args.extend(["iossimulator-xcrun"]) + elif env["arch"] == "arm32": + args.extend(["ios-xcrun"]) + elif env["arch"] == "arm64": + args.extend(["ios64-xcrun"]) + else: + raise ValueError("iOS architecture not supported: %s" % env["arch"]) + + elif env["platform"] == "windows": + args.extend(["enable-capieng"]) + if env["arch"] == "x86_32": + if env["use_mingw"]: + args.extend( + [ + "mingw", + "--cross-compile-prefix=i686-w64-mingw32-", + ] + ) + else: + args.extend(["VC-WIN32"]) + else: + if env["use_mingw"]: + args.extend( + [ + "mingw64", + "--cross-compile-prefix=x86_64-w64-mingw32-", + ] + ) + else: + args.extend(["VC-WIN64A"]) + + jobs = env.GetOption("num_jobs") + ssl_env.Execute( + [ + Mkdir(build_dir), + "cd %s && perl %s/Configure %s" % (build_dir, source_dir, " ".join(['"%s"' % a for a in args])), + "make -C %s -j%s" % (build_dir, jobs), + "make -C %s install_sw install_ssldirs -j%s" % (build_dir, jobs), + ] + ) + return None + + +def build_openssl(env): + # Since the OpenSSL build system does not support macOS universal binaries, we first need to build the two libraries + # separately, then we join them together using lipo. + if env["platform"] == "macos" and env["arch"] == "universal": + build_envs = { + "x86_64": env.Clone(), + "arm64": env.Clone(), + } + arch_ssl = [] + for arch in build_envs: + benv = build_envs[arch] + benv["arch"] = arch + generate(benv) + ssl = benv.OpenSSLBuilder() + arch_ssl.extend(ssl) + benv.NoCache(ssl) # Needs refactoring to properly cache generated headers. + + # x86_64 and arm64 includes are equivalent. + env["SSL_INCLUDE"] = build_envs["arm64"]["SSL_INCLUDE"] + + # Join libraries using lipo. + ssl_libs = list(map(lambda arch: build_envs[arch]["SSL_LIBRARY"], build_envs)) + ssl_crypto_libs = list(map(lambda arch: build_envs[arch]["SSL_CRYPTO_LIBRARY"], build_envs)) + ssl = [ + env.Command([env["SSL_LIBRARY"]], ssl_libs, "lipo $SOURCES -output $TARGETS -create"), + env.Command([env["SSL_CRYPTO_LIBRARY"]], ssl_libs, "lipo $SOURCES -output $TARGETS -create"), + ] + env.Depends(ssl, arch_ssl) + else: + ssl = env.OpenSSLBuilder() + env.NoCache(ssl) # Needs refactoring to properly cache generated headers. + + env.Prepend(CPPPATH=[env["SSL_INCLUDE"]]) + env.Prepend(LIBPATH=[env["SSL_BUILD"]]) + if env["platform"] == "windows": + env.PrependUnique(LIBS=["crypt32", "ws2_32"]) + + env.Prepend(LIBS=env["SSL_LIBS"]) + + return ssl + + +def options(opts): + opts.Add(PathVariable("openssl_source", "Path to the openssl sources.", "thirdparty/openssl")) + opts.Add("openssl_build", "Destination path of the openssl build.", "bin/thirdparty/openssl") + opts.Add(BoolVariable("openssl_debug", "Make a debug build of OpenSSL.", False)) + + +def exists(env): + return True + + +def generate(env): + env["SSL_SOURCE"] = env.Dir(env["openssl_source"]).abspath + env["SSL_BUILD"] = env.Dir( + env["openssl_build"] + + "/{}/{}/{}".format(env["platform"], env["arch"], "debug" if env["openssl_debug"] else "release") + ).abspath + env["SSL_INSTALL"] = env["SSL_BUILD"] + "/dest" + env["SSL_INCLUDE"] = env["SSL_INSTALL"] + "/include" + env["SSL_LIBRARY"] = env.File(env["SSL_BUILD"] + "/libssl.a") + env["SSL_CRYPTO_LIBRARY"] = env.File(env["SSL_BUILD"] + "/libcrypto.a") + env["SSL_LIBS"] = [env["SSL_LIBRARY"], env["SSL_CRYPTO_LIBRARY"]] + env.Append(BUILDERS={"OpenSSLBuilder": env.Builder(action=ssl_action, emitter=ssl_emitter)}) + env.AddMethod(build_openssl, "OpenSSL")