diff options
author | Steven Knight <knight@baldmt.com> | 2004-01-15 13:28:43 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2004-01-15 13:28:43 (GMT) |
commit | ecd9231176b6cd74395ffc5b8836eaa450fccb7d (patch) | |
tree | a3cd7f007df34f31576c99f9650d35d5893872b3 | |
parent | 9cc5ac377415fc2404265c614f9cf76b877fece2 (diff) | |
download | SCons-ecd9231176b6cd74395ffc5b8836eaa450fccb7d.zip SCons-ecd9231176b6cd74395ffc5b8836eaa450fccb7d.tar.gz SCons-ecd9231176b6cd74395ffc5b8836eaa450fccb7d.tar.bz2 |
Fix MSVS Project file invocation when running scons.bat.
-rw-r--r-- | src/CHANGES.txt | 4 | ||||
-rw-r--r-- | src/engine/SCons/Tool/msvs.py | 63 | ||||
-rw-r--r-- | test/msvs.py | 96 |
3 files changed, 102 insertions, 61 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt index d567560..45b9df3 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -122,6 +122,10 @@ RELEASE 0.95 - XXX - Supply meaningful error messages, not stack traces, if we try to add a non-Node as a source, dependency, or ignored dependency of a Node. + - Generate MSVS Project files that re-invoke SCons properly regardless + of whether the file was built via scons.bat or scons.py. + (Thanks to Niall Douglas for contributing code and testing.) + From Vincent Risi: - Add support for the bcc32, ilink32 and tlib Borland tools. diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py index ee860e3..e4272c3 100644 --- a/src/engine/SCons/Tool/msvs.py +++ b/src/engine/SCons/Tool/msvs.py @@ -77,6 +77,29 @@ def _generateGUID(slnfile, name): solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:28] + "}" return solution +# 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 = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-__VERSION__'), join(sys.prefix, 'scons-__VERSION__'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" +exec_script_main_xml = string.replace(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]) + class Config: pass @@ -233,7 +256,9 @@ class _GenerateV6DSP(_DSPGenerator): self.file.write('# PROP %sOutput_Dir "%s"\n' '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir)) (d,c) = os.path.split(str(self.conspath)) - cmd = '%s %s -C %s -f %s %s' % (sys.executable, os.path.normpath(sys.argv[0]), d, c, buildtarget) + cmd = '%s -c "%s" -C %s -f %s %s' % (python_executable, + exec_script_main, + d, c, buildtarget) self.file.write('# PROP %sCmd_Line "%s"\n' '# PROP %sRebuild_Opt "-c && %s"\n' '# PROP %sTarget_File "%s"\n' @@ -356,11 +381,16 @@ class _GenerateV6DSP(_DSPGenerator): class _GenerateV7DSP(_DSPGenerator): """Generates a Project file for MSVS .NET""" + def __init__(self, dspfile, source, env, version): + _DSPGenerator.__init__(self, dspfile, source, env) + if version==7.0: self.version="7.00" + else: self.version="7.10" + def PrintHeader(self): self.file.write('<?xml version="1.0" encoding = "Windows-1252"?>\n' '<VisualStudioProject\n' ' ProjectType="Visual C++"\n' - ' Version="7.00"\n' + ' Version="%s"\n' ' Name="%s"\n' ' SccProjectName=""\n' ' SccLocalPath=""\n' @@ -368,7 +398,7 @@ class _GenerateV7DSP(_DSPGenerator): ' <Platforms>\n' ' <Platform\n' ' Name="Win32"/>\n' - ' </Platforms>\n' % self.name) + ' </Platforms>\n' % (self.version, self.name)) def PrintProject(self): @@ -383,13 +413,13 @@ class _GenerateV7DSP(_DSPGenerator): buildtarget = self.configs[kind].buildtarget (d,c) = os.path.split(str(self.conspath)) - cmd = '%s %s -C %s -f %s %s\n' % (sys.executable,\ - os.path.normpath(sys.argv[0]),\ - d,c,buildtarget) + cmd = '%s -c "%s" -C %s -f %s %s' % (python_executable, + exec_script_main_xml, + d, c, buildtarget) - cleancmd = '%s %s -C %s -f %s -c %s' % (sys.executable,\ - os.path.normpath(sys.argv[0]),\ - d,c,buildtarget) + cleancmd = '%s -c "%s" -C %s -f %s -c %s' % (python_executable, + exec_script_main_xml, + d, c, buildtarget) self.file.write(' <Configuration\n' ' Name="%s|Win32"\n' @@ -530,8 +560,11 @@ class _DSWGenerator: class _GenerateV7DSW(_DSWGenerator): """Generates a Solution file for MSVS .NET""" - def __init__(self, dswfile, dspfile, source, env): - _DSWGenerator.__init__(self, dswfile,dspfile,source,env) + def __init__(self, dswfile, dspfile, source, env, version): + _DSWGenerator.__init__(self, dswfile, dspfile, source, env) + + if version==7.0: self.version="7.00" + else: self.version="8.00" if env.has_key('slnguid') and env['slnguid']: self.slnguid = env['slnguid'] @@ -584,13 +617,13 @@ class _GenerateV7DSW(_DSWGenerator): def PrintSolution(self): """Writes a solution file""" - self.file.write('Microsoft Visual Studio Solution File, Format Version 7.00\n' + self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n' # the next line has the GUID for an external makefile project. 'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "%s", "%s", "%s"\n' 'EndProject\n' 'Global\n' ' GlobalSection(SolutionConfiguration) = preSolution\n'\ - % (self.name, os.path.basename(self.dspfile), self.slnguid)) + % (self.version, self.name, os.path.basename(self.dspfile), self.slnguid)) confkeys = self.configs.keys() confkeys.sort() cnt = 0 @@ -673,7 +706,7 @@ def GenerateDSP(dspfile, source, env): """Generates a Project file based on the version of MSVS that is being used""" if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0: - g = _GenerateV7DSP(dspfile, source, env) + g = _GenerateV7DSP(dspfile, source, env, float(env['MSVS_VERSION'])) g.Build() else: g = _GenerateV6DSP(dspfile, source, env) @@ -683,7 +716,7 @@ def GenerateDSW(dswfile, dspfile, source, env): """Generates a Solution/Workspace file based on the version of MSVS that is being used""" if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0: - g = _GenerateV7DSW(dswfile, dspfile, source, env) + g = _GenerateV7DSW(dswfile, dspfile, source, env, float(env['MSVS_VERSION'])) g.Build() else: g = _GenerateV6DSW(dswfile, dspfile, source, env) diff --git a/test/msvs.py b/test/msvs.py index 03f08cb..e447cb0 100644 --- a/test/msvs.py +++ b/test/msvs.py @@ -24,14 +24,16 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import TestSCons -import sys -import re -import os.path import os -import TestCmd +import os.path +import re +import string +import sys import time +import TestCmd +import TestSCons + expected_dspfile = '''\ # Microsoft Developer Studio Project File - Name="Test" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 @@ -66,8 +68,8 @@ CFG=Test - Win32 Release # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "<WORKPATH>" # PROP BASE Intermediate_Dir "<WORKPATH>" -# PROP BASE Cmd_Line "<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" -# PROP BASE Rebuild_Opt "-c && <PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" +# PROP BASE Cmd_Line "<PYTHON> -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" +# PROP BASE Rebuild_Opt "-c && <PYTHON> -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" # PROP BASE Target_File "<WORKPATH>\Test.exe" # PROP BASE Bsc_Name "" # PROP BASE Target_Dir "" @@ -75,8 +77,8 @@ CFG=Test - Win32 Release # PROP Use_Debug_Libraries 0 # PROP Output_Dir "<WORKPATH>" # PROP Intermediate_Dir "<WORKPATH>" -# PROP Cmd_Line "<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" -# PROP Rebuild_Opt "-c && <PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" +# PROP Cmd_Line "<PYTHON> -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" +# PROP Rebuild_Opt "-c && <PYTHON> -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" # PROP Target_File "<WORKPATH>\Test.exe" # PROP Bsc_Name "" # PROP Target_Dir "" @@ -214,10 +216,10 @@ expected_vcprojfile = '''\ ATLMinimizesCRunTimeLibraryUsage="FALSE"> <Tool Name="VCNMakeTool" - BuildCommandLine="<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe + BuildCommandLine="<PYTHON> -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe " - CleanCommandLine="<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct -c <WORKPATH>\Test.exe" - RebuildCommandLine="<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe + CleanCommandLine="<PYTHON> -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct -c <WORKPATH>\Test.exe" + RebuildCommandLine="<PYTHON> -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe " Output="<WORKPATH>\Test.exe"/> </Configuration> @@ -272,6 +274,16 @@ test = TestSCons.TestSCons(match = TestCmd.match_re) if sys.platform != 'win32': test.pass_test() +exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-0.94'), join(sys.prefix, 'scons-0.94'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" +exec_script_main_xml = string.replace(exec_script_main, "'", "'") + +def substitute(input, workpath=test.workpath(), python=sys.executable): + result = string.replace(input, r'<WORKPATH>', workpath) + result = string.replace(result, r'<PYTHON>', python) + result = string.replace(result, r'<SCONS_SCRIPT_MAIN>', exec_script_main) + result = string.replace(result, r'<SCONS_SCRIPT_MAIN_XML>', exec_script_main_xml) + return result + #### # Determine which environments are installed on the test machine. test.write('SConstruct',''' @@ -312,25 +324,15 @@ env.MSVSProject(target = 'Test.dsp', test.run(arguments="Test.dsp") test.fail_test(not os.path.exists(test.workpath('Test.dsp'))) - test.fail_test(not os.path.exists(test.workpath('Test.dsw'))) - - # check to see that we got what we expected: - expected_dspfile = expected_dspfile.replace(r'<WORKPATH>',test.workpath()) - expected_dspfile = expected_dspfile.replace(r'<PYTHON>',sys.executable) - expected_dspfile = expected_dspfile.replace(r'<SCONS>',os.path.join(os.environ['SCONS_SCRIPT_DIR'],'scons.py')) - expected_dswfile = expected_dswfile.replace(r'<WORKPATH>',test.workpath()) - - f = open(test.workpath('Test.dsp')) - dsp = f.read() - f.close() - + dsp = test.read('Test.dsp', 'r') + expect = substitute(expected_dspfile) # don't compare the pickled data - assert dsp[:len(expected_dspfile)] == expected_dspfile + assert dsp[:len(expect)] == expect - f = open(test.workpath('Test.dsw')) - dsw = f.read() - f.close() - assert dsw == expected_dswfile + test.fail_test(not os.path.exists(test.workpath('Test.dsw'))) + dsw = test.read('Test.dsw', 'r') + expect = substitute(expected_dswfile) + assert dsw == expect test.run(arguments='-c .') @@ -374,23 +376,16 @@ env.MSVSProject(target = 'Test.vcproj', test.run(arguments="Test.vcproj") test.fail_test(not os.path.exists(test.workpath('Test.vcproj'))) - test.fail_test(not os.path.exists(test.workpath('Test.sln'))) - - f = open(test.workpath('Test.vcproj')) - vcproj = f.read() - f.close() - expected_vcprojfile = expected_vcprojfile.replace(r'<WORKPATH>',test.workpath()) - expected_vcprojfile = expected_vcprojfile.replace(r'<PYTHON>',sys.executable) - expected_vcprojfile = expected_vcprojfile.replace(r'<SCONS>',os.path.join(os.environ['SCONS_SCRIPT_DIR'],'scons.py')) - + test.read('Test.vcproj', 'r') + expect = substitute(expected_vcprojfile) # don't compare the pickled data - assert vcproj[:len(expected_vcprojfile)] == expected_vcprojfile + assert vcproj[:len(expect)] == expect - f = open(test.workpath('Test.sln')) - sln = f.read() - f.close() - - assert sln[:len(expected_slnfile)] == expected_slnfile + test.fail_test(not os.path.exists(test.workpath('Test.sln'))) + sln = test.read('Test.sln', 'r') + expect = substitute(expected_slnfile) + # don't compare the pickled data + assert sln[:len(expect)] == expect test.run(arguments='-c .') @@ -407,9 +402,18 @@ env.MSVSProject(target = 'Test.vcproj', test.fail_test(os.path.exists(test.workpath('Test.vcproj'))) test.fail_test(os.path.exists(test.workpath('Test.sln'))) -test.pass_test() - + # Test that running SCons with $PYTHON_ROOT in the environment + # changes the .vcproj output as expected. + os.environ['PYTHON_ROOT'] = 'xyzzy' + test.run(arguments='Test.vcproj') + python = os.path.join('$(PYTHON_ROOT)', os.path.split(sys.executable)[1]) + test.fail_test(not os.path.exists(test.workpath('Test.vcproj'))) + test.read('Test.vcproj', 'r') + expect = substitute(expected_vcprojfile, python=python) + # don't compare the pickled data + assert vcproj[:len(expect)] == expect +test.pass_test() |