Merge pull request #102 from Faless/build/builders

[SCons] Refactor CMake and OpenSSL tools to use actions.
This commit is contained in:
Fabio Alessandrelli
2023-06-20 16:24:45 +02:00
committed by GitHub
3 changed files with 187 additions and 170 deletions

View File

@@ -1,47 +1,14 @@
import os, sys
def exists(env):
return True
import SCons.Util
import SCons.Builder
import SCons.Action
def generate(env):
env.AddMethod(cmake_configure, "CMakeConfigure")
env.AddMethod(cmake_build, "CMakeBuild")
env.AddMethod(cmake_platform_flags, "CMakePlatformFlags")
def cmake_configure(env, source, target, opt_args):
args = [
"-B",
target,
]
if env["platform"] == "windows":
if env.get("is_msvc", False):
args.extend(["-G", "NMake Makefiles"])
elif sys.platform in ["win32", "msys", "cygwin"]:
args.extend(["-G", "Ninja"])
else:
args.extend(["-G", "Unix Makefiles"])
for arg in opt_args:
args.append(arg)
args.append(source)
return env.Execute("cmake " + " ".join(['"%s"' % a for a in args]))
def cmake_build(env, source, target="", opt_args=[]):
jobs = env.GetOption("num_jobs")
return env.Execute(
"cmake --build %s %s -j%s %s"
% (source, "-t %s" % target if target else "", jobs, " ".join(['"%s"' % a for a in opt_args]))
)
def cmake_platform_flags(env, config=None):
if config is None:
config = {}
def cmake_platform_config(env):
config = {
"CMAKE_BUILD_TYPE": env["CMAKEBUILDTYPE"],
}
if "CC" in env:
config["CMAKE_C_COMPILER"] = env["CC"]
@@ -60,8 +27,8 @@ def cmake_platform_flags(env, config=None):
config["CMAKE_SYSTEM_VERSION"] = api
config["CMAKE_ANDROID_ARCH_ABI"] = abi
config["ANDROID_ABI"] = abi
config["CMAKE_TOOLCHAIN_FILE"] = "%s/build/cmake/android.toolchain.cmake" % os.environ.get(
"ANDROID_NDK_ROOT", ""
config["CMAKE_TOOLCHAIN_FILE"] = "%s/build/cmake/android.toolchain.cmake" % env.get(
"ANDROID_NDK_ROOT", os.environ.get("ANDROID_NDK_ROOT", "")
)
config["CMAKE_ANDROID_STL_TYPE"] = "c++_static"
@@ -95,7 +62,7 @@ def cmake_platform_flags(env, config=None):
raise ValueError("iOS architecture not supported: %s" % env["arch"])
config["CMAKE_SYSTEM_NAME"] = "iOS"
config["CMAKE_OSX_ARCHITECTURES"] = env["arch"]
if env["ios_min_version"] != "default":
if env.get("ios_min_version", "default") != "default":
config["CMAKE_OSX_DEPLOYMENT_TARGET"] = env["ios_min_version"]
if env["ios_simulator"]:
config["CMAKE_OSX_SYSROOT"] = "iphonesimulator"
@@ -103,4 +70,40 @@ def cmake_platform_flags(env, config=None):
elif env["platform"] == "windows":
config["CMAKE_SYSTEM_NAME"] = "Windows"
return config
flags = ["'-D%s=%s'" % it for it in config.items()]
if env["CMAKEGENERATOR"]:
flags.extend(["-G", env["CMAKEGENERATOR"]])
elif env["platform"] == "windows":
if env.get("is_msvc", False):
flags.extend(["-G", "NMake Makefiles"])
elif sys.platform in ["win32", "msys", "cygwin"]:
flags.extend(["-G", "Ninja"])
else:
flags.extend(["-G", "Unix Makefiles"])
return flags
def cmake_emitter(target, source, env):
return [str(target[0]) + "/CMakeCache.txt"] + target[1:], [str(source[0]) + "/CMakeLists.txt"] + source[1:]
cmake_configure_action = SCons.Action.Action("$CMAKECONFCOM", "$CMAKECONFCOMSTR")
cmake_build_action = SCons.Action.Action("$CMAKEBUILDCOM", "$CMAKEBUILDCOMSTR")
cmake_builder = SCons.Builder.Builder(action=[cmake_configure_action, cmake_build_action], emitter=cmake_emitter)
def exists(env):
return True
def generate(env):
env["CMAKE"] = "cmake"
env["_cmake_platform_config"] = cmake_platform_config
env["CMAKEPLATFORMCONFIG"] = "${_cmake_platform_config(__env__)}"
env["CMAKEBUILDTYPE"] = "Release"
env["CMAKEGENERATOR"] = ""
env["CMAKECONFFLAGS"] = SCons.Util.CLVar("")
env["CMAKECONFCOM"] = "$CMAKE -B ${TARGET.dir} $CMAKEPLATFORMCONFIG $CMAKECONFFLAGS ${SOURCE.dir}"
env["CMAKEBUILDFLAGS"] = SCons.Util.CLVar("")
env["CMAKEBUILDCOM"] = "$CMAKE --build ${TARGET.dir} $CMAKEBUILDFLAGS"
env["BUILDERS"]["CMake"] = cmake_builder

View File

@@ -1,117 +1,106 @@
import os, sys
import SCons.Util
import SCons.Builder
import SCons.Action
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_platform_target(env):
targets = {}
platform = env["platform"]
if platform == "linux":
targets = {
"x86_32": "linux-x86",
"x86_64": "linux-x86_64",
}
elif platform == "android":
targets = {
"arm64": "android-arm64",
"arm32": "android-arm",
"x86_32": "android-x86",
"x86_64": "android-x86_64",
}
elif platform == "macos":
targets = {
"x86_64": "darwin64-x86_64",
"arm64": "darwin64-arm64",
}
elif platform == "ios":
if env["ios_simulator"]:
targets = {
"x86_64": "iossimulator-xcrun",
"arm64": "iossimulator-xcrun",
}
else:
targets = {
"arm64": "ios64-xcrun",
"arm32": "ios-xcrun",
}
elif platform == "windows":
if env.get("is_msvc", False):
targets = {
"x86_32": "VC-WIN32",
"x86_64": "VC-WIN64A",
}
else:
targets = {
"x86_32": "mingw",
"x86_64": "mingw64",
}
arch = env["arch"]
target = targets.get(arch, "")
if target == "":
raise ValueError("Architecture '%s' not supported for platform: '%s'" % (arch, platform))
return target
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 = [
def ssl_default_options(env):
ssl_config_options = [
"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"] == "windows":
ssl_config_options.append("enable-capieng")
return ssl_config_options
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", "")
def ssl_platform_config(env):
opts = ssl_default_options(env)
target = ssl_platform_target(env)
args = []
if env["platform"] == "android" and env.get("android_api_level", ""):
api = int(env["android_api_level"])
args.append("-D__ANDROID_API__=%s" % api)
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"])
# OSXCross toolchain setup.
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"])
for k in ["CC", "CXX", "AR", "AS", "RANLIB"]:
args.append("%s=%s" % (k, env[k]))
elif env["platform"] == "windows":
args.extend(["enable-capieng"])
is_win_host = sys.platform in ["win32", "msys", "cygwin"]
if env.get("is_msvc", False):
args.extend(["VC-WIN32" if env["arch"] == "x86_32" else "VC-WIN64A"])
else:
if env["arch"] == "x86_32":
args.extend(["mingw"])
if not is_win_host:
args.extend(["--cross-compile-prefix=i686-w64-mingw32-"])
else:
args.extend(["mingw64"])
if not is_win_host:
args.extend(["--cross-compile-prefix=x86_64-w64-mingw32-"])
jobs = env.GetOption("num_jobs")
make_cmd = ["make -C %s -j%s" % (build_dir, jobs), "make -C %s install_sw install_ssldirs -j%s" % (build_dir, jobs)]
if env["platform"] == "windows" and env.get("is_msvc", False):
make_cmd = ["cd %s && nmake install_sw install_ssldirs" % build_dir]
ssl_env.Execute(
[
Mkdir(build_dir),
Mkdir(install_dir),
"cd {} && perl -- {} {}".format(
build_dir, os.path.join(source_dir, "Configure"), " ".join(['"%s"' % a for a in args])
),
]
+ make_cmd
)
return None
if not (is_win_host or env.get("is_msvc", False)):
mingw_prefixes = {
"x86_32": "--cross-compile-prefix=i686-w64-mingw32-",
"x86_64": "--cross-compile-prefix=x86_64-w64-mingw32-",
}
args.append(mingw_prefixes[env["arch"]])
return opts + [target] + args
def build_openssl(env):
def ssl_emitter(target, source, env):
return env["SSL_LIBS"], [env.File(env["SSL_SOURCE"] + "/Configure"), env.File(env["SSL_SOURCE"] + "/VERSION.dat")]
def build_openssl(env, jobs=None):
if jobs is None:
jobs = int(env.GetOption("num_jobs"))
# 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":
@@ -124,6 +113,7 @@ def build_openssl(env):
benv = build_envs[arch]
benv["arch"] = arch
generate(benv)
benv["SSLBUILDJOBS"] = max([1, int(jobs / len(build_envs))])
ssl = benv.OpenSSLBuilder()
arch_ssl.extend(ssl)
benv.NoCache(ssl) # Needs refactoring to properly cache generated headers.
@@ -132,16 +122,17 @@ def build_openssl(env):
env["SSL_INCLUDE"] = build_envs["arm64"]["SSL_INCLUDE"]
# Join libraries using lipo.
lipo_action = "lipo $SOURCES -create -output $TARGET"
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"),
]
ssl = env.Command(env["SSL_LIBRARY"], ssl_libs, lipo_action)
ssl += env.Command(env["SSL_CRYPTO_LIBRARY"], ssl_crypto_libs, lipo_action)
env.Depends(ssl, arch_ssl)
else:
ssl = env.OpenSSLBuilder()
env.NoCache(ssl) # Needs refactoring to properly cache generated headers.
benv = env.Clone()
benv["SSLBUILDJOBS"] = jobs
ssl = benv.OpenSSLBuilder()
benv.NoCache(ssl) # Needs refactoring to properly cache generated headers.
env.Prepend(CPPPATH=[env["SSL_INCLUDE"]])
env.Prepend(LIBPATH=[env["SSL_BUILD"]])
@@ -164,6 +155,14 @@ def exists(env):
def generate(env):
# Android needs the NDK in ENV, and proper PATH setup.
if env["platform"] == "android" and env["ENV"].get("ANDROID_NDK_ROOT", "") == "":
cc_path = os.path.dirname(env["CC"])
if cc_path and cc_path not in env["ENV"]:
env.PrependENVPath("PATH", cc_path)
if "ANDROID_NDK_ROOT" not in env["ENV"]:
env["ENV"]["ANDROID_NDK_ROOT"] = env.get("ANDROID_NDK_ROOT", os.environ.get("ANDROID_NDK_ROOT", ""))
env["SSL_SOURCE"] = env.Dir(env["openssl_source"]).abspath
env["SSL_BUILD"] = env.Dir(
env["openssl_build"]
@@ -175,5 +174,33 @@ def generate(env):
env["SSL_LIBRARY"] = env.File(env["SSL_BUILD"] + "/libssl" + lib_ext)
env["SSL_CRYPTO_LIBRARY"] = env.File(env["SSL_BUILD"] + "/libcrypto" + lib_ext)
env["SSL_LIBS"] = [env["SSL_LIBRARY"], env["SSL_CRYPTO_LIBRARY"]]
env.Append(BUILDERS={"OpenSSLBuilder": env.Builder(action=ssl_action, emitter=ssl_emitter)})
# Configure action
env["PERL"] = env.get("PERL", "perl")
env["_ssl_platform_config"] = ssl_platform_config
env["SSLPLATFORMCONFIG"] = "${_ssl_platform_config(__env__)}"
env["SSLCONFFLAGS"] = SCons.Util.CLVar("")
# fmt: off
env["SSLCONFIGCOM"] = "cd ${TARGET.dir} && $PERL -- ${SOURCE.abspath} --prefix=$SSL_INSTALL --openssldir=$SSL_INSTALL $SSLPLATFORMCONFIG $SSLCONFFLAGS"
# fmt: on
# Build action
env["SSLBUILDJOBS"] = "${__env__.GetOption('num_jobs')}"
# fmt: off
env["SSLBUILDCOM"] = "make -j$SSLBUILDJOBS -C ${TARGET.dir} && make -j$SSLBUILDJOBS -C ${TARGET.dir} install_sw install_ssldirs"
# fmt: on
# Windows MSVC needs to build using NMake
if env["platform"] == "windows" and env.get("is_msvc", False):
env["SSLBUILDCOM"] = "cd ${TARGET.dir} && nmake install_sw install_ssldirs"
env["BUILDERS"]["OpenSSLBuilder"] = SCons.Builder.Builder(
action=[
Mkdir("$SSL_BUILD"),
Mkdir("$SSL_INSTALL"),
SCons.Action.Action("$SSLCONFIGCOM", "$SSLCONFIGCOMSTR"),
SCons.Action.Action("$SSLBUILDCOM", "$SSLBUILDCOMSTR"),
],
emitter=ssl_emitter,
)
env.AddMethod(build_openssl, "OpenSSL")

View File

@@ -12,49 +12,36 @@ def rtc_cmake_config(env):
"OPENSSL_INCLUDE_DIR": env["SSL_INCLUDE"],
"OPENSSL_SSL_LIBRARY": env["SSL_LIBRARY"],
"OPENSSL_CRYPTO_LIBRARY": env["SSL_CRYPTO_LIBRARY"],
"OPENSSL_ROOT_DIR": env["SSL_BUILD"],
"CMAKE_BUILD_TYPE": "%s" % ("RelWithDebInfo" if env["debug_symbols"] else "Release"),
"OPENSSL_ROOT_DIR": env["SSL_INSTALL"],
}
return env.CMakePlatformFlags(config)
return config
def rtc_emitter(target, source, env):
def build_library(env):
if env["platform"] == "windows":
env.PrependUnique(LIBS=["iphlpapi", "bcrypt"])
env.Prepend(LIBS=env["RTC_LIBS"])
env.Depends(env["RTC_LIBS"], env["SSL_LIBS"])
env.Depends(
env["RTC_LIBS"],
[env.File(__file__), env.Dir(env["RTC_SOURCE"]), env.File(env["RTC_SOURCE"] + "/CMakeLists.txt")],
)
return env["RTC_LIBS"], env.Dir(env["RTC_SOURCE"])
def rtc_action(target, source, env):
rtc_env = env.Clone()
build_dir = env["RTC_BUILD"]
source_dir = env["RTC_SOURCE"]
opts = rtc_cmake_config(rtc_env)
rtc_env.CMakeConfigure(source_dir, build_dir, ["-D%s=%s" % it for it in opts.items()])
opt_args = []
if env.get("is_msvc", False):
opt_args = ["--config", opts["CMAKE_BUILD_TYPE"]]
rtc_env.CMakeBuild(build_dir, "datachannel-static", opt_args=opt_args)
return None
rtc_targets = [env.Dir(env["RTC_BUILD"])] + env["RTC_LIBS"]
rtc_sources = [env.Dir(env["RTC_SOURCE"])]
rtc_env.Append(CMAKECONFFLAGS=["'-D%s=%s'" % it for it in rtc_cmake_config(env).items()])
rtc_env.Append(CMAKEBUILDFLAGS=["-t", "datachannel-static", "-j%s" % env.GetOption("num_jobs")])
rtc = rtc_env.CMake(rtc_targets, rtc_sources, CMAKEBUILDTYPE=env["RTC_BUILD_TYPE"])
rtc_env.Depends(rtc, rtc_env["SSL_LIBS"])
return rtc
def exists(env):
return "CMakeConfigure" in env and "CMakeBuild" in env
return "CMake" in env
def generate(env):
env["RTC_SOURCE"] = env.Dir("#thirdparty/libdatachannel").abspath
env["RTC_BUILD_TYPE"] = "RelWithDebInfo" if env["debug_symbols"] else "Release"
env["RTC_BUILD"] = env.Dir(
"#bin/thirdparty/libdatachannel/{}/{}/{}".format(
env["platform"], env["arch"], "RelWithDebInfo" if env["debug_symbols"] else "Release"
)
"#bin/thirdparty/libdatachannel/{}/{}/{}".format(env["platform"], env["arch"], env["RTC_BUILD_TYPE"])
).abspath
env["RTC_INCLUDE"] = env["RTC_SOURCE"] + "/include"
lib_ext = ".a"
@@ -71,6 +58,6 @@ def generate(env):
"deps/usrsctp/usrsctplib/{}usrsctp{}".format(lib_prefix, lib_ext),
]
]
env.Append(BUILDERS={"BuildLibDataChannel": env.Builder(action=rtc_action, emitter=rtc_emitter)})
env.AddMethod(build_library, "BuildLibDataChannel")
env.Append(LIBPATH=[env["RTC_BUILD"]])
env.Append(CPPPATH=[env["RTC_INCLUDE"]])