# -*- mode: python -*-

import json

Import([
    'env',
    'get_option',
    'jsEngine',
    'use_libunwind',
    'use_system_libunwind',
    'use_system_version_of_library',
    'use_vendored_libunwind',
    'wiredtiger',
    'releaseBuild',
    'ssl_provider',
])

snappySuffix = '-1.1.7'
icuSuffix = '-57.1'
tomcryptSuffix = '-1.18.2'
libarchiveSuffix = '-3.4.0'
libkmipSuffix = '-0ecda33'
variantSuffix = '-1.4.0'

thirdPartyEnvironmentModifications = {
    'abseil-cpp': {'CPPPATH': ['#/src/third_party/abseil-cpp/dist'], },
    'cares': {
        'CPPPATH': [
            '#src/third_party/cares/dist/include',
            '#src/third_party/cares/platform/${TARGET_OS}_${TARGET_ARCH}/install/include'
        ],
    },
    'percona_incl': {'CPPPATH': ['#/src/third_party/install/include'], },
    'libarchive': {'CPPPATH': ['#/src/third_party/libarchive' + libarchiveSuffix], },
    'libkmip': {'CPPPATH': ['#/src/third_party/libkmip' + libkmipSuffix + '/libkmip/include'], },
    'kmippp' : {'CPPPATH': ['#/src/third_party/libkmip' + libkmipSuffix], },
    'fmt': {'CPPPATH': ['#src/third_party/fmt/dist/include'], },
    'immer': {'CPPPATH': ['#src/third_party/immer/dist'], },
    's2': {'CPPPATH': ['#src/third_party/s2'], },
    'safeint': {
        'CPPPATH': ['#src/third_party/SafeInt'],
        # SAFEINT_USE_INTRINSICS=0 for overflow-safe constexpr multiply. See comment in SafeInt.hpp.
        'CPPDEFINES': [('SAFEINT_USE_INTRINSICS', 0)],
    },
    'timelib': {'CPPPATH': ['#/src/third_party/timelib/dist'], },
    'unwind': {},
    'variant': {'CPPPATH': ['#src/third_party/variant' + variantSuffix + '/include'], },
    'mozjs': {
        'CPPPATH': [
            '#/src/third_party/mozjs/include',
            '#/src/third_party/mozjs/mongo_sources',
            '#/src/third_party/mozjs/platform/' + env["TARGET_ARCH"] + "/" + env["TARGET_OS"] +
            "/include",
        ],
        'FORCEINCLUDES': ['js-config.h', ],
    },
    'murmurhash3': {'CPPPATH': ['#src/third_party/murmurhash3', ], },
    'librdkafka': {
        'CPPPATH': [
            '#/src/third_party/librdkafka/dist/src',
            '#/src/third_party/librdkafka/dist/src-cpp',
        ],
    },
}


def injectMozJS(thisEnv):
    thisEnv.InjectThirdParty(libraries=['mozjs'])

    if thisEnv.TargetOSIs('windows'):
        thisEnv.Append(CPPDEFINES=[
            '_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING',
        ], )
    else:
        thisEnv.Append(CXXFLAGS=[
            '-Wno-non-virtual-dtor',
            '-Wno-invalid-offsetof',
        ], )

    thisEnv.Prepend(CPPDEFINES=[
        'JS_USE_CUSTOM_ALLOCATOR',
        'STATIC_JS_API=1',
    ])

    if get_option('spider-monkey-dbg') == "on":
        thisEnv.Prepend(CPPDEFINES=[
            'DEBUG',
            'JS_DEBUG',
        ])


env.AddMethod(injectMozJS, 'InjectMozJS')

if not use_system_version_of_library('tcmalloc'):
    # GPerftools does this slightly differently than the others.
    thirdPartyEnvironmentModifications['gperftools'] = {}

if not use_system_version_of_library('pcre2'):
    thirdPartyEnvironmentModifications['pcre2'] = {
        'CPPPATH': ['#/src/third_party/pcre2/src'],
    }

if not use_system_version_of_library('boost'):

    # On at least Apple clang, proto throws this error.
    #
    # See https://github.com/boostorg/proto/issues/30.
    #
    # We use a generator so we can filter out conf tests, where applying this
    # flag could change their meaning.
    def NoErrorForUnknownWarningOptionGenerator(target, source, env, for_signature):
        if 'conftest' in str(target[0]):
            return str()
        return '-Wno-error=unknown-warning-option'

    thirdPartyEnvironmentModifications['boost'] = {
        'CPPPATH': ['#/src/third_party/boost'],

        # We could narror further to just clang on Darwin, but there is
        # little harm in applying for all clang.
        'NOERROR_FOR_UNKNOWN_WARNING_OPTION_GEN': NoErrorForUnknownWarningOptionGenerator,
        'CCFLAGS': ['$NOERROR_FOR_UNKNOWN_WARNING_OPTION_GEN'] if env.ToolchainIs('clang') else []
    }

if not use_system_version_of_library('snappy'):
    thirdPartyEnvironmentModifications['snappy'] = {
        'CPPPATH': ['#/src/third_party/snappy' + snappySuffix],
    }

# Valgrind is a header only include as valgrind.h includes everything we need
if not use_system_version_of_library('valgrind'):
    thirdPartyEnvironmentModifications['valgrind'] = {
        'CPPPATH': ['#/src/third_party/valgrind/include'],
    }

if not use_system_version_of_library('zlib'):
    thirdPartyEnvironmentModifications['zlib'] = {
        'CPPPATH': ['#/src/third_party/zlib'],
    }

if not use_system_version_of_library('zstd'):
    thirdPartyEnvironmentModifications['zstd'] = {
        'CPPPATH': ['#/src/third_party/zstandard/zstd/lib'],
    }

if not use_system_version_of_library('google-benchmark'):
    thirdPartyEnvironmentModifications['benchmark'] = {
        'CPPPATH': ['#/src/third_party/benchmark/dist/include'],
    }

if "tom" in env["MONGO_CRYPTO"]:
    thirdPartyEnvironmentModifications['tomcrypt'] = {
        'CPPPATH': ['#/src/third_party/tomcrypt' + tomcryptSuffix + '/src/headers'],
    }

if not use_system_version_of_library('stemmer'):
    thirdPartyEnvironmentModifications['stemmer'] = {
        'CPPPATH': ['#/src/third_party/libstemmer_c/include'],
    }

# Note that the wiredtiger.h header is generated, so
# we want to look for it in the build directory not
# the source directory.
if wiredtiger and not use_system_version_of_library('wiredtiger'):
    thirdPartyEnvironmentModifications['wiredtiger'] = {
        'CPPPATH': ['$BUILD_DIR/third_party/wiredtiger'],
    }

if not use_system_version_of_library('yaml'):
    thirdPartyEnvironmentModifications['yaml'] = {
        'CPPPATH': ['#/src/third_party/yaml-cpp/yaml-cpp/include'],
        'CPPDEFINES': ['_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING']
                      if env.ToolchainIs('msvc') else [],
    }

if not use_system_version_of_library('asio'):
    thirdPartyEnvironmentModifications['asio'] = {
        'CPPPATH': ['#/src/third_party/asio-master/asio/include'],
    }

if not use_system_version_of_library('intel_decimal128'):
    thirdPartyEnvironmentModifications['intel_decimal128'] = {
        'CPPPATH': ['#/src/third_party/IntelRDFPMathLib20U1/LIBRARY/src'],
    }

if not use_system_version_of_library('icu'):
    thirdPartyEnvironmentModifications['icu'] = {
        'CPPPATH': [
            '#/src/third_party/icu4c' + icuSuffix + '/source/common',
            '#/src/third_party/icu4c' + icuSuffix + '/source/i18n',
        ],
    }

if not use_system_version_of_library('libbson'):

    platform_directory = "build_linux"

    if env['TARGET_ARCH'] == 's390x':
        platform_directory = "build_linux_s390x"

    if env.TargetOSIs('windows'):
        platform_directory = "build_windows"
    elif env.TargetOSIs('darwin'):
        platform_directory = "build_osx"

    thirdPartyEnvironmentModifications['libbson'] = {
        'CPPPATH': [
            '#/src/third_party/libbson/dist/src/libbson/src',
            '#/src/third_party/libbson/' + platform_directory,
            '#/src/third_party/libbson/' + platform_directory + '/bson',
        ],
        'CPPDEFINES': ['BSON_STATIC'],
    }

if not use_system_version_of_library('libmongocrypt'):

    platform_directory = "build_linux"
    crypto_directory = "build_libcrypto"

    if env.TargetOSIs('windows'):
        platform_directory = "build_windows"
        crypto_directory = "build_cng"
    elif env.TargetOSIs('darwin'):
        platform_directory = "build_osx"
        crypto_directory = "build_commoncrypto"

    if get_option('ssl') == 'off':
        crypto_directory = "build_none"

    thirdPartyEnvironmentModifications['libmongocrypt'] = {
        'CPPPATH': [
            '#/src/third_party/libmongocrypt/dist/src',
            '#/src/third_party/libmongocrypt/dist/kms-message/src',
            '#/src/third_party/libmongocrypt/' + platform_directory,
            '#/src/third_party/libmongocrypt/' + crypto_directory,
        ],
        'CPPDEFINES': [
            'KMS_MSG_STATIC',
            'MONGOCRYPT_STATIC_DEFINE',
        ],
    }

if not use_system_version_of_library('protobuf'):
    thirdPartyEnvironmentModifications['protobuf'] = {
        'CPPPATH': ['#src/third_party/protobuf/dist/src'],
    }

if not use_system_version_of_library('grpc'):
    thirdPartyEnvironmentModifications['grpc'] = {
        'CPPPATH': ['#src/third_party/grpc/dist/include'],
    }
    thirdPartyEnvironmentModifications['re2'] = {
        'CPPPATH': ['#src/third_party/re2/dist'],
    }
    thirdPartyEnvironmentModifications['cares'] = {
        'CPPPATH': [
            '#src/third_party/cares/dist/include',
            '#src/third_party/cares/platform/${TARGET_OS}_${TARGET_ARCH}/install/include'
        ],
    }

# Vendored libunwind can be configured to use liblzma for decompressing
# minidebuginfo sections, but we disable that feature via
# `unwind/scripts/host-config.sh`. If vendored libunwind ever needs
# minidebuginfo support, we'd say so here, and we'd dynamically link with
# system lzma. Until then, it would be an unnecessary dynamic dependency.
# However, the system libunwind is assumed to need `lzma` unconditionally.
vendored_libunwind_needs_lzma = False

if use_system_libunwind:
    thirdPartyEnvironmentModifications['unwind'] = {
        'SYSLIBDEPS_PRIVATE': [env['LIBDEPS_UNWIND_SYSLIBDEP'], env['LIBDEPS_LZMA_SYSLIBDEP']],
    }
elif use_vendored_libunwind and vendored_libunwind_needs_lzma:
    thirdPartyEnvironmentModifications['unwind'] = {
        'SYSLIBDEPS_PRIVATE': [env['LIBDEPS_LZMA_SYSLIBDEP']],
    }


def injectThirdParty(thisEnv, libraries=[], parts=[]):
    libraries = thisEnv.Flatten([libraries])
    parts = thisEnv.Flatten([parts])
    for lib in libraries:
        mods = thirdPartyEnvironmentModifications.get(lib, None)
        if mods is None:
            continue
        if not parts:
            thisEnv.PrependUnique(**mods)
        else:
            for part in parts:
                thisEnv.PrependUnique({part: mods[part]})


env.AddMethod(injectThirdParty, 'InjectThirdParty')


def shouldBuildStreams(thisEnv):
    # TODO https://jira.mongodb.org/browse/SERVER-74963: Streams release builds.
    # TODO https://jira.mongodb.org/browse/SERVER-74961: Support other platforms.
    return not releaseBuild and thisEnv.TargetOSIs(
        'linux') and thisEnv['TARGET_ARCH'] == 'x86_64' and ssl_provider == 'openssl'


env.AddMethod(shouldBuildStreams, 'ShouldBuildStreams')

env = env.Clone()

# Construct an empty object file that we can use to produce the
# library for every shim. This avoids the need to create and name a
# different empty source file for every third-party library, as we did
# in the past.

empty_source = env.Textfile(
    target='third_party_shim.cpp',
    source=str(),
)
env.Alias('generated-sources', empty_source)

empty_object = env.LibraryObject(target='third_party_shim', source=empty_source,
                                 NINJA_GENSOURCE_INDEPENDENT=True)


def shim_library(env, name, **kwargs):
    # Add the 'virtual-libdep' tag, which will prevent shim libraries
    # from actually being linked to. They don't provide any symbols,
    # so there is no need to do so. Instead, they just act as a node
    # in the library dependency graph to reach other libraries.
    libdeps_tags = kwargs.get('LIBDEPS_TAGS', env.get('LIBDEPS_TAGS', [])).copy()
    libdeps_tags.append('virtual-libdep')
    kwargs['LIBDEPS_TAGS'] = libdeps_tags
    return env.Library(
        target=f'shim_{name}',
        source=empty_object[0],
        # Since nothing will link to this library per the
        # `virtual-libdep` tag above, we can also skip installing it.
        AIB_IGNORE=True,
        **kwargs,
    )


env.AddMethod(shim_library, 'ShimLibrary')

murmurEnv = env.Clone()
murmurEnv.InjectThirdParty(libraries=['fmt'])
murmurEnv.SConscript('murmurhash3/SConscript', exports={'env': murmurEnv})

s2Env = env.Clone()
s2Env.InjectThirdParty(libraries=[
    's2',
    'boost',
    'abseil-cpp',
    'fmt',
    'safeint',
    'variant',
])
s2Env.InjectMongoIncludePaths()
s2Env.SConscript('s2/SConscript', exports={'env': s2Env})

if jsEngine:
    mozjsEnv = env.Clone()
    mozjsEnv.SConscript('mozjs/SConscript', exports={'env': mozjsEnv})

if use_libunwind:
    unwindEnv = env.Clone(LIBDEPS_NO_INHERIT=[
        '$BUILD_DIR/third_party/shim_allocator',
    ], )
    if use_system_libunwind:
        unwindEnv = unwindEnv.Clone(SYSLIBDEPS=[
            env['LIBDEPS_UNWIND_SYSLIBDEP'],
        ])
    else:
        unwindEnv = unwindEnv.Clone()

        # SCons uses the "$CC" tool for both C and assembler files. Distinguish them for the sake of
        # later tools like our Ninja SCons module.
        unwindEnv['ASPP'] = '$CC'
        unwindEnv['ASPPCOM'] = unwindEnv['ASPPCOM'].replace('$CC ', '$ASPP ')

        def registerConsumerModifications(env, **kwargs):
            for k, v in kwargs.items():
                thirdPartyEnvironmentModifications['unwind'][k] = v

        unwindEnv.AddMethod(registerConsumerModifications, 'RegisterConsumerModifications')
        unwindEnv.SConscript(
            'unwind/SConscript', exports={
                'env': unwindEnv,
                'vendored_libunwind_needs_lzma': vendored_libunwind_needs_lzma,
            })
        unwindEnv.Append(LIBDEPS_INTERFACE=[
            'unwind/unwind',
        ])

    unwindEnv.ShimLibrary(name="unwind", NINJA_GENSOURCE_INDEPENDENT=True)

fmtEnv = env.Clone()
if use_system_version_of_library("fmt"):
    fmtEnv = fmtEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_FMT_SYSLIBDEP'],
    ])
else:
    fmtEnv = fmtEnv.Clone()
    fmtEnv.InjectThirdParty(libraries=['fmt'])
    fmtEnv.InjectMongoIncludePaths()
    fmtEnv.SConscript('fmt/SConscript', exports={'env': fmtEnv})
    fmtEnv = fmtEnv.Clone(LIBDEPS_INTERFACE=[
        'fmt/fmt',
    ])

fmtEnv.ShimLibrary(name="fmt")

pcre2Env = env.Clone()
if use_system_version_of_library("pcre2"):
    pcre2Env = pcre2Env.Clone(SYSLIBDEPS=[
        env['LIBDEPS_PCRE2_SYSLIBDEP'],
    ])
else:
    pcre2Env = pcre2Env.Clone()
    pcre2Env.InjectThirdParty(libraries=['pcre2'])
    pcre2Env.SConscript('pcre2' + '/SConscript', exports={'env': pcre2Env})
    pcre2Env = pcre2Env.Clone(LIBDEPS_INTERFACE=[
        'pcre2/pcre2',
    ])

pcre2Env.ShimLibrary(name="pcre2")

boostEnv = env.Clone()
if use_system_version_of_library("boost"):
    # On windows, we don't need the syslibdeps because autolib will select the right libraries
    # for us automatically.
    if not env.TargetOSIs('windows'):
        boostEnv = boostEnv.Clone(SYSLIBDEPS=[
            env['LIBDEPS_BOOST_PROGRAM_OPTIONS_SYSLIBDEP'],
            env['LIBDEPS_BOOST_FILESYSTEM_SYSLIBDEP'],
            env['LIBDEPS_BOOST_SYSTEM_SYSLIBDEP'],
            env['LIBDEPS_BOOST_IOSTREAMS_SYSLIBDEP'],
            env['LIBDEPS_BOOST_THREAD_SYSLIBDEP'],
            env['LIBDEPS_BOOST_LOG_SYSLIBDEP'],
        ])
else:
    boostDirectory = 'boost'
    boostEnv = boostEnv.Clone()
    boostEnv.InjectThirdParty(libraries=['boost'])
    boostEnv.SConscript(boostDirectory + '/SConscript', exports={'env': boostEnv})
    boostEnv = boostEnv.Clone(LIBDEPS_INTERFACE=[
        boostDirectory + '/boost_filesystem',
        boostDirectory + '/boost_iostreams',
        boostDirectory + '/boost_log',
        boostDirectory + '/boost_program_options',
        boostDirectory + '/boost_system',
    ])

boostEnv.ShimLibrary(name="boost")

abseilDirectory = 'abseil-cpp'
abseilEnv = env.Clone()
abseilEnv.InjectThirdParty(libraries=['abseil-cpp'])
abseilEnv.SConscript(abseilDirectory + '/SConscript', exports={'env': abseilEnv})
abseilEnv = abseilEnv.Clone(LIBDEPS_INTERFACE=[
    abseilDirectory + '/absl_city',
    abseilDirectory + '/absl_hash',
    abseilDirectory + '/absl_int128',
    abseilDirectory + '/absl_low_level_hash',
    abseilDirectory + '/absl_raw_hash_set',
])

abseilEnv.ShimLibrary(name="abseil")

snappyEnv = env.Clone()
if use_system_version_of_library("snappy"):
    snappyEnv = snappyEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_SNAPPY_SYSLIBDEP'],
    ])
else:
    snappyEnv = snappyEnv.Clone()
    snappyEnv.InjectThirdParty(libraries=['snappy'])
    snappyEnv.InjectMongoIncludePaths()
    snappyEnv.SConscript('snappy' + snappySuffix + '/SConscript', exports={'env': snappyEnv})
    snappyEnv = snappyEnv.Clone(LIBDEPS_INTERFACE=[
        'snappy' + snappySuffix + '/snappy',
    ])

snappyEnv.ShimLibrary(name="snappy")

zlibEnv = env.Clone()
if use_system_version_of_library("zlib"):
    zlibEnv = zlibEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_ZLIB_SYSLIBDEP'],
    ])
else:
    zlibEnv = zlibEnv.Clone()
    zlibEnv.InjectThirdParty(libraries=['zlib'])
    zlibEnv.SConscript('zlib' + '/SConscript', exports={'env': zlibEnv})
    zlibEnv = zlibEnv.Clone(LIBDEPS_INTERFACE=[
        'zlib/zlib',
    ])

zlibEnv.ShimLibrary(name="zlib", NINJA_GENSOURCE_INDEPENDENT=True)

zstdEnv = env.Clone()
if use_system_version_of_library("zstd"):
    zstdEnv = zstdEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_ZSTD_SYSLIBDEP'],
    ])
else:
    zstdEnv = zstdEnv.Clone()
    zstdEnv.InjectThirdParty(libraries=['zstd'])
    zstdEnv.SConscript('zstandard/SConscript', exports={'env': zstdEnv})
    zstdEnv = zstdEnv.Clone(LIBDEPS_INTERFACE=[
        'zstandard/zstd',
    ])

zstdEnv.ShimLibrary(name="zstd", )

benchmarkEnv = env.Clone()
if use_system_version_of_library("google-benchmark"):
    benchmarkEnv = benchmarkEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_BENCHMARK_SYSLIBDEP'],
    ])
else:
    benchmarkEnv = benchmarkEnv.Clone()
    benchmarkEnv.InjectThirdParty(libraries=['benchmark'])
    benchmarkEnv.SConscript(
        'benchmark/SConscript',
        exports={'env': benchmarkEnv},
    )
    benchmarkEnv = benchmarkEnv.Clone(LIBDEPS_INTERFACE=[
        'benchmark/benchmark',
    ])

benchmarkEnv.ShimLibrary(name="benchmark")

if "tom" in env["MONGO_CRYPTO"]:
    tomcryptEnv = env.Clone()
    tomcryptEnv.SConscript(
        'tomcrypt' + tomcryptSuffix + '/SConscript',
        exports={'env': tomcryptEnv},
    )
    tomcryptEnv = tomcryptEnv.Clone(LIBDEPS_INTERFACE=[
        'tomcrypt' + tomcryptSuffix + '/tomcrypt',
    ])

    tomcryptEnv.ShimLibrary(name="tomcrypt", )

gperftoolsEnv = env.Clone(LIBDEPS_NO_INHERIT=[
    '$BUILD_DIR/third_party/shim_allocator',
], )
if gperftoolsEnv['MONGO_ALLOCATOR'] in ["tcmalloc", "tcmalloc-experimental"]:
    if use_system_version_of_library("tcmalloc"):
        gperftoolsEnv = gperftoolsEnv.Clone(SYSLIBDEPS=[
            env['LIBDEPS_TCMALLOC_SYSLIBDEP'],
        ])
    else:
        gperftoolsEnv = gperftoolsEnv.Clone()
        gperftoolsEnv.InjectThirdParty(libraries=['gperftools'])

        # Allow gperftools to determine its own consumer-side include/ dirs.
        # Needed because those are in a platform-specific subdirectory.
        def registerConsumerModifications(env, **kwargs):
            for k, v in kwargs.items():
                thirdPartyEnvironmentModifications['gperftools'][k] = v

        gperftoolsEnv.AddMethod(registerConsumerModifications, 'RegisterConsumerModifications')
        gperftoolsEnv.SConscript(
            'gperftools' + '/SConscript',
            exports={'env': gperftoolsEnv},
        )
        gperftoolsEnv = gperftoolsEnv.Clone(LIBDEPS_INTERFACE=[
            'gperftools/tcmalloc_minimal',
        ])

gperftoolsEnv.ShimLibrary(
    name="allocator",
    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'
    ],
    NINJA_GENSOURCE_INDEPENDENT=True,
)

stemmerEnv = env.Clone()
if use_system_version_of_library("stemmer"):
    stemmerEnv = stemmerEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_STEMMER_SYSLIBDEP'],
    ])
else:
    stemmerEnv = stemmerEnv.Clone()
    stemmerEnv.InjectThirdParty(libraries=['stemmer'])
    stemmerEnv.SConscript('libstemmer_c/SConscript', exports={'env': stemmerEnv})
    stemmerEnv = stemmerEnv.Clone(LIBDEPS_INTERFACE=[
        'libstemmer_c/stemmer',
    ])

stemmerEnv.ShimLibrary(name="stemmer")

yamlEnv = env.Clone()
if use_system_version_of_library("yaml"):
    yamlEnv = yamlEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_YAML_SYSLIBDEP'],
    ])
else:
    yamlEnv = yamlEnv.Clone()
    yamlEnv.InjectThirdParty(libraries=['yaml', 'boost'])
    yamlEnv.SConscript('yaml-cpp/SConscript', exports={'env': yamlEnv})
    yamlEnv = yamlEnv.Clone(LIBDEPS_INTERFACE=[
        'yaml-cpp/yaml',
    ])

yamlEnv.ShimLibrary(name="yaml")

timelibEnv = env.Clone()
timelibEnv.InjectThirdParty(libraries=['timelib'])
timelibEnv.SConscript('timelib' + '/SConscript', exports={'env': timelibEnv})
timelibEnv = timelibEnv.Clone(LIBDEPS_INTERFACE=[
    'timelib' + '/timelib',
])

timelibEnv.ShimLibrary(name='timelib', )

wiredtigerEnv = env.Clone()
if wiredtiger:
    if use_system_version_of_library("wiredtiger"):
        wiredtigerEnv = wiredtigerEnv.Clone(SYSLIBDEPS=[
            env['LIBDEPS_WIREDTIGER_SYSLIBDEP'],
        ])
    else:
        wiredtigerEnv = wiredtigerEnv.Clone()
        wiredtigerEnv.InjectThirdParty(libraries=['wiredtiger', 'wiredtiger_checksum'])
        wiredtigerEnv.SConscript('wiredtiger/SConscript', exports={'env': wiredtigerEnv})
        wiredtigerEnv = wiredtigerEnv.Clone(LIBDEPS_INTERFACE=[
            'wiredtiger/wiredtiger',
            'wiredtiger/wiredtiger_checksum',
        ])

    wiredtigerEnv.ShimLibrary(name="wiredtiger")

asioEnv = env.Clone()
if use_system_version_of_library("asio"):
    # Normally, we would request LIBDEPS_ASIO_SYSLIBDEP here, but on most systems, the system asio
    # will be header only so there is no library required. In the rare case where one is, it can be
    # injected via LIBS= on the command line.
    asioEnv = asioEnv.Clone()
else:
    asioEnv = asioEnv.Clone()
    asioEnv.InjectThirdParty(libraries=['asio'])
    asioEnv.SConscript('asio-master/SConscript', exports={'env': asioEnv})
    asioEnv = asioEnv.Clone(LIBDEPS_INTERFACE=[
        'asio-master/asio',
    ])

asioEnv.ShimLibrary(name="asio")

intelDecimal128Env = env.Clone()
if use_system_version_of_library("intel_decimal128"):
    intelDecimal128Env = intelDecimal128Env.Clone(SYSLIBDEPS=[
        env['LIBDEPS_INTEL_DECIMAL128_SYSLIBDEP'],
    ])
else:
    intelDecimal128Env = intelDecimal128Env.Clone()
    intelDecimal128Env.InjectThirdParty(libraries=['intel_decimal128'])
    intelDecimal128Env.SConscript(
        'IntelRDFPMathLib20U1/SConscript',
        exports={'env': intelDecimal128Env},
    )
    intelDecimal128Env = intelDecimal128Env.Clone(LIBDEPS_INTERFACE=[
        'IntelRDFPMathLib20U1/intel_decimal128',
    ])

intelDecimal128Env.ShimLibrary(name="intel_decimal128", )

icuEnv = env.Clone()
if use_system_version_of_library("icu"):
    icuEnv = icuEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_ICUDATA_SYSLIBDEP'],
        env['LIBDEPS_ICUI18N_SYSLIBDEP'],
        env['LIBDEPS_ICUUC_SYSLIBDEP'],
    ])
else:
    icuEnv = icuEnv.Clone()
    icuEnv.InjectThirdParty(libraries=['icu'])
    icuEnv.SConscript('icu4c' + icuSuffix + '/source/SConscript', exports={'env': icuEnv})
    icuEnv = icuEnv.Clone(LIBDEPS_INTERFACE=[
        'icu4c' + icuSuffix + '/source/icu_i18n',
    ])

icuEnv.ShimLibrary(name="icu", )

libbsonEnv = env.Clone()
if use_system_version_of_library("libbson"):
    libbsonEnv = libbsonEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_LIBBSON_SYSLIBDEP'],
    ])
else:
    libbsonEnv = libbsonEnv.Clone()
    libbsonEnv.InjectThirdParty(libraries=['libbson'])
    libbsonEnv.SConscript('libbson/SConscript', exports={'env': libbsonEnv})
    libbsonEnv = libbsonEnv.Clone(LIBDEPS_INTERFACE=[
        'libbson/libbson',
    ])

libbsonEnv.ShimLibrary(name="libbson", )

mcEnv = env.Clone()
if use_system_version_of_library("libmongocrypt"):
    mcEnv = mcEnv.Clone(SYSLIBDEPS=[
        env['LIBDEPS_LIBMONGOCRYPT_SYSLIBDEP'],
    ])
else:
    mcEnv = mcEnv.Clone()
    mcEnv.InjectThirdParty(libraries=['libmongocrypt'])
    mcEnv.SConscript('libmongocrypt/SConscript', exports={'env': mcEnv})
    mcEnv = mcEnv.Clone(LIBDEPS_INTERFACE=[
        'libmongocrypt/libmongocrypt',
    ])

mcEnv.ShimLibrary(name="libmongocrypt", )

if env.TargetOSIs('linux') and env['ENABLE_GRPC_BUILD']:

    protobufEnv = env.Clone(NINJA_GENSOURCE_INDEPENDENT=True)
    if use_system_version_of_library("protobuf"):
        protobufEnv = protobufEnv.Clone(
            SYSLIBDEPS=[
                env['LIBDEPS_PROTOBUF_SYSLIBDEP'],
                env['LIBDEPS_PROTOC_SYSLIBDEP'],
            ], )
    else:
        protobufEnv.SConscript(dirs=[
            'protobuf',
        ], duplicate=False, exports={'env': env})
        protobufEnv = protobufEnv.Clone(LIBDEPS_INTERFACE=[
            'protobuf/protoc',
        ])
    protobufEnv.ShimLibrary(name="protobuf", )

    grpcEnv = env.Clone()
    if use_system_version_of_library("grpc"):
        grpcEnv = grpcEnv.Clone(SYSLIBDEPS=[
            env['LIBDEPS_GRPC_SYSLIBDEP'],
            env['LIBDEPS_GRPCXX_SYSLIBDEP'],
            env['LIBDEPS_GRPCXX_REFLECTION_SYSLIBDEP'],
        ])
    else:
        grpcEnv.SConscript(dirs=[
            'cares',
            're2',
            'grpc',
        ], duplicate=False, exports={'env': env})
        grpcEnv = grpcEnv.Clone(LIBDEPS_INTERFACE=[
            'grpc/grpc++_reflection',
        ])
    grpcEnv.ShimLibrary(name="grpc", )

libarchiveEnv = env.Clone()
libarchiveEnv.InjectThirdParty(libraries=['libarchive'])
libarchiveEnv.SConscript('libarchive' + libarchiveSuffix + '/libarchive/SConscript', exports={ 'env' : libarchiveEnv})
libarchiveEnv = libarchiveEnv.Clone(
    LIBDEPS_INTERFACE=[
        'libarchive' + libarchiveSuffix + '/libarchive/libarchive',
    ])

libarchiveEnv.Library(
    target='shim_libarchive',
    source=[
        'shim_libarchive.cpp',
    ])

libkmipEnv = env.Clone()
libkmipEnv.InjectThirdParty(libraries=['libkmip'])
libkmipEnv.SConscript('libkmip' + libkmipSuffix + '/libkmip/SConscript', exports={ 'env' : libkmipEnv })
libkmipEnv = libkmipEnv.Clone(
    LIBDEPS_INTERFACE=[
        'libkmip' + libkmipSuffix + '/libkmip/libkmip',
    ])

libkmipEnv.Library(
    target='shim_libkmip',
    source=[
        'shim_libkmip.cpp',
    ])

kmipppEnv = env.Clone()
kmipppEnv.InjectThirdParty(libraries=['kmippp'])
kmipppEnv.SConscript('libkmip' + libkmipSuffix + '/kmippp/SConscript', exports={ 'env' : kmipppEnv })
kmipppEnv = kmipppEnv.Clone(
    LIBDEPS_INTERFACE=[
        'libkmip' + libkmipSuffix + '/kmippp/kmippp',
    ])

kmipppEnv.Library(
    target='shim_kmippp',
    source=[
        'shim_kmippp.cpp',
    ])

if env.ShouldBuildStreams():
    libKafkaEnv = env.Clone()
    libKafkaEnv.InjectThirdParty(libraries=['librdkafka'])
    libKafkaEnv.SConscript('librdkafka/SConscript', exports={'env': libKafkaEnv})
    libKafkaEnv = libKafkaEnv.Clone(LIBDEPS_INTERFACE=[
        'librdkafka/rdkafka',
        'librdkafka/rdkafka++',
    ])
