# -*- mode: python; -*-

# This SConscript describes build rules for the "mongo" project.

import os
import itertools
from buildscripts import utils

Import("env")
Import("shellEnv")
Import("testEnv")
Import("has_option")
Import("usesm usev8")
Import("installSetup")
Import("enforce_glibc")
Import("darwin windows solaris linux nix")

env.SConscript(['base/SConscript',
                'db/auth/SConscript',
                'db/fts/SConscript',
                'db/SConscript',
                'platform/SConscript',
                's/SConscript',
                'unittest/SConscript'])

def add_exe( v ):
    return "${PROGPREFIX}%s${PROGSUFFIX}" % v

# ------    SOURCE FILE SETUP -----------

env.StaticLibrary('foundation',
                  [ 'util/assert_util.cpp',
                    'util/concurrency/mutexdebugger.cpp',
                    'util/debug_util.cpp',
                    'util/exception_filter_win32.cpp',
                    'util/file.cpp',
                    'util/log.cpp',
                    'util/platform_init.cpp',
                    'util/signal_handlers.cpp',
                    'util/text.cpp',
                    'util/time_support.cpp',
                    'util/timer.cpp'
                    ],
                  LIBDEPS=['stacktrace',
                           '$BUILD_DIR/mongo/base/base',
                           '$BUILD_DIR/mongo/platform/platform',
                           '$BUILD_DIR/third_party/shim_allocator',
                           '$BUILD_DIR/third_party/shim_boost'])

env.CppUnitTest('text_test', 'util/text_test.cpp', LIBDEPS=['foundation'])

env.StaticLibrary('stringutils', ['util/stringutils.cpp', 'util/base64.cpp',])

env.StaticLibrary('md5', [
        'util/md5.cpp'
        ])

env.CppUnitTest( "md5_test", ["util/md5_test.cpp", "util/md5main.cpp" ],
                 LIBDEPS=["md5"] )

env.CppUnitTest( "stringutils_test", [ "util/stringutils_test.cpp" ],
                 LIBDEPS=["stringutils"] )

env.StaticLibrary('bson', [
        'bson/mutable/mutable_bson.cpp',
        'bson/mutable/mutable_bson_builder.cpp',
        'bson/mutable/mutable_bson_heap.cpp',
        'bson/mutable/mutable_bson_internal.cpp',
        'bson/util/bson_extract.cpp',
        'util/safe_num.cpp',
        'bson/bson_validate.cpp',
        'bson/oid.cpp',
        'db/jsobj.cpp',
        'db/json.cpp'
        ], LIBDEPS=[
        'base/base',
        'md5',
        'stringutils',
        '$BUILD_DIR/mongo/platform/platform',
        ])

env.CppUnitTest('builder_test', ['bson/util/builder_test.cpp'],
                LIBDEPS=['bson'])

env.CppUnitTest('mutable_bson_test', ['bson/mutable/mutable_bson_test.cpp'],
                 LIBDEPS=['bson'])

env.CppUnitTest('mutable_bson_heap_test', ['bson/mutable/mutable_bson_heap_test.cpp'],
                 LIBDEPS=['bson'])

env.CppUnitTest('mutable_bson_builder_test', ['bson/mutable/mutable_bson_builder_test.cpp'],
                LIBDEPS=['bson'])

env.CppUnitTest('mutable_bson_algo_test', ['bson/mutable/mutable_bson_algo_test.cpp'],
                LIBDEPS=['bson'])

env.CppUnitTest('safe_num_test', ['util/safe_num_test.cpp'],
                LIBDEPS=['bson'])

env.CppUnitTest('string_map_test', ['util/string_map_test.cpp'],
                LIBDEPS=['bson','foundation'])


env.CppUnitTest('bson_field_test', ['bson/bson_field_test.cpp'],
                LIBDEPS=['bson'])

env.CppUnitTest('bson_validate_test', ['bson/bson_validate_test.cpp'],
                LIBDEPS=['bson'])

env.CppUnitTest('namespacestring_test', ['db/namespacestring_test.cpp'],
                LIBDEPS=['bson'])

env.CppUnitTest('index_set_test', ['db/index_set_test.cpp'],
                LIBDEPS=['bson','index_set'])


env.CppUnitTest('bson_extract_test', ['bson/util/bson_extract_test.cpp'], LIBDEPS=['bson'])

env.CppUnitTest('descriptive_stats_test',
                ['util/descriptive_stats_test.cpp'],
                LIBDEPS=['foundation', 'bson']);

env.CppUnitTest('sock_test', ['util/net/sock_test.cpp'],
                LIBDEPS=['mongocommon', 'notmongodormongos'],
                NO_CRUTCH=True)

env.StaticLibrary( 'mongohasher', [ "db/hasher.cpp" ] )


commonFiles = [ "pch.cpp",
                "buildinfo.cpp",
                "db/lasterror.cpp",
                "db/namespace.cpp",
                "shell/mongo.cpp",
                "util/background.cpp",
                "util/intrusive_counter.cpp",
                "util/util.cpp",
                "util/file_allocator.cpp",
                "util/trace.cpp",
                "util/ramlog.cpp",
                "util/progress_meter.cpp",
                "util/concurrency/task.cpp",
                "util/concurrency/thread_pool.cpp",
                "util/password.cpp",
                "util/concurrency/rwlockimpl.cpp",
                "util/histogram.cpp",
                "util/concurrency/spin_lock.cpp",
                "util/text_startuptest.cpp",
                "util/stack_introspect.cpp",
                "util/concurrency/synchronization.cpp",
                "util/net/sock.cpp",
                "util/net/ssl_manager.cpp",
                "util/net/httpclient.cpp",
                "util/net/message.cpp",
                "util/net/message_port.cpp",
                "util/net/listen.cpp",
                "util/startup_test.cpp",
                "util/version.cpp",
                "client/connpool.cpp",
                "client/dbclient.cpp",
                "client/dbclient_rs.cpp",
                "client/dbclientcursor.cpp",
                "client/model.cpp",
                'client/sasl_client_authenticate.cpp',
                "client/syncclusterconnection.cpp",
                "db/dbmessage.cpp"
                ]

commonSysLibdeps = []

if env['MONGO_BUILD_SASL_CLIENT']:
    commonFiles.extend(['client/sasl_client_authenticate_impl.cpp',
                        'util/gsasl_session.cpp'])
    commonSysLibdeps.append('gsasl')

# handle processinfo*
processInfoFiles = [ "util/processinfo.cpp" ]

processInfoPlatformFile = env.File( "util/processinfo_${PYSYSPLATFORM}.cpp" )
# NOTE( schwerin ): This is a very un-scons-y way to make this decision, and prevents one from using
# code generation to produce util/processinfo_$PYSYSPLATFORM.cpp.
if not os.path.exists( str( processInfoPlatformFile ) ):
    processInfoPlatformFile = env.File( "util/processinfo_none.cpp" )

processInfoFiles.append( processInfoPlatformFile )

env.StaticLibrary("processinfo",
                  processInfoFiles,
                  LIBDEPS=["foundation", "bson"])

env.CppUnitTest("processinfo_test",
                ["util/processinfo_test.cpp"],
                LIBDEPS=["processinfo"])

env.StaticLibrary("server_parameters",
                  ["db/server_parameters.cpp"],
                  LIBDEPS=["foundation","bson"])

env.CppUnitTest("server_parameters_test",
                [ "db/server_parameters_test.cpp" ],
                LIBDEPS=["server_parameters"] )


env.StaticLibrary("fail_point",
                  ["util/fail_point.cpp",
                   "util/fail_point_registry.cpp",
                   "util/fail_point_service.cpp"],
                  LIBDEPS=["foundation", "bson"])

env.StaticLibrary('mongocommon', commonFiles,
                  LIBDEPS=['bson',
                           'foundation',
                           'mongohasher',
                           'md5',
                           'processinfo',
                           'stacktrace',
                           'stringutils',
                           'fail_point',
                           '$BUILD_DIR/third_party/pcrecpp',
                           '$BUILD_DIR/third_party/murmurhash3/murmurhash3',
                           '$BUILD_DIR/third_party/shim_boost'],
                  SYSLIBDEPS=commonSysLibdeps)

env.StaticLibrary("coredb", [
        "client/parallel.cpp",
        "db/commands.cpp",
        "db/commands/authentication_commands.cpp",
        "db/commands/connection_status.cpp",
        "db/commands/fail_point_cmd.cpp",
        "db/commands/find_and_modify_common.cpp",
        "db/commands/hashcmd.cpp",
        "db/commands/isself.cpp",
        "db/commands/mr_common.cpp",
        "db/commands/rename_collection_common.cpp",
        "db/commands/server_status.cpp",
        "db/commands/parameters.cpp",
        "db/pipeline/pipeline.cpp",
        "db/dbcommands_generic.cpp",
        "db/dbwebserver.cpp",
        "db/keypattern.cpp",
        "db/matcher.cpp",
        "db/pipeline/accumulator.cpp",
        "db/pipeline/accumulator_add_to_set.cpp",
        "db/pipeline/accumulator_avg.cpp",
        "db/pipeline/accumulator_first.cpp",
        "db/pipeline/accumulator_last.cpp",
        "db/pipeline/accumulator_min_max.cpp",
        "db/pipeline/accumulator_push.cpp",
        "db/pipeline/accumulator_single_value.cpp",
        "db/pipeline/accumulator_sum.cpp",
        "db/pipeline/builder.cpp",
        "db/pipeline/doc_mem_monitor.cpp",
        "db/pipeline/document.cpp",
        "db/pipeline/document_source.cpp",
        "db/pipeline/document_source_bson_array.cpp",
        "db/pipeline/document_source_command_shards.cpp",
        "db/pipeline/document_source_filter.cpp",
        "db/pipeline/document_source_filter_base.cpp",
        "db/pipeline/document_source_geo_near.cpp",
        "db/pipeline/document_source_group.cpp",
        "db/pipeline/document_source_limit.cpp",
        "db/pipeline/document_source_match.cpp",
        "db/pipeline/document_source_out.cpp",
        "db/pipeline/document_source_project.cpp",
        "db/pipeline/document_source_skip.cpp",
        "db/pipeline/document_source_sort.cpp",
        "db/pipeline/document_source_unwind.cpp",
        "db/pipeline/expression.cpp",
        "db/pipeline/expression_context.cpp",
        "db/pipeline/field_path.cpp",
        "db/pipeline/value.cpp",
        "db/projection.cpp",
        "db/querypattern.cpp",
        "db/queryutil.cpp",
        "db/stats/timer_stats.cpp",
        "db/stats/top.cpp",
        "s/shardconnection.cpp",
        ],
                  LIBDEPS=['db/auth/serverauth',
                           'db/common',
                           'server_parameters',
                           'geoparser',
                           'geoquery',
                           '$BUILD_DIR/mongo/foundation'])

coreServerFiles = [ "db/client_basic.cpp",
                    "db/common.cpp",
                    "util/net/miniwebserver.cpp",
                    "db/indexkey.cpp",
                    "db/stats/counters.cpp",
                    "db/stats/service_stats.cpp",
                    ]

env.StaticLibrary('ntservice', ['util/ntservice.cpp'], LIBDEPS=['foundation'])
if windows:
    env.CppUnitTest('ntservice_test', 'util/ntservice_test.cpp',
                    LIBDEPS=['ntservice'],
                    LIBS=['shell32', env['LIBS']])

scripting_common_files = [ "scripting/engine.cpp",
                           "scripting/utils.cpp",
                           "scripting/bench.cpp",
                           ]

env.StaticLibrary('bson_template_evaluator', ["scripting/bson_template_evaluator.cpp"],
                  LIBDEPS=['bson'])
env.CppUnitTest('bson_template_evaluator_test', ['scripting/bson_template_evaluator_test.cpp'],
                LIBDEPS=['bson_template_evaluator'])

if usesm:
    env.StaticLibrary('scripting', scripting_common_files + ['scripting/engine_spidermonkey.cpp',
                                                             'scripting/sm_db.cpp'],
                      LIBDEPS=['$BUILD_DIR/third_party/js-1.7/js', 'bson_template_evaluator'])
elif usev8:
    env.StaticLibrary('scripting', scripting_common_files + ['scripting/engine_v8.cpp',
                                                             'scripting/v8_db.cpp',
                                                             'scripting/v8_utils.cpp',
                                                             'scripting/v8_profiler.cpp'],
                       LIBDEPS=['bson_template_evaluator', '$BUILD_DIR/third_party/shim_v8'])
else:
    env.StaticLibrary('scripting', scripting_common_files + ['scripting/engine_none.cpp'],
                      LIBDEPS=['bson_template_evaluator'])

mmapFiles = [ "util/mmap.cpp" ]

if has_option( "mm" ):
    mmapFiles += [ "util/mmap_mm.cpp" ]
else:
    mmapFiles += [ "util/mmap_${OS_FAMILY}.cpp" ]

# handle systeminfo*
systemInfoPlatformFile = env.File( "util/systeminfo_${PYSYSPLATFORM}.cpp" )
# NOTE( schwerin ): This is a very un-scons-y way to make this decision, and prevents one from using
# code generation to produce util/systeminfo_$PYSYSPLATFORM.cpp.
if not os.path.exists( str( systemInfoPlatformFile ) ):
    systemInfoPlatformFile = env.File( "util/systeminfo_none.cpp" )

coreServerFiles.append( systemInfoPlatformFile )

if has_option( "asio" ):
    coreServerFiles += [ "util/net/message_server_asio.cpp" ]

env.StaticLibrary('index_set', [ 'db/index_set.cpp' ] )

# mongod files - also files used in tools. present in dbtests, but not in mongos and not in client libs.
serverOnlyFiles = [ "db/curop.cpp",
                    "db/kill_current_op.cpp",
                    "db/memconcept.cpp",
                    "db/interrupt_status_mongod.cpp",
                    "db/d_globals.cpp",
                    "db/pagefault.cpp",
                    "util/compress.cpp",
                    "db/ttl.cpp",
                    "db/d_concurrency.cpp",
                    "db/lockstat.cpp",
                    "db/lockstate.cpp",
                    "db/key.cpp",
                    "db/btreebuilder.cpp",
                    "util/logfile.cpp",
                    "util/alignedbuilder.cpp",
                    "util/elapsed_tracker.cpp",
                    "util/touch_pages.cpp",
                    "db/mongommf.cpp",
                    "db/dur.cpp",
                    "db/durop.cpp",
                    "db/dur_writetodatafiles.cpp",
                    "db/dur_preplogbuffer.cpp",
                    "db/dur_commitjob.cpp",
                    "db/dur_recover.cpp",
                    "db/dur_journal.cpp",
                    "db/introspect.cpp",
                    "db/btree.cpp",
                    "db/btree_stats.cpp",
                    "db/clientcursor.cpp",
                    "db/tests.cpp",
                    "db/repl.cpp",
                    "db/repl/rs.cpp",
                    "db/repl/consensus.cpp",
                    "db/repl/rs_initiate.cpp",
                    "db/repl/replset_commands.cpp",
                    "db/repl/manager.cpp",
                    "db/repl/health.cpp",
                    "db/repl/heartbeat.cpp",
                    "db/repl/rs_config.cpp",
                    "db/repl/rs_rollback.cpp",
                    "db/repl/rs_sync.cpp",
                    "db/repl/rs_initialsync.cpp",
                    "db/repl/bgsync.cpp",
                    "db/oplog.cpp",
                    "db/prefetch.cpp",
                    "db/repl_block.cpp",
                    "db/btreecursor.cpp",
                    "db/intervalbtreecursor.cpp",
                    "db/btreeposition.cpp",
                    "db/cloner.cpp",
                    "db/namespace_details.cpp",
                    "db/cap.cpp",
                    "db/matcher_covered.cpp",
                    "db/dbeval.cpp",
                    "db/restapi.cpp",
                    "db/dbhelpers.cpp",
                    "db/instance.cpp",
                    "db/client.cpp",
                    "db/database.cpp",
                    "db/pdfile.cpp",
                    "db/record.cpp",
                    "db/cursor.cpp",
                    "db/queryoptimizer.cpp",
                    "db/queryoptimizercursorimpl.cpp",
                    "db/extsort.cpp",
                    "db/index.cpp",
                    "db/index_update.cpp",
                    "db/index_rebuilder.cpp",
                    "db/scanandorder.cpp",
                    "db/explain.cpp",
                    "db/geo/2d.cpp",
                    "db/geo/geonear.cpp",
                    "db/geo/haystack.cpp",
                    "db/geo/s2common.cpp",
                    "db/geo/s2cursor.cpp",
                    "db/geo/s2index.cpp",
                    "db/geo/s2nearcursor.cpp",
                    "db/hashindex.cpp",
                    "db/ops/count.cpp",
                    "db/ops/delete.cpp",
                    "db/ops/query.cpp",
                    "db/ops/update.cpp",
                    "db/ops/update_internal.cpp",
                    "db/dbcommands.cpp",
                    "db/dbcommands_admin.cpp",

                    # most commands are only for mongod
                    "db/commands/fsync.cpp",
                    "db/commands/distinct.cpp",
                    "db/commands/find_and_modify.cpp",
                    "db/commands/group.cpp",
                    "db/commands/index_stats.cpp",
                    "db/commands/mr.cpp",
                    "db/commands/pipeline_command.cpp",
                    "db/commands/storage_details.cpp",
                    "db/pipeline/pipeline_d.cpp",
                    "db/pipeline/document_source_cursor.cpp",
                    "db/driverHelpers.cpp" ]

