Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- #
- # Copyright (c) 2012 science+computing ag
- # Author: Anselm Kruis <a.kruis@science-computing.de>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- """Patch the MinGW gcc to use a particular version of the Microsoft C Runtime"""
- import tempfile
- import os.path
- import subprocess
- import re
- import sys
- class PatchGcc(object):
- MSVCR_VERSIONS = { "90": ("0x0900",
- """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
- </requestedPrivileges>
- </security>
- </trustInfo>
- <dependency>
- <dependentAssembly>
- <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
- </dependentAssembly>
- </dependency>
- </assembly>
- """ ) }
- GCC_EXE_PREFIX="" if hasattr(sys, "getwindowsversion") else "i686-pc-mingw32-"
- GCC=GCC_EXE_PREFIX + "gcc"
- WINDRES=GCC_EXE_PREFIX + "windres"
- PRIMARY_SPEC_NAME = "specs"
- LIBS_TO_CHECK = ( "libmoldname%(version)s.a", "libmsvcr%(version)s.a" )
- def getPrimarySpecsDir(self):
- gcc = self.GCC
- searchDirs = subprocess.check_output([gcc, "-print-search-dirs"])
- searchDirs = re.split(r"[\r\n]+", searchDirs)
- key = "install: "
- for l in searchDirs:
- if l.startswith(key):
- return l[len(key):]
- raise RuntimeError("Can't detect the innstall directory of " + gcc)
- def installedFile(self, name):
- path = subprocess.check_output([self.GCC, "-print-file-name=" + name]).strip()
- return path if os.path.exists(path) and os.path.isabs(path) else None
- def createManifestResource(self, name, index, manifest):
- with tempfile.NamedTemporaryFile(delete=False) as rcFile:
- with tempfile.NamedTemporaryFile(delete=False) as manifestFile:
- manifestFile.write("\xEF\xBB\xBF") # BOM
- manifestFile.write(manifest.encode("utf-8"))
- rcFile.write('#include "winuser.h"\r\n');
- rcFile.write('%d RT_MANIFEST %s\r\n' % (index, os.path.basename(manifestFile.name)))
- try:
- subprocess.check_call([self.WINDRES, "--input-format=rc", "--output-format=coff",
- "--include-dir", os.path.dirname(manifestFile.name),
- "--input", rcFile.name, "--output", name])
- finally:
- os.remove(manifestFile.name)
- os.remove(rcFile.name)
- def createSpec(self, specFile, requestedVersion):
- specs = subprocess.check_output([self.GCC, "-dumpspecs"])
- specs = re.split(r"\r?\n", specs)
- for i,line in enumerate(specs):
- line = line.strip()
- if line in( "*cpp:", "*cc1plus:"):
- specs[i+1] += " -D__MSVCRT_VERSION__=%s" % (self.MSVCR_VERSIONS[requestedVersion][0],)
- elif line == "*link_gcc_c_sequence:":
- specs[i+1] += " %%{shared|mdll: msvcr%(requestedVersion)s.dll.res%%s} %%{!shared: %%{!mdll: msvcr%(requestedVersion)s.exe.res%%s}}" % locals()
- elif line == "*libgcc:":
- specs[i+1] = "-lcontinue_on_invalid_param " + specs[i+1].replace("-lmoldname", "-lmoldname" + requestedVersion).replace("-lmsvcrt", "-lmsvcr" + requestedVersion)
- with open(specFile, "wb") as fp:
- fp.write("\r\n".join(specs))
- def main(self, args):
- """
- Patch the MinGW gcc
- Usage: mingw32-patch-gcc4msvcrXX.py <VERSION>
- where <VERSION> is one of "60", "90"
- """
- if not args:
- print self.main.__doc__
- return
- requestedVersion = args[0]
- specFile = os.path.join(self.getPrimarySpecsDir(), self.PRIMARY_SPEC_NAME)
- # special case
- if requestedVersion == "60":
- if os.path.exists(specFile):
- os.remove(specFile)
- else:
- # checks
- if requestedVersion not in self.MSVCR_VERSIONS:
- raise ValueError("Unsupported version number %s" % (requestedVersion,))
- for name in self.LIBS_TO_CHECK:
- name = name % {"version": requestedVersion}
- libPath = self.installedFile(name)
- if not libPath:
- raise RuntimeError("Installation is missing library %s" % (name,))
- libPath = os.path.dirname(libPath) # we need it later on
- # check the manifest files
- manifest = self.MSVCR_VERSIONS[requestedVersion][1]
- if manifest:
- for i, name in enumerate(('exe', 'dll')):
- name = "msvcr%s.%s.res" % (requestedVersion, name)
- if not self.installedFile(name):
- self.createManifestResource(os.path.join(libPath,name), i+1, manifest)
- # create the spec file
- self.createSpec(specFile, requestedVersion)
- return 0
- if __name__ == "__main__":
- import sys
- sys.exit(PatchGcc().main(sys.argv[1:]))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement