# -*- mode: python; -*- # # This is the principle SConscript file, invoked by the SConstruct. Its job is # to delegate to any and all per-module SConscript files. from functools import partial from site_scons.mongo import insort_wrapper import SCons Import('dynamicRT') Import('env') Import('get_option') Import('has_option') Import('module_sconscripts') def shim_hack(target, source, env, inject_target=None, exclusions=None): if exclusions is None: exclusions = set(inject_target) elif isinstance(exclusions, str): exclusions = {exclusions, inject_target} elif isinstance(exclusions, (list, set)): exclusions = set(exclusions) exclusions.add(inject_target) # If we allowed conftests to become dependent, any TryLink # that happened after we made the below modifications would # cause the configure steps to try to compile tcmalloc and any # of its dependencies. Oops! if any('conftest' in str(t) for t in target): return target, source # It is possible that 'env' isn't a unique # OverrideEnvironment, since if you didn't pass any kw args # into your builder call, you just reuse the env you were # called with. That could mean that we see the same # environment here multiple times. But that is really OK, # since the operation we are performing would be performed on # all of them anyway. libdeps_no_inherit = set(env.get('LIBDEPS_NO_INHERIT', [])) exclusions.update(libdeps_no_inherit) if f"$BUILD_DIR/{inject_target}" not in exclusions: lds = env.get('LIBDEPS', []) shim_target = f"$BUILD_DIR/{inject_target}" if shim_target not in lds: insort_wrapper(lds, shim_target) env['LIBDEPS'] = lds return target, source def nodefaultlibs_hack(target, source, env): if any('conftest' in str(t) for t in target): return target, source runtime_shim_names = [ 'shim_crt', 'shim_cxx', ] runtime_shims = [f"$BUILD_DIR/{name}" for name in runtime_shim_names] # If we're building either the CRT or CXX shim, don't insert the # nodefaultlibs argument because it makes static library insertion not work # in clang and gcc. if any(name in str(t) for name in runtime_shim_names for t in target): return target, source libdeps_no_inherit = set(env.get('LIBDEPS_NO_INHERIT', [])) if not any(shim in libdeps_no_inherit for shim in runtime_shims): linkflags = env.get('LINKFLAGS', []) if '-nodefaultlibs' not in linkflags: linkflags = ['-nodefaultlibs'] + linkflags env['LINKFLAGS'] = linkflags return target, source def hack_builder_emitters(env, hack_method): for builder_name in ('Program', 'SharedLibrary', 'LoadableModule', 'StaticLibrary'): builder = env['BUILDERS'][builder_name] base_emitter = builder.emitter builder.emitter = SCons.Builder.ListEmitter([hack_method, base_emitter]) # Here, we "hoist" libgcc*.a symbols out of the toolchain and stuff them into # our own library so they don't get added piecemeal to every shared object and # executable in a build directly out of the toolchain. libcrtEnv = env.Clone(LIBS=[]) libcxxEnv = env.Clone(LIBS=[]) if dynamicRT == "force": if env.ToolchainIs('gcc', 'clang'): # Clang ang GCC get configured here because the dynamic runtimes are # injected in ways that would not be fully applied to conftests. The # only way to fix that means running part of the build before we can # run conftests. It may be worth it to do that at some point, but it's # complexity we should consider later if it's determined we need it. hack_builder_emitters(env, nodefaultlibs_hack) libcrtEnv.AppendUnique( LINKFLAGS=[ "-Wl,-z,muldefs", "-static-libgcc", "-Wl,--push-state", "-Wl,-Bstatic", "-Wl,--no-warn-execstack", "-Wl,--whole-archive", "-lgcc", "-lgcc_eh", "-Wl,--no-whole-archive", "-Wl,--pop-state", ], SYSLIBDEPS=[ ':libgcc_s.so', ] ) if has_option("libc++"): cxx_lib = "c++" else: cxx_lib = "stdc++" libcxxEnv.AppendUnique( LINKFLAGS=[ "-Wl,-z,muldefs", f"-static-lib{cxx_lib}", "-Wl,--push-state", "-Wl,-Bstatic", "-Wl,--no-warn-execstack", "-Wl,--whole-archive", f"-l{cxx_lib}", "-Wl,--no-whole-archive", "-Wl,--pop-state", ] ) libcrtEnv.ShimLibrary( name="crt", needs_link=(dynamicRT == "force"), LIBDEPS_TAGS=[ # TODO: Remove when SERVER-48291 is merged into stable build tools. # An inserted dependency must be linked to every node, including what would # be considered a leaf node to ensure that a system dependency is not linked # in before this one. This tag allows nodes tagged as leaf nodes to still # get the correct allocator. 'lint-leaf-node-allowed-dep', # This tag allows this dependency to be linked to nodes marked as not # allowed to have public dependencies. 'lint-public-dep-allowed' ] ) libcxxEnv.ShimLibrary( name="cxx", needs_link=(dynamicRT == "force"), LIBDEPS_TAGS=[ # TODO: Remove when SERVER-48291 is merged into stable build tools. # An inserted dependency must be linked to every node, including what would # be considered a leaf node to ensure that a system dependency is not linked # in before this one. This tag allows nodes tagged as leaf nodes to still # get the correct allocator. 'lint-leaf-node-allowed-dep', # This tag allows this dependency to be linked to nodes marked as not # allowed to have public dependencies. 'lint-public-dep-allowed' ] ) if get_option("build-tools") == "next": # Add any "global" dependencies here. This is where we make every build node # depend on a list of other build nodes, such as an allocator or libunwind # or libstdx or similar. env.AppendUnique( LIBDEPS_GLOBAL=[ '$BUILD_DIR/shim_crt' if dynamicRT == "force" else [], '$BUILD_DIR/shim_cxx' if dynamicRT == "force" else [], '$BUILD_DIR/third_party/shim_allocator', ], ) else: if dynamicRT == "force": hack_builder_emitters( env, partial( shim_hack, inject_target='shim_crt')) hack_builder_emitters( env, partial( shim_hack, inject_target='shim_cxx')) hack_builder_emitters( env, partial( shim_hack, inject_target='third_party/shim_allocator', exclusions='gperftools/gperftools')) # NOTE: We must do third_party first as it adds methods to the environment # that we need in the mongo sconscript env.SConscript('third_party/SConscript', exports=['env']) # Inject common dependencies from third_party globally for all core mongo code # and modules. Ideally, pcre wouldn't be here, but enough things require it # now that it seems hopeless to remove it. env.InjectThirdParty(libraries=[ 'abseil-cpp', 'boost', 'fmt', 'pcre', 'safeint', 'variant', ]) # Run the core mongodb SConscript. env.SConscript('mongo/SConscript', exports=['env']) # Run SConscripts for any modules in play env.SConscript(module_sconscripts, exports=['env'])