Skip to content

The vcxproj file created using MSVSProject fails to build the project when SCons installed via scoop #4809

@madmiraal

Description

@madmiraal

Describe the bug
The vcxproj file created using MSVSProject fails to build the project with the following error:

1>Traceback (most recent call last):
1>  File "<string>", line 1, in <module>
1>ModuleNotFoundError: No module named 'SCons'
1>C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.MakeFile.Targets(45,5): error MSB3073: The command "echo Starting SCons && "C:\Users\Marcel\scoop\apps\python\current\python.exe" -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-4.9.1'), join(sys.prefix, 'scons-4.9.1'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" -C "C:\Users\Marcel\Temp\SCons" -f SConstruct "C:\Users\Marcel\Temp\SCons\hello.exe"" exited with code 1.
1>Done building project "Hello.vcxproj" -- FAILED.

Required information

  • Link to SCons Users thread discussing your issue: https://discord.com/channels/571796279483564041/1456022630631997662
  • Version of SCons: 4.9.1
  • Version of Python: 3.10.1
  • Which python distribution if applicable (python.org, cygwin, anaconda, macports, brew,etc): scoop (https://scoop.sh/)
  • How you installed SCons: scoop
  • What Platform are you on? (Linux/Windows and which version): Windows 11 Home 24H2
  • How to reproduce your issue? Please include a small self contained reproducer. Likely a SConstruct should do for most issues.
env = Environment()
sources = ['hello.cpp']
includes = ['hello.h']
program = env.Program(target='hello.exe', source=sources)
env.MSVSProject(
    target='Hello' + env['MSVSPROJECTSUFFIX'],
    srcs=sources,
    incs=includes,
    buildtarget=program,
    variant='Release',
)
  • How you invoke scons (The command line you're using "scons --flags some_arguments"): scons

I think the problem lies with the way MSVSProject creates the NMake*Commands in the vcxproj file:

<NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo Starting SCons &amp;&amp; &quot;C:\Users\Marcel\scoop\apps\python\current\python.exe&quot; -c &quot;from os.path import join; import sys; sys.path = [ join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons&apos;), join(sys.prefix, &apos;scons&apos;) ] + sys.path; import SCons.Script; SCons.Script.main()&quot; -C &quot;C:\Users\Marcel\Temp\SCons&quot; -f SConstruct &quot;C:\Users\Marcel\Temp\SCons\hello.exe&quot;</NMakeBuildCommandLine>
<NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo Starting SCons &amp;&amp; &quot;C:\Users\Marcel\scoop\apps\python\current\python.exe&quot; -c &quot;from os.path import join; import sys; sys.path = [ join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons&apos;), join(sys.prefix, &apos;scons&apos;) ] + sys.path; import SCons.Script; SCons.Script.main()&quot; -C &quot;C:\Users\Marcel\Temp\SCons&quot; -f SConstruct &quot;C:\Users\Marcel\Temp\SCons\hello.exe&quot;</NMakeReBuildCommandLine>
<NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo Starting SCons &amp;&amp; &quot;C:\Users\Marcel\scoop\apps\python\current\python.exe&quot; -c &quot;from os.path import join; import sys; sys.path = [ join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons&apos;), join(sys.prefix, &apos;scons&apos;) ] + sys.path; import SCons.Script; SCons.Script.main()&quot; -C &quot;C:\Users\Marcel\Temp\SCons&quot; -f SConstruct -c &quot;C:\Users\Marcel\Temp\SCons\hello.exe&quot;</NMakeCleanCommandLine>

It appears to be a roundabout way of launching SCons: It launches python with -c and string for the following python script:

from os.path import join
import sys
sys.path = [
    join(sys.prefix, 'Lib', 'site-packages', 'scons-4.9.1'),
    join(sys.prefix, 'scons-4.9.1'),
    join(sys.prefix, 'Lib', 'site-packages', 'scons'),
    join(sys.prefix, 'scons')
] + sys.path;
import SCons.Script
SCons.Script.main()

If the script can't find the scons module in the modified sys.path it fails.

However, scons must (or at least should) be in the user's path; otherwise we wouldn't be able to run the SConstruct that is used to create the vcxproj file.

It works when I replace the

&quot;C:\Users\Marcel\scoop\apps\python\current\python.exe&quot; -c &quot;from os.path import join; import sys; sys.path = [ join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;scons-4.9.1&apos;), join(sys.prefix, &apos;Lib&apos;, &apos;site-packages&apos;, &apos;scons&apos;), join(sys.prefix, &apos;scons&apos;) ] + sys.path; import SCons.Script; SCons.Script.main()&quot;

with scons:

<NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo Starting SCons &amp;&amp; scons -C &quot;C:\Users\Marcel\Temp\SCons&quot; -f SConstruct &quot;C:\Users\Marcel\Temp\SCons\hello.exe&quot;</NMakeBuildCommandLine>
<NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo Starting SCons &amp;&amp; scons -C &quot;C:\Users\Marcel\Temp\SCons&quot; -f SConstruct &quot;C:\Users\Marcel\Temp\SCons\hello.exe&quot;</NMakeReBuildCommandLine>
<NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo Starting SCons &amp;&amp; scons -C &quot;C:\Users\Marcel\Temp\SCons&quot; -f SConstruct -c &quot;C:\Users\Marcel\Temp\SCons\hello.exe&quot;</NMakeCleanCommandLine>

To get MSVSProject to create a working vcxproj file, I added the following line to the SConstruct file:

env["MSVSSCONS"] = "scons"

The updated SConstruct file:

env = Environment()
env["MSVSSCONS"] = "scons"
sources = ['hello.cpp']
includes = ['hello.h']
program = env.Program(target='hello.exe', source=sources)
env.MSVSProject(
    target='Hello' + env['MSVSPROJECTSUFFIX'],
    srcs=sources,
    incs=includes,
    buildtarget=program,
    variant='Release',
)

Within SCons, the default value for MSVSSCONS is set here:

scons/SCons/Tool/msvs.py

Lines 2145 to 2151 in f544c99

# Allow consumers to provide their own versions of MSVSSCONS and
# 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))
if 'MSVSSCONSFLAGS' not in env:
env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.get_abspath()}" -f ${MSVSSCONSCRIPT.name}'

and it gets the values used from here:

scons/SCons/Tool/msvs.py

Lines 162 to 187 in f544c99

def getExecScriptMain(env, xml=None):
if 'SCONS_HOME' not in env:
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 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()
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])

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions