SCons: Refactor LTO options with `lto=<none|thin|full>`
Adds support for LTO on macOS and Android. We don't have much experience with LTO on these platforms so for now we keep it disabled by default even when `production=yes` is set. Similarly for iOS where we ship object files for the user to link in Xcode so LTO makes builds extremely slow to link. `production=yes` defaults to full LTO. ThinLTO is much faster for LLVM-based compilers but seems to produce bigger binaries (at least for the Web platform).
This commit is contained in:
parent
69233093d7
commit
c2c659db32
62
SConstruct
62
SConstruct
|
@ -170,7 +170,7 @@ opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectur
|
||||||
opts.Add(EnumVariable("float", "Floating-point precision", "32", ("32", "64")))
|
opts.Add(EnumVariable("float", "Floating-point precision", "32", ("32", "64")))
|
||||||
opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none")))
|
opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none")))
|
||||||
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
|
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
|
||||||
opts.Add(BoolVariable("use_lto", "Use link-time optimization", False))
|
opts.Add(EnumVariable("lto", "Link-time optimization (for production buids)", "none", ("none", "thin", "full")))
|
||||||
|
|
||||||
# Components
|
# Components
|
||||||
opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True))
|
opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True))
|
||||||
|
@ -438,35 +438,6 @@ if selected_platform in platform_list:
|
||||||
)
|
)
|
||||||
env.SetOption("num_jobs", safer_cpu_count)
|
env.SetOption("num_jobs", safer_cpu_count)
|
||||||
|
|
||||||
# 'dev' and 'production' are aliases to set default options if they haven't been set
|
|
||||||
# manually by the user.
|
|
||||||
if env["dev"]:
|
|
||||||
env["verbose"] = methods.get_cmdline_bool("verbose", True)
|
|
||||||
env["warnings"] = ARGUMENTS.get("warnings", "extra")
|
|
||||||
env["werror"] = methods.get_cmdline_bool("werror", True)
|
|
||||||
if env["tools"]:
|
|
||||||
env["tests"] = methods.get_cmdline_bool("tests", True)
|
|
||||||
if env["production"]:
|
|
||||||
env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
|
|
||||||
env["use_lto"] = methods.get_cmdline_bool("use_lto", True)
|
|
||||||
env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
|
|
||||||
if not env["tools"] and env["target"] == "debug":
|
|
||||||
print(
|
|
||||||
"WARNING: Requested `production` build with `tools=no target=debug`, "
|
|
||||||
"this will give you a full debug template (use `target=release_debug` "
|
|
||||||
"for an optimized template with debug features)."
|
|
||||||
)
|
|
||||||
if env.msvc:
|
|
||||||
print(
|
|
||||||
"WARNING: For `production` Windows builds, you should use MinGW with GCC "
|
|
||||||
"or Clang instead of Visual Studio, as they can better optimize the "
|
|
||||||
"GDScript VM in a very significant way. MSVC LTO also doesn't work "
|
|
||||||
"reliably for our use case."
|
|
||||||
"If you want to use MSVC nevertheless for production builds, set "
|
|
||||||
"`debug_symbols=no use_lto=no` instead of the `production=yes` option."
|
|
||||||
)
|
|
||||||
Exit(255)
|
|
||||||
|
|
||||||
env.extra_suffix = ""
|
env.extra_suffix = ""
|
||||||
|
|
||||||
if env["extra_suffix"] != "":
|
if env["extra_suffix"] != "":
|
||||||
|
@ -517,6 +488,37 @@ if selected_platform in platform_list:
|
||||||
# We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
|
# We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
|
||||||
env.Prepend(CCFLAGS=["/std:c++17"])
|
env.Prepend(CCFLAGS=["/std:c++17"])
|
||||||
|
|
||||||
|
# 'dev' and 'production' are aliases to set default options if they haven't been set
|
||||||
|
# manually by the user.
|
||||||
|
if env["dev"]:
|
||||||
|
env["verbose"] = methods.get_cmdline_bool("verbose", True)
|
||||||
|
env["warnings"] = ARGUMENTS.get("warnings", "extra")
|
||||||
|
env["werror"] = methods.get_cmdline_bool("werror", True)
|
||||||
|
if env["tools"]:
|
||||||
|
env["tests"] = methods.get_cmdline_bool("tests", True)
|
||||||
|
if env["production"]:
|
||||||
|
env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
|
||||||
|
env["lto"] = ARGUMENTS.get("lto", "full")
|
||||||
|
env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
|
||||||
|
if not env["tools"] and env["target"] == "debug":
|
||||||
|
print(
|
||||||
|
"WARNING: Requested `production` build with `tools=no target=debug`, "
|
||||||
|
"this will give you a full debug template (use `target=release_debug` "
|
||||||
|
"for an optimized template with debug features)."
|
||||||
|
)
|
||||||
|
if env.msvc:
|
||||||
|
print(
|
||||||
|
"WARNING: For `production` Windows builds, you should use MinGW with GCC "
|
||||||
|
"or Clang instead of Visual Studio, as they can better optimize the "
|
||||||
|
"GDScript VM in a very significant way. MSVC LTO also doesn't work "
|
||||||
|
"reliably for our use case."
|
||||||
|
"If you want to use MSVC nevertheless for production builds, set "
|
||||||
|
"`debug_symbols=no lto=none` instead of the `production=yes` option."
|
||||||
|
)
|
||||||
|
Exit(255)
|
||||||
|
if env["lto"] != "none":
|
||||||
|
print("Using LTO: " + env["lto"])
|
||||||
|
|
||||||
# Enforce our minimal compiler version requirements
|
# Enforce our minimal compiler version requirements
|
||||||
cc_version = methods.get_compiler_version(env) or {
|
cc_version = methods.get_compiler_version(env) or {
|
||||||
"major": None,
|
"major": None,
|
||||||
|
|
|
@ -47,6 +47,9 @@ def get_flags():
|
||||||
return [
|
return [
|
||||||
("arch", "arm64"), # Default for convenience.
|
("arch", "arm64"), # Default for convenience.
|
||||||
("tools", False),
|
("tools", False),
|
||||||
|
# Benefits of LTO for Android (size, performance) haven't been clearly established yet.
|
||||||
|
# So for now we override the default value which may be set when using `production=yes`.
|
||||||
|
("lto", "none"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,6 +135,15 @@ def configure(env):
|
||||||
env.Append(CPPDEFINES=["_DEBUG"])
|
env.Append(CPPDEFINES=["_DEBUG"])
|
||||||
env.Append(CPPFLAGS=["-UNDEBUG"])
|
env.Append(CPPFLAGS=["-UNDEBUG"])
|
||||||
|
|
||||||
|
# LTO
|
||||||
|
if env["lto"] != "none":
|
||||||
|
if env["lto"] == "thin":
|
||||||
|
env.Append(CCFLAGS=["-flto=thin"])
|
||||||
|
env.Append(LINKFLAGS=["-flto=thin"])
|
||||||
|
else:
|
||||||
|
env.Append(CCFLAGS=["-flto"])
|
||||||
|
env.Append(LINKFLAGS=["-flto"])
|
||||||
|
|
||||||
# Compiler configuration
|
# Compiler configuration
|
||||||
|
|
||||||
env["SHLIBSUFFIX"] = ".so"
|
env["SHLIBSUFFIX"] = ".so"
|
||||||
|
|
|
@ -39,6 +39,9 @@ def get_flags():
|
||||||
("arch", "arm64"), # Default for convenience.
|
("arch", "arm64"), # Default for convenience.
|
||||||
("tools", False),
|
("tools", False),
|
||||||
("use_volk", False),
|
("use_volk", False),
|
||||||
|
# Disable by default even if production is set, as it makes linking in Xcode
|
||||||
|
# on exports very slow and that's not what most users expect.
|
||||||
|
("lto", "none"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,9 +73,14 @@ def configure(env):
|
||||||
env.Append(CCFLAGS=["-gdwarf-2", "-O0"])
|
env.Append(CCFLAGS=["-gdwarf-2", "-O0"])
|
||||||
env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)])
|
env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)])
|
||||||
|
|
||||||
if env["use_lto"]:
|
# LTO
|
||||||
env.Append(CCFLAGS=["-flto"])
|
if env["lto"] != "none":
|
||||||
env.Append(LINKFLAGS=["-flto"])
|
if env["lto"] == "thin":
|
||||||
|
env.Append(CCFLAGS=["-flto=thin"])
|
||||||
|
env.Append(LINKFLAGS=["-flto=thin"])
|
||||||
|
else:
|
||||||
|
env.Append(CCFLAGS=["-flto"])
|
||||||
|
env.Append(LINKFLAGS=["-flto"])
|
||||||
|
|
||||||
## Compiler configuration
|
## Compiler configuration
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ def get_opts():
|
||||||
return [
|
return [
|
||||||
EnumVariable("linker", "Linker program", "default", ("default", "bfd", "gold", "lld", "mold")),
|
EnumVariable("linker", "Linker program", "default", ("default", "bfd", "gold", "lld", "mold")),
|
||||||
BoolVariable("use_llvm", "Use the LLVM compiler", False),
|
BoolVariable("use_llvm", "Use the LLVM compiler", False),
|
||||||
BoolVariable("use_thinlto", "Use ThinLTO (LLVM only, requires linker=lld, implies use_lto=yes)", False),
|
|
||||||
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
|
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
|
||||||
BoolVariable("use_coverage", "Test Godot coverage", False),
|
BoolVariable("use_coverage", "Test Godot coverage", False),
|
||||||
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
|
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
|
||||||
|
@ -129,13 +128,6 @@ def configure(env):
|
||||||
else:
|
else:
|
||||||
env.Append(LINKFLAGS=["-fuse-ld=%s" % env["linker"]])
|
env.Append(LINKFLAGS=["-fuse-ld=%s" % env["linker"]])
|
||||||
|
|
||||||
if env["use_thinlto"]:
|
|
||||||
if not env["use_llvm"] or env["linker"] != "lld":
|
|
||||||
print("ThinLTO is only compatible with LLVM and the LLD linker, use `use_llvm=yes linker=lld`.")
|
|
||||||
sys.exit(255)
|
|
||||||
else:
|
|
||||||
env["use_lto"] = True # ThinLTO implies LTO
|
|
||||||
|
|
||||||
if env["use_coverage"]:
|
if env["use_coverage"]:
|
||||||
env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
|
env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
|
||||||
env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
|
env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
|
||||||
|
@ -178,8 +170,12 @@ def configure(env):
|
||||||
env.Append(CCFLAGS=["-fsanitize-recover=memory"])
|
env.Append(CCFLAGS=["-fsanitize-recover=memory"])
|
||||||
env.Append(LINKFLAGS=["-fsanitize=memory"])
|
env.Append(LINKFLAGS=["-fsanitize=memory"])
|
||||||
|
|
||||||
if env["use_lto"]:
|
# LTO
|
||||||
if env["use_thinlto"]:
|
if env["lto"] != "none":
|
||||||
|
if env["lto"] == "thin":
|
||||||
|
if not env["use_llvm"]:
|
||||||
|
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
|
||||||
|
sys.exit(255)
|
||||||
env.Append(CCFLAGS=["-flto=thin"])
|
env.Append(CCFLAGS=["-flto=thin"])
|
||||||
env.Append(LINKFLAGS=["-flto=thin"])
|
env.Append(LINKFLAGS=["-flto=thin"])
|
||||||
elif not env["use_llvm"] and env.GetOption("num_jobs") > 1:
|
elif not env["use_llvm"] and env.GetOption("num_jobs") > 1:
|
||||||
|
|
|
@ -40,6 +40,9 @@ def get_flags():
|
||||||
return [
|
return [
|
||||||
("arch", detect_arch()),
|
("arch", detect_arch()),
|
||||||
("use_volk", False),
|
("use_volk", False),
|
||||||
|
# Benefits of LTO for macOS (size, performance) haven't been clearly established yet.
|
||||||
|
# So for now we override the default value which may be set when using `production=yes`.
|
||||||
|
("lto", "none"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,6 +169,15 @@ def configure(env):
|
||||||
env["RANLIB"] = basecmd + "ranlib"
|
env["RANLIB"] = basecmd + "ranlib"
|
||||||
env["AS"] = basecmd + "as"
|
env["AS"] = basecmd + "as"
|
||||||
|
|
||||||
|
# LTO
|
||||||
|
if env["lto"] != "none":
|
||||||
|
if env["lto"] == "thin":
|
||||||
|
env.Append(CCFLAGS=["-flto=thin"])
|
||||||
|
env.Append(LINKFLAGS=["-flto=thin"])
|
||||||
|
else:
|
||||||
|
env.Append(CCFLAGS=["-flto"])
|
||||||
|
env.Append(LINKFLAGS=["-flto"])
|
||||||
|
|
||||||
if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]:
|
if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]:
|
||||||
env.extra_suffix += ".san"
|
env.extra_suffix += ".san"
|
||||||
env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"])
|
env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"])
|
||||||
|
|
|
@ -31,7 +31,6 @@ def get_opts():
|
||||||
return [
|
return [
|
||||||
("initial_memory", "Initial WASM memory (in MiB)", 32),
|
("initial_memory", "Initial WASM memory (in MiB)", 32),
|
||||||
BoolVariable("use_assertions", "Use Emscripten runtime assertions", False),
|
BoolVariable("use_assertions", "Use Emscripten runtime assertions", False),
|
||||||
BoolVariable("use_thinlto", "Use ThinLTO", False),
|
|
||||||
BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False),
|
BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False),
|
||||||
BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False),
|
BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False),
|
||||||
BoolVariable("use_lsan", "Use Emscripten leak sanitizer (LSAN)", False),
|
BoolVariable("use_lsan", "Use Emscripten leak sanitizer (LSAN)", False),
|
||||||
|
@ -110,12 +109,13 @@ def configure(env):
|
||||||
env["ENV"] = os.environ
|
env["ENV"] = os.environ
|
||||||
|
|
||||||
# LTO
|
# LTO
|
||||||
if env["use_thinlto"]:
|
if env["lto"] != "none":
|
||||||
env.Append(CCFLAGS=["-flto=thin"])
|
if env["lto"] == "thin":
|
||||||
env.Append(LINKFLAGS=["-flto=thin"])
|
env.Append(CCFLAGS=["-flto=thin"])
|
||||||
elif env["use_lto"]:
|
env.Append(LINKFLAGS=["-flto=thin"])
|
||||||
env.Append(CCFLAGS=["-flto=full"])
|
else:
|
||||||
env.Append(LINKFLAGS=["-flto=full"])
|
env.Append(CCFLAGS=["-flto"])
|
||||||
|
env.Append(LINKFLAGS=["-flto"])
|
||||||
|
|
||||||
# Sanitizers
|
# Sanitizers
|
||||||
if env["use_ubsan"]:
|
if env["use_ubsan"]:
|
||||||
|
|
|
@ -191,7 +191,6 @@ def get_opts():
|
||||||
),
|
),
|
||||||
BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed.", False),
|
BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed.", False),
|
||||||
BoolVariable("use_llvm", "Use the LLVM compiler", False),
|
BoolVariable("use_llvm", "Use the LLVM compiler", False),
|
||||||
BoolVariable("use_thinlto", "Use ThinLTO", False),
|
|
||||||
BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
|
BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
|
||||||
BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
|
BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
|
||||||
]
|
]
|
||||||
|
@ -449,7 +448,10 @@ def configure_msvc(env, vcvars_msvc_config):
|
||||||
|
|
||||||
## LTO
|
## LTO
|
||||||
|
|
||||||
if env["use_lto"]:
|
if env["lto"] != "none":
|
||||||
|
if env["lto"] == "thin":
|
||||||
|
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
|
||||||
|
sys.exit(255)
|
||||||
env.AppendUnique(CCFLAGS=["/GL"])
|
env.AppendUnique(CCFLAGS=["/GL"])
|
||||||
env.AppendUnique(ARFLAGS=["/LTCG"])
|
env.AppendUnique(ARFLAGS=["/LTCG"])
|
||||||
if env["progress"]:
|
if env["progress"]:
|
||||||
|
@ -562,17 +564,19 @@ def configure_mingw(env):
|
||||||
if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
|
if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
|
||||||
env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
|
env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
|
||||||
|
|
||||||
if env["use_lto"]:
|
if env["lto"] != "none":
|
||||||
if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
|
if env["lto"] == "thin":
|
||||||
|
if not env["use_llvm"]:
|
||||||
|
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
|
||||||
|
sys.exit(255)
|
||||||
|
env.Append(CCFLAGS=["-flto=thin"])
|
||||||
|
env.Append(LINKFLAGS=["-flto=thin"])
|
||||||
|
elif not env["use_llvm"] and env.GetOption("num_jobs") > 1:
|
||||||
env.Append(CCFLAGS=["-flto"])
|
env.Append(CCFLAGS=["-flto"])
|
||||||
env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))])
|
env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))])
|
||||||
else:
|
else:
|
||||||
if env["use_thinlto"]:
|
env.Append(CCFLAGS=["-flto"])
|
||||||
env.Append(CCFLAGS=["-flto=thin"])
|
env.Append(LINKFLAGS=["-flto"])
|
||||||
env.Append(LINKFLAGS=["-flto=thin"])
|
|
||||||
else:
|
|
||||||
env.Append(CCFLAGS=["-flto"])
|
|
||||||
env.Append(LINKFLAGS=["-flto"])
|
|
||||||
|
|
||||||
env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE)])
|
env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE)])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue