# -*- mode: python; -*- # This SConscript describes build rules for the "mongo" project. import os import itertools import subprocess import sys from buildscripts import utils import SCons.Action Import("env") Import("has_option") Import("get_option") Import("usev8") Import("use_system_version_of_library") # Boost we need everywhere. 's2' is spammed in all over the place by # db/geo unfortunately. pcre is also used many places. env.InjectThirdPartyIncludePaths(libraries=['boost', 's2', 'pcre']) env.InjectMongoIncludePaths() env.SConscript( dirs=[ 'base', 'bson', 'client', 'crypto', 'db', 'dbtests', 'installer', 'logger', 'platform', 'rpc', 's', 'scripting', 'shell', 'tools', 'unittest', 'util', ], ) def get_toolchain_ver(tool): # By default we don't know the version of each tool, and only report what # command gets executed (gcc vs /opt/mongodbtoolchain/bin/gcc). verstr = "version unknown" proc = None if env.ToolchainIs('clang', 'gcc'): proc = SCons.Action._subproc(env, env.subst("${%s} --version" % tool), stdout=subprocess.PIPE, stderr='devnull', stdin='devnull', universal_newlines=True, error='raise', shell=True) verstr = proc.stdout.readline() elif env.ToolchainIs('msvc') and env.TargetOSIs('windows'): proc = SCons.Action._subproc(env, env.subst("${%s}" % tool), stdout='devnull', stderr=subprocess.PIPE, stdin='devnull', universal_newlines=True, error='raise', shell=True) verstr = proc.stderr.readline() # If we started a process, we should drain its stdout/stderr and wait for # it to end. if proc: proc.communicate() return env.subst('${%s}: %s' % (tool, verstr)) js_engine_ver = get_option("js-engine") if get_option("server-js") == "on" else "none" # On windows, we need to escape the backslashes in the command-line # so that windows paths look okay. cmd_line = " ".join(sys.argv).encode('string-escape') if env.TargetOSIs('windows'): cmd_line = cmd_line.replace('\\', r'\\') module_list = '{ %s }' % ', '.join([ '"{0}"'.format(x) for x in env['MONGO_MODULES'] ]) versionInfo = env.Substfile( 'util/version.cpp.in', SUBST_DICT=[ ('@mongo_code_version@', env['MONGO_CODE_VERSION']), ('@buildinfo_git_version@', env['MONGO_GIT_VERSION']), ('@buildinfo_js_engine@', js_engine_ver), ('@buildinfo_allocator@', GetOption('allocator')), ('@buildinfo_ccflags@', env['CCFLAGS']), ('@buildinfo_cflags@', env['CFLAGS']), ('@buildinfo_cxxflags@', env['CXXFLAGS']), ('@buildinfo_linkflags@', env['LINKFLAGS']), ('@buildinfo_cmdline@', ''), ('@buildinfo_modules@', module_list), ('@buildinfo_target_arch@', env['TARGET_ARCH']), ('@buildinfo_target_os@', env.GetTargetOSName()), ('@buildinfo_cc_version@', get_toolchain_ver('CC')), ('@buildinfo_cxx_version@', get_toolchain_ver('CXX')), ]) config_header_substs = ( ('@mongo_config_byte_order@', 'MONGO_CONFIG_BYTE_ORDER'), ('@mongo_config_debug_build@', 'MONGO_CONFIG_DEBUG_BUILD'), ('@mongo_config_have___declspec_thread@', 'MONGO_CONFIG_HAVE___DECLSPEC_THREAD'), ('@mongo_config_have___thread@', 'MONGO_CONFIG_HAVE___THREAD'), ('@mongo_config_have_execinfo_backtrace@', 'MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE'), ('@mongo_config_have_header_unistd_h@', 'MONGO_CONFIG_HAVE_HEADER_UNISTD_H'), ('@mongo_config_have_posix_monotonic_clock@', 'MONGO_CONFIG_HAVE_POSIX_MONOTONIC_CLOCK'), ('@mongo_config_have_std_is_trivially_copyable@', 'MONGO_CONFIG_HAVE_STD_IS_TRIVIALLY_COPYABLE'), ('@mongo_config_have_std_make_unique@', 'MONGO_CONFIG_HAVE_STD_MAKE_UNIQUE'), ('@mongo_config_optimized_build@', 'MONGO_CONFIG_OPTIMIZED_BUILD'), ('@mongo_config_ssl@', 'MONGO_CONFIG_SSL'), ('@mongo_config_ssl_fips@', 'MONGO_CONFIG_SSL_FIPS'), ('@mongo_config_use_gdbserver@', 'MONGO_CONFIG_USE_GDBSERVER'), ) def makeConfigHeaderDefine(self, key): val = "// #undef {0}".format(key) if key in self['CONFIG_HEADER_DEFINES']: val = "#define {0} {1}".format(key, self['CONFIG_HEADER_DEFINES'][key]) return val env.AddMethod(makeConfigHeaderDefine) configHeaderFile = env.Substfile( 'config.h.in', SUBST_DICT=[(k, env.makeConfigHeaderDefine(v)) for (k, v) in config_header_substs] ) env.Library('version', [ 'util/version.cpp' ], LIBDEPS=[ 'bson/bson', '$BUILD_DIR/mongo/base/base' ]) env.CppUnitTest( target="util/version_test", source=["util/version_test.cpp"], LIBDEPS=[] ) mongod = env.Program( target="mongod", source=[ "db/db.cpp", "db/mongod_options_init.cpp", ], LIBDEPS=[ "db/coredb", "db/conn_pool_options", "db/mongod_options", "db/mongodandmongos", "db/mongodwebserver", "db/serveronly", "util/ntservice", ], ) env.Default(env.Install('#/', mongod)) # tools rewrittenTools = [ "mongodump", "mongorestore", "mongoexport", "mongoimport", "mongostat", "mongotop", "bsondump", "mongofiles", "mongooplog" ] # mongobridge and mongoperf env.Install( '#/', [ env.Program("mongoperf", [ "client/examples/mongoperf.cpp", ], LIBDEPS=[ "util/ntservice_mock", "db/serveronly", "db/coredb", "util/signal_handlers_synchronous", ]), ]) # mongos env.Install( '#/', env.Program( "mongos", [ "s/server.cpp", "s/mongos_options.cpp", "s/mongos_options_init.cpp", ], LIBDEPS=[ 's/catalog/legacy/catalog_manager_legacy', 's/client/sharding_connection_hook', 's/commands/cluster_commands', "s/mongoscore", "db/coredb", "s/coreshard", "util/ntservice", "db/mongodandmongos", "db/conn_pool_options", '$BUILD_DIR/mongo/util/options_parser/options_parser_init', ])) # --- sniffer --- mongosniff_built = False if env.TargetOSIs('osx') or env["_HAVEPCAP"]: mongosniff_built = True sniffEnv = env.Clone() sniffEnv.Append( CPPDEFINES="MONGO_EXPOSE_MACROS" ) if not env.TargetOSIs('windows'): sniffEnv.Append( LIBS=[ "pcap" ] ) else: sniffEnv.Append( LIBS=[ "wpcap" ] ) sniffEnv.Install( '#/', sniffEnv.Program( "mongosniff", "tools/sniffer.cpp", LIBDEPS = [ "db/serveronly", "db/coredb", "util/signal_handlers_synchronous", ] ) ) # --- shell --- if not has_option('noshell') and usev8: shell_core_env = env.Clone() if has_option("safeshell"): shell_core_env.Append(CPPDEFINES=["MONGO_SAFE_SHELL"]) shell_core_env.Library("shell_core", source=[ "shell/bench.cpp", "shell/clientAndShell.cpp", "shell/linenoise.cpp", "shell/linenoise_utf8.cpp", "shell/mk_wcwidth.cpp", "shell/mongo-server.cpp", "shell/shell_utils.cpp", "shell/shell_utils_extended.cpp", "shell/shell_utils_launcher.cpp", "shell/shell_options_init.cpp" ], LIBDEPS=[ 'db/index/external_key_generator', 'db/catalog/index_key_validate', 'scripting/scripting', 'util/processinfo', 'util/signal_handlers', 'shell/mongojs', ]) # mongo shell options shell_core_env.Library("shell_options", ["shell/shell_options.cpp"], LIBDEPS=['$BUILD_DIR/mongo/util/options_parser/options_parser_init']) shellEnv = env.Clone() if env.TargetOSIs('windows'): shellEnv.Append(LIBS=["winmm.lib"]) mongo_shell = shellEnv.Program( "mongo", "shell/dbshell.cpp", LIBDEPS=["$BUILD_DIR/third_party/shim_pcrecpp", "shell_options", "shell_core", "db/server_options_core", "client/clientdriver", "$BUILD_DIR/mongo/util/password", ]) shellEnv.Install( '#/', mongo_shell ) else: shellEnv = None # ---- INSTALL ------- # binaries distBinaries = [] if env.TargetOSIs('windows'): distBinaries.extend(['mongod.pdb', 'mongos.pdb']) def add_exe( v ): return "${PROGPREFIX}%s${PROGSUFFIX}" % v def installBinary( e, name ): name = add_exe( name ) if env.TargetOSIs('solaris', 'linux') and (not has_option("nostrip")): name = e.Command('stripped/%s' % name, name, Copy('$TARGET', '$SOURCE'))[0] e.AddPostAction(name, 'strip $TARGET') distBinaries.append(name) inst = e.Install( "$INSTALL_DIR/bin", name ) if env.TargetOSIs('posix'): e.AddPostAction( inst, 'chmod 755 $TARGET' ) def installExternalBinary( e, name_str ): name = env.File("#/%s" % add_exe(name_str)) if not name.isfile(): env.FatalError("ERROR: external binary not found: {0}", name) distBinaries.append(name) inst = e.Install( "$INSTALL_DIR/bin", name ) if env.TargetOSIs('posix'): e.AddPostAction( inst, 'chmod 755 $TARGET' ) # "--use-new-tools" adds dependencies for rewritten (Go) tools # It is required for "dist" but optional for "install" if has_option("use-new-tools"): toolsRoot = "src/mongo-tools" for t in rewrittenTools: installExternalBinary(env, "%s/%s" % (toolsRoot, t)) # legacy tools installBinary(env, "mongoperf") env.Alias("tools", '#/' + add_exe("mongoperf")) env.Alias("tools", "#/" + add_exe("mongobridge")) if mongosniff_built: installBinary(env, "mongosniff") env.Alias("tools", '#/' + add_exe("mongosniff")) installBinary( env, "mongod" ) installBinary( env, "mongos" ) if shellEnv is not None: installBinary( shellEnv, "mongo" ) env.Alias( "core", [ '#/%s' % b for b in [ add_exe( "mongo" ), add_exe( "mongod" ), add_exe( "mongos" ) ] ] ) # Stage the top-level mongodb banners distsrc = env.Dir('#distsrc') env.Append(MODULE_BANNERS = [distsrc.File('README'), distsrc.File('THIRD-PARTY-NOTICES')]) # If no module has introduced a file named LICENSE.txt, then inject the AGPL. if sum(itertools.imap(lambda x: x.name == "LICENSE.txt", env['MODULE_BANNERS'])) == 0: env.Append(MODULE_BANNERS = [distsrc.File('GNU-AGPL-3.0')]) # All module banners get staged to the top level of the tarfile, so we # need to fail if we are going to have a name collision. module_banner_filenames = set([f.name for f in env['MODULE_BANNERS']]) if not len(module_banner_filenames) == len(env['MODULE_BANNERS']): # TODO: Be nice and identify conflicts in error. env.FatalError("ERROR: Filename conflicts exist in module banners.") # Build a set of directories containing module banners, and use that # to build a --transform option for each directory so that the files # are tar'ed up to the proper location. module_banner_dirs = set([Dir('#').rel_path(f.get_dir()) for f in env['MODULE_BANNERS']]) module_banner_transforms = ["--transform %s=$SERVER_DIST_BASENAME" % d for d in module_banner_dirs] # Allow modules to map original file name directories to subdirectories # within the archive (e.g. { "src/mongo/db/modules/enterprise/docs": "snmp"}) archive_addition_transforms = [] for full_dir, archive_dir in env["ARCHIVE_ADDITION_DIR_MAP"].items(): archive_addition_transforms.append("--transform \"%s=$SERVER_DIST_BASENAME/%s\"" % (full_dir, archive_dir)) # "dist" target is valid only when --use-new-tools is specified # Attempts to build release artifacts without tools must fail if has_option("use-new-tools"): env.Command( '#/${SERVER_ARCHIVE}', ['#buildscripts/make_archive.py'] + env["MODULE_BANNERS"] + env["ARCHIVE_ADDITIONS"] + distBinaries, ' '.join(['$PYTHON ${SOURCES[0]} -o $TARGET'] + archive_addition_transforms + module_banner_transforms + [ '--transform ${str(Dir(BUILD_DIR))}/mongo/stripped=$SERVER_DIST_BASENAME/bin', '--transform ${str(Dir(BUILD_DIR))}/mongo=$SERVER_DIST_BASENAME/bin', '--transform ${str(Dir(BUILD_DIR))}/mongo/stripped/src/mongo-tools=$SERVER_DIST_BASENAME/bin', '--transform src/mongo-tools=$SERVER_DIST_BASENAME/bin', '${TEMPFILE(SOURCES[1:])}'])) env.Alias("dist", source='#/${SERVER_ARCHIVE}') else: def failDist(env, target, source): env.FatalError("ERROR: 'dist' target only valid with --use-new-tools.") env.Alias("dist", [], [ failDist ] ) env.AlwaysBuild("dist") #final alias env.Alias( "install", "$INSTALL_DIR" )