# -*- mode: python; -*- # This SConscript describes build rules for the "mongo" project. import itertools import os import re import sys from buildscripts import utils Import("env") Import("has_option") Import("get_option") Import("usemozjs") Import("use_system_version_of_library") env = env.Clone() env.InjectMongoIncludePaths() env.SConscript( dirs=[ 'base', 'bson', 'client', 'crypto', 'db', 'dbtests', 'executor', 'idl', 'installer', 'logger', 'platform', 'rpc', 's', 'scripting', 'shell', 'tools', 'transport', 'unittest', 'util', ], exports=[ 'env', ], ) # NOTE: This library does not really belong here. Its presence here is # temporary. Do not add to this library, do not remove from it, and do # not declare other libraries in this file. baseSource=[ 'base/data_range.cpp', 'base/data_range_cursor.cpp', 'base/data_type.cpp', 'base/data_type_string_data.cpp', 'base/data_type_terminated.cpp', 'base/error_codes.cpp', 'base/global_initializer.cpp', 'base/global_initializer_registerer.cpp', 'base/init.cpp', 'base/initializer.cpp', 'base/initializer_context.cpp', 'base/initializer_dependency_graph.cpp', 'base/make_string_vector.cpp', 'base/parse_number.cpp', 'base/simple_string_data_comparator.cpp', 'base/status.cpp', 'base/string_data.cpp', 'base/validate_locale.cpp', 'bson/bson_comparator_interface_base.cpp', 'bson/bson_depth.cpp', 'bson/bson_validate.cpp', 'bson/bsonelement.cpp', 'bson/bsonmisc.cpp', 'bson/bsonobj.cpp', 'bson/bsonobjbuilder.cpp', 'bson/bsontypes.cpp', 'bson/json.cpp', 'bson/oid.cpp', 'bson/simple_bsonelement_comparator.cpp', 'bson/simple_bsonobj_comparator.cpp', 'bson/timestamp.cpp', 'logger/component_message_log_domain.cpp', 'logger/console.cpp', 'logger/log_component.cpp', 'logger/log_component_settings.cpp', 'logger/log_manager.cpp', 'logger/log_severity.cpp', 'logger/logger.cpp', 'logger/logstream_builder.cpp', 'logger/message_event_utf8_encoder.cpp', 'logger/message_log_domain.cpp', 'logger/ramlog.cpp', 'logger/redaction.cpp', 'logger/rotatable_file_manager.cpp', 'logger/rotatable_file_writer.cpp', 'platform/decimal128.cpp', 'platform/posix_fadvise.cpp', 'platform/process_id.cpp', 'platform/random.cpp', 'platform/shared_library.cpp', 'platform/shared_library_${TARGET_OS_FAMILY}.cpp', 'platform/stack_locator.cpp', 'platform/stack_locator_${TARGET_OS}.cpp', 'platform/strcasestr.cpp', 'platform/strnlen.cpp', 'util/allocator.cpp', 'util/assert_util.cpp', 'util/base64.cpp', 'util/concurrency/idle_thread_block.cpp', 'util/concurrency/thread_name.cpp', 'util/duration.cpp', 'util/exception_filter_win32.cpp', 'util/exit.cpp', 'util/file.cpp', 'util/hex.cpp', 'util/itoa.cpp', 'util/log.cpp', 'util/platform_init.cpp', 'util/signal_handlers_synchronous.cpp', 'util/stacktrace.cpp', 'util/stacktrace_${TARGET_OS_FAMILY}.cpp', 'util/startup_test.cpp', 'util/stringutils.cpp', 'util/system_clock_source.cpp', 'util/system_tick_source.cpp', 'util/text.cpp', 'util/time_support.cpp', 'util/timer.cpp', 'util/version.cpp', ] baseLibDeps=[ # NOTE: This library *must not* depend on any libraries than # the ones declared here. Do not add to this list. '$BUILD_DIR/third_party/murmurhash3/murmurhash3', '$BUILD_DIR/third_party/shim_allocator', '$BUILD_DIR/third_party/shim_boost', '$BUILD_DIR/third_party/shim_intel_decimal128', '$BUILD_DIR/third_party/shim_pcrecpp', '$BUILD_DIR/third_party/shim_tz', 'logger/max_log_size', 'util/debugger', 'util/quick_exit', ] env.Library( target='base', source=baseSource, LIBDEPS=baseLibDeps, ) 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'] ]) # This generates a numeric representation of the version string so that # you can easily compare versions of MongoDB without having to parse # the version string. # # The rules for this are # {major}{minor}{release}{pre/rc/final} # If the version is pre-release and not an rc, the final number is 0 # If the version is an RC, the final number of 1 + rc number # If the version is pre-release between RC's, the final number is 1 + rc number # If the version is a final release, the final number is 99 # # Examples: # 3.1.1-123 = 3010100 # 3.1.1-rc2 = 3010103 # 3.1.1-rc2-123 = 3010103 # 3.1.1 = 3010199 # version_parts = [ x for x in re.match(r'^(\d+)\.(\d+)\.(\d+)-?((?:(rc)(\d+))?.*)?', env['MONGO_VERSION']).groups() ] version_extra = version_parts[3] if version_parts[3] else "" if version_parts[4] == 'rc': version_parts[3] = int(version_parts[5]) + -50 elif version_parts[3]: version_parts[2] = int(version_parts[2]) + 1 version_parts[3] = -100 else: version_parts[3] = 0 version_parts = [ int(x) for x in version_parts[:4]] # This turns the MONGO_BUILDINFO_ENVIRONMENT_DATA tuples into a std::vector of # std::tuple. buildInfoInitializer = [] for tup in env['MONGO_BUILDINFO_ENVIRONMENT_DATA']: def pyToCXXBool(val): return "true" if val else "false" def wrapInQuotes(val): return '"{0}"'.format(val) buildInfoInitializer.append( 'std::make_tuple({0})'.format(', '.join( ( wrapInQuotes(tup[0]), wrapInQuotes(env.subst(tup[1])), pyToCXXBool(tup[2]), pyToCXXBool(tup[3]), ) )) ) buildInfoInitializer = '{{ {0} }}'.format(', '.join(buildInfoInitializer)) generatedVersionFile = env.Substfile( 'util/version_constants.h.in', SUBST_DICT=[ ('@mongo_version@', env['MONGO_VERSION']), ('@mongo_version_major@', version_parts[0]), ('@mongo_version_minor@', version_parts[1]), ('@mongo_version_patch@', version_parts[2]), ('@mongo_version_extra@', version_parts[3]), ('@mongo_version_extra_str@', version_extra), ('@mongo_git_hash@', env['MONGO_GIT_HASH']), ('@buildinfo_js_engine@', js_engine_ver), ('@buildinfo_allocator@', env['MONGO_ALLOCATOR']), ('@buildinfo_modules@', module_list), ('@buildinfo_environment_data@', buildInfoInitializer), ]) env.Alias('generated-sources', generatedVersionFile) if env.TargetOSIs('windows'): enterpriseEnv = env.Clone().InjectModule("enterprise") generatedResourceConstantFile = enterpriseEnv.Substfile( 'util/resource_constants.h.in', SUBST_DICT=[ ('@mongo_version@', env['MONGO_VERSION']), ('@mongo_version_major@', version_parts[0]), ('@mongo_version_minor@', version_parts[1]), ('@mongo_version_patch@', version_parts[2]), ('@mongo_git_hash@', env['MONGO_GIT_HASH']), ]) env.Alias('generated-sources', generatedResourceConstantFile) 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_fips_mode_set@', 'MONGO_CONFIG_HAVE_FIPS_MODE_SET'), ('@mongo_config_have_header_unistd_h@', 'MONGO_CONFIG_HAVE_HEADER_UNISTD_H'), ('@mongo_config_have_memset_s@', 'MONGO_CONFIG_HAVE_MEMSET_S'), ('@mongo_config_have_posix_monotonic_clock@', 'MONGO_CONFIG_HAVE_POSIX_MONOTONIC_CLOCK'), ('@mongo_config_have_pthread_setname_np@', 'MONGO_CONFIG_HAVE_PTHREAD_SETNAME_NP'), ('@mongo_config_have_std_enable_if_t@', 'MONGO_CONFIG_HAVE_STD_ENABLE_IF_T'), ('@mongo_config_have_std_make_unique@', 'MONGO_CONFIG_HAVE_STD_MAKE_UNIQUE'), ('@mongo_config_have_strnlen@', 'MONGO_CONFIG_HAVE_STRNLEN'), ('@mongo_config_have_thread_local@', 'MONGO_CONFIG_HAVE_THREAD_LOCAL'), ('@mongo_config_optimized_build@', 'MONGO_CONFIG_OPTIMIZED_BUILD'), ('@mongo_config_ssl@', 'MONGO_CONFIG_SSL'), ('@mongo_config_ssl_has_asn1_any_definitions@', 'MONGO_CONFIG_HAVE_ASN1_ANY_DEFINITIONS'), ('@mongo_config_wiredtiger_enabled@', 'MONGO_CONFIG_WIREDTIGER_ENABLED'), ) 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) generateConfigHeaderFile = env.Substfile( 'config.h.in', SUBST_DICT=[(k, env.makeConfigHeaderDefine(v)) for (k, v) in config_header_substs] ) env.Alias('generated-sources', generateConfigHeaderFile) mongodLibDeps = [ 'db/assemble_response', 'db/commands/core', 'db/conn_pool_options', 'db/catalog/catalog', 'db/clientcursor', 'db/dbdirectclient', 'db/ftdc/ftdc_mongod', 'db/index_d', 'db/initialize_snmp', 'db/mongod_options', 'db/mongodandmongos', 'db/op_observer_d', 'db/repl/repl_set_commands', 'db/repair_database', 'db/repl/storage_interface_impl', 'db/repl/topology_coordinator_impl', 'db/s/balancer', 'db/serveronly', 'db/service_context_d', 'db/startup_warnings_mongod', 'db/ttl_d', 'executor/network_interface_factory', 'rpc/rpc', 's/commands/shared_cluster_commands', 'transport/service_entry_point_utils', 'transport/transport_layer_legacy', 'util/clock_sources', 'util/fail_point', 'util/ntservice', 'util/version_impl', ] if has_option('use-cpu-profiler'): mongodLibDeps.append('db/commands/cpuprofiler') mongod = env.Program( target="mongod", source=[ "db/db.cpp", "db/mongod_options_init.cpp", "db/service_entry_point_mongod.cpp", ] + env.WindowsResourceFile("db/db.rc"), LIBDEPS=mongodLibDeps, ) env.Default(env.Install('#/', mongod)) # tools rewrittenTools = [ "mongodump", "mongorestore", "mongoexport", "mongoimport", "mongostat", "mongotop", "bsondump", "mongofiles", "mongooplog" ] # mongoperf env.Install( '#/', [ env.Program("mongoperf", [ "client/examples/mongoperf.cpp", ] + env.WindowsResourceFile("client/examples/mongoperf.rc"), LIBDEPS=[ "db/serveronly", ]), ]) # mongos env.Install( '#/', env.Program( target='mongos', source=[ 's/cluster_cursor_stats.cpp', 's/mongos_options.cpp', 's/mongos_options_init.cpp', 's/s_sharding_server_status.cpp', 's/server.cpp', 's/service_entry_point_mongos.cpp', 's/sharding_uptime_reporter.cpp', 's/version_mongos.cpp', ] + env.WindowsResourceFile("s/server.rc"), LIBDEPS=[ 'db/commands/core', 'db/conn_pool_options', 'db/logical_time_metadata_hook', 'db/mongodandmongos', 'db/server_options', 'db/stats/counters', 's/client/sharding_connection_hook', 's/commands/cluster_commands', 's/commands/shared_cluster_commands', 's/coreshard', 's/is_mongos', 's/sharding_egress_metadata_hook_for_mongos', 's/sharding_initialization', 'transport/service_entry_point_utils', 'transport/transport_layer_legacy', 'util/clock_sources', 'util/fail_point', 'util/ntservice', 'util/options_parser/options_parser_init', 'util/version_impl', ])) env.Library("linenoise_utf8", source=[ "shell/linenoise_utf8.cpp", ]) # --- shell --- if not has_option('noshell') and usemozjs: 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/linenoise.cpp", "shell/mk_wcwidth.cpp", "shell/mongo-server.cpp", "shell/shell_options.cpp", "shell/shell_options_init.cpp", "shell/shell_utils.cpp", "shell/shell_utils_extended.cpp", "shell/shell_utils_launcher.cpp", ], LIBDEPS=[ 'db/catalog/index_key_validate', 'db/index/external_key_generator', 'db/query/command_request_response', 'db/query/query_request', 'db/server_options_core', 'linenoise_utf8', 'rpc/protocol', 'scripting/scripting', 'shell/mongojs', 'transport/message_compressor', 'util/net/network', 'util/options_parser/options_parser_init', 'util/processinfo', 'util/signal_handlers', 'util/version_impl', 'executor/thread_pool_task_executor', 'executor/network_interface_thread_pool', 'executor/network_interface_factory' ], # Because `::environ` is resolved in `/usr/lib/crt1.o` on FreeBSD, this library # needs to be marked `incomplete` on FreeBSD. LIBDEPS_TAGS=[] if not env.TargetOSIs('freebsd') else [ 'illegal_cyclic_or_unresolved_dependencies_whitelisted', ], ) shellEnv = env.Clone() if env.TargetOSIs('windows'): shellEnv.Append(LIBS=["winmm.lib"]) mongo_shell = shellEnv.Program( "mongo", ["shell/dbshell.cpp"] + env.WindowsResourceFile("shell/shell.rc"), LIBDEPS=["$BUILD_DIR/third_party/shim_pcrecpp", "shell_core", "db/server_options_core", "client/clientdriver", "$BUILD_DIR/mongo/util/password", ]) shellEnv.Install( '#/', mongo_shell ) else: shellEnv = None # ---- INSTALL ------- # binaries distBinaries = [] distDebugSymbols = [] def add_exe( v ): return "${PROGPREFIX}%s${PROGSUFFIX}" % v def failMissingObjCopy(env, target, source): env.FatalError("Generating debug symbols requires objcopy, please set the OBJCOPY variable.") def installBinary( e, name ): debug_sym_name = name name = add_exe( name ) debug_sym_cmd = None if e.TargetOSIs('linux', 'solaris'): if 'OBJCOPY' not in e: debug_sym_cmd = failMissingObjCopy else: debug_sym_cmd = '${OBJCOPY} --only-keep-debug ${SOURCE} ${TARGET}' debug_sym_name += '.debug' elif e.TargetOSIs('darwin'): debug_sym_name += '.dSYM' debug_sym_cmd = 'dsymutil -o ${TARGET} ${SOURCE}' elif e.ToolchainIs('msvc'): debug_sym_name += '.pdb' distBinaries.append(debug_sym_name) distDebugSymbols.append(debug_sym_name) if debug_sym_cmd: debug_sym = e.Command( debug_sym_name, name, debug_sym_cmd ) e.Install("#/", debug_sym) e.Alias('debugsymbols', debug_sym) distDebugSymbols.append(debug_sym) if env.TargetOSIs('linux', 'solaris') and (not has_option("nostrip")): strip_cmd = e.Command( 'stripped/%s' % name, [name, debug_sym], '${OBJCOPY} --strip-debug --add-gnu-debuglink ${SOURCES[1]} ${SOURCES[0]} $TARGET' ) distBinaries.append('stripped/%s' % name) else: 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)) if has_option("build-mongoreplay") and get_option("build-mongoreplay") == "true": installExternalBinary(env, "%s/%s" % (toolsRoot, "mongoreplay")) # legacy tools installBinary(env, "mongoperf") env.Alias("tools", '#/' + add_exe("mongoperf")) env.Alias("tools", "#/" + add_exe("mongobridge")) 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'), distsrc.File('MPL-2')]) # 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)) for target in env["DIST_BINARIES"]: installBinary(env, "db/modules/" + target) # "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( target='#/${SERVER_ARCHIVE}', source=['#buildscripts/make_archive.py'] + env["MODULE_BANNERS"] + env["ARCHIVE_ADDITIONS"] + distBinaries, action=' '.join( ['$PYTHON ${SOURCES[0]} -o $TARGET'] + archive_addition_transforms + module_banner_transforms + [ '--transform $BUILD_DIR/mongo/db/modules/enterprise=$SERVER_DIST_BASENAME/bin', '--transform $BUILD_DIR/mongo/stripped/db/modules/enterprise=$SERVER_DIST_BASENAME/bin', '--transform $BUILD_DIR/mongo/stripped=$SERVER_DIST_BASENAME/bin', '--transform $BUILD_DIR/mongo=$SERVER_DIST_BASENAME/bin', '--transform $BUILD_DIR/mongo/stripped/src/mongo-tools=$SERVER_DIST_BASENAME/bin', '--transform src/mongo-tools=$SERVER_DIST_BASENAME/bin', '${TEMPFILE(SOURCES[1:])}' ], ), BUILD_DIR=env.Dir('$BUILD_DIR').path ) 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") debug_symbols_dist = env.Command( target='#/${SERVER_DIST_BASENAME}-debugsymbols${DIST_ARCHIVE_SUFFIX}', source=['#buildscripts/make_archive.py'] + distDebugSymbols, action=' '.join( [ '$PYTHON ${SOURCES[0]} -o $TARGET', '--transform $BUILD_DIR/mongo/db/modules/enterprise=$SERVER_DIST_BASENAME', '--transform $BUILD_DIR/mongo=$SERVER_DIST_BASENAME', '${TEMPFILE(SOURCES[1:])}', ] ), BUILD_DIR=env.Dir('$BUILD_DIR').path ) env.Alias('dist-debugsymbols', debug_symbols_dist) #final alias env.Alias( "install", "$INSTALL_DIR" )