diff --git a/CHANGES.txt b/CHANGES.txt index 17dfb07d05..ee1139a9e8 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -135,6 +135,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER Note that these are called for every build command run by SCons. It could have considerable performance impact if not used carefully. to connect to the server during start up. + - Ninja: Added command line variable NINJA_CMD_ARGS that allows to pass through ninja command line args. + This can also be set in your Environment(). + From Mats Wichmann: - Tweak the way default site_scons paths on Windows are expressed to diff --git a/RELEASE.txt b/RELEASE.txt index aa60c8be94..c2bd2b4e42 100755 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -14,7 +14,8 @@ NOTE: If you build with Python 3.10.0 and then rebuild with 3.10.1 (or higher), NEW FUNCTIONALITY ----------------- -- Added MSVC_USE_SCRIPT_ARGS variable to pass arguments to MSVC_USE_SCRIPT. +- Added MSVC_USE_SCRIPT_ARGS Environment variable which specifies command line arguments + to pass to the script specified by MSVC_USE_SCRIPT. - Added Configure.CheckMember() checker to check if struct/class has the specified member. - Added SHELL_ENV_GENERATORS construction variable. This variable should be set to a list (or an iterable) which contains functions to be called in order @@ -24,6 +25,8 @@ NEW FUNCTIONALITY performance impact if not used carefully. - Added MSVC_USE_SETTINGS variable to pass a dictionary to configure the msvc compiler system environment as an alternative to bypassing Visual Studio autodetection entirely. +- Ninja: Added command line variable NINJA_CMD_ARGS that allows to pass through ninja command line args. + This can also be set in your Environment(). - Added a global policy setting and an environment policy variable for specifying the action to be taken when an msvc request cannot be satisfied. The available options are "error", "exception", "warning", "warn", "ignore", and "suppress". The global policy variable may be diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py index 04a7abbe74..ca659dccfc 100644 --- a/SCons/Tool/ninja/__init__.py +++ b/SCons/Tool/ninja/__init__.py @@ -87,7 +87,7 @@ def ninja_builder(env, target, source): if str(env.get("NINJA_DISABLE_AUTO_RUN")).lower() not in ['1', 'true']: num_jobs = env.get('NINJA_MAX_JOBS', env.GetOption("num_jobs")) - cmd += ['-j' + str(num_jobs)] + NINJA_CMDLINE_TARGETS + cmd += ['-j' + str(num_jobs)] + env.get('NINJA_CMD_ARGS', '').split() + NINJA_CMDLINE_TARGETS print(f"ninja will be run with command line targets: {' '.join(NINJA_CMDLINE_TARGETS)}") print("Executing:", str(' '.join(cmd))) @@ -125,6 +125,14 @@ def execute_ninja(): sys.stdout.write("\n") +def options(opts): + """ + Add command line Variables for Ninja builder. + """ + opts.AddVariables( + ("NINJA_CMD_ARGS", "Arguments to pass to ninja"), + ) + def exists(env): """Enable if called.""" @@ -197,7 +205,7 @@ def generate(env): env["NINJA_SCONS_DAEMON_PORT"] = env.get('NINJA_SCONS_DAEMON_PORT', random.randint(10000, 60000)) if GetOption("disable_ninja"): - env.SConsignFile(os.path.join(str(env['NINJA_DIR']),'.ninja.sconsign')) + env.SConsignFile(os.path.join(str(env['NINJA_DIR']), '.ninja.sconsign')) # here we allow multiple environments to construct rules and builds # into the same ninja file diff --git a/SCons/Tool/ninja/ninja.xml b/SCons/Tool/ninja/ninja.xml index 6b247d0c0a..664d521780 100644 --- a/SCons/Tool/ninja/ninja.xml +++ b/SCons/Tool/ninja/ninja.xml @@ -77,7 +77,7 @@ See its __doc__ string for a discussion of the format. IMPLICIT_COMMAND_DEPENDENCIES NINJA_SCONS_DAEMON_KEEP_ALIVE NINJA_SCONS_DAEMON_PORT - + NINJA_CMD_ARGS @@ -395,5 +395,22 @@ python -m pip install ninja + + + + A string which will pass arguments through SCons to the ninja command when scons executes ninja. + Has no effect if &cv-NINJA_DISABLE_AUTO_RUN; is set. + + + This value can also be passed on the command line: + + +scons NINJA_CMD_ARGS=-v +or +scons NINJA_CMD_ARGS="-v -j 3" + + + + diff --git a/SCons/Tool/packaging/__init__.py b/SCons/Tool/packaging/__init__.py index 68cedeb12a..6fe01c190f 100644 --- a/SCons/Tool/packaging/__init__.py +++ b/SCons/Tool/packaging/__init__.py @@ -217,10 +217,11 @@ def generate(env): env['BUILDERS']['Package'] = Package env['BUILDERS']['Tag'] = Tag + def exists(env): return 1 -# XXX + def options(opts): opts.AddVariables( EnumVariable('PACKAGETYPE', diff --git a/test/ninja/generate_and_build.py b/test/ninja/generate_and_build.py index 91be108176..e1c26d4bb0 100644 --- a/test/ninja/generate_and_build.py +++ b/test/ninja/generate_and_build.py @@ -49,12 +49,17 @@ test.file_fixture('ninja_test_sconscripts/sconstruct_generate_and_build', 'SConstruct') # generate simple build -test.run(stdout=None) +test.run(stdout=None, arguments='NINJA_CMD_ARGS=-v') test.must_contain_all_lines(test.stdout(), ['Generating: build.ninja']) test.must_contain_all(test.stdout(), 'Executing:') test.must_contain_all(test.stdout(), 'ninja%(_exe)s -f' % locals()) +test.must_contain_all(test.stdout(), ' -j1 -v') test.run(program=test.workpath('foo' + _exe), stdout="foo.c") +# Test multiple args for NINJA_CMD_ARGS +test.run(stdout=None, arguments={'NINJA_CMD_ARGS':"-v -j3"}) +test.must_contain_all(test.stdout(), ' -v -j3') + # clean build and ninja files test.run(arguments='-c', stdout=None) test.must_contain_all_lines(test.stdout(), [ diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py index 575912146a..a70df0fe7f 100644 --- a/testing/framework/TestCmd.py +++ b/testing/framework/TestCmd.py @@ -1125,6 +1125,9 @@ def command_args(self, program=None, interpreter=None, arguments=None): interpreter = [interpreter] cmd = list(interpreter) + cmd if arguments: + if isinstance(arguments, dict): + cmd.extend(["%s=%s" % (k, v) for k, v in arguments.items()]) + return cmd if isinstance(arguments, str): arguments = arguments.split() cmd.extend(arguments) @@ -1569,6 +1572,9 @@ def run(self, program=None, The specified program will have the original directory prepended unless it is enclosed in a [list]. + + argument: If this is a dict() then will create arguments with KEY+VALUE for + each entry in the dict. """ if self.external: if not program: diff --git a/testing/framework/TestCmdTests.py b/testing/framework/TestCmdTests.py index 3b29091f72..8e5ecda29f 100644 --- a/testing/framework/TestCmdTests.py +++ b/testing/framework/TestCmdTests.py @@ -2261,6 +2261,12 @@ def test_command_args(self): expect = ['PYTHON', default_prog, 'arg3', 'arg4'] assert r == expect, (expect, r) + # Test arguments = dict + r = test.command_args(interpreter='PYTHON', arguments={'VAR1':'1'}) + expect = ['PYTHON', default_prog, 'VAR1=1'] + assert r == expect, (expect, r) + + test.interpreter_set('default_python') r = test.command_args() @@ -2585,7 +2591,7 @@ def test_send(self): with open(t.recv_out_path, 'rb') as f: result = to_str(f.read()) expect = 'script_recv: ' + input - assert result == expect, repr(result) + assert result == expect, "Result:[%s] should match\nExpected:[%s]" % (result, expect) p = test.start(stdin=1) input = 'send() input to the receive script\n' @@ -3103,7 +3109,7 @@ def test_workpath(self): assert wpath == os.path.join(test.workdir, 'foo', 'bar') - +@unittest.skipIf(sys.platform == 'win32', "Don't run on win32") class readable_TestCase(TestCmdTestCase): def test_readable(self): """Test readable()""" @@ -3183,7 +3189,7 @@ def test_writable(self): assert not _is_writable(test.workpath('file1')) - +@unittest.skipIf(sys.platform == 'win32', "Don't run on win32") class executable_TestCase(TestCmdTestCase): def test_executable(self): """Test executable()""" @@ -3331,70 +3337,8 @@ def test_variables(self): assert stderr == "", stderr - if __name__ == "__main__": - tclasses = [ - __init__TestCase, - basename_TestCase, - cleanup_TestCase, - chmod_TestCase, - combine_TestCase, - command_args_TestCase, - description_TestCase, - diff_TestCase, - diff_stderr_TestCase, - diff_stdout_TestCase, - exit_TestCase, - fail_test_TestCase, - interpreter_TestCase, - match_TestCase, - match_exact_TestCase, - match_re_dotall_TestCase, - match_re_TestCase, - match_stderr_TestCase, - match_stdout_TestCase, - no_result_TestCase, - pass_test_TestCase, - preserve_TestCase, - program_TestCase, - read_TestCase, - rmdir_TestCase, - run_TestCase, - run_verbose_TestCase, - set_diff_function_TestCase, - set_match_function_TestCase, - sleep_TestCase, - start_TestCase, - stderr_TestCase, - stdin_TestCase, - stdout_TestCase, - subdir_TestCase, - symlink_TestCase, - tempdir_TestCase, - timeout_TestCase, - unlink_TestCase, - touch_TestCase, - verbose_TestCase, - workdir_TestCase, - workdirs_TestCase, - workpath_TestCase, - writable_TestCase, - write_TestCase, - variables_TestCase, - ] - if sys.platform != 'win32': - tclasses.extend([ - executable_TestCase, - readable_TestCase, - ]) - suite = unittest.TestSuite() - for tclass in tclasses: - loader = unittest.TestLoader() - loader.testMethodPrefix = 'test_' - names = loader.getTestCaseNames(tclass) - suite.addTests([tclass(n) for n in names]) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + unittest.main() # Local Variables: # tab-width:4