Fix MSVS Project file invocation when running scons.bat.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 15 Jan 2004 13:28:43 +0000 (13:28 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 15 Jan 2004 13:28:43 +0000 (13:28 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@876 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Tool/msvs.py
test/msvs.py

index d567560423c75618e94cf024b78b7bf822cedfb7..45b9df3f8c4e18c6ebda7a9d320d44608a1c1d7c 100644 (file)
@@ -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.
index ee860e3def73ed1d4749fd22a3f86694ab66f24a..e4272c3cc073733c2371576da5cc54108a581166 100644 (file)
@@ -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, "'", "&apos;")
+
+# 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 &quot;%s&quot; -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 &quot;%s&quot; -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)
index 03f08cb618d1c69c823faa48f407b31ccc1d2691..e447cb0b931970474b074f2762feb71c7d0916d1 100644 (file)
 
 __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, "'", "&apos;")
+
+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()