Advertisement
Guest User

mingw32-patch-gcc4msvcrXX.py

a guest
Jun 10th, 2012
176
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.95 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright (c) 2012 science+computing ag
  5. # Author: Anselm Kruis <a.kruis@science-computing.de>
  6. #
  7. #    This program is free software: you can redistribute it and/or modify
  8. #    it under the terms of the GNU General Public License as published by
  9. #    the Free Software Foundation, either version 2 of the License, or
  10. #    (at your option) any later version.
  11. #
  12. #    This program is distributed in the hope that it will be useful,
  13. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. #    GNU General Public License for more details.
  16. #
  17. #    You should have received a copy of the GNU General Public License
  18. #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19. #
  20.  
  21. """Patch the MinGW gcc to use a particular version of the Microsoft C Runtime"""
  22.  
  23. import tempfile
  24. import os.path
  25. import subprocess
  26. import re
  27. import sys
  28.  
  29. class PatchGcc(object):
  30.     MSVCR_VERSIONS = { "90": ("0x0900",
  31. """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  32. <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  33.  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
  34.    <security>
  35.      <requestedPrivileges>
  36.        <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
  37.      </requestedPrivileges>
  38.    </security>
  39.  </trustInfo>
  40.  <dependency>
  41.    <dependentAssembly>
  42.      <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
  43.    </dependentAssembly>
  44.  </dependency>
  45. </assembly>
  46. """ )            }
  47.  
  48.     GCC_EXE_PREFIX="" if hasattr(sys, "getwindowsversion") else "i686-pc-mingw32-"
  49.     GCC=GCC_EXE_PREFIX + "gcc"
  50.     WINDRES=GCC_EXE_PREFIX + "windres"
  51.  
  52.     PRIMARY_SPEC_NAME = "specs"
  53.    
  54.     LIBS_TO_CHECK = ( "libmoldname%(version)s.a", "libmsvcr%(version)s.a" )
  55.  
  56.     def getPrimarySpecsDir(self):
  57.         gcc = self.GCC
  58.         searchDirs = subprocess.check_output([gcc, "-print-search-dirs"])
  59.         searchDirs = re.split(r"[\r\n]+", searchDirs)
  60.         key = "install: "
  61.         for l in searchDirs:
  62.             if l.startswith(key):
  63.                 return l[len(key):]
  64.         raise RuntimeError("Can't detect the innstall directory of " + gcc)
  65.  
  66.     def installedFile(self, name):
  67.         path = subprocess.check_output([self.GCC, "-print-file-name=" + name]).strip()
  68.         return path if os.path.exists(path) and os.path.isabs(path) else None
  69.  
  70.     def createManifestResource(self, name, index, manifest):
  71.         with tempfile.NamedTemporaryFile(delete=False) as rcFile:
  72.             with tempfile.NamedTemporaryFile(delete=False) as manifestFile:
  73.                 manifestFile.write("\xEF\xBB\xBF") # BOM
  74.                 manifestFile.write(manifest.encode("utf-8"))
  75.             rcFile.write('#include "winuser.h"\r\n');
  76.             rcFile.write('%d RT_MANIFEST %s\r\n' % (index, os.path.basename(manifestFile.name)))
  77.         try:
  78.             subprocess.check_call([self.WINDRES, "--input-format=rc", "--output-format=coff",
  79.                                    "--include-dir", os.path.dirname(manifestFile.name),
  80.                                    "--input", rcFile.name, "--output", name])
  81.         finally:
  82.             os.remove(manifestFile.name)
  83.             os.remove(rcFile.name)
  84.        
  85.     def createSpec(self, specFile, requestedVersion):
  86.         specs = subprocess.check_output([self.GCC, "-dumpspecs"])
  87.         specs = re.split(r"\r?\n", specs)
  88.         for i,line in enumerate(specs):
  89.             line = line.strip()
  90.             if line in( "*cpp:", "*cc1plus:"):
  91.                 specs[i+1] += " -D__MSVCRT_VERSION__=%s" % (self.MSVCR_VERSIONS[requestedVersion][0],)
  92.             elif line == "*link_gcc_c_sequence:":
  93.                 specs[i+1] += " %%{shared|mdll: msvcr%(requestedVersion)s.dll.res%%s} %%{!shared: %%{!mdll: msvcr%(requestedVersion)s.exe.res%%s}}" % locals()
  94.             elif line == "*libgcc:":
  95.                 specs[i+1] = "-lcontinue_on_invalid_param " + specs[i+1].replace("-lmoldname", "-lmoldname" + requestedVersion).replace("-lmsvcrt", "-lmsvcr" + requestedVersion)
  96.         with open(specFile, "wb") as fp:
  97.             fp.write("\r\n".join(specs))
  98.        
  99.     def main(self, args):
  100.         """
  101.        Patch the MinGW gcc
  102.  
  103.        Usage: mingw32-patch-gcc4msvcrXX.py <VERSION>
  104.        where <VERSION> is one of "60", "90"
  105.        """
  106.         if not args:
  107.             print self.main.__doc__
  108.             return
  109.  
  110.         requestedVersion = args[0]
  111.        
  112.         specFile = os.path.join(self.getPrimarySpecsDir(), self.PRIMARY_SPEC_NAME)
  113.         # special case
  114.         if requestedVersion == "60":
  115.             if os.path.exists(specFile):
  116.                 os.remove(specFile)
  117.         else:
  118.             # checks
  119.             if requestedVersion not in self.MSVCR_VERSIONS:
  120.                 raise ValueError("Unsupported version number %s" % (requestedVersion,))
  121.             for name in self.LIBS_TO_CHECK:
  122.                 name = name % {"version": requestedVersion}
  123.                 libPath = self.installedFile(name)
  124.                 if not libPath:
  125.                     raise RuntimeError("Installation is missing library %s" % (name,))
  126.             libPath = os.path.dirname(libPath) # we need it later on
  127.            
  128.             # check the manifest files
  129.             manifest = self.MSVCR_VERSIONS[requestedVersion][1]
  130.             if manifest:
  131.                 for i, name in enumerate(('exe', 'dll')):
  132.                     name = "msvcr%s.%s.res" % (requestedVersion, name)
  133.                     if not self.installedFile(name):
  134.                         self.createManifestResource(os.path.join(libPath,name), i+1, manifest)
  135.  
  136.             # create the spec file
  137.             self.createSpec(specFile, requestedVersion)
  138.         return 0
  139.  
  140. if __name__ == "__main__":
  141.     import sys
  142.     sys.exit(PatchGcc().main(sys.argv[1:]))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement