"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "SCons/Tool/ninja/__init__.py" between
SCons-4.3.0.tar.gz and SCons-4.4.0.tar.gz

About: SCons is a software construction tool (a Python script and a set of modules as a superior alternative to the classic "Make" build tool).

__init__.py  (SCons-4.3.0):__init__.py  (SCons-4.4.0)
skipping to change at line 29 skipping to change at line 29
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
"""Generate build.ninja files from SCons aliases.""" """Generate build.ninja files from SCons aliases."""
import importlib import importlib
import os import os
import traceback
import subprocess import subprocess
import sys import sys
import SCons import SCons
import SCons.Script
import SCons.Tool.ninja.Globals import SCons.Tool.ninja.Globals
from SCons.Script import GetOption from SCons.Script import GetOption
from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS from .Globals import NINJA_RULES, NINJA_POOLS, NINJA_CUSTOM_HANDLERS, NINJA_DEFA ULT_TARGETS, NINJA_CMDLINE_TARGETS
from .Methods import register_custom_handler, register_custom_rule_mapping, regi ster_custom_rule, register_custom_pool, \ from .Methods import register_custom_handler, register_custom_rule_mapping, regi ster_custom_rule, register_custom_pool, \
set_build_node_callback, get_generic_shell_command, CheckNinjaCompdbExpand, get_command, \ set_build_node_callback, get_generic_shell_command, CheckNinjaCompdbExpand, get_command, \
gen_get_response_file_command gen_get_response_file_command
from .Overrides import ninja_hack_linkcom, ninja_hack_arcom, NinjaNoResponseFile s, ninja_always_serial, AlwaysExecAction from .Overrides import ninja_hack_linkcom, ninja_hack_arcom, NinjaNoResponseFile s, ninja_always_serial, AlwaysExecAction
from .Utils import ninja_add_command_line_options, \ from .Utils import ninja_add_command_line_options, \
ninja_noop, ninja_print_conf_log, ninja_csig, ninja_contents, ninja_stat, ni nja_whereis ninja_noop, ninja_print_conf_log, ninja_csig, ninja_contents, ninja_stat, ni nja_whereis, NinjaExperimentalWarning
try: try:
import ninja import ninja
NINJA_BINARY = ninja.__file__ NINJA_BINARY = ninja.__file__
except ImportError: except ImportError:
NINJA_BINARY = False NINJA_BINARY = False
else: else:
from .NinjaState import NinjaState from .NinjaState import NinjaState
NINJA_STATE = None NINJA_STATE = None
skipping to change at line 66 skipping to change at line 68
if not isinstance(source, list): if not isinstance(source, list):
source = [source] source = [source]
if not isinstance(target, list): if not isinstance(target, list):
target = [target] target = [target]
# We have no COMSTR equivalent so print that we're generating # We have no COMSTR equivalent so print that we're generating
# here. # here.
print("Generating:", str(target[0])) print("Generating:", str(target[0]))
generated_build_ninja = target[0].get_abspath() generated_build_ninja = target[0].get_abspath()
NINJA_STATE.generate() try:
NINJA_STATE.generate()
except Exception:
raise SCons.Errors.BuildError(
errstr=f"ERROR: an exception occurred while generating the ninja fil
e:\n{traceback.format_exc()}",
node=target)
if env["PLATFORM"] == "win32": if env["PLATFORM"] == "win32":
# TODO: Is this necessary as you set env variable in the ninja build fil e per target? # TODO: Is this necessary as you set env variable in the ninja build fil e per target?
# this is not great, its doesn't consider specific # this is not great, its doesn't consider specific
# node environments, which means on linux the build could # node environments, which means on linux the build could
# behave differently, because on linux you can set the environment # behave differently, because on linux you can set the environment
# per command in the ninja file. This is only needed if # per command in the ninja file. This is only needed if
# running ninja directly from a command line that hasn't # running ninja directly from a command line that hasn't
# had the environment setup (vcvarsall.bat) # had the environment setup (vcvarsall.bat)
with open('run_ninja_env.bat', 'w') as f: with open('run_ninja_env.bat', 'w') as f:
for key in env['ENV']: for key in env['ENV']:
f.write('set {}={}\n'.format(key, env['ENV'][key])) f.write('set {}={}\n'.format(key, env['ENV'][key]))
f.write('{} -f {} %*\n'.format(NINJA_STATE.ninja_bin_path, generated _build_ninja)) f.write('{} -f {} %*\n'.format(NINJA_STATE.ninja_bin_path, generated _build_ninja))
cmd = ['run_ninja_env.bat'] cmd = ['run_ninja_env.bat']
else: else:
cmd = [NINJA_STATE.ninja_bin_path, '-f', generated_build_ninja] cmd = [NINJA_STATE.ninja_bin_path, '-f', generated_build_ninja]
if not env.get("NINJA_DISABLE_AUTO_RUN"): 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)] + env.get('NINJA_CMD_ARGS', '').split() +
NINJA_CMDLINE_TARGETS
print(f"ninja will be run with command line targets: {' '.join(NINJA_CMD
LINE_TARGETS)}")
print("Executing:", str(' '.join(cmd))) print("Executing:", str(' '.join(cmd)))
# execute the ninja build at the end of SCons, trying to # execute the ninja build at the end of SCons, trying to
# reproduce the output like a ninja build would # reproduce the output like a ninja build would
def execute_ninja(): def execute_ninja():
proc = subprocess.Popen(cmd, proc = subprocess.Popen(cmd,
stderr=sys.stderr, stderr=sys.stderr,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
universal_newlines=True, universal_newlines=True,
skipping to change at line 119 skipping to change at line 129
sys.stdout.write('\x1b[2K') # erase previous line sys.stdout.write('\x1b[2K') # erase previous line
sys.stdout.write("\r") sys.stdout.write("\r")
else: else:
sys.stdout.write(os.linesep) sys.stdout.write(os.linesep)
sys.stdout.write(output) sys.stdout.write(output)
sys.stdout.flush() sys.stdout.flush()
# this will only erase ninjas [#/#] lines # this will only erase ninjas [#/#] lines
# leaving warnings and other output, seems a bit # leaving warnings and other output, seems a bit
# prone to failure with such a simple check # prone to failure with such a simple check
erase_previous = output.startswith('[') erase_previous = output.startswith('[')
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): def exists(env):
"""Enable if called.""" """Enable if called."""
if 'ninja' not in GetOption('experimental'): if 'ninja' not in GetOption('experimental'):
return False return False
# This variable disables the tool when storing the SCons command in the # This variable disables the tool when storing the SCons command in the
# generated ninja file to ensure that the ninja tool is not loaded when # generated ninja file to ensure that the ninja tool is not loaded when
# SCons should do actual work as a subprocess of a ninja build. The ninja # SCons should do actual work as a subprocess of a ninja build. The ninja
skipping to change at line 162 skipping to change at line 181
target = [ninja_file, ] target = [ninja_file, ]
# No source should have been passed. Drop it. # No source should have been passed. Drop it.
if source: if source:
source = [] source = []
return target, source return target, source
def generate(env): def generate(env):
"""Generate the NINJA builders.""" """Generate the NINJA builders."""
global NINJA_STATE global NINJA_STATE, NINJA_CMDLINE_TARGETS
if 'ninja' not in GetOption('experimental'): if 'ninja' not in GetOption('experimental'):
return return
if not SCons.Tool.ninja.Globals.ninja_builder_initialized: if not SCons.Tool.ninja.Globals.ninja_builder_initialized:
SCons.Tool.ninja.Globals.ninja_builder_initialized = True SCons.Tool.ninja.Globals.ninja_builder_initialized = True
ninja_add_command_line_options() ninja_add_command_line_options()
if not NINJA_BINARY: if not NINJA_BINARY:
skipping to change at line 186 skipping to change at line 205
env["NINJA_FILE_NAME"] = env.get("NINJA_FILE_NAME", "build.ninja") env["NINJA_FILE_NAME"] = env.get("NINJA_FILE_NAME", "build.ninja")
# Add the Ninja builder. # Add the Ninja builder.
always_exec_ninja_action = AlwaysExecAction(ninja_builder, {}) always_exec_ninja_action = AlwaysExecAction(ninja_builder, {})
ninja_builder_obj = SCons.Builder.Builder(action=always_exec_ninja_action, ninja_builder_obj = SCons.Builder.Builder(action=always_exec_ninja_action,
emitter=ninja_emitter) emitter=ninja_emitter)
env.Append(BUILDERS={"Ninja": ninja_builder_obj}) env.Append(BUILDERS={"Ninja": ninja_builder_obj})
env["NINJA_ALIAS_NAME"] = env.get("NINJA_ALIAS_NAME", "generate-ninja") env["NINJA_ALIAS_NAME"] = env.get("NINJA_ALIAS_NAME", "generate-ninja")
env['NINJA_DIR'] = env.Dir(env.get("NINJA_DIR", '#/.ninja')) env['NINJA_DIR'] = env.Dir(env.get("NINJA_DIR", '#/.ninja'))
env["NINJA_SCONS_DAEMON_KEEP_ALIVE"] = env.get("NINJA_SCONS_DAEMON_KEEP_ALIV
E", 180000)
if GetOption("disable_ninja"):
env.SConsignFile(os.path.join(str(env['NINJA_DIR']), '.ninja.sconsign'))
# here we allow multiple environments to construct rules and builds # here we allow multiple environments to construct rules and builds
# into the same ninja file # into the same ninja file
if NINJA_STATE is None: if NINJA_STATE is None:
ninja_file = env.Ninja() ninja_file = env.Ninja()
env['NINJA_FILE'] = ninja_file[0] env['NINJA_FILE'] = ninja_file[0]
env.AlwaysBuild(ninja_file) env.AlwaysBuild(ninja_file)
env.Alias("$NINJA_ALIAS_NAME", ninja_file)
# We need to force SCons to only build the ninja target when ninja tool
is loaded.
# The ninja tool is going to 'rip the guts out' of scons and make it bas
ically unable
# to do anything in terms of building, so any targets besides the ninja
target will
# end up doing nothing besides causing confusion. We save the targets ho
wever, so that
# SCons and invoke ninja to build them in lieu of the user.
NINJA_CMDLINE_TARGETS = SCons.Script.BUILD_TARGETS
SCons.Script.BUILD_TARGETS = SCons.Script.TargetList(env.Alias("$NINJA_A
LIAS_NAME", ninja_file))
else: else:
if str(NINJA_STATE.ninja_file) != env["NINJA_FILE_NAME"]: if str(NINJA_STATE.ninja_file) != env["NINJA_FILE_NAME"]:
SCons.Warnings.SConsWarning("Generating multiple ninja files not sup ported, set ninja file name before tool initialization.") SCons.Warnings.SConsWarning("Generating multiple ninja files not sup ported, set ninja file name before tool initialization.")
ninja_file = [NINJA_STATE.ninja_file] ninja_file = [NINJA_STATE.ninja_file]
def ninja_generate_deps(env): def ninja_generate_deps(env):
"""Return a list of SConscripts """Return a list of SConscripts
TODO: Should we also include files loaded from site_scons/*** TODO: Should we also include files loaded from site_scons/***
or even all loaded modules? https://stackoverflow.com/questions/485810 0/how-to-list-imported-modules or even all loaded modules? https://stackoverflow.com/questions/485810 0/how-to-list-imported-modules
TODO: Do we want this to be Nodes? TODO: Do we want this to be Nodes?
""" """
return sorted([str(s) for s in SCons.Node.SConscriptNodes]) return sorted([str(s) for s in SCons.Node.SConscriptNodes])
env['_NINJA_REGENERATE_DEPS_FUNC'] = ninja_generate_deps env['_NINJA_REGENERATE_DEPS_FUNC'] = ninja_generate_deps
env['NINJA_REGENERATE_DEPS'] = env.get('NINJA_REGENERATE_DEPS', '${_NINJA_RE GENERATE_DEPS_FUNC(__env__)}') env['NINJA_REGENERATE_DEPS'] = env.get('NINJA_REGENERATE_DEPS', '${_NINJA_RE GENERATE_DEPS_FUNC(__env__)}')
# This adds the required flags such that the generated compile # This adds the required flags such that the generated compile
# commands will create depfiles as appropriate in the Ninja file. # commands will create depfiles as appropriate in the Ninja file.
if env["PLATFORM"] == "win32": if 'CCDEPFLAGS' not in env:
env.Append(CCFLAGS=["/showIncludes"]) # Issue some warning here
pass
else: else:
env.Append(CCFLAGS=["-MMD", "-MF", "${TARGET}.d"]) env.Append(CCFLAGS='$CCDEPFLAGS')
env.AddMethod(CheckNinjaCompdbExpand, "CheckNinjaCompdbExpand") env.AddMethod(CheckNinjaCompdbExpand, "CheckNinjaCompdbExpand")
# Provide a way for custom rule authors to easily access command # Provide a way for custom rule authors to easily access command
# generation. # generation.
env.AddMethod(get_generic_shell_command, "NinjaGetGenericShellCommand") env.AddMethod(get_generic_shell_command, "NinjaGetGenericShellCommand")
env.AddMethod(get_command, "NinjaGetCommand") env.AddMethod(get_command, "NinjaGetCommand")
env.AddMethod(gen_get_response_file_command, "NinjaGenResponseFileProvider") env.AddMethod(gen_get_response_file_command, "NinjaGenResponseFileProvider")
env.AddMethod(set_build_node_callback, "NinjaSetBuildNodeCallback") env.AddMethod(set_build_node_callback, "NinjaSetBuildNodeCallback")
skipping to change at line 266 skipping to change at line 297
# will return "${*COM}" as their pre-subst'd command line. However # will return "${*COM}" as their pre-subst'd command line. However
# if a user in a SConscript overwrites those values via key access # if a user in a SConscript overwrites those values via key access
# like env["LINKCOM"] = "$( $ICERUN $)" + env["LINKCOM"] then # like env["LINKCOM"] = "$( $ICERUN $)" + env["LINKCOM"] then
# those actions no longer return the "bracketted" string and # those actions no longer return the "bracketted" string and
# instead return something that looks more expanded. So to # instead return something that looks more expanded. So to
# continue working even if a user has done this we map both the # continue working even if a user has done this we map both the
# "bracketted" and semi-expanded versions. # "bracketted" and semi-expanded versions.
def robust_rule_mapping(var, rule, tool): def robust_rule_mapping(var, rule, tool):
provider = gen_get_response_file_command(env, rule, tool) provider = gen_get_response_file_command(env, rule, tool)
env.NinjaRuleMapping("${" + var + "}", provider) env.NinjaRuleMapping("${" + var + "}", provider)
env.NinjaRuleMapping(env.get(var, None), provider)
# some of these construction vars could be generators, e.g.
# CommandGeneratorAction, so if the var is not a string, we
# can't parse the generated string.
if isinstance(env.get(var), str):
env.NinjaRuleMapping(env.get(var, None), provider)
robust_rule_mapping("CCCOM", "CC", "$CC") robust_rule_mapping("CCCOM", "CC", "$CC")
robust_rule_mapping("SHCCCOM", "CC", "$CC") robust_rule_mapping("SHCCCOM", "CC", "$CC")
robust_rule_mapping("CXXCOM", "CXX", "$CXX") robust_rule_mapping("CXXCOM", "CXX", "$CXX")
robust_rule_mapping("SHCXXCOM", "CXX", "$CXX") robust_rule_mapping("SHCXXCOM", "CXX", "$CXX")
robust_rule_mapping("LINKCOM", "LINK", "$LINK") robust_rule_mapping("LINKCOM", "LINK", "$LINK")
robust_rule_mapping("SHLINKCOM", "LINK", "$SHLINK") robust_rule_mapping("SHLINKCOM", "LINK", "$SHLINK")
robust_rule_mapping("ARCOM", "AR", "$AR") robust_rule_mapping("ARCOM", "AR", "$AR")
# Make SCons node walk faster by preventing unnecessary work # Make SCons node walk faster by preventing unnecessary work
env.Decider("timestamp-match") env.Decider("timestamp-match")
# Used to determine if a build generates a source file. Ninja # Used to determine if a build generates a source file. Ninja
# requires that all generated sources are added as order_only # requires that all generated sources are added as order_only
# dependencies to any builds that *might* use them. # dependencies to any builds that *might* use them.
# TODO: switch to using SCons to help determine this (Github Issue #3624) # TODO: switch to using SCons to help determine this (Github Issue #3624)
env["NINJA_GENERATED_SOURCE_SUFFIXES"] = [".h", ".hpp"] env["NINJA_GENERATED_SOURCE_SUFFIXES"] = env.get('NINJA_GENERATED_SOURCE_SUF FIXES', [".h", ".hpp"])
# Force ARCOM so use 's' flag on ar instead of separately running ranlib # Force ARCOM so use 's' flag on ar instead of separately running ranlib
ninja_hack_arcom(env) ninja_hack_arcom(env)
if GetOption('disable_ninja'): if GetOption('disable_ninja'):
return env return env
SCons.Warnings.SConsWarning("Initializing ninja tool... this feature is expe print("Initializing ninja tool... this feature is experimental. SCons intern
rimental. SCons internals and all environments will be affected.") als and all environments will be affected.")
print(f"SCons running in ninja mode. {env['NINJA_FILE']} will be generated."
)
# This is the point of no return, anything after this comment # This is the point of no return, anything after this comment
# makes changes to SCons that are irreversible and incompatible # makes changes to SCons that are irreversible and incompatible
# with a normal SCons build. We return early if __NINJA_NO=1 has # with a normal SCons build. We return early if __NINJA_NO=1 has
# been given on the command line (i.e. by us in the generated # been given on the command line (i.e. by us in the generated
# ninja file) here to prevent these modifications from happening # ninja file) here to prevent these modifications from happening
# when we want SCons to do work. Everything before this was # when we want SCons to do work. Everything before this was
# necessary to setup the builder and other functions so that the # necessary to setup the builder and other functions so that the
# tool can be unconditionally used in the users's SCons files. # tool can be unconditionally used in the users's SCons files.
if not exists(env): if not exists(env):
skipping to change at line 431 skipping to change at line 467
NINJA_STATE.add_build(target) NINJA_STATE.add_build(target)
else: else:
target.build() target.build()
SCons.Taskmaster.Task.execute = ninja_execute SCons.Taskmaster.Task.execute = ninja_execute
# Make needs_execute always return true instead of determining out of # Make needs_execute always return true instead of determining out of
# date-ness. # date-ness.
SCons.Script.Main.BuildTask.needs_execute = lambda x: True SCons.Script.Main.BuildTask.needs_execute = lambda x: True
def ninja_Set_Default_Targets(env, tlist):
"""
Record the default targets if they were ever set by the user. Ninja
will need to write the default targets and make sure not to include
the scons daemon shutdown target.
"""
SCons.Script._Get_Default_Targets = SCons.Script._Set_Default_Targets_Ha
s_Been_Called
SCons.Script.DEFAULT_TARGETS = ninja_file
for t in tlist:
if isinstance(t, SCons.Node.Node):
NINJA_DEFAULT_TARGETS.append(t)
else:
nodes = env.arg2nodes(t, env.fs.Entry)
NINJA_DEFAULT_TARGETS.extend(nodes)
SCons.Script._Set_Default_Targets = ninja_Set_Default_Targets
# We will eventually need to overwrite TempFileMunge to make it # We will eventually need to overwrite TempFileMunge to make it
# handle persistent tempfiles or get an upstreamed change to add # handle persistent tempfiles or get an upstreamed change to add
# some configurability to it's behavior in regards to tempfiles. # some configurability to it's behavior in regards to tempfiles.
# #
# Set all three environment variables that Python's # Set all three environment variables that Python's
# tempfile.mkstemp looks at as it behaves differently on different # tempfile.mkstemp looks at as it behaves differently on different
# platforms and versions of Python. # platforms and versions of Python.
# build_dir = env.subst("$NINJA_DIR") # build_dir = env.subst("$NINJA_DIR")
# if build_dir == "": # if build_dir == "":
# build_dir = "." # build_dir = "."
# os.environ["TMPDIR"] = env.Dir("{}/.response_files".format(build_dir)).get _abspath() # os.environ["TMPDIR"] = env.Dir("{}/.response_files".format(build_dir)).get _abspath()
# os.environ["TEMP"] = os.environ["TMPDIR"] # os.environ["TEMP"] = os.environ["TMPDIR"]
# os.environ["TMP"] = os.environ["TMPDIR"] # os.environ["TMP"] = os.environ["TMPDIR"]
# if not os.path.isdir(os.environ["TMPDIR"]): # if not os.path.isdir(os.environ["TMPDIR"]):
# env.Execute(SCons.Defaults.Mkdir(os.environ["TMPDIR"])) # env.Execute(SCons.Defaults.Mkdir(os.environ["TMPDIR"]))
env['TEMPFILEDIR'] = "$NINJA_DIR/.response_files" env['TEMPFILEDIR'] = "$NINJA_DIR/.response_files"
env["TEMPFILE"] = NinjaNoResponseFiles env["TEMPFILE"] = NinjaNoResponseFiles
env.Alias('run-ninja-scons-daemon', 'run_ninja_scons_daemon_phony')
env.Alias('shutdown-ninja-scons-daemon', 'shutdown_ninja_scons_daemon_phony'
)
 End of changes. 17 change blocks. 
14 lines changed or deleted 77 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)