From 9a83650d6881e93a59487e0715830ba80de645b9 Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Sun, 18 Jan 2026 10:16:57 -0500 Subject: [PATCH 1/9] MSVS: update generation of the vcxproj embedded python script Changes: * Replace the existing two code paths that generate the msvs tool vcxproj file with a single code path that generates the one-line python script string compatible with all cases. Prior to this change, the default test runs would not test the alternate path as SCONS_LIB_DIR is set in the test os environment. * The msvs test case SCons version string was changed from `self.scons_version` to `SCons.__version__`. Depending on the tests run, the test framework version may not match the SCons library version being tested (e.g., retaining packaging version). The test now matches what the msvs tool uses. * Modify the embedded vcxproj script and generated python executable string for consistency with each other with respect to SCons env and os.environ usage. * Modify the embedded vcxproj script to retrieve SCONS_HOME and SCONS_LIB_DIR from the environment if needed. * Priority order for msvs tool SCons library specification: 1. env['SCONS_HOME'] literal path when generated if True 2. os.environ.get('SCONS_HOME', ) if True 3. os.environ.get('SCONS_LIB_DIR', ) if True 4. if exists and is valid SCons library 5. first in list of generated locations that exists and is valid SCons library * Modify generation of python executable path order: 1. env['PYTHON_ROOT'] literal path if True 2. $(PYTHON_ROOT) if os.environ['PYTHON_ROOT'] is True 3. sys.executable literal path * Add bare asterisk after second argument in msvs_substitute function in testing/framework/TestSConsMSVS.py requiring keyword argument specifications for all optional arguments. The first two arguments are by position the remaining seven arguments must be keyword specified. --- SCons/Tool/msvs.py | 68 ++++++++++++++++++++------- test/MSVS/common-prefix.py | 4 +- test/MSVS/runfile.py | 2 +- test/MSVS/vs-6.0-clean.py | 4 +- test/MSVS/vs-6.0-files.py | 4 +- test/MSVS/vs-6.0-variant_dir.py | 6 +-- test/MSVS/vs-7.0-clean.py | 4 +- test/MSVS/vs-7.0-files.py | 7 ++- test/MSVS/vs-7.0-scc-files.py | 6 +-- test/MSVS/vs-7.0-scc-legacy-files.py | 5 +- test/MSVS/vs-7.0-variant_dir.py | 4 +- test/MSVS/vs-7.1-clean.py | 4 +- test/MSVS/vs-7.1-files.py | 7 ++- test/MSVS/vs-7.1-scc-files.py | 6 +-- test/MSVS/vs-7.1-scc-legacy-files.py | 5 +- test/MSVS/vs-7.1-variant_dir.py | 4 +- test/MSVS/vs-files.py | 7 ++- test/MSVS/vs-mult-auto-guid.py | 4 +- test/MSVS/vs-mult-auto-vardir-guid.py | 4 +- test/MSVS/vs-mult-auto-vardir.py | 4 +- test/MSVS/vs-mult-auto.py | 4 +- test/MSVS/vs-mult-noauto-vardir.py | 4 +- test/MSVS/vs-mult-noauto.py | 4 +- test/MSVS/vs-scc-files.py | 6 +-- test/MSVS/vs-scc-legacy-files.py | 5 +- test/MSVS/vs-variant_dir.py | 4 +- testing/framework/TestSConsMSVS.py | 55 ++++++++++++++++++---- 27 files changed, 151 insertions(+), 90 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index b35e267802..aaf02e5a0a 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -160,32 +160,66 @@ def msvs_parse_version(s): # things and ends up with "-c" as sys.argv[0]. Consequently, we have # the MSVS Project file invoke SCons the same way that scons.bat does, # which works regardless of how we were invoked. +_exec_script_main_template = None + def getExecScriptMain(env, xml=None): - if 'SCONS_HOME' not in env: - env['SCONS_HOME'] = os.environ.get('SCONS_HOME') + global _exec_script_main_template + scons_home = env.get('SCONS_HOME') - if not scons_home and 'SCONS_LIB_DIR' in os.environ: - scons_home = os.environ['SCONS_LIB_DIR'] - if scons_home: - exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home - else: - version = SCons.__version__ - exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%(version)s'), join(sys.prefix, 'scons-%(version)s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % locals() + os_scons_home = os.environ.get('SCONS_HOME') + os_scons_libdir = os.environ.get('SCONS_LIB_DIR') + + if 'SCONS_HOME' not in env: + env['SCONS_HOME'] = os_scons_home + + if _exec_script_main_template is None: + _exec_script_main_template = "; ".join([ + "from os.path import isdir, isfile, join", + "import os", + "import sys", + "sconslibs = lambda l: [p for p in l if p and isdir(p) and isfile(join(p, 'SCons', '__init__.py'))]", + "libspec = r'{scons_home}'", + "libspec = libspec if libspec else os.environ.get('SCONS_HOME', r'{os_scons_home}')", + "libspec = libspec if libspec else os.environ.get('SCONS_LIB_DIR', r'{os_scons_libdir}')", + "libs = [libspec] if libspec else sconslibs([r'{scons_genlib}'])", + "libs = libs if libs else sconslibs([join(sys.prefix, 'Lib', 'site-packages', 'scons-{scons_version}'), join(sys.prefix, 'scons-{scons_version}'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons'), join(sys.prefix, 'Lib', 'site-packages')])", + "sys.path = libs[:1] + sys.path if libs else sys.path", + # "print(f'libs = {{libs}}')", + # "print(f'sys.path = {{sys.path}}')", + "import SCons.Script", + "SCons.Script.main()", + ]) + + exec_script_main = _exec_script_main_template.format( + scons_home=os.path.abspath(scons_home) if scons_home else '', + os_scons_home=os.path.abspath(os_scons_home) if os_scons_home else '', + os_scons_libdir=os.path.abspath(os_scons_libdir) if os_scons_libdir else '', + scons_genlib=os.path.abspath(os.path.join(os.path.dirname(SCons.__file__), "..")), + scons_version=SCons.__version__, + ) + # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) + if xml: exec_script_main = xmlify(exec_script_main) + return exec_script_main # The string for the Python executable we tell the Project file to use # is either sys.executable or, if an external PYTHON_ROOT environment # variable exists, $(PYTHON)ROOT\\python.exe (generalized a little to # pluck the actual executable name from sys.executable). -try: - python_root = os.environ['PYTHON_ROOT'] -except KeyError: - python_executable = sys.executable -else: - python_executable = os.path.join('$$(PYTHON_ROOT)', - os.path.split(sys.executable)[1]) + +def getPythonExecutable(env): + pyhead, pytail = os.path.split(sys.executable) + pyroot = env.get('PYTHON_ROOT') + if not pyroot: + pyroot = os.environ.get('PYTHON_ROOT') + if pyroot: + pyroot = '$$(PYTHON_ROOT)' + if not pyroot: + pyroot = pyhead + pyexe = os.path.join(pyroot, pytail) + return pyexe class Config: pass @@ -2147,7 +2181,7 @@ def generate(env) -> None: # MSVSSCONSFLAGS. This helps support consumers who use wrapper scripts to # invoke scons. if 'MSVSSCONS' not in env: - env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env)) + env['MSVSSCONS'] = '"%s" -c "%s"' % (getPythonExecutable(env), getExecScriptMain(env)) if 'MSVSSCONSFLAGS' not in env: env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.get_abspath()}" -f ${MSVSSCONSCRIPT.name}' diff --git a/test/MSVS/common-prefix.py b/test/MSVS/common-prefix.py index e8b47d19fa..22bb611f02 100644 --- a/test/MSVS/common-prefix.py +++ b/test/MSVS/common-prefix.py @@ -137,7 +137,7 @@ test.must_exist(test.workpath('work1', 'Test.vcproj')) vcproj = test.read(['work1', 'Test.vcproj'], 'r') expected_vcprojfile = vcproj_template % locals() -expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work1', 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '8.0', subdir='work1', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) @@ -163,7 +163,7 @@ test.must_exist(test.workpath('work2', 'Test.vcproj')) vcproj = test.read(['work2', 'Test.vcproj'], 'r') expected_vcprojfile = vcproj_template % locals() -expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work2', 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '8.0', subdir='work2', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/runfile.py b/test/MSVS/runfile.py index 14778e0b64..fc9e35b447 100644 --- a/test/MSVS/runfile.py +++ b/test/MSVS/runfile.py @@ -113,7 +113,7 @@ test.must_exist(test.workpath('work1', 'Test.vcproj')) vcproj = test.read(['work1', 'Test.vcproj'], 'r') -expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work1', 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '8.0', subdir='work1', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-6.0-clean.py b/test/MSVS/vs-6.0-clean.py index 28763971b7..6f6119920c 100644 --- a/test/MSVS/vs-6.0-clean.py +++ b/test/MSVS/vs-6.0-clean.py @@ -70,13 +70,13 @@ test.must_exist(test.workpath('Test.dsp')) dsp = test.read('Test.dsp', 'r') -expect = test.msvs_substitute(expected_dspfile, '6.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_dspfile, '6.0', sconscript='SConstruct') # don't compare the pickled data assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp) test.must_exist(test.workpath('Test.dsw')) dsw = test.read('Test.dsw', 'r') -expect = test.msvs_substitute(expected_dswfile, '6.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_dswfile, '6.0', sconscript='SConstruct') assert dsw == expect, test.diff_substr(expect, dsw) test.run(arguments='-c .') diff --git a/test/MSVS/vs-6.0-files.py b/test/MSVS/vs-6.0-files.py index 7a2c7c54f6..e5142b7493 100644 --- a/test/MSVS/vs-6.0-files.py +++ b/test/MSVS/vs-6.0-files.py @@ -48,13 +48,13 @@ test.must_exist(test.workpath('Test.dsp')) dsp = test.read('Test.dsp', 'r') -expect = test.msvs_substitute(expected_dspfile, '6.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_dspfile, '6.0', sconscript='SConstruct') # don't compare the pickled data assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp) test.must_exist(test.workpath('Test.dsw')) dsw = test.read('Test.dsw', 'r') -expect = test.msvs_substitute(expected_dswfile, '6.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_dswfile, '6.0', sconscript='SConstruct') assert dsw == expect, test.diff_substr(expect, dsw) test.run(arguments='-c .') diff --git a/test/MSVS/vs-6.0-variant_dir.py b/test/MSVS/vs-6.0-variant_dir.py index 90b6fa90b3..d945a32fac 100644 --- a/test/MSVS/vs-6.0-variant_dir.py +++ b/test/MSVS/vs-6.0-variant_dir.py @@ -54,14 +54,14 @@ test.run(arguments=".") dsp = test.read(['src', 'Test.dsp'], 'r') -expect = test.msvs_substitute(expected_dspfile, '6.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_dspfile, '6.0', sconscript='SConstruct') # don't compare the pickled data assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp) test.must_exist(test.workpath('src', 'Test.dsw')) dsw = test.read(['src', 'Test.dsw'], 'r') -expect = test.msvs_substitute(expected_dswfile, '6.0', 'src') -assert dsw == expect, test.diff_substr(expect, dsw) +expect = test.msvs_substitute(expected_dswfile, '6.0', subdir='src') +assert dsw == expect, test.diff_substr(expect, subdir=dsw) test.must_match(['build', 'Test.dsp'], """\ This is just a placeholder file. diff --git a/test/MSVS/vs-7.0-clean.py b/test/MSVS/vs-7.0-clean.py index 0eea6c3e0d..9fb2f95a82 100644 --- a/test/MSVS/vs-7.0-clean.py +++ b/test/MSVS/vs-7.0-clean.py @@ -71,13 +71,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.0-files.py b/test/MSVS/vs-7.0-files.py index 6049ae84bd..ebd05add63 100644 --- a/test/MSVS/vs-7.0-files.py +++ b/test/MSVS/vs-7.0-files.py @@ -49,13 +49,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) @@ -83,8 +83,7 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct', - python=python) +expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct', python=python) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-7.0-scc-files.py b/test/MSVS/vs-7.0-scc-files.py index 8730bf642e..5b19aed629 100644 --- a/test/MSVS/vs-7.0-scc-files.py +++ b/test/MSVS/vs-7.0-scc-files.py @@ -96,15 +96,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct', - vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct', - sln_sccinfo=expected_sln_sccinfo) +expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct', sln_sccinfo=expected_sln_sccinfo) # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.0-scc-legacy-files.py b/test/MSVS/vs-7.0-scc-legacy-files.py index 1e996ccc80..20a326574a 100644 --- a/test/MSVS/vs-7.0-scc-legacy-files.py +++ b/test/MSVS/vs-7.0-scc-legacy-files.py @@ -77,14 +77,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct', - vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.0-variant_dir.py b/test/MSVS/vs-7.0-variant_dir.py index df0511688d..2ecda28e78 100644 --- a/test/MSVS/vs-7.0-variant_dir.py +++ b/test/MSVS/vs-7.0-variant_dir.py @@ -52,13 +52,13 @@ test.run(arguments=".") vcproj = test.read(['src', 'Test.vcproj'], 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', 'Test.sln')) sln = test.read(['src', 'Test.sln'], 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', 'src') +expect = test.msvs_substitute(expected_slnfile, '7.0', subdir='src') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-clean.py b/test/MSVS/vs-7.1-clean.py index 207b710b45..07fe437362 100644 --- a/test/MSVS/vs-7.1-clean.py +++ b/test/MSVS/vs-7.1-clean.py @@ -71,13 +71,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-files.py b/test/MSVS/vs-7.1-files.py index ea06cc0096..55d93e3a6b 100644 --- a/test/MSVS/vs-7.1-files.py +++ b/test/MSVS/vs-7.1-files.py @@ -49,13 +49,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) @@ -83,8 +83,7 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct', - python=python) +expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct', python=python) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-7.1-scc-files.py b/test/MSVS/vs-7.1-scc-files.py index ac86f3f0fd..29001bd9e6 100644 --- a/test/MSVS/vs-7.1-scc-files.py +++ b/test/MSVS/vs-7.1-scc-files.py @@ -96,15 +96,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct', - vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct', - sln_sccinfo=expected_sln_sccinfo) +expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct', sln_sccinfo=expected_sln_sccinfo) # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-scc-legacy-files.py b/test/MSVS/vs-7.1-scc-legacy-files.py index bfcd91ba5c..d17e247ee4 100644 --- a/test/MSVS/vs-7.1-scc-legacy-files.py +++ b/test/MSVS/vs-7.1-scc-legacy-files.py @@ -77,14 +77,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct', - vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-variant_dir.py b/test/MSVS/vs-7.1-variant_dir.py index 2d6114bb78..02d2a15708 100644 --- a/test/MSVS/vs-7.1-variant_dir.py +++ b/test/MSVS/vs-7.1-variant_dir.py @@ -52,13 +52,13 @@ test.run(arguments=".") vcproj = test.read(['src', 'Test.vcproj'], 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', 'Test.sln')) sln = test.read(['src', 'Test.sln'], 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', 'src') +expect = test.msvs_substitute(expected_slnfile, '7.0', subdir='src') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-files.py b/test/MSVS/vs-files.py index 73eff8b401..7f084836b5 100644 --- a/test/MSVS/vs-files.py +++ b/test/MSVS/vs-files.py @@ -59,13 +59,13 @@ else: test.must_not_exist(test.workpath(filters_file)) vcxproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct') + expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct') # don't compare the pickled data assert vcxproj[:len(expect)] == expect, test.diff_substr(expect, vcxproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') - expect = test.msvs_substitute(expected_slnfile, vc_version, None, 'SConstruct') + expect = test.msvs_substitute(expected_slnfile, vc_version, sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) @@ -99,8 +99,7 @@ test.must_exist(test.workpath(project_file)) vcxproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct', - python=python) + expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct', python=python) # don't compare the pickled data assert vcxproj[:len(expect)] == expect, test.diff_substr(expect, vcxproj) diff --git a/test/MSVS/vs-mult-auto-guid.py b/test/MSVS/vs-mult-auto-guid.py index 59608bafa6..84737acfe8 100644 --- a/test/MSVS/vs-mult-auto-guid.py +++ b/test/MSVS/vs-mult-auto-guid.py @@ -115,13 +115,13 @@ test.must_exist(test.workpath(project_file_1)) vcproj = test.read(project_file_1, 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath(project_file_2)) vcproj = test.read(project_file_2, 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-auto-vardir-guid.py b/test/MSVS/vs-mult-auto-vardir-guid.py index 58a1fa2f4b..c5ae26becb 100644 --- a/test/MSVS/vs-mult-auto-vardir-guid.py +++ b/test/MSVS/vs-mult-auto-vardir-guid.py @@ -121,13 +121,13 @@ test.must_exist(test.workpath('src', project_file_1)) vcproj = test.read(['src', project_file_1], 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', project_file_2)) vcproj = test.read(['src', project_file_2], 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-auto-vardir.py b/test/MSVS/vs-mult-auto-vardir.py index b8e4a7b8cb..7b39524d78 100644 --- a/test/MSVS/vs-mult-auto-vardir.py +++ b/test/MSVS/vs-mult-auto-vardir.py @@ -116,13 +116,13 @@ test.must_exist(test.workpath('src', project_file_1)) vcproj = test.read(['src', project_file_1], 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', project_file_2)) vcproj = test.read(['src', project_file_2], 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-auto.py b/test/MSVS/vs-mult-auto.py index 0e87aaf5b5..55f95069c5 100644 --- a/test/MSVS/vs-mult-auto.py +++ b/test/MSVS/vs-mult-auto.py @@ -110,13 +110,13 @@ test.must_exist(test.workpath(project_file_1)) vcproj = test.read(project_file_1, 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath(project_file_2)) vcproj = test.read(project_file_2, 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-noauto-vardir.py b/test/MSVS/vs-mult-noauto-vardir.py index c6b313db53..c811cf1b45 100644 --- a/test/MSVS/vs-mult-noauto-vardir.py +++ b/test/MSVS/vs-mult-noauto-vardir.py @@ -87,13 +87,13 @@ test.must_exist(test.workpath('src', project_file_1)) vcproj = test.read(['src', project_file_1], 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', project_file_2)) vcproj = test.read(['src', project_file_2], 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-noauto.py b/test/MSVS/vs-mult-noauto.py index 1d458f2b77..af50c50313 100644 --- a/test/MSVS/vs-mult-noauto.py +++ b/test/MSVS/vs-mult-noauto.py @@ -81,13 +81,13 @@ test.must_exist(test.workpath(project_file_1)) vcproj = test.read(project_file_1, 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath(project_file_2)) vcproj = test.read(project_file_2, 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-scc-files.py b/test/MSVS/vs-scc-files.py index e0a7dc0437..c7ea96072b 100644 --- a/test/MSVS/vs-scc-files.py +++ b/test/MSVS/vs-scc-files.py @@ -111,15 +111,13 @@ test.must_exist(test.workpath(project_file)) vcproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct', - vcproj_sccinfo=expected_vcproj_sccinfo) + expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') - expect = test.msvs_substitute(expected_slnfile, vc_version, None, 'SConstruct', - sln_sccinfo=expected_sln_sccinfo) + expect = test.msvs_substitute(expected_slnfile, vc_version, sconscript='SConstruct', sln_sccinfo=expected_sln_sccinfo) # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-scc-legacy-files.py b/test/MSVS/vs-scc-legacy-files.py index d8150e1bb0..215b89d9d8 100644 --- a/test/MSVS/vs-scc-legacy-files.py +++ b/test/MSVS/vs-scc-legacy-files.py @@ -95,14 +95,13 @@ test.must_exist(test.workpath(project_file)) vcproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct', - vcproj_sccinfo=expected_vcproj_sccinfo) + expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') - expect = test.msvs_substitute(expected_slnfile, vc_version, None, 'SConstruct') + expect = test.msvs_substitute(expected_slnfile, vc_version, sconscript='SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-variant_dir.py b/test/MSVS/vs-variant_dir.py index 116d0c9674..751f36d6fc 100644 --- a/test/MSVS/vs-variant_dir.py +++ b/test/MSVS/vs-variant_dir.py @@ -60,13 +60,13 @@ test.run(arguments=".") vcproj = test.read(['src', project_file], 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct') + expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', 'Test.sln')) sln = test.read(['src', 'Test.sln'], 'r') - expect = test.msvs_substitute(expected_slnfile, '8.0', 'src') + expect = test.msvs_substitute(expected_slnfile, '8.0', subdir='src') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index 0c4b510d21..0412f9fde6 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -832,6 +832,48 @@ def get_tested_proj_file_vc_versions(): return ['8.0', '9.0', '10.0', '11.0', '12.0', '14.0', '14.1', '14.2', '14.3'] +_exec_script_main_template = None + +def get_exec_script_main(scons_home=None): + """ + Returns the python script string embedded in the msvs project files. + """ + global _exec_script_main_template + + scons_home = scons_home + os_scons_home = os.environ.get('SCONS_HOME') + os_scons_libdir = os.environ.get('SCONS_LIB_DIR') + + if _exec_script_main_template is None: + _exec_script_main_template = "; ".join([ + "from os.path import isdir, isfile, join", + "import os", + "import sys", + "sconslibs = lambda l: [p for p in l if p and isdir(p) and isfile(join(p, 'SCons', '__init__.py'))]", + "libspec = r'{scons_home}'", + "libspec = libspec if libspec else os.environ.get('SCONS_HOME', r'{os_scons_home}')", + "libspec = libspec if libspec else os.environ.get('SCONS_LIB_DIR', r'{os_scons_libdir}')", + "libs = [libspec] if libspec else sconslibs([r'{scons_genlib}'])", + "libs = libs if libs else sconslibs([join(sys.prefix, 'Lib', 'site-packages', 'scons-{scons_version}'), join(sys.prefix, 'scons-{scons_version}'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons'), join(sys.prefix, 'Lib', 'site-packages')])", + "sys.path = libs[:1] + sys.path if libs else sys.path", + # "print(f'libs = {{libs}}')", + # "print(f'sys.path = {{sys.path}}')", + "import SCons.Script", + "SCons.Script.main()", + ]) + + exec_script_main = _exec_script_main_template.format( + scons_home=os.path.abspath(scons_home) if scons_home else '', + os_scons_home=os.path.abspath(os_scons_home) if os_scons_home else '', + os_scons_libdir=os.path.abspath(os_scons_libdir) if os_scons_libdir else '', + scons_genlib=os.path.abspath(os.path.join(os.path.dirname(SCons.__file__), "..")), + scons_version=SCons.__version__, + ) + # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) + + return exec_script_main + + class TestSConsMSVS(TestSCons): """Subclass for testing MSVS-specific portions of SCons.""" @@ -875,12 +917,14 @@ def msvs_substitute( self, input, msvs_ver, + *, subdir=None, sconscript=None, python=None, project_guid=None, vcproj_sccinfo: str = '', sln_sccinfo: str = '', + scons_home=None, ): if not hasattr(self, '_msvs_versions'): self.msvs_versions() @@ -899,10 +943,7 @@ def msvs_substitute( if project_guid is None: project_guid = PROJECT_GUID - if 'SCONS_LIB_DIR' in os.environ: - exec_script_main = f"from os.path import join; import sys; sys.path = [ r'{os.environ['SCONS_LIB_DIR']}' ] + sys.path; import SCons.Script; SCons.Script.main()" - else: - exec_script_main = f"from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-{self.scons_version}'), join(sys.prefix, 'scons-{self.scons_version}'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" + exec_script_main = get_exec_script_main(scons_home=scons_home) exec_script_main_xml = exec_script_main.replace("'", "'") result = input.replace(r'', workpath) @@ -1149,6 +1190,7 @@ def msvs_substitute_projects( solution_guid_2=None, vcproj_sccinfo: str = '', sln_sccinfo: str = '', + scons_home=None, ): if not hasattr(self, '_msvs_versions'): self.msvs_versions() @@ -1176,10 +1218,7 @@ def msvs_substitute_projects( if solution_guid_2 is None: solution_guid_2 = SOLUTION_GUID_2 - if 'SCONS_LIB_DIR' in os.environ: - exec_script_main = f"from os.path import join; import sys; sys.path = [ r'{os.environ['SCONS_LIB_DIR']}' ] + sys.path; import SCons.Script; SCons.Script.main()" - else: - exec_script_main = f"from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-{self.scons_version}'), join(sys.prefix, 'scons-{self.scons_version}'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" + exec_script_main = get_exec_script_main(scons_home=scons_home) exec_script_main_xml = exec_script_main.replace("'", "'") result = input.replace(r'', workpath) From f7d7d2adde1888556ead6108846991e8b1987f7b Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Tue, 20 Jan 2026 17:00:03 -0500 Subject: [PATCH 2/9] MSVS: revise generation of the vcxproj embedded python script Changes: * Change SCons/Tool/msvs.py function comment before getExecScriptMain and replace with docstring. Taken from PR #4817. * Revert python executable code * Generate scons_home (user env, SCONS_HOME, or SCONS_LIB_DIR path specification) and scons_path (currently executing SCons module path) paths in unified script in SCons/Tool/msvs.py and testing/framework/TestSConsMSVS.py. Similar to the two code paths in PR #4817. * Set the SCONS_HOME variable in the testenv as is done with SCONS_LIB_DIR. Add SCONS_HOME to testing/framework/TestSConsMSVS.py. --- SCons/Tool/msvs.py | 84 ++++++++++++++---------------- runtest.py | 1 + testing/framework/TestSConsMSVS.py | 39 ++++++-------- 3 files changed, 56 insertions(+), 68 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index aaf02e5a0a..73727e39df 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -36,6 +36,7 @@ import pickle import re import sys +import textwrap import SCons.Builder import SCons.Node.FS @@ -152,50 +153,46 @@ def msvs_parse_version(s): num, suite = version_re.match(s).groups() return float(num), suite -# This is how we re-invoke SCons from inside MSVS Project files. -# The problem is that we might have been invoked as either scons.bat -# or scons.py. If we were invoked directly as scons.py, then we could -# use sys.argv[0] to find the SCons "executable," but that doesn't work -# if we were invoked as scons.bat, which uses "python -c" to execute -# things and ends up with "-c" as sys.argv[0]. Consequently, we have -# the MSVS Project file invoke SCons the same way that scons.bat does, -# which works regardless of how we were invoked. _exec_script_main_template = None def getExecScriptMain(env, xml=None): + """ + This is how we re-invoke SCons from inside MSVS Project files. + The problem is that we might have been invoked as either scons.bat + or scons.py. If we were invoked directly as scons.py, then we could + use sys.argv[0] to find the SCons "executable," but that doesn't work + if we were invoked as scons.bat, which uses "python -c" to execute + things and ends up with "-c" as sys.argv[0]. Consequently, we have + the MSVS Project file invoke SCons the same way that scons.bat does, + which works regardless of how we were invoked. + + :param env: Environment to operate on + :param xml: Extra XML to add to generated MSVS project file + """ global _exec_script_main_template - scons_home = env.get('SCONS_HOME') - os_scons_home = os.environ.get('SCONS_HOME') - os_scons_libdir = os.environ.get('SCONS_LIB_DIR') - if 'SCONS_HOME' not in env: - env['SCONS_HOME'] = os_scons_home + env['SCONS_HOME'] = os.environ.get('SCONS_HOME') + scons_home = env.get('SCONS_HOME') + if not scons_home and 'SCONS_LIB_DIR' in os.environ: + scons_home = os.environ['SCONS_LIB_DIR'] if _exec_script_main_template is None: - _exec_script_main_template = "; ".join([ - "from os.path import isdir, isfile, join", - "import os", - "import sys", - "sconslibs = lambda l: [p for p in l if p and isdir(p) and isfile(join(p, 'SCons', '__init__.py'))]", - "libspec = r'{scons_home}'", - "libspec = libspec if libspec else os.environ.get('SCONS_HOME', r'{os_scons_home}')", - "libspec = libspec if libspec else os.environ.get('SCONS_LIB_DIR', r'{os_scons_libdir}')", - "libs = [libspec] if libspec else sconslibs([r'{scons_genlib}'])", - "libs = libs if libs else sconslibs([join(sys.prefix, 'Lib', 'site-packages', 'scons-{scons_version}'), join(sys.prefix, 'scons-{scons_version}'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons'), join(sys.prefix, 'Lib', 'site-packages')])", - "sys.path = libs[:1] + sys.path if libs else sys.path", - # "print(f'libs = {{libs}}')", - # "print(f'sys.path = {{sys.path}}')", - "import SCons.Script", - "SCons.Script.main()", - ]) + _exec_script_main_template = "; ".join(textwrap.dedent( + """\ + import sys + scons_home = r'{scons_home}' + scons_path = r'{scons_path}' + scons_spec = scons_home if scons_home else scons_path + sys.path = [scons_spec] + sys.path + import SCons.Script + SCons.Script.main() + """ + ).splitlines()) exec_script_main = _exec_script_main_template.format( scons_home=os.path.abspath(scons_home) if scons_home else '', - os_scons_home=os.path.abspath(os_scons_home) if os_scons_home else '', - os_scons_libdir=os.path.abspath(os_scons_libdir) if os_scons_libdir else '', - scons_genlib=os.path.abspath(os.path.join(os.path.dirname(SCons.__file__), "..")), - scons_version=SCons.__version__, + scons_path=os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))), ) # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) @@ -208,18 +205,13 @@ def getExecScriptMain(env, xml=None): # is either sys.executable or, if an external PYTHON_ROOT environment # variable exists, $(PYTHON)ROOT\\python.exe (generalized a little to # pluck the actual executable name from sys.executable). - -def getPythonExecutable(env): - pyhead, pytail = os.path.split(sys.executable) - pyroot = env.get('PYTHON_ROOT') - if not pyroot: - pyroot = os.environ.get('PYTHON_ROOT') - if pyroot: - pyroot = '$$(PYTHON_ROOT)' - if not pyroot: - pyroot = pyhead - pyexe = os.path.join(pyroot, pytail) - return pyexe +try: + python_root = os.environ['PYTHON_ROOT'] +except KeyError: + python_executable = sys.executable +else: + python_executable = os.path.join('$$(PYTHON_ROOT)', + os.path.split(sys.executable)[1]) class Config: pass @@ -2181,7 +2173,7 @@ def generate(env) -> None: # MSVSSCONSFLAGS. This helps support consumers who use wrapper scripts to # invoke scons. if 'MSVSSCONS' not in env: - env['MSVSSCONS'] = '"%s" -c "%s"' % (getPythonExecutable(env), getExecScriptMain(env)) + env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env)) if 'MSVSSCONSFLAGS' not in env: env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.get_abspath()}" -f ${MSVSSCONSCRIPT.name}' diff --git a/runtest.py b/runtest.py index 1688e18e06..ee264ecacd 100755 --- a/runtest.py +++ b/runtest.py @@ -540,6 +540,7 @@ def footer(self, f): # Because SCons is really aggressive about finding its modules, # it sometimes finds SCons modules elsewhere on the system. # This forces SCons to use the modules that are being tested. + testenv['SCONS_HOME'] = scons_lib_dir testenv['SCONS_LIB_DIR'] = scons_lib_dir if args.scons_exec: diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index 0412f9fde6..d54234044f 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -38,6 +38,7 @@ import os import sys import platform +import textwrap import traceback from xml.etree import ElementTree @@ -841,33 +842,27 @@ def get_exec_script_main(scons_home=None): global _exec_script_main_template scons_home = scons_home - os_scons_home = os.environ.get('SCONS_HOME') - os_scons_libdir = os.environ.get('SCONS_LIB_DIR') + if not scons_home and 'SCONS_HOME' in os.environ: + scons_home = os.environ['SCONS_HOME'] + if not scons_home and 'SCONS_LIB_DIR' in os.environ: + scons_home = os.environ['SCONS_LIB_DIR'] if _exec_script_main_template is None: - _exec_script_main_template = "; ".join([ - "from os.path import isdir, isfile, join", - "import os", - "import sys", - "sconslibs = lambda l: [p for p in l if p and isdir(p) and isfile(join(p, 'SCons', '__init__.py'))]", - "libspec = r'{scons_home}'", - "libspec = libspec if libspec else os.environ.get('SCONS_HOME', r'{os_scons_home}')", - "libspec = libspec if libspec else os.environ.get('SCONS_LIB_DIR', r'{os_scons_libdir}')", - "libs = [libspec] if libspec else sconslibs([r'{scons_genlib}'])", - "libs = libs if libs else sconslibs([join(sys.prefix, 'Lib', 'site-packages', 'scons-{scons_version}'), join(sys.prefix, 'scons-{scons_version}'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons'), join(sys.prefix, 'Lib', 'site-packages')])", - "sys.path = libs[:1] + sys.path if libs else sys.path", - # "print(f'libs = {{libs}}')", - # "print(f'sys.path = {{sys.path}}')", - "import SCons.Script", - "SCons.Script.main()", - ]) + _exec_script_main_template = "; ".join(textwrap.dedent( + """\ + import sys + scons_home = r'{scons_home}' + scons_path = r'{scons_path}' + scons_spec = scons_home if scons_home else scons_path + sys.path = [scons_spec] + sys.path + import SCons.Script + SCons.Script.main() + """ + ).splitlines()) exec_script_main = _exec_script_main_template.format( scons_home=os.path.abspath(scons_home) if scons_home else '', - os_scons_home=os.path.abspath(os_scons_home) if os_scons_home else '', - os_scons_libdir=os.path.abspath(os_scons_libdir) if os_scons_libdir else '', - scons_genlib=os.path.abspath(os.path.join(os.path.dirname(SCons.__file__), "..")), - scons_version=SCons.__version__, + scons_path=os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))), ) # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) From 3e2769723e69b308fb9d50d754daa3a68b41e794 Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Wed, 21 Jan 2026 04:02:35 -0500 Subject: [PATCH 3/9] MSVS: revise the vcxproj embedded python script contents Changes: * Add check that the generated path contains SCons. * Add the generated path to the python system path only when it contains SCons. * Print an alert message when the generated path does not contain SCons. * Print an alert message when the generated path does not contain SCons and SCons was found on python system path. --- SCons/Tool/msvs.py | 6 +++++- testing/framework/TestSConsMSVS.py | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index 73727e39df..b628e20e68 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -180,12 +180,16 @@ def getExecScriptMain(env, xml=None): if _exec_script_main_template is None: _exec_script_main_template = "; ".join(textwrap.dedent( """\ + import os.path import sys scons_home = r'{scons_home}' scons_path = r'{scons_path}' scons_spec = scons_home if scons_home else scons_path - sys.path = [scons_spec] + sys.path + have_scons = bool(scons_spec and os.path.isdir(scons_spec) and os.path.isfile(os.path.join(scons_spec, 'SCons', '__init__.py'))) + sys.path = [scons_spec] + sys.path if have_scons else sys.path + _ = None if have_scons else print(f'python: *** ATTENTION: SCons was not found at the generated path location (\\\'{{scons_spec}}\\\'). ***') import SCons.Script + _ = None if have_scons else print(f'python: *** ATTENTION: SCons was found on the python system path (\\\'{{os.path.dirname(os.path.dirname(SCons.__file__))}}\\\'). ***') SCons.Script.main() """ ).splitlines()) diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index d54234044f..60ad53c898 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -850,12 +850,16 @@ def get_exec_script_main(scons_home=None): if _exec_script_main_template is None: _exec_script_main_template = "; ".join(textwrap.dedent( """\ + import os.path import sys scons_home = r'{scons_home}' scons_path = r'{scons_path}' scons_spec = scons_home if scons_home else scons_path - sys.path = [scons_spec] + sys.path + have_scons = bool(scons_spec and os.path.isdir(scons_spec) and os.path.isfile(os.path.join(scons_spec, 'SCons', '__init__.py'))) + sys.path = [scons_spec] + sys.path if have_scons else sys.path + _ = None if have_scons else print(f'python: *** ATTENTION: SCons was not found at the generated path location (\\\'{{scons_spec}}\\\'). ***') import SCons.Script + _ = None if have_scons else print(f'python: *** ATTENTION: SCons was found on the python system path (\\\'{{os.path.dirname(os.path.dirname(SCons.__file__))}}\\\'). ***') SCons.Script.main() """ ).splitlines()) From 0a5ba77e954327d669e30c8480c9b0ab8f4eadab Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Sat, 24 Jan 2026 15:58:28 -0500 Subject: [PATCH 4/9] MSVS: revise the vcxproj embedded python script contents Changes: * Suppress generating the currently executing SCons module path if SCons appears to be installed as a python library (i.e., in the python installation tree). * Modify the candidate evaluation priority similar to the current master code and add a new code path when using an out-of-python-tree SCons installation. * The modified evaluation order is: 1. If scons_home is defined: * Record scons_home as found iff the path contains SCons. * Stop evaluating remaining alternatives. 2. If scons_abspath is defined: * Record scons_abspath as found iff the path contains SCons. * Stop evaluating remaining alternatives. 3. Evaluate known library locations: * Record the first library path that contains SCons as found. * Use importlib to find the SCons module path prior to import. * Add a valid module spec origin path to the front of the sys.path list if: * a module path was not found earlier, or * the module spec origin path is different than the module path found earlier. * Refine diagnostic messaging. --- SCons/Tool/msvs.py | 101 +++++++++++++++++++++++++---- testing/framework/TestSConsMSVS.py | 60 +++++++++++++---- 2 files changed, 137 insertions(+), 24 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index b628e20e68..7a352d0363 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -177,26 +177,101 @@ def getExecScriptMain(env, xml=None): if not scons_home and 'SCONS_LIB_DIR' in os.environ: scons_home = os.environ['SCONS_LIB_DIR'] + if scons_home is None: + scons_home = '' + + scons_abspath = os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))) + + def _in_pytree(scons_abspath): + scons_norm = os.path.normcase(scons_abspath) + for py_prefix in [sys.prefix]: # sys.exec_prefix also on windows? + py_norm = os.path.normcase(os.path.abspath(py_prefix)) + try: + common = os.path.commonpath([py_norm, scons_norm]) + if common == py_norm: + return True + break + except ValueError: + pass + return False + + in_pytree = _in_pytree(scons_abspath) + # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}', sys.exec_prefix='{sys.exec_prefix}'") + + if in_pytree: + scons_abspath = '' + if _exec_script_main_template is None: - _exec_script_main_template = "; ".join(textwrap.dedent( + _exec_script_main_template = "; ".join([line for block in [textwrap.dedent(s).splitlines() for s in [ + # Import libraries and functions. """\ - import os.path + import importlib.util import sys - scons_home = r'{scons_home}' - scons_path = r'{scons_path}' - scons_spec = scons_home if scons_home else scons_path - have_scons = bool(scons_spec and os.path.isdir(scons_spec) and os.path.isfile(os.path.join(scons_spec, 'SCons', '__init__.py'))) - sys.path = [scons_spec] + sys.path if have_scons else sys.path - _ = None if have_scons else print(f'python: *** ATTENTION: SCons was not found at the generated path location (\\\'{{scons_spec}}\\\'). ***') + from os.path import abspath, dirname, isdir, isfile, join, normcase, realpath + """, + # Initialize the generated paths: + # * convert scons_home to an absolute path, + # * clear scons_abspath when equal to the scons_home absolute path. + """\ + usrinit = lambda p: abspath(p) if p else p + geninit = lambda p, u: '' if (p and u and normcase(p) == normcase(u)) else p + usr_path = usrinit(r'{scons_home}') + gen_path = geninit(r'{scons_abspath}', usr_path) + """, + # Evaluate candidate lists: + # 1. If scons_home is defined: + # * Record scons_home as found iff the path contains SCons. + # * Stop evaluating remaining alternatives. + # 2. If scons_abspath is defined: + # * Record scons_abspath as found iff the path contains SCons. + # * Stop evaluating remaining alternatives. + # 3. Evaluate known library locations: + # * Record the first library path that contains SCons as found. + """\ + state = {{}} + isvalid = lambda p: p and isdir(p) and isfile(join(p, 'SCons', '__init__.py')) + store = lambda k, l, s: {{k: l[0], 'Found': l[0], 'Stop': True}} if l else {{k: '', 'Stop': s}} + check = lambda k, l, s: state.update(store(k, [p for p in l if isvalid(p)], s)) if not state.get('Stop') else None + _ = [check(k, l, s) for k, l, s in [('usr', [usr_path], bool(usr_path)), ('gen', [gen_path], bool(gen_path)), ('lib', [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]], False)]] + """, + # If an SCons module path was found, add the path to the front of + # the sys.path list. + """\ + path = state.get('Found', '') + _ = sys.path.insert(0, path) if path else None + """, + # Use importlib to find the SCons module path prior to import. + # Add a valid module spec origin path to the front of the sys.path list if: + # * a module path was not found earlier, or + # * the module spec origin path is different than the module + # path found earlier. + """\ + spec = importlib.util.find_spec('SCons') + orig = dirname(dirname(abspath(spec.origin))) if (spec and spec.origin) else '' + syspath = orig and (not path or normcase(abspath(path)) != normcase(orig)) + _ = sys.path.insert(0, orig) if syspath else None + """, + # Display diagnostic messages. + """\ + _ = print(f'proj: *** SCons not found at user path \\\'{{usr_path}}\\\'. ***') if (usr_path and state.get('usr') == '') else None + _ = print(f'proj: *** SCons not found at generated path \\\'{{gen_path}}\\\' ***.') if (gen_path and state.get('gen') == '') else None + _ = print( 'proj: *** SCons not found. ***') if (not orig) else None + """, + # Display SCons module path (if found). + """\ + _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\', syspath={{syspath}}).') if (orig) else None + """, + # Import SCons and run main script. + """\ import SCons.Script - _ = None if have_scons else print(f'python: *** ATTENTION: SCons was found on the python system path (\\\'{{os.path.dirname(os.path.dirname(SCons.__file__))}}\\\'). ***') SCons.Script.main() - """ - ).splitlines()) + """, + ]] for line in block]) exec_script_main = _exec_script_main_template.format( - scons_home=os.path.abspath(scons_home) if scons_home else '', - scons_path=os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))), + scons_home=scons_home, + scons_abspath=scons_abspath, + scons_version=SCons.__version__, ) # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index 60ad53c898..c201dc1c20 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -847,26 +847,64 @@ def get_exec_script_main(scons_home=None): if not scons_home and 'SCONS_LIB_DIR' in os.environ: scons_home = os.environ['SCONS_LIB_DIR'] + if scons_home is None: + scons_home = '' + + scons_abspath = os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))) + + def _in_pytree(scons_abspath): + scons_norm = os.path.normcase(scons_abspath) + for py_prefix in [sys.prefix]: # sys.exec_prefix also on windows? + py_norm = os.path.normcase(os.path.abspath(py_prefix)) + try: + common = os.path.commonpath([py_norm, scons_norm]) + if common == py_norm: + return True + break + except ValueError: + pass + return False + + in_pytree = _in_pytree(scons_abspath) + # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}', sys.exec_prefix='{sys.exec_prefix}'") + + if in_pytree: + scons_abspath = '' + if _exec_script_main_template is None: _exec_script_main_template = "; ".join(textwrap.dedent( """\ - import os.path + import importlib.util import sys - scons_home = r'{scons_home}' - scons_path = r'{scons_path}' - scons_spec = scons_home if scons_home else scons_path - have_scons = bool(scons_spec and os.path.isdir(scons_spec) and os.path.isfile(os.path.join(scons_spec, 'SCons', '__init__.py'))) - sys.path = [scons_spec] + sys.path if have_scons else sys.path - _ = None if have_scons else print(f'python: *** ATTENTION: SCons was not found at the generated path location (\\\'{{scons_spec}}\\\'). ***') + from os.path import abspath, dirname, isdir, isfile, join, normcase, realpath + usrinit = lambda p: abspath(p) if p else p + geninit = lambda p, u: '' if (p and u and normcase(p) == normcase(u)) else p + usr_path = usrinit(r'{scons_home}') + gen_path = geninit(r'{scons_abspath}', usr_path) + state = {{}} + isvalid = lambda p: p and isdir(p) and isfile(join(p, 'SCons', '__init__.py')) + store = lambda k, l, s: {{k: l[0], 'Found': l[0], 'Stop': True}} if l else {{k: '', 'Stop': s}} + check = lambda k, l, s: state.update(store(k, [p for p in l if isvalid(p)], s)) if not state.get('Stop') else None + _ = [check(k, l, s) for k, l, s in [('usr', [usr_path], bool(usr_path)), ('gen', [gen_path], bool(gen_path)), ('lib', [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]], False)]] + path = state.get('Found', '') + _ = sys.path.insert(0, path) if path else None + spec = importlib.util.find_spec('SCons') + orig = dirname(dirname(abspath(spec.origin))) if (spec and spec.origin) else '' + syspath = orig and (not path or normcase(abspath(path)) != normcase(orig)) + _ = sys.path.insert(0, orig) if syspath else None + _ = print(f'proj: *** SCons not found at user path \\\'{{usr_path}}\\\'. ***') if (usr_path and state.get('usr') == '') else None + _ = print(f'proj: *** SCons not found at generated path \\\'{{gen_path}}\\\' ***.') if (gen_path and state.get('gen') == '') else None + _ = print( 'proj: *** SCons not found. ***') if (not orig) else None + _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\', syspath={{syspath}}).') if (orig) else None import SCons.Script - _ = None if have_scons else print(f'python: *** ATTENTION: SCons was found on the python system path (\\\'{{os.path.dirname(os.path.dirname(SCons.__file__))}}\\\'). ***') SCons.Script.main() - """ + """, ).splitlines()) exec_script_main = _exec_script_main_template.format( - scons_home=os.path.abspath(scons_home) if scons_home else '', - scons_path=os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))), + scons_home=scons_home, + scons_abspath=scons_abspath, + scons_version=SCons.__version__, ) # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) From b2170a1f290d54009dba4086ac9b556ee345d198 Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Mon, 26 Jan 2026 13:32:35 -0500 Subject: [PATCH 5/9] MSVS: revise the vcxproj embedded python script contents Changes: * Revert setting SCONS_HOME in the testenv in runtest.py. * Simplify the generated embedded python script. * Simplified evaluation order: 1. If scons_home is defined: * If SCons is not found using scons_home, display an error message and exit the embedded python script 2. If scons_abspath is defined: * If SCons is not found using scons_abspath, display an error message and exit the embedded python script 3. Evaluate local library locations plus the python system path: * If SCons is not found using the extended python system path, display an error message and exit the embedded python script 4. Add the found SCons path to the front of the python system path 5. Display the SCons path 6. Import and run SCons/Tool/msvs.py --- SCons/Tool/msvs.py | 79 +++++------------------------- runtest.py | 1 - testing/framework/TestSConsMSVS.py | 46 +++++++---------- 3 files changed, 30 insertions(+), 96 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index 7a352d0363..c1b6bf93bd 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -177,9 +177,6 @@ def getExecScriptMain(env, xml=None): if not scons_home and 'SCONS_LIB_DIR' in os.environ: scons_home = os.environ['SCONS_LIB_DIR'] - if scons_home is None: - scons_home = '' - scons_abspath = os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))) def _in_pytree(scons_abspath): @@ -198,79 +195,29 @@ def _in_pytree(scons_abspath): in_pytree = _in_pytree(scons_abspath) # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}', sys.exec_prefix='{sys.exec_prefix}'") - if in_pytree: - scons_abspath = '' - if _exec_script_main_template is None: - _exec_script_main_template = "; ".join([line for block in [textwrap.dedent(s).splitlines() for s in [ - # Import libraries and functions. + _exec_script_main_template = "; ".join(textwrap.dedent( """\ import importlib.util import sys - from os.path import abspath, dirname, isdir, isfile, join, normcase, realpath - """, - # Initialize the generated paths: - # * convert scons_home to an absolute path, - # * clear scons_abspath when equal to the scons_home absolute path. - """\ - usrinit = lambda p: abspath(p) if p else p - geninit = lambda p, u: '' if (p and u and normcase(p) == normcase(u)) else p - usr_path = usrinit(r'{scons_home}') - gen_path = geninit(r'{scons_abspath}', usr_path) - """, - # Evaluate candidate lists: - # 1. If scons_home is defined: - # * Record scons_home as found iff the path contains SCons. - # * Stop evaluating remaining alternatives. - # 2. If scons_abspath is defined: - # * Record scons_abspath as found iff the path contains SCons. - # * Stop evaluating remaining alternatives. - # 3. Evaluate known library locations: - # * Record the first library path that contains SCons as found. - """\ - state = {{}} - isvalid = lambda p: p and isdir(p) and isfile(join(p, 'SCons', '__init__.py')) - store = lambda k, l, s: {{k: l[0], 'Found': l[0], 'Stop': True}} if l else {{k: '', 'Stop': s}} - check = lambda k, l, s: state.update(store(k, [p for p in l if isvalid(p)], s)) if not state.get('Stop') else None - _ = [check(k, l, s) for k, l, s in [('usr', [usr_path], bool(usr_path)), ('gen', [gen_path], bool(gen_path)), ('lib', [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]], False)]] - """, - # If an SCons module path was found, add the path to the front of - # the sys.path list. - """\ - path = state.get('Found', '') - _ = sys.path.insert(0, path) if path else None - """, - # Use importlib to find the SCons module path prior to import. - # Add a valid module spec origin path to the front of the sys.path list if: - # * a module path was not found earlier, or - # * the module spec origin path is different than the module - # path found earlier. - """\ + from os.path import abspath, dirname, isdir, isfile, join, realpath + usr_path = r'{scons_home}' + gen_path = r'{scons_abspath}' + syspath = sys.path + search, path = ([usr_path], usr_path) if usr_path else ([gen_path], gen_path) if gen_path else ([join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + sys.path, None) + sys.path = search spec = importlib.util.find_spec('SCons') orig = dirname(dirname(abspath(spec.origin))) if (spec and spec.origin) else '' - syspath = orig and (not path or normcase(abspath(path)) != normcase(orig)) - _ = sys.path.insert(0, orig) if syspath else None - """, - # Display diagnostic messages. - """\ - _ = print(f'proj: *** SCons not found at user path \\\'{{usr_path}}\\\'. ***') if (usr_path and state.get('usr') == '') else None - _ = print(f'proj: *** SCons not found at generated path \\\'{{gen_path}}\\\' ***.') if (gen_path and state.get('gen') == '') else None - _ = print( 'proj: *** SCons not found. ***') if (not orig) else None - """, - # Display SCons module path (if found). - """\ - _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\', syspath={{syspath}}).') if (orig) else None - """, - # Import SCons and run main script. - """\ + sys.path = [orig] + syspath if orig else syspath + _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\').') if orig else (print(f'proj: Error: SCons not found (path=\\\'{{path if path else search}}\\\').'), sys.exit(1)) import SCons.Script SCons.Script.main() - """, - ]] for line in block]) + """ + ).splitlines()) exec_script_main = _exec_script_main_template.format( - scons_home=scons_home, - scons_abspath=scons_abspath, + scons_home=scons_home if scons_home else '', + scons_abspath=scons_abspath if not in_pytree else '', scons_version=SCons.__version__, ) # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) diff --git a/runtest.py b/runtest.py index ee264ecacd..1688e18e06 100755 --- a/runtest.py +++ b/runtest.py @@ -540,7 +540,6 @@ def footer(self, f): # Because SCons is really aggressive about finding its modules, # it sometimes finds SCons modules elsewhere on the system. # This forces SCons to use the modules that are being tested. - testenv['SCONS_HOME'] = scons_lib_dir testenv['SCONS_LIB_DIR'] = scons_lib_dir if args.scons_exec: diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index c201dc1c20..f7f0fe6b8c 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -842,14 +842,15 @@ def get_exec_script_main(scons_home=None): global _exec_script_main_template scons_home = scons_home - if not scons_home and 'SCONS_HOME' in os.environ: - scons_home = os.environ['SCONS_HOME'] + # Some tests may fail if SCONS_HOME is defined in the os environment when + # the tests are run. The SCons location set in the user's os environment + # may point to a different SCons than the SCons currently being tested. + # This behavior is consistent with the main branch code at the time. + # if not scons_home and 'SCONS_HOME' in os.environ: + # scons_home = os.environ['SCONS_HOME'] if not scons_home and 'SCONS_LIB_DIR' in os.environ: scons_home = os.environ['SCONS_LIB_DIR'] - if scons_home is None: - scons_home = '' - scons_abspath = os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))) def _in_pytree(scons_abspath): @@ -868,42 +869,29 @@ def _in_pytree(scons_abspath): in_pytree = _in_pytree(scons_abspath) # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}', sys.exec_prefix='{sys.exec_prefix}'") - if in_pytree: - scons_abspath = '' - if _exec_script_main_template is None: _exec_script_main_template = "; ".join(textwrap.dedent( """\ import importlib.util import sys - from os.path import abspath, dirname, isdir, isfile, join, normcase, realpath - usrinit = lambda p: abspath(p) if p else p - geninit = lambda p, u: '' if (p and u and normcase(p) == normcase(u)) else p - usr_path = usrinit(r'{scons_home}') - gen_path = geninit(r'{scons_abspath}', usr_path) - state = {{}} - isvalid = lambda p: p and isdir(p) and isfile(join(p, 'SCons', '__init__.py')) - store = lambda k, l, s: {{k: l[0], 'Found': l[0], 'Stop': True}} if l else {{k: '', 'Stop': s}} - check = lambda k, l, s: state.update(store(k, [p for p in l if isvalid(p)], s)) if not state.get('Stop') else None - _ = [check(k, l, s) for k, l, s in [('usr', [usr_path], bool(usr_path)), ('gen', [gen_path], bool(gen_path)), ('lib', [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]], False)]] - path = state.get('Found', '') - _ = sys.path.insert(0, path) if path else None + from os.path import abspath, dirname, isdir, isfile, join, realpath + usr_path = r'{scons_home}' + gen_path = r'{scons_abspath}' + syspath = sys.path + search, path = ([usr_path], usr_path) if usr_path else ([gen_path], gen_path) if gen_path else ([join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + sys.path, None) + sys.path = search spec = importlib.util.find_spec('SCons') orig = dirname(dirname(abspath(spec.origin))) if (spec and spec.origin) else '' - syspath = orig and (not path or normcase(abspath(path)) != normcase(orig)) - _ = sys.path.insert(0, orig) if syspath else None - _ = print(f'proj: *** SCons not found at user path \\\'{{usr_path}}\\\'. ***') if (usr_path and state.get('usr') == '') else None - _ = print(f'proj: *** SCons not found at generated path \\\'{{gen_path}}\\\' ***.') if (gen_path and state.get('gen') == '') else None - _ = print( 'proj: *** SCons not found. ***') if (not orig) else None - _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\', syspath={{syspath}}).') if (orig) else None + sys.path = [orig] + syspath if orig else syspath + _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\').') if orig else (print(f'proj: Error: SCons not found (path=\\\'{{path if path else search}}\\\').'), sys.exit(1)) import SCons.Script SCons.Script.main() - """, + """ ).splitlines()) exec_script_main = _exec_script_main_template.format( - scons_home=scons_home, - scons_abspath=scons_abspath, + scons_home=scons_home if scons_home else '', + scons_abspath=scons_abspath if not in_pytree else '', scons_version=SCons.__version__, ) # print("exec_script_main:\n", ' ' + '\n '.join(exec_script_main.split("; "))) From b6a2b51d186daf62d89ec59d4ceaaf1228cbe232 Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Thu, 29 Jan 2026 14:09:51 -0500 Subject: [PATCH 6/9] MSVS: revise the vcxproj embedded python script contents to be backward compatible with current master Changes: * Determine the SCons module path in the same manner as the current master code. * Adjust the SCons module path using the generated path location under certain conditions. --- SCons/Tool/msvs.py | 40 +++++++++++++------------- testing/framework/TestSConsMSVS.py | 46 +++++++++++++++--------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index c1b6bf93bd..b2e7382ff3 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -33,6 +33,7 @@ import uuid import ntpath import os +import pathlib import pickle import re import sys @@ -180,36 +181,35 @@ def getExecScriptMain(env, xml=None): scons_abspath = os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))) def _in_pytree(scons_abspath): - scons_norm = os.path.normcase(scons_abspath) - for py_prefix in [sys.prefix]: # sys.exec_prefix also on windows? - py_norm = os.path.normcase(os.path.abspath(py_prefix)) - try: - common = os.path.commonpath([py_norm, scons_norm]) - if common == py_norm: - return True - break - except ValueError: - pass - return False + py_comps = pathlib.Path(os.path.normcase(os.path.abspath(sys.prefix))).parts + comps = pathlib.Path(os.path.normcase(scons_abspath)).parts + rval = bool(comps[:len(py_comps)] == py_comps) + return rval in_pytree = _in_pytree(scons_abspath) - # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}', sys.exec_prefix='{sys.exec_prefix}'") + # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}'") if _exec_script_main_template is None: _exec_script_main_template = "; ".join(textwrap.dedent( """\ import importlib.util import sys - from os.path import abspath, dirname, isdir, isfile, join, realpath + from os.path import abspath, dirname, join, normcase, realpath + from pathlib import Path usr_path = r'{scons_home}' gen_path = r'{scons_abspath}' - syspath = sys.path - search, path = ([usr_path], usr_path) if usr_path else ([gen_path], gen_path) if gen_path else ([join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + sys.path, None) - sys.path = search - spec = importlib.util.find_spec('SCons') - orig = dirname(dirname(abspath(spec.origin))) if (spec and spec.origin) else '' - sys.path = [orig] + syspath if orig else syspath - _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\').') if orig else (print(f'proj: Error: SCons not found (path=\\\'{{path if path else search}}\\\').'), sys.exit(1)) + syspath = list(sys.path) + memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} + origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] + pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False + search = ([usr_path] + syspath if usr_path else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) + begpath = origin(search) + user = begpath and usr_path and normcase(begpath) == normcase(abspath(usr_path)) + endpath = (search.insert(0, gen_path), origin([gen_path]))[-1] if (not user and gen_path and (not begpath or pytree(begpath))) else '' + path = endpath if endpath else begpath + _ = (print(f'proj: Error: SCons not found (path=\\\'{{search}}\\\').'), sys.exit(1)) if (not path) else None + sys.path = [path] + syspath + print(f'proj: Using SCons path \\\'{{path}}\\\' (realpath=\\\'{{realpath(path)}}\\\').') import SCons.Script SCons.Script.main() """ diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index f7f0fe6b8c..aec9c86b2f 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -37,6 +37,7 @@ import os import sys +import pathlib import platform import textwrap import traceback @@ -835,7 +836,7 @@ def get_tested_proj_file_vc_versions(): _exec_script_main_template = None -def get_exec_script_main(scons_home=None): +def get_exec_script_main(scons_home=''): """ Returns the python script string embedded in the msvs project files. """ @@ -854,36 +855,35 @@ def get_exec_script_main(scons_home=None): scons_abspath = os.path.abspath(os.path.dirname(os.path.dirname(SCons.__file__))) def _in_pytree(scons_abspath): - scons_norm = os.path.normcase(scons_abspath) - for py_prefix in [sys.prefix]: # sys.exec_prefix also on windows? - py_norm = os.path.normcase(os.path.abspath(py_prefix)) - try: - common = os.path.commonpath([py_norm, scons_norm]) - if common == py_norm: - return True - break - except ValueError: - pass - return False + py_comps = pathlib.Path(os.path.normcase(os.path.abspath(sys.prefix))).parts + comps = pathlib.Path(os.path.normcase(scons_abspath)).parts + rval = bool(comps[:len(py_comps)] == py_comps) + return rval in_pytree = _in_pytree(scons_abspath) - # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}', sys.exec_prefix='{sys.exec_prefix}'") + # print(f"in_pytree={in_pytree}, scons_abspath=`{scons_abspath}', sys.prefix='{sys.prefix}'") if _exec_script_main_template is None: _exec_script_main_template = "; ".join(textwrap.dedent( """\ import importlib.util import sys - from os.path import abspath, dirname, isdir, isfile, join, realpath + from os.path import abspath, dirname, join, normcase, realpath + from pathlib import Path usr_path = r'{scons_home}' gen_path = r'{scons_abspath}' - syspath = sys.path - search, path = ([usr_path], usr_path) if usr_path else ([gen_path], gen_path) if gen_path else ([join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + sys.path, None) - sys.path = search - spec = importlib.util.find_spec('SCons') - orig = dirname(dirname(abspath(spec.origin))) if (spec and spec.origin) else '' - sys.path = [orig] + syspath if orig else syspath - _ = print(f'proj: Using SCons path \\\'{{orig}}\\\' (realpath=\\\'{{realpath(orig)}}\\\').') if orig else (print(f'proj: Error: SCons not found (path=\\\'{{path if path else search}}\\\').'), sys.exit(1)) + syspath = list(sys.path) + memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} + origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] + pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False + search = ([usr_path] + syspath if usr_path else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) + begpath = origin(search) + user = begpath and usr_path and normcase(begpath) == normcase(abspath(usr_path)) + endpath = (search.insert(0, gen_path), origin([gen_path]))[-1] if (not user and gen_path and (not begpath or pytree(begpath))) else '' + path = endpath if endpath else begpath + _ = (print(f'proj: Error: SCons not found (path=\\\'{{search}}\\\').'), sys.exit(1)) if (not path) else None + sys.path = [path] + syspath + print(f'proj: Using SCons path \\\'{{path}}\\\' (realpath=\\\'{{realpath(path)}}\\\').') import SCons.Script SCons.Script.main() """ @@ -947,9 +947,9 @@ def msvs_substitute( sconscript=None, python=None, project_guid=None, + scons_home: str = '', vcproj_sccinfo: str = '', sln_sccinfo: str = '', - scons_home=None, ): if not hasattr(self, '_msvs_versions'): self.msvs_versions() @@ -1213,9 +1213,9 @@ def msvs_substitute_projects( project_guid_2=None, solution_guid_1=None, solution_guid_2=None, + scons_home: str = '', vcproj_sccinfo: str = '', sln_sccinfo: str = '', - scons_home=None, ): if not hasattr(self, '_msvs_versions'): self.msvs_versions() From 63603ab030c28b3671ad4e13f0aad0fadbe8bdd2 Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:27:19 -0500 Subject: [PATCH 7/9] MSVS: revise the vcxproj embedded python script contents to be backward compatible with the current master with minimal changes Changes: * Remove test suite enhancements that have no bearing on the changes in this PR. * Determine the SCons module path in the same manner as the current master code. * Adjust the SCons module path using the generated path location under certain conditions. --- SCons/Tool/msvs.py | 38 ++++++++++++--------------- test/MSVS/common-prefix.py | 4 +-- test/MSVS/runfile.py | 2 +- test/MSVS/vs-6.0-clean.py | 4 +-- test/MSVS/vs-6.0-files.py | 4 +-- test/MSVS/vs-6.0-variant_dir.py | 6 ++--- test/MSVS/vs-7.0-clean.py | 4 +-- test/MSVS/vs-7.0-files.py | 7 ++--- test/MSVS/vs-7.0-scc-files.py | 6 +++-- test/MSVS/vs-7.0-scc-legacy-files.py | 5 ++-- test/MSVS/vs-7.0-variant_dir.py | 4 +-- test/MSVS/vs-7.1-clean.py | 4 +-- test/MSVS/vs-7.1-files.py | 7 ++--- test/MSVS/vs-7.1-scc-files.py | 6 +++-- test/MSVS/vs-7.1-scc-legacy-files.py | 5 ++-- test/MSVS/vs-7.1-variant_dir.py | 4 +-- test/MSVS/vs-files.py | 7 ++--- test/MSVS/vs-mult-auto-guid.py | 4 +-- test/MSVS/vs-mult-auto-vardir-guid.py | 4 +-- test/MSVS/vs-mult-auto-vardir.py | 4 +-- test/MSVS/vs-mult-auto.py | 4 +-- test/MSVS/vs-mult-noauto-vardir.py | 4 +-- test/MSVS/vs-mult-noauto.py | 4 +-- test/MSVS/vs-scc-files.py | 6 +++-- test/MSVS/vs-scc-legacy-files.py | 5 ++-- test/MSVS/vs-variant_dir.py | 4 +-- testing/framework/TestSConsMSVS.py | 18 ++++++------- 27 files changed, 91 insertions(+), 83 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index b2e7382ff3..68a364f1eb 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -154,22 +154,17 @@ def msvs_parse_version(s): num, suite = version_re.match(s).groups() return float(num), suite +# This is how we re-invoke SCons from inside MSVS Project files. +# The problem is that we might have been invoked as either scons.bat +# or scons.py. If we were invoked directly as scons.py, then we could +# use sys.argv[0] to find the SCons "executable," but that doesn't work +# if we were invoked as scons.bat, which uses "python -c" to execute +# things and ends up with "-c" as sys.argv[0]. Consequently, we have +# the MSVS Project file invoke SCons the same way that scons.bat does, +# which works regardless of how we were invoked. _exec_script_main_template = None def getExecScriptMain(env, xml=None): - """ - This is how we re-invoke SCons from inside MSVS Project files. - The problem is that we might have been invoked as either scons.bat - or scons.py. If we were invoked directly as scons.py, then we could - use sys.argv[0] to find the SCons "executable," but that doesn't work - if we were invoked as scons.bat, which uses "python -c" to execute - things and ends up with "-c" as sys.argv[0]. Consequently, we have - the MSVS Project file invoke SCons the same way that scons.bat does, - which works regardless of how we were invoked. - - :param env: Environment to operate on - :param xml: Extra XML to add to generated MSVS project file - """ global _exec_script_main_template if 'SCONS_HOME' not in env: @@ -194,22 +189,23 @@ def _in_pytree(scons_abspath): """\ import importlib.util import sys - from os.path import abspath, dirname, join, normcase, realpath + from os.path import abspath, dirname, join, normcase from pathlib import Path - usr_path = r'{scons_home}' - gen_path = r'{scons_abspath}' + usr = r'{scons_home}' + gen = r'{scons_abspath}' + usrpath = abspath(usr) if usr else '' + genpath = gen if (gen and (not usrpath or normcase(usrpath) != normcase(gen))) else '' syspath = list(sys.path) memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False - search = ([usr_path] + syspath if usr_path else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) + search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) begpath = origin(search) - user = begpath and usr_path and normcase(begpath) == normcase(abspath(usr_path)) - endpath = (search.insert(0, gen_path), origin([gen_path]))[-1] if (not user and gen_path and (not begpath or pytree(begpath))) else '' + endpath = (search.insert(0, genpath), origin([genpath]))[-1] if (genpath and (not begpath or pytree(begpath))) else '' path = endpath if endpath else begpath - _ = (print(f'proj: Error: SCons not found (path=\\\'{{search}}\\\').'), sys.exit(1)) if (not path) else None + _ = (print(f'proj: Error: SCons not found (search=\\\'{{search}}\\\').'), sys.exit(1)) if (not path) else None sys.path = [path] + syspath - print(f'proj: Using SCons path \\\'{{path}}\\\' (realpath=\\\'{{realpath(path)}}\\\').') + print(f'proj: Using SCons path \\\'{{path}}\\\'.') import SCons.Script SCons.Script.main() """ diff --git a/test/MSVS/common-prefix.py b/test/MSVS/common-prefix.py index 22bb611f02..e8b47d19fa 100644 --- a/test/MSVS/common-prefix.py +++ b/test/MSVS/common-prefix.py @@ -137,7 +137,7 @@ test.must_exist(test.workpath('work1', 'Test.vcproj')) vcproj = test.read(['work1', 'Test.vcproj'], 'r') expected_vcprojfile = vcproj_template % locals() -expect = test.msvs_substitute(expected_vcprojfile, '8.0', subdir='work1', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work1', 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) @@ -163,7 +163,7 @@ test.must_exist(test.workpath('work2', 'Test.vcproj')) vcproj = test.read(['work2', 'Test.vcproj'], 'r') expected_vcprojfile = vcproj_template % locals() -expect = test.msvs_substitute(expected_vcprojfile, '8.0', subdir='work2', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work2', 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/runfile.py b/test/MSVS/runfile.py index fc9e35b447..14778e0b64 100644 --- a/test/MSVS/runfile.py +++ b/test/MSVS/runfile.py @@ -113,7 +113,7 @@ test.must_exist(test.workpath('work1', 'Test.vcproj')) vcproj = test.read(['work1', 'Test.vcproj'], 'r') -expect = test.msvs_substitute(expected_vcprojfile, '8.0', subdir='work1', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work1', 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-6.0-clean.py b/test/MSVS/vs-6.0-clean.py index 6f6119920c..28763971b7 100644 --- a/test/MSVS/vs-6.0-clean.py +++ b/test/MSVS/vs-6.0-clean.py @@ -70,13 +70,13 @@ test.must_exist(test.workpath('Test.dsp')) dsp = test.read('Test.dsp', 'r') -expect = test.msvs_substitute(expected_dspfile, '6.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_dspfile, '6.0', None, 'SConstruct') # don't compare the pickled data assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp) test.must_exist(test.workpath('Test.dsw')) dsw = test.read('Test.dsw', 'r') -expect = test.msvs_substitute(expected_dswfile, '6.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_dswfile, '6.0', None, 'SConstruct') assert dsw == expect, test.diff_substr(expect, dsw) test.run(arguments='-c .') diff --git a/test/MSVS/vs-6.0-files.py b/test/MSVS/vs-6.0-files.py index e5142b7493..7a2c7c54f6 100644 --- a/test/MSVS/vs-6.0-files.py +++ b/test/MSVS/vs-6.0-files.py @@ -48,13 +48,13 @@ test.must_exist(test.workpath('Test.dsp')) dsp = test.read('Test.dsp', 'r') -expect = test.msvs_substitute(expected_dspfile, '6.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_dspfile, '6.0', None, 'SConstruct') # don't compare the pickled data assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp) test.must_exist(test.workpath('Test.dsw')) dsw = test.read('Test.dsw', 'r') -expect = test.msvs_substitute(expected_dswfile, '6.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_dswfile, '6.0', None, 'SConstruct') assert dsw == expect, test.diff_substr(expect, dsw) test.run(arguments='-c .') diff --git a/test/MSVS/vs-6.0-variant_dir.py b/test/MSVS/vs-6.0-variant_dir.py index d945a32fac..90b6fa90b3 100644 --- a/test/MSVS/vs-6.0-variant_dir.py +++ b/test/MSVS/vs-6.0-variant_dir.py @@ -54,14 +54,14 @@ test.run(arguments=".") dsp = test.read(['src', 'Test.dsp'], 'r') -expect = test.msvs_substitute(expected_dspfile, '6.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_dspfile, '6.0', None, 'SConstruct') # don't compare the pickled data assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp) test.must_exist(test.workpath('src', 'Test.dsw')) dsw = test.read(['src', 'Test.dsw'], 'r') -expect = test.msvs_substitute(expected_dswfile, '6.0', subdir='src') -assert dsw == expect, test.diff_substr(expect, subdir=dsw) +expect = test.msvs_substitute(expected_dswfile, '6.0', 'src') +assert dsw == expect, test.diff_substr(expect, dsw) test.must_match(['build', 'Test.dsp'], """\ This is just a placeholder file. diff --git a/test/MSVS/vs-7.0-clean.py b/test/MSVS/vs-7.0-clean.py index 9fb2f95a82..0eea6c3e0d 100644 --- a/test/MSVS/vs-7.0-clean.py +++ b/test/MSVS/vs-7.0-clean.py @@ -71,13 +71,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.0-files.py b/test/MSVS/vs-7.0-files.py index ebd05add63..6049ae84bd 100644 --- a/test/MSVS/vs-7.0-files.py +++ b/test/MSVS/vs-7.0-files.py @@ -49,13 +49,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) @@ -83,7 +83,8 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct', python=python) +expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct', + python=python) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-7.0-scc-files.py b/test/MSVS/vs-7.0-scc-files.py index 5b19aed629..8730bf642e 100644 --- a/test/MSVS/vs-7.0-scc-files.py +++ b/test/MSVS/vs-7.0-scc-files.py @@ -96,13 +96,15 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct', + vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct', sln_sccinfo=expected_sln_sccinfo) +expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct', + sln_sccinfo=expected_sln_sccinfo) # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.0-scc-legacy-files.py b/test/MSVS/vs-7.0-scc-legacy-files.py index 20a326574a..1e996ccc80 100644 --- a/test/MSVS/vs-7.0-scc-legacy-files.py +++ b/test/MSVS/vs-7.0-scc-legacy-files.py @@ -77,13 +77,14 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct', + vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.0', None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.0-variant_dir.py b/test/MSVS/vs-7.0-variant_dir.py index 2ecda28e78..df0511688d 100644 --- a/test/MSVS/vs-7.0-variant_dir.py +++ b/test/MSVS/vs-7.0-variant_dir.py @@ -52,13 +52,13 @@ test.run(arguments=".") vcproj = test.read(['src', 'Test.vcproj'], 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', 'Test.sln')) sln = test.read(['src', 'Test.sln'], 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', subdir='src') +expect = test.msvs_substitute(expected_slnfile, '7.0', 'src') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-clean.py b/test/MSVS/vs-7.1-clean.py index 07fe437362..207b710b45 100644 --- a/test/MSVS/vs-7.1-clean.py +++ b/test/MSVS/vs-7.1-clean.py @@ -71,13 +71,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-files.py b/test/MSVS/vs-7.1-files.py index 55d93e3a6b..ea06cc0096 100644 --- a/test/MSVS/vs-7.1-files.py +++ b/test/MSVS/vs-7.1-files.py @@ -49,13 +49,13 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) @@ -83,7 +83,8 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct', python=python) +expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct', + python=python) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-7.1-scc-files.py b/test/MSVS/vs-7.1-scc-files.py index 29001bd9e6..ac86f3f0fd 100644 --- a/test/MSVS/vs-7.1-scc-files.py +++ b/test/MSVS/vs-7.1-scc-files.py @@ -96,13 +96,15 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct', + vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct', sln_sccinfo=expected_sln_sccinfo) +expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct', + sln_sccinfo=expected_sln_sccinfo) # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-scc-legacy-files.py b/test/MSVS/vs-7.1-scc-legacy-files.py index d17e247ee4..bfcd91ba5c 100644 --- a/test/MSVS/vs-7.1-scc-legacy-files.py +++ b/test/MSVS/vs-7.1-scc-legacy-files.py @@ -77,13 +77,14 @@ test.must_exist(test.workpath('Test.vcproj')) vcproj = test.read('Test.vcproj', 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.1', sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) +expect = test.msvs_substitute(expected_vcprojfile, '7.1', None, 'SConstruct', + vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') -expect = test.msvs_substitute(expected_slnfile, '7.1', sconscript='SConstruct') +expect = test.msvs_substitute(expected_slnfile, '7.1', None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-7.1-variant_dir.py b/test/MSVS/vs-7.1-variant_dir.py index 02d2a15708..2d6114bb78 100644 --- a/test/MSVS/vs-7.1-variant_dir.py +++ b/test/MSVS/vs-7.1-variant_dir.py @@ -52,13 +52,13 @@ test.run(arguments=".") vcproj = test.read(['src', 'Test.vcproj'], 'r') -expect = test.msvs_substitute(expected_vcprojfile, '7.0', sconscript='SConstruct') +expect = test.msvs_substitute(expected_vcprojfile, '7.0', None, 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', 'Test.sln')) sln = test.read(['src', 'Test.sln'], 'r') -expect = test.msvs_substitute(expected_slnfile, '7.0', subdir='src') +expect = test.msvs_substitute(expected_slnfile, '7.0', 'src') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-files.py b/test/MSVS/vs-files.py index 7f084836b5..73eff8b401 100644 --- a/test/MSVS/vs-files.py +++ b/test/MSVS/vs-files.py @@ -59,13 +59,13 @@ else: test.must_not_exist(test.workpath(filters_file)) vcxproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct') + expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct') # don't compare the pickled data assert vcxproj[:len(expect)] == expect, test.diff_substr(expect, vcxproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') - expect = test.msvs_substitute(expected_slnfile, vc_version, sconscript='SConstruct') + expect = test.msvs_substitute(expected_slnfile, vc_version, None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) @@ -99,7 +99,8 @@ test.must_exist(test.workpath(project_file)) vcxproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct', python=python) + expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct', + python=python) # don't compare the pickled data assert vcxproj[:len(expect)] == expect, test.diff_substr(expect, vcxproj) diff --git a/test/MSVS/vs-mult-auto-guid.py b/test/MSVS/vs-mult-auto-guid.py index 84737acfe8..59608bafa6 100644 --- a/test/MSVS/vs-mult-auto-guid.py +++ b/test/MSVS/vs-mult-auto-guid.py @@ -115,13 +115,13 @@ test.must_exist(test.workpath(project_file_1)) vcproj = test.read(project_file_1, 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath(project_file_2)) vcproj = test.read(project_file_2, 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-auto-vardir-guid.py b/test/MSVS/vs-mult-auto-vardir-guid.py index c5ae26becb..58a1fa2f4b 100644 --- a/test/MSVS/vs-mult-auto-vardir-guid.py +++ b/test/MSVS/vs-mult-auto-vardir-guid.py @@ -121,13 +121,13 @@ test.must_exist(test.workpath('src', project_file_1)) vcproj = test.read(['src', project_file_1], 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', project_file_2)) vcproj = test.read(['src', project_file_2], 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-auto-vardir.py b/test/MSVS/vs-mult-auto-vardir.py index 7b39524d78..b8e4a7b8cb 100644 --- a/test/MSVS/vs-mult-auto-vardir.py +++ b/test/MSVS/vs-mult-auto-vardir.py @@ -116,13 +116,13 @@ test.must_exist(test.workpath('src', project_file_1)) vcproj = test.read(['src', project_file_1], 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', project_file_2)) vcproj = test.read(['src', project_file_2], 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-auto.py b/test/MSVS/vs-mult-auto.py index 55f95069c5..0e87aaf5b5 100644 --- a/test/MSVS/vs-mult-auto.py +++ b/test/MSVS/vs-mult-auto.py @@ -110,13 +110,13 @@ test.must_exist(test.workpath(project_file_1)) vcproj = test.read(project_file_1, 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath(project_file_2)) vcproj = test.read(project_file_2, 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-noauto-vardir.py b/test/MSVS/vs-mult-noauto-vardir.py index c811cf1b45..c6b313db53 100644 --- a/test/MSVS/vs-mult-noauto-vardir.py +++ b/test/MSVS/vs-mult-noauto-vardir.py @@ -87,13 +87,13 @@ test.must_exist(test.workpath('src', project_file_1)) vcproj = test.read(['src', project_file_1], 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', project_file_2)) vcproj = test.read(['src', project_file_2], 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-mult-noauto.py b/test/MSVS/vs-mult-noauto.py index af50c50313..1d458f2b77 100644 --- a/test/MSVS/vs-mult-noauto.py +++ b/test/MSVS/vs-mult-noauto.py @@ -81,13 +81,13 @@ test.must_exist(test.workpath(project_file_1)) vcproj = test.read(project_file_1, 'r') - expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, sconscript='SConstruct', project_guid=project_guid_1) + expect = test.msvs_substitute(expected_vcprojfile_1, vc_version, None, 'SConstruct', project_guid=project_guid_1) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath(project_file_2)) vcproj = test.read(project_file_2, 'r') - expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, sconscript='SConstruct', project_guid=project_guid_2) + expect = test.msvs_substitute(expected_vcprojfile_2, vc_version, None, 'SConstruct', project_guid=project_guid_2) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) diff --git a/test/MSVS/vs-scc-files.py b/test/MSVS/vs-scc-files.py index c7ea96072b..e0a7dc0437 100644 --- a/test/MSVS/vs-scc-files.py +++ b/test/MSVS/vs-scc-files.py @@ -111,13 +111,15 @@ test.must_exist(test.workpath(project_file)) vcproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) + expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct', + vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') - expect = test.msvs_substitute(expected_slnfile, vc_version, sconscript='SConstruct', sln_sccinfo=expected_sln_sccinfo) + expect = test.msvs_substitute(expected_slnfile, vc_version, None, 'SConstruct', + sln_sccinfo=expected_sln_sccinfo) # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-scc-legacy-files.py b/test/MSVS/vs-scc-legacy-files.py index 215b89d9d8..d8150e1bb0 100644 --- a/test/MSVS/vs-scc-legacy-files.py +++ b/test/MSVS/vs-scc-legacy-files.py @@ -95,13 +95,14 @@ test.must_exist(test.workpath(project_file)) vcproj = test.read(project_file, 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct', vcproj_sccinfo=expected_vcproj_sccinfo) + expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct', + vcproj_sccinfo=expected_vcproj_sccinfo) # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('Test.sln')) sln = test.read('Test.sln', 'r') - expect = test.msvs_substitute(expected_slnfile, vc_version, sconscript='SConstruct') + expect = test.msvs_substitute(expected_slnfile, vc_version, None, 'SConstruct') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/test/MSVS/vs-variant_dir.py b/test/MSVS/vs-variant_dir.py index 751f36d6fc..116d0c9674 100644 --- a/test/MSVS/vs-variant_dir.py +++ b/test/MSVS/vs-variant_dir.py @@ -60,13 +60,13 @@ test.run(arguments=".") vcproj = test.read(['src', project_file], 'r') - expect = test.msvs_substitute(expected_vcprojfile, vc_version, sconscript='SConstruct') + expect = test.msvs_substitute(expected_vcprojfile, vc_version, None, 'SConstruct') # don't compare the pickled data assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj) test.must_exist(test.workpath('src', 'Test.sln')) sln = test.read(['src', 'Test.sln'], 'r') - expect = test.msvs_substitute(expected_slnfile, '8.0', subdir='src') + expect = test.msvs_substitute(expected_slnfile, '8.0', 'src') # don't compare the pickled data assert sln[:len(expect)] == expect, test.diff_substr(expect, sln) diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index aec9c86b2f..e9eaafe15e 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -868,22 +868,23 @@ def _in_pytree(scons_abspath): """\ import importlib.util import sys - from os.path import abspath, dirname, join, normcase, realpath + from os.path import abspath, dirname, join, normcase from pathlib import Path - usr_path = r'{scons_home}' - gen_path = r'{scons_abspath}' + usr = r'{scons_home}' + gen = r'{scons_abspath}' + usrpath = abspath(usr) if usr else '' + genpath = gen if (gen and (not usrpath or normcase(usrpath) != normcase(gen))) else '' syspath = list(sys.path) memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False - search = ([usr_path] + syspath if usr_path else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) + search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) begpath = origin(search) - user = begpath and usr_path and normcase(begpath) == normcase(abspath(usr_path)) - endpath = (search.insert(0, gen_path), origin([gen_path]))[-1] if (not user and gen_path and (not begpath or pytree(begpath))) else '' + endpath = (search.insert(0, genpath), origin([genpath]))[-1] if (genpath and (not begpath or pytree(begpath))) else '' path = endpath if endpath else begpath - _ = (print(f'proj: Error: SCons not found (path=\\\'{{search}}\\\').'), sys.exit(1)) if (not path) else None + _ = (print(f'proj: Error: SCons not found (search=\\\'{{search}}\\\').'), sys.exit(1)) if (not path) else None sys.path = [path] + syspath - print(f'proj: Using SCons path \\\'{{path}}\\\' (realpath=\\\'{{realpath(path)}}\\\').') + print(f'proj: Using SCons path \\\'{{path}}\\\'.') import SCons.Script SCons.Script.main() """ @@ -942,7 +943,6 @@ def msvs_substitute( self, input, msvs_ver, - *, subdir=None, sconscript=None, python=None, From eacb5d2e51d1e76daefd27f24acf757683fd6adc Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Sun, 1 Feb 2026 13:50:30 -0500 Subject: [PATCH 8/9] MSVS: revise the vcxproj embedded python script Bug fix: remove extra library specification that does not exist in main branch (holdover from earlier versions) from default code path. --- SCons/Tool/msvs.py | 2 +- testing/framework/TestSConsMSVS.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index 68a364f1eb..75c5e52c31 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -199,7 +199,7 @@ def _in_pytree(scons_abspath): memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False - search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) + search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',)]] + syspath) begpath = origin(search) endpath = (search.insert(0, genpath), origin([genpath]))[-1] if (genpath and (not begpath or pytree(begpath))) else '' path = endpath if endpath else begpath diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index e9eaafe15e..b1efe098b7 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -878,7 +878,7 @@ def _in_pytree(scons_abspath): memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False - search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',), ('Lib', 'site-packages')]] + syspath) + search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',)]] + syspath) begpath = origin(search) endpath = (search.insert(0, genpath), origin([genpath]))[-1] if (genpath and (not begpath or pytree(begpath))) else '' path = endpath if endpath else begpath From ff494a53c217bfb7ad86e03a07e566925e64fdf0 Mon Sep 17 00:00:00 2001 From: Joseph Brill <48932340+jcbrill@users.noreply.github.com> Date: Wed, 4 Feb 2026 14:31:47 -0500 Subject: [PATCH 9/9] MSVS: minor change of the vcxproj embedded python script --- SCons/Tool/msvs.py | 5 +++-- testing/framework/TestSConsMSVS.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index 75c5e52c31..f20847817d 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -196,9 +196,10 @@ def _in_pytree(scons_abspath): usrpath = abspath(usr) if usr else '' genpath = gen if (gen and (not usrpath or normcase(usrpath) != normcase(gen))) else '' syspath = list(sys.path) - memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} + pycomps = Path(normcase(abspath(sys.prefix))).parts + memo = {{}} origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] - pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False + pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(pycomps)] == pycomps)[-1] if p else False search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',)]] + syspath) begpath = origin(search) endpath = (search.insert(0, genpath), origin([genpath]))[-1] if (genpath and (not begpath or pytree(begpath))) else '' diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index b1efe098b7..99157ccb3f 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -875,9 +875,10 @@ def _in_pytree(scons_abspath): usrpath = abspath(usr) if usr else '' genpath = gen if (gen and (not usrpath or normcase(usrpath) != normcase(gen))) else '' syspath = list(sys.path) - memo = {{'pycomps': Path(normcase(abspath(sys.prefix))).parts}} + pycomps = Path(normcase(abspath(sys.prefix))).parts + memo = {{}} origin = lambda l: (sys.path.clear(), sys.path.extend(l), memo.update({{'spec': importlib.util.find_spec('SCons')}}), dirname(dirname(abspath(memo['spec'].origin))) if (memo['spec'] and memo['spec'].origin) else '')[-1] - pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(memo['pycomps'])] == memo['pycomps'])[-1] if p else False + pytree = lambda p: (memo.update({{'comps': Path(normcase(p)).parts}}), memo['comps'][:len(pycomps)] == pycomps)[-1] if p else False search = ([usrpath] + syspath if usrpath else [join(sys.prefix, *t) for t in [('Lib', 'site-packages', 'scons-{scons_version}'), ('scons-{scons_version}',), ('Lib', 'site-packages', 'scons'), ('scons',)]] + syspath) begpath = origin(search) endpath = (search.insert(0, genpath), origin([genpath]))[-1] if (genpath and (not begpath or pytree(begpath))) else ''