env.Library( "dbcmdline", "db/cmdline.cpp", LIBDEPS=['bson', 'server_parameters'] )
env.CppUnitTest('cmdline_test', 'db/cmdline_test.cpp', LIBDEPS=['dbcmdline'])

env.CppUnitTest('diskloc_test', 'db/diskloc_test.cpp', LIBDEPS=[])

env.CppUnitTest('v8_deadline_monitor_test', 'scripting/v8_deadline_monitor_test.cpp', LIBDEPS=[])

env.Library('stacktrace', 'util/stacktrace.cpp')

env.Program('lame_stacktrace_test', 'util/lame_stacktrace_test.cpp',
            LIBDEPS=['stacktrace',
                     '$BUILD_DIR/mongo/base/base'])

serverOnlyFiles += mmapFiles

serverOnlyFiles += [ "db/stats/snapshots.cpp" ]

env.Library('coreshard', ['client/distlock.cpp',
                          's/config.cpp',
                          's/grid.cpp',
                          's/chunk.cpp',
                          's/shard.cpp',
                          's/shardkey.cpp'],
            LIBDEPS=['s/base']);
    
mongosLibraryFiles = [
    "s/interrupt_status_mongos.cpp",
    "s/strategy.cpp",
    "s/strategy_shard.cpp",
    "s/strategy_single.cpp",
    "s/commands_admin.cpp",
    "s/commands_public.cpp",
    "s/request.cpp",
    "s/client_info.cpp",
    "s/cursors.cpp",
    "s/s_only.cpp",
    "s/balance.cpp",
    "s/balancer_policy.cpp",
    "s/writeback_listener.cpp",
    "s/version_manager.cpp",
    ]

env.Library( "mongoscore",
             mongosLibraryFiles,
             LIBDEPS=['db/auth/authmongos',
                      'db/fts/ftsmongos'
                      ] )

env.CppUnitTest( "balancer_policy_test" , [ "s/balancer_policy_tests.cpp" ] ,
                 LIBDEPS=["mongoscore", "coreshard", "mongocommon","coreserver","coredb","dbcmdline","mongodandmongos"] ,
                 NO_CRUTCH=True)

env.CppUnitTest("dbclient_rs_test", [ "client/dbclient_rs_test.cpp" ],
                 LIBDEPS=[
                    "coredb",
                    "coreserver",
                    "coreshard",
                    "dbcmdline",
                    "mocklib",
                    "mongocommon",
                    "mongodandmongos",
                    "mongoscore"],
                 NO_CRUTCH=True)

env.CppUnitTest("scoped_db_conn_test", [ "client/scoped_db_conn_test.cpp" ],
                 LIBDEPS=[
                    "coredb",
                    "coreserver",
                    "coreshard",
                    "dbcmdline",
                    "mongocommon",
                    "mongodandmongos",
                    "mongoscore"],
                 NO_CRUTCH=True)

env.CppUnitTest("shard_conn_test", [ "s/shard_conn_test.cpp" ],
                 LIBDEPS=[
                    "mongoscore",
                    "coreshard",
                    "mongocommon",
                    "coreserver",
                    "coredb",
                    "dbcmdline",
                    "mongodandmongos",
                    "mocklib"],
                 NO_CRUTCH=True)

env.CppUnitTest("shard_test", [ "s/shard_test.cpp" ],
                LIBDEPS=[ "mongoscore",
                          "coreshard",
                          "mongocommon",
                          "coreserver",
                          "coredb",
                          "dbcmdline",
                          "mongodandmongos",
                          "mocklib"],
                NO_CRUTCH=True)


# Should only need stuff from util, unittest and platform
env.CppUnitTest("fail_point_test", [ "util/fail_point_test.cpp" ],
                LIBDEPS=["fail_point"])

serverOnlyFiles += [ "s/d_logic.cpp",
                     "s/d_writeback.cpp",
                     "s/d_migrate.cpp",
                     "s/d_state.cpp",
                     "s/d_split.cpp",
                     "client/distlock_test.cpp",
                     "s/d_chunk_manager.cpp",
                     "db/module.cpp" ]

env.StaticLibrary("defaultversion", "s/default_version.cpp")

env.StaticLibrary("geometry", [ "db/geo/hash.cpp", "db/geo/shapes.cpp", ], LIBDEPS = [ "bson" ])
env.StaticLibrary("geoparser", [ "db/geo/geoparser.cpp", ],
                  LIBDEPS = [ "bson",
                              "geometry",
                              '$BUILD_DIR/third_party/s2/s2' ])
env.StaticLibrary("geoquery", [ "db/geo/geoquery.cpp", ],
                  LIBDEPS = [ "bson",
                              "geometry",
                              '$BUILD_DIR/third_party/s2/s2' ])

env.CppUnitTest("hash_test", [ "db/geo/hash_test.cpp" ], LIBDEPS = ["geometry" ])
env.CppUnitTest("geoparser_test", [ "db/geo/geoparser_test.cpp" ], LIBDEPS = ["geoparser"])

env.StaticLibrary("serveronly", serverOnlyFiles,
                  LIBDEPS=["coreshard",
                           "db/auth/authmongod",
                           "db/fts/ftsmongod",
                           "db/common",
                           "dbcmdline",
                           "defaultversion",
                           "geoparser",
                           "geoquery",
                           "index_set",
                           '$BUILD_DIR/third_party/shim_snappy'])

# These files go into mongos and mongod only, not into the shell or any tools.
mongodAndMongosFiles = [
    "db/connection_factory.cpp",
    "db/initialize_server_global_state.cpp",
    "db/server_extra_log_context.cpp",
    "util/net/message_server_port.cpp",
    ]
env.StaticLibrary("mongodandmongos", mongodAndMongosFiles)

# These files go into the tools, tests, shell, etc. but not mongod or mongos
everythingButMongodAndMongosFiles = [
    "client/connection_factory.cpp",
    ]
env.StaticLibrary("notmongodormongos", everythingButMongodAndMongosFiles)

mongodOnlyFiles = [ "db/db.cpp", "db/compact.cpp", "db/commands/touch.cpp" ]

# ----- TARGETS ------

env.StaticLibrary("gridfs", "client/gridfs.cpp")

if has_option( 'use-cpu-profiler' ):
    coreServerFiles.append( 'db/commands/cpuprofile.cpp' )
    env.Append(LIBS=['unwind'])

env.StaticLibrary("coreserver", coreServerFiles, LIBDEPS=["mongocommon", "scripting"])

# main db target
mongod = env.Install(
    '#/', env.Program( "mongod", mongodOnlyFiles,
                       LIBDEPS=["coredb",
                                "coreserver",
                                "mongodandmongos",
                                "ntservice",
                                "serveronly",
                                ] + env['MODULE_LIBDEPS_MONGOD'] ) )
Default( mongod )

# tools
allToolFiles = [ "tools/tool.cpp", "tools/stat_util.cpp" ]
env.StaticLibrary("alltools", allToolFiles, LIBDEPS=["serveronly", "coreserver", "coredb",
                                                     "notmongodormongos"])

normalTools = [ "dump", "restore", "export", "import", "stat", "top", "oplog" ]
env.Alias( "tools", [ "#/${PROGPREFIX}mongo" + x + "${PROGSUFFIX}" for x in normalTools ] )
for x in normalTools:
    env.Install( '#/', env.Program( "mongo" + x, [ "tools/" + x + ".cpp" ],
                                    LIBDEPS=["alltools"]) )

env.StaticLibrary("docgenerator", "tools/docgenerator.cpp")

#some special tools
env.Install( '#/', [
        env.Program( "mongofiles", "tools/files.cpp", LIBDEPS=["alltools", "gridfs"] ),
        env.Program( "docgen", "tools/docgeneratormain.cpp", LIBDEPS=["alltools", "docgenerator"] ),
        env.Program( "loadgen", "tools/loadgenerator.cpp", LIBDEPS=["alltools", "docgenerator"] ),
        env.Program( "bsondump", "tools/bsondump.cpp", LIBDEPS=["alltools"]),
        env.Program( "mongobridge", "tools/bridge.cpp", LIBDEPS=["alltools"]),
        env.Program( "mongoperf", "client/examples/mongoperf.cpp", LIBDEPS=["alltools"] ),
        ] )

# mongos
mongos = env.Program(
    "mongos", [ "s/server.cpp"] ,
    LIBDEPS=["mongoscore", "coreserver", "coredb", "mongocommon", "coreshard", "dbcmdline", "ntservice",
             "mongodandmongos", "s/upgrade"] + env['MODULE_LIBDEPS_MONGOS'])
env.Install( '#/', mongos )

env.Library("clientandshell", ["client/clientAndShell.cpp"],
                              LIBDEPS=["mongocommon",
                                       "defaultversion",
                                       "gridfs",
                                       "notmongodormongos"])
env.Library("allclient", "client/clientOnly.cpp", LIBDEPS=["clientandshell"])

if has_option( "sharedclient" ):
    sharedClientLibName = str( env.SharedLibrary( "mongoclient", [], LIBDEPS=["allclient"] )[0] )

# dbtests test binary
env.StaticLibrary('testframework', ['dbtests/framework.cpp'], LIBDEPS=['unittest/unittest'])

env.StaticLibrary('mocklib', [
        'dbtests/mock/mock_conn_registry.cpp',
        'dbtests/mock/mock_dbclient_connection.cpp',
        'dbtests/mock/mock_dbclient_cursor.cpp',
        'dbtests/mock/mock_remote_db_server.cpp',
        'dbtests/mock/mock_replica_set.cpp'
    ],
    LIBDEPS=['mongocommon'])

test = testEnv.Install(
    '#/',
    testEnv.Program("test",
                    [ f for f in Glob("dbtests/*.cpp") if not str(f).endswith('framework.cpp') ],
                    LIBDEPS = [
                       "mongocommon",
                       "serveronly",
                       "coreserver",
                       "coredb",
                       "testframework",
                       "gridfs",
                       "notmongodormongos",
                       "s/upgrade",
                       "mocklib"]))

if len(testEnv.subst('$PROGSUFFIX')):
    testEnv.Alias( "test", "#/${PROGPREFIX}test${PROGSUFFIX}" )

env.Install( '#/', testEnv.Program( "perftest", [ "dbtests/perf/perftest.cpp" ], LIBDEPS=["serveronly", "coreserver", "coredb", "testframework", "notmongodormongos" ] ) )

# --- sniffer ---
mongosniff_built = False
if darwin or env["_HAVEPCAP"]:
    mongosniff_built = True
    sniffEnv = env.Clone()
    sniffEnv.Append( CPPDEFINES="MONGO_EXPOSE_MACROS" )

    if not windows:
        sniffEnv.Append( LIBS=[ "pcap" ] )
    else:
        sniffEnv.Append( LIBS=[ "wpcap" ] )

    sniffEnv.Install( '#/', sniffEnv.Program( "mongosniff", "tools/sniffer.cpp",
                                              LIBDEPS=["gridfs", "serveronly", "coreserver", "coredb", "notmongodormongos"]))

# --- shell ---

# if you add a file here, you need to add it in scripting/engine.cpp and shell/createCPPfromJavaScriptFiles.js as well
env.JSHeader("shell/mongo.cpp",
             ["shell/assert.js", "shell/types.js", "shell/utils.js", "shell/utils_sh.js",
              "shell/db.js", "shell/mongo.js", "shell/mr.js", "shell/query.js",
              "shell/collection.js"])

# if you add a file here, you need to add it in shell/shell_utils.cpp and shell/createCPPfromJavaScriptFiles.js as well
env.JSHeader("shell/mongo-server.cpp",
             ["shell/servers.js", "shell/shardingtest.js",
              "shell/servers_misc.js", "shell/replsettest.js", "shell/replsetbridge.js"])

coreShellFiles = [ "shell/dbshell.cpp",
                   "shell/shell_utils.cpp",
                   "shell/shell_utils_extended.cpp",
                   "shell/shell_utils_launcher.cpp",
                   "shell/mongo-server.cpp",
                   "shell/linenoise.cpp",
                   "shell/linenoise_utf8.cpp",
                   "shell/mk_wcwidth.cpp"]

if shellEnv is not None:
    mongo_shell = shellEnv.Program(
        "mongo",
        coreShellFiles,
        LIBDEPS=[ "clientandshell", "mongocommon", "scripting", 
                 "$BUILD_DIR/third_party/pcrecpp"] + env['MODULE_LIBDEPS_MONGOSHELL'] )

    shellEnv.Install( '#/', mongo_shell )

#  ----  INSTALL -------

# binaries

def checkGlibc(target,source,env):
    import subprocess
    import SCons.Errors
    stringProcess = subprocess.Popen( [ "strings", str( target[0] ) ], stdout=subprocess.PIPE )
    stringResult = stringProcess.communicate()[0]
    if stringResult.count( "GLIBC_2.4" ) > 0:
        print( "************* " + str( target[0] ) + " has GLIBC_2.4 dependencies!" )
        raise SCons.Errors.BuildError(
            node=target[0],
            errstr="target has GLIBC_2.4 dependencies!")

distBinaries = []

if windows:
    distBinaries.extend(['mongod.pdb', 'mongos.pdb'])

def installBinary( e, name ):
    global distBinaries

    name = add_exe( name )

    if enforce_glibc:
        e.AddPostAction( name, checkGlibc )

    if (solaris or 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)

    if not installSetup.binaries:
        return

    inst = e.Install( "$INSTALL_DIR/bin", name )

    if nix:
        e.AddPostAction( inst, 'chmod 755 $TARGET' )

for t in ["mongo" + x for x in normalTools] + ["mongofiles", "bsondump", "mongoperf" ]:
    installBinary( env, t )
    env.Alias("tools", '#/' + add_exe(t))

env.Alias("tools", "#/" + add_exe("perftest"))
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( env, "mongo" )

env.Alias( "core", [ '#/%s' % b for b in [ add_exe( "mongo" ), add_exe( "mongod" ), add_exe( "mongos" ) ] ] )

#headers
if installSetup.headers:
    for id in [ "", "util/", "util/net/", "util/mongoutils/", "util/concurrency/", "db/",
                "db/stats/", "db/repl/", "db/ops/", "client/", "bson/", "bson/util/", "s/",
                "scripting/", "base/", "platform/" ]:
        env.Install( "$INSTALL_DIR/include/" + id, Glob( id + "*.h" ) )
        env.Install( "$INSTALL_DIR/include/" + id, Glob( id + "*.hpp" ) )

#lib
if installSetup.libraries:
    env.Install('$INSTALL_DIR/$NIX_LIB_DIR', '#${LIBPREFIX}mongoclient${LIBSUFFIX}')
    if has_option( "sharedclient" ):
        env.Install( "$INSTALL_DIR/$NIX_LIB_DIR",  '#${SHLIBPREFIX}mongoclient${SHLIBSUFFIX}')

# 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.
    print "ERROR: Filename conflicts exist in module banners."
    Exit(-1)

# 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]

env.Command(
    '#/${SERVER_ARCHIVE}',
    ['#buildscripts/make_archive.py'] + env["MODULE_BANNERS"] + distBinaries,
    ' '.join(['$PYTHON ${SOURCES[0]} -o $TARGET'] + module_banner_transforms + [
            '--transform ${str(Dir(BUILD_DIR))}/mongo/stripped=$SERVER_DIST_BASENAME/bin',
            '--transform ${str(Dir(BUILD_DIR))}/mongo=$SERVER_DIST_BASENAME/bin',
            '${TEMPFILE(SOURCES[1:])}']))

#final alias
env.Alias( "install", "$INSTALL_DIR" )

env.Alias("clientBuild", ['#buildscripts/build_and_test_client.py',
                          '#/${PROGPREFIX}mongod${PROGSUFFIX}',
                          '#$CLIENT_ARCHIVE'],
          '$PYTHON ${SOURCES[0]} ${SOURCES[2]} ${EXTRAPATH and "--extrapath"} $EXTRAPATH'
          )
env.AlwaysBuild("clientBuild")
