Skip to content

Commit f659b76

Browse files
committed
SERVER-42408 Add build.ninja generation to SCons
1 parent a2fa801 commit f659b76

File tree

10 files changed

+943
-25
lines changed

10 files changed

+943
-25
lines changed

SConstruct

Lines changed: 112 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ SetOption('random', 1)
9595
# using the nargs='const' mechanism.
9696
#
9797

98+
add_option('ninja',
99+
choices=['true', 'false'],
100+
default='false',
101+
nargs='?',
102+
const='true',
103+
type='choice',
104+
help='Enable the build.ninja generator tool',
105+
)
106+
107+
add_option('ccache',
108+
choices=['true', 'false'],
109+
default='false',
110+
nargs='?',
111+
const='true',
112+
type='choice',
113+
help='Enable ccache support',
114+
)
115+
98116
add_option('prefix',
99117
default='$BUILD_ROOT/install',
100118
help='installation prefix',
@@ -659,6 +677,9 @@ env_vars.Add('ARFLAGS',
659677
help='Sets flags for the archiver',
660678
converter=variable_shlex_converter)
661679

680+
env_vars.Add('CCACHE',
681+
help='Path to ccache used for the --ccache option. Defaults to first ccache in PATH.')
682+
662683
env_vars.Add(
663684
'CACHE_SIZE',
664685
help='Maximum size of the cache (in gigabytes)',
@@ -801,6 +822,20 @@ env_vars.Add('MSVC_USE_SCRIPT',
801822
env_vars.Add('MSVC_VERSION',
802823
help='Sets the version of Visual Studio to use (e.g. 12.0, 11.0, 10.0)')
803824

825+
env_vars.Add('NINJA_SUFFIX',
826+
help="""A suffix to add to the end of generated build.ninja
827+
files. Useful for when compiling multiple build ninja files for
828+
different configurations, for instance:
829+
830+
scons --sanitize=asan --ninja NINJA_SUFFIX=asan ninja-install-all-meta
831+
scons --sanitize=tsan --ninja NINJA_SUFFIX=tsan ninja-install-all-meta
832+
833+
Will generate the files (respectively):
834+
835+
install-all-meta.build.ninja.asan
836+
install-all-meta.build.ninja.tsan
837+
""")
838+
804839
env_vars.Add('OBJCOPY',
805840
help='Sets the path to objcopy',
806841
default=WhereIs('objcopy'))
@@ -1477,12 +1512,18 @@ if link_model.startswith("dynamic"):
14771512
if optBuild:
14781513
env.SetConfigHeaderDefine("MONGO_CONFIG_OPTIMIZED_BUILD")
14791514

1480-
# Enable the fast decider if exlicltly requested or if in 'auto' mode and not in conflict with other
1481-
# options.
1482-
if get_option('build-fast-and-loose') == 'on' or \
1483-
(get_option('build-fast-and-loose') == 'auto' and \
1484-
not has_option('release') and \
1485-
not has_option('cache')):
1515+
# Enable the fast decider if explicitly requested or if in 'auto' mode
1516+
# and not in conflict with other options like the ninja option which
1517+
# sets it's own decider
1518+
if (
1519+
not get_option('ninja') == 'true' and
1520+
get_option('build-fast-and-loose') == 'on' or
1521+
(
1522+
get_option('build-fast-and-loose') == 'auto' and
1523+
not has_option('release') and
1524+
not has_option('cache')
1525+
)
1526+
):
14861527
# See http://www.scons.org/wiki/GoFastButton for details
14871528
env.Decider('MD5-timestamp')
14881529
env.SetOption('max_drift', 1)
@@ -1541,12 +1582,9 @@ if env['_LIBDEPS'] == '$_LIBDEPS_OBJS':
15411582
fake_lib.write(str(uuid.uuid4()))
15421583
fake_lib.write('\n')
15431584

1544-
def noop_action(env, target, source):
1545-
pass
1546-
15471585
env['ARCOM'] = write_uuid_to_file
15481586
env['ARCOMSTR'] = 'Generating placeholder library $TARGET'
1549-
env['RANLIBCOM'] = noop_action
1587+
env['RANLIBCOM'] = ''
15501588
env['RANLIBCOMSTR'] = 'Skipping ranlib for $TARGET'
15511589

15521590
libdeps.setup_environment(env, emitting_shared=(link_model.startswith("dynamic")))
@@ -3673,6 +3711,70 @@ def doConfigure(myenv):
36733711

36743712

36753713
env = doConfigure( env )
3714+
env["NINJA_SYNTAX"] = "#site_scons/third_party/ninja_syntax.py"
3715+
3716+
# Now that we are done with configure checks, enable icecream, if available.
3717+
env.Tool('icecream')
3718+
3719+
if get_option('ninja') == 'true':
3720+
env.Tool("ninja")
3721+
def test_txt_writer(alias_name):
3722+
"""Find all the tests registered to alias_name and write them to a file via ninja."""
3723+
rule_written = False
3724+
3725+
def wrapper(env, ninja, node, dependencies):
3726+
"""Make a Ninja-able version of the test files."""
3727+
rule = alias_name.upper() + "_GENERATOR"
3728+
if not rule_written:
3729+
ninja.rule(
3730+
rule,
3731+
description="Generate test list text file",
3732+
command="echo $in > $out",
3733+
)
3734+
rule_written = True
3735+
3736+
alias = env.Alias(alias_name)
3737+
paths = []
3738+
children = alias.children()
3739+
for child in children:
3740+
paths.append('\t' + str(child))
3741+
3742+
ninja.build(
3743+
str(node),
3744+
rule,
3745+
inputs='\n'.join(paths),
3746+
implicit=dependencies,
3747+
)
3748+
3749+
return wrapper
3750+
env.NinjaRegisterFunctionHandler("unit_test_list_builder_action", test_txt_writer('$UNITTEST_ALIAS'))
3751+
env.NinjaRegisterFunctionHandler("integration_test_list_builder_action", test_txt_writer('$INTEGRATION_TEST_ALIAS'))
3752+
env.NinjaRegisterFunctionHandler("benchmark_list_builder_action", test_txt_writer('$BENCHMARK_ALIAS'))
3753+
3754+
def fakelib_in_ninja():
3755+
"""Generates empty .a files"""
3756+
rule_written = False
3757+
3758+
def wrapper(env, ninja, node, dependencies):
3759+
if not rule_written:
3760+
cmd = "touch $out"
3761+
if not env.TargetOSIs("posix"):
3762+
cmd = "cmd /c copy NUL $out"
3763+
ninja.rule(
3764+
"FAKELIB",
3765+
command=cmd,
3766+
)
3767+
rule_written = True
3768+
3769+
ninja.build(node.get_path(), rule='FAKELIB', implicit=dependencies)
3770+
3771+
return wrapper
3772+
3773+
env.NinjaRegisterFunctionHandler("write_uuid_to_file", fakelib_in_ninja())
3774+
3775+
# Load ccache after icecream since order matters when we're both changing CCCOM
3776+
if get_option('ccache') == 'true':
3777+
env.Tool('ccache')
36763778

36773779
# TODO: Later, this should live somewhere more graceful.
36783780
if get_option('install-mode') == 'hygienic':
@@ -3767,8 +3869,6 @@ if get_option('install-mode') == 'hygienic':
37673869
elif get_option('separate-debug') == "on":
37683870
env.FatalError('Cannot use --separate-debug without --install-mode=hygienic')
37693871

3770-
# Now that we are done with configure checks, enable icecream, if available.
3771-
env.Tool('icecream')
37723872

37733873
# If the flags in the environment are configured for -gsplit-dwarf,
37743874
# inject the necessary emitter.

site_scons/libdeps.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
88
For example, consider a program 'try' that depends on a lib 'tc', which in
99
turn uses a symbol from a lib 'tb' which in turn uses a library from 'ta'.
10+
1011
Without this package, the Program declaration for "try" looks like this:
1112
1213
Program('try', ['try.c', 'path/to/${LIBPREFIX}tc${LIBSUFFIX}',
13-
'path/to/${LIBPREFIX}tc${LIBSUFFIX}',
14-
'path/to/${LIBPREFIX}tc${LIBSUFFIX}',])
14+
'path/to/${LIBPREFIX}tb${LIBSUFFIX}',
15+
'path/to/${LIBPREFIX}ta${LIBSUFFIX}',])
1516
1617
With this library, we can instead write the following
1718

site_scons/site_tools/auto_install_binaries.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2019 MongoDB Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# TODO: Versioned libraries
216
# TODO: library dependency chaining for windows dynamic builds, static dev packages
317
# TODO: Injectible component dependencies (jscore -> resmoke, etc.)

site_scons/site_tools/ccache.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright 2019 MongoDB Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import math
16+
import os
17+
import SCons
18+
19+
def exists(env):
20+
"""Always enable"""
21+
ccache_path = env.get('CCACHE', env.WhereIs('ccache'))
22+
return os.path.exists(ccache_path)
23+
24+
25+
def generate(env):
26+
"""Add ccache support."""
27+
# ccache does not support response files so force scons to always
28+
# use the full command
29+
#
30+
# Note: This only works for Python versions >= 3.5
31+
env['MAXLINELENGTH'] = math.inf
32+
env['CCACHE'] = env.get('CCACHE', env.WhereIs('ccache'))
33+
env['CCCOM'] = '$CCACHE ' + env['CCCOM']
34+
env['CXXCOM'] = '$CCACHE ' + env['CXXCOM']
35+
env['SHCCCOM'] = '$CCACHE ' + env['SHCCCOM']
36+
env['SHCXXCOM'] = '$CCACHE ' + env['SHCXXCOM']
37+
38+

site_scons/site_tools/icecream.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ def generate(env):
6666
# Make an isolated environment so that our setting of ICECC_VERSION in the environment
6767
# doesn't appear when executing icecc_create_env
6868
toolchain_env = env.Clone()
69+
toolchain_env.Decider("timestamp-newer")
6970
if toolchain_env.ToolchainIs('clang'):
70-
toolchain = env.Command(
71+
toolchain = toolchain_env.Command(
7172
target=icecc_version,
7273
source=[
7374
'$ICECC_CREATE_ENV',
@@ -153,10 +154,11 @@ def icecc_version_arch_gen(target, source, env, for_signature):
153154
env['ICECC_VERSION_ARCH_GEN'] = icecc_version_arch_gen
154155

155156
# Make compile jobs flow through icecc
156-
env['CCCOM'] = '$( ICECC_VERSION=${ICECC_VERSION_ARCH_GEN}${ICECC_VERSION_GEN} $ICECC $) ' + env['CCCOM']
157-
env['CXXCOM'] = '$( ICECC_VERSION=${ICECC_VERSION_ARCH_GEN}${ICECC_VERSION_GEN} $ICECC $) ' + env['CXXCOM']
158-
env['SHCCCOM'] = '$( ICECC_VERSION=${ICECC_VERSION_ARCH_GEN}${ICECC_VERSION_GEN} $ICECC $) ' + env['SHCCCOM']
159-
env['SHCXXCOM'] = '$( ICECC_VERSION=${ICECC_VERSION_ARCH_GEN}${ICECC_VERSION_GEN} $ICECC $) ' + env['SHCXXCOM']
157+
env['ENV']['ICECC_VERSION'] = env.subst('${ICECC_VERSION_ARCH_GEN}${ICECC_VERSION_GEN}')
158+
env['CCCOM'] = '$( $ICECC $) ' + env['CCCOM']
159+
env['CXXCOM'] = '$( $ICECC $) ' + env['CXXCOM']
160+
env['SHCCCOM'] = '$( $ICECC $) ' + env['SHCCCOM']
161+
env['SHCXXCOM'] = '$( $ICECC $) ' + env['SHCXXCOM']
160162

161163
# Make link like jobs flow through icerun so we don't kill the
162164
# local machine.

site_scons/site_tools/idl_tool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def idl_scanner(node, env, path):
4747
try:
4848
deps_str = subprocess.check_output(cmd).decode('utf-8')
4949
except subprocess.CalledProcessError as e:
50-
print(("IDLC ERROR: %s" % (e.output) ))
50+
print("IDLC ERROR: %s" % e.output)
5151
raise
5252

5353
deps_list = deps_str.splitlines()

0 commit comments

Comments
 (0)