summaryrefslogtreecommitdiff
path: root/SConstruct
diff options
context:
space:
mode:
Diffstat (limited to 'SConstruct')
-rw-r--r--SConstruct165
1 files changed, 156 insertions, 9 deletions
diff --git a/SConstruct b/SConstruct
index 2f96c965b83..f1d4d225009 100644
--- a/SConstruct
+++ b/SConstruct
@@ -429,6 +429,15 @@ add_option("cxx-std",
help="Select the C++ langauge standard to build with",
)
+add_option("dynamic-runtime",
+ choices=["force", "off", "auto"],
+ const="on",
+ default="auto",
+ help="Force the static compiler and C++ runtimes to be linked dynamically",
+ nargs="?",
+ type="choice",
+)
+
def find_mongo_custom_variables():
files = []
paths = [path for path in sys.path if 'site_scons' in path]
@@ -1146,6 +1155,25 @@ for var in ['CC', 'CXX']:
env.AddMethod(mongo_platform.env_os_is_wrapper, 'TargetOSIs')
env.AddMethod(mongo_platform.env_get_os_name_wrapper, 'GetTargetOSName')
+
+def shim_library(env, name, needs_link=False, *args, **kwargs):
+ nodes = env.Library(
+ target=f"shim_{name}" if name else name,
+ source=[
+ f"shim_{name}.cpp" if name else name,
+ ],
+ *args,
+ **kwargs
+ )
+
+ for n in nodes:
+ setattr(n.attributes, "needs_link", needs_link)
+
+ return nodes
+
+env.AddMethod(shim_library, 'ShimLibrary')
+
+
def conf_error(env, msg, *args):
print(msg.format(*args))
print("See {0} for details".format(env.File('$CONFIGURELOG').abspath))
@@ -1634,6 +1662,122 @@ if link_model.startswith("dynamic"):
return []
env['LIBDEPS_TAG_EXPANSIONS'].append(libdeps_tags_expand_incomplete)
+
+# If requested, wrap the static runtime libraries in shims and use those to link
+# them dynamically. This allows us to "convert" runtimes in toolchains that have
+# linker scripts in place of shared libraries which actually link the static
+# library instead. The benefit of making this conversion is that shared
+# libraries produced by these toolchains are smaller because we don't end up
+# spreading runtime symbols all over the place, and in turn they should also
+# get loaded by the dynamic linker more quickly as well.
+dynamicRT = get_option("dynamic-runtime")
+
+if dynamicRT == "auto":
+ if env.ToolchainIs('msvc'):
+ # TODO: SERVER-53102
+ # Windows Enterprise *requires* a dynamic CRT because it needs to have
+ # shared state in order to load the external libraries required for SSL,
+ # LDAP, etc. This state of affairs may eventually change as Windows
+ # dynamic builds improve, but for now we just force a dynamic CRT with
+ # Windows until we have some way of detecting when we can get away with
+ # a static CRT.
+ #
+ # Ideally, we should be determining whether a static build is requested,
+ # and if so, whether a dynamic CRT *must* be used in such a case.
+
+ dynamicRT = "force"
+
+ elif get_option("link-model") != "dynamic":
+ dynamicRT = "off"
+
+ elif env.TargetOSIs('linux') and env.ToolchainIs('gcc', 'clang'):
+ def CheckRuntimeLibraries(context):
+ context.Message("Checking whether any runtime libraries are linker scripts... ")
+
+ result = {}
+ libs = [ 'libgcc', 'libgcc_s', 'libgcc_eh' ]
+
+ if get_option('libc++'):
+ libs.append('libc++')
+ else:
+ libs.append('libstdc++')
+
+ compiler = subprocess.Popen(
+ [context.env['CXX'], "-print-search-dirs"],
+ stdout=subprocess.PIPE
+ )
+
+ # This just pulls out the library paths and *only* the library
+ # paths, deleting all other lines. It also removes the leading
+ # "libraries" tag from the line so only the paths are left in
+ # the output.
+ sed = subprocess.Popen(
+ [
+ "sed",
+ "/^lib/b 1;d;:1;s,.*:[^=]*=,,",
+ ],
+ stdin=compiler.stdout,
+ stdout=subprocess.PIPE
+ )
+ compiler.stdout.close()
+
+ search_paths = sed.communicate()[0].decode('utf-8').split(':')
+
+ for lib in libs:
+ for search_path in search_paths:
+ lib_file = os.path.join(search_path, lib + ".so")
+ if os.path.exists(lib_file):
+ file_type = subprocess.check_output(["file", lib_file]).decode('utf-8')
+ match = re.search('ASCII text', file_type)
+ result[lib] = bool(match)
+ break
+ if any(result.values()):
+ ret = "yes"
+ else:
+ ret = "no"
+ context.Result(ret)
+ return ret
+
+ detectStaticRuntime = Configure(detectEnv, help=False, custom_tests = {
+ 'CheckRuntimeLibraries' : CheckRuntimeLibraries,
+ })
+
+ if detectStaticRuntime.CheckRuntimeLibraries() == "yes":
+ # TODO: SERVER-48291
+ # Set this to "force" when the issue with jsCore test failures with
+ # dynamic runtime have been resolved.
+ dynamicRT = "off"
+ else:
+ dynamicRT = "off"
+
+ detectStaticRuntime.Finish()
+
+if dynamicRT == "force":
+ if not (env.TargetOSIs('linux') or env.TargetOSIs('windows')):
+ env.FatalError("A dynamic runtime can be forced only on Windows and Linux at this time.")
+
+ # GCC and Clang get configured in src/SConscript so as to avoid affecting
+ # the conftests.
+ if env.ToolchainIs('msvc'):
+ if debugBuild:
+ env.Append(CCFLAGS=["/MDd"])
+ else:
+ env.Append(CCFLAGS=["/MD"])
+
+ else:
+ if get_option("link-model") != "dynamic":
+ env.FatalError("A dynamic runtime can only be forced with dynamic linking on this toolchain.")
+
+ if not env.ToolchainIs('gcc', 'clang'):
+ env.FatalError("Don't know how to force a dynamic runtime on this toolchain.")
+
+if dynamicRT == "off" and env.ToolchainIs('msvc'):
+ if debugBuild:
+ env.Append(CCFLAGS=["/MTd"])
+ else:
+ env.Append(CCFLAGS=["/MT"])
+
+
if optBuild:
env.SetConfigHeaderDefine("MONGO_CONFIG_OPTIMIZED_BUILD")
@@ -2090,11 +2234,6 @@ elif env.TargetOSIs('windows'):
if not any(flag.startswith('/DEBUG') for flag in env['LINKFLAGS']):
env.Append(LINKFLAGS=["/DEBUG"])
- # /MD: use the multithreaded, DLL version of the run-time library (MSVCRT.lib/MSVCR###.DLL)
- # /MDd: Defines _DEBUG, _MT, _DLL, and uses MSVCRTD.lib/MSVCRD###.DLL
-
- env.Append(CCFLAGS=["/MDd" if debugBuild else "/MD"])
-
if optBuild:
# /O1: optimize for size
# /O2: optimize for speed (as opposed to size)
@@ -2226,7 +2365,6 @@ if env.TargetOSIs('posix'):
"-fno-strict-aliasing",
"-fasynchronous-unwind-tables",
"-ggdb" if not env.TargetOSIs('emscripten') else "-g",
- "-pthread",
"-Wall",
"-Wsign-compare",
"-Wno-unknown-pragmas",
@@ -2243,8 +2381,14 @@ if env.TargetOSIs('posix'):
# On OS X, clang doesn't want the pthread flag at link time, or it
# issues warnings which make it impossible for us to declare link
# warnings as errors. See http://stackoverflow.com/a/19382663.
- if not (env.TargetOSIs('darwin') and env.ToolchainIs('clang')):
- env.Append( LINKFLAGS=["-pthread"] )
+ #
+ # We don't need it anyway since we explicitly link to -lpthread,
+ # so all we need beyond that is the preprocessor variable.
+ if not env.ToolchainIs('clang'):
+ env.Append(
+ CPPDEFINES=[("_REENTRANT", "1")],
+ LINKFLAGS=["-pthread"]
+ )
# SERVER-9761: Ensure early detection of missing symbols in dependent libraries at program
# startup.
@@ -3810,8 +3954,10 @@ def doConfigure(myenv):
language='C++')
if posix_system:
conf.env.SetConfigHeaderDefine("MONGO_CONFIG_HAVE_HEADER_UNISTD_H")
+ conf.CheckLib('c')
conf.CheckLib('rt')
conf.CheckLib('dl')
+ conf.CheckLib('pthread')
if posix_monotonic_clock:
conf.env.SetConfigHeaderDefine("MONGO_CONFIG_HAVE_POSIX_MONOTONIC_CLOCK")
@@ -4777,6 +4923,7 @@ module_sconscripts = moduleconfig.get_module_sconscripts(mongo_modules)
# and they are exported here, as well.
Export([
'debugBuild',
+ 'dynamicRT',
'endian',
'free_monitoring',
'get_option',
@@ -5007,4 +5154,4 @@ for i, s in enumerate(BUILD_TARGETS):
# SConscripts have been read but before building begins.
if get_option('build-tools') == 'next':
libdeps.LibdepLinter(env).final_checks()
- libdeps.generate_libdeps_graph(env) \ No newline at end of file
+ libdeps.generate_libdeps_graph(env)