1*cda5da8dSAndroid Build Coastguard Worker"""distutils._msvccompiler 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerContains MSVCCompiler, an implementation of the abstract CCompiler class 4*cda5da8dSAndroid Build Coastguard Workerfor Microsoft Visual Studio 2015. 5*cda5da8dSAndroid Build Coastguard Worker 6*cda5da8dSAndroid Build Coastguard WorkerThe module is compatible with VS 2015 and later. You can find legacy support 7*cda5da8dSAndroid Build Coastguard Workerfor older versions in distutils.msvc9compiler and distutils.msvccompiler. 8*cda5da8dSAndroid Build Coastguard Worker""" 9*cda5da8dSAndroid Build Coastguard Worker 10*cda5da8dSAndroid Build Coastguard Worker# Written by Perry Stoll 11*cda5da8dSAndroid Build Coastguard Worker# hacked by Robin Becker and Thomas Heller to do a better job of 12*cda5da8dSAndroid Build Coastguard Worker# finding DevStudio (through the registry) 13*cda5da8dSAndroid Build Coastguard Worker# ported to VS 2005 and VS 2008 by Christian Heimes 14*cda5da8dSAndroid Build Coastguard Worker# ported to VS 2015 by Steve Dower 15*cda5da8dSAndroid Build Coastguard Worker 16*cda5da8dSAndroid Build Coastguard Workerimport os 17*cda5da8dSAndroid Build Coastguard Workerimport subprocess 18*cda5da8dSAndroid Build Coastguard Workerimport winreg 19*cda5da8dSAndroid Build Coastguard Worker 20*cda5da8dSAndroid Build Coastguard Workerfrom distutils.errors import DistutilsExecError, DistutilsPlatformError, \ 21*cda5da8dSAndroid Build Coastguard Worker CompileError, LibError, LinkError 22*cda5da8dSAndroid Build Coastguard Workerfrom distutils.ccompiler import CCompiler, gen_lib_options 23*cda5da8dSAndroid Build Coastguard Workerfrom distutils import log 24*cda5da8dSAndroid Build Coastguard Workerfrom distutils.util import get_platform 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Workerfrom itertools import count 27*cda5da8dSAndroid Build Coastguard Worker 28*cda5da8dSAndroid Build Coastguard Workerdef _find_vc2015(): 29*cda5da8dSAndroid Build Coastguard Worker try: 30*cda5da8dSAndroid Build Coastguard Worker key = winreg.OpenKeyEx( 31*cda5da8dSAndroid Build Coastguard Worker winreg.HKEY_LOCAL_MACHINE, 32*cda5da8dSAndroid Build Coastguard Worker r"Software\Microsoft\VisualStudio\SxS\VC7", 33*cda5da8dSAndroid Build Coastguard Worker access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY 34*cda5da8dSAndroid Build Coastguard Worker ) 35*cda5da8dSAndroid Build Coastguard Worker except OSError: 36*cda5da8dSAndroid Build Coastguard Worker log.debug("Visual C++ is not registered") 37*cda5da8dSAndroid Build Coastguard Worker return None, None 38*cda5da8dSAndroid Build Coastguard Worker 39*cda5da8dSAndroid Build Coastguard Worker best_version = 0 40*cda5da8dSAndroid Build Coastguard Worker best_dir = None 41*cda5da8dSAndroid Build Coastguard Worker with key: 42*cda5da8dSAndroid Build Coastguard Worker for i in count(): 43*cda5da8dSAndroid Build Coastguard Worker try: 44*cda5da8dSAndroid Build Coastguard Worker v, vc_dir, vt = winreg.EnumValue(key, i) 45*cda5da8dSAndroid Build Coastguard Worker except OSError: 46*cda5da8dSAndroid Build Coastguard Worker break 47*cda5da8dSAndroid Build Coastguard Worker if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir): 48*cda5da8dSAndroid Build Coastguard Worker try: 49*cda5da8dSAndroid Build Coastguard Worker version = int(float(v)) 50*cda5da8dSAndroid Build Coastguard Worker except (ValueError, TypeError): 51*cda5da8dSAndroid Build Coastguard Worker continue 52*cda5da8dSAndroid Build Coastguard Worker if version >= 14 and version > best_version: 53*cda5da8dSAndroid Build Coastguard Worker best_version, best_dir = version, vc_dir 54*cda5da8dSAndroid Build Coastguard Worker return best_version, best_dir 55*cda5da8dSAndroid Build Coastguard Worker 56*cda5da8dSAndroid Build Coastguard Workerdef _find_vc2017(): 57*cda5da8dSAndroid Build Coastguard Worker """Returns "15, path" based on the result of invoking vswhere.exe 58*cda5da8dSAndroid Build Coastguard Worker If no install is found, returns "None, None" 59*cda5da8dSAndroid Build Coastguard Worker 60*cda5da8dSAndroid Build Coastguard Worker The version is returned to avoid unnecessarily changing the function 61*cda5da8dSAndroid Build Coastguard Worker result. It may be ignored when the path is not None. 62*cda5da8dSAndroid Build Coastguard Worker 63*cda5da8dSAndroid Build Coastguard Worker If vswhere.exe is not available, by definition, VS 2017 is not 64*cda5da8dSAndroid Build Coastguard Worker installed. 65*cda5da8dSAndroid Build Coastguard Worker """ 66*cda5da8dSAndroid Build Coastguard Worker root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles") 67*cda5da8dSAndroid Build Coastguard Worker if not root: 68*cda5da8dSAndroid Build Coastguard Worker return None, None 69*cda5da8dSAndroid Build Coastguard Worker 70*cda5da8dSAndroid Build Coastguard Worker try: 71*cda5da8dSAndroid Build Coastguard Worker path = subprocess.check_output([ 72*cda5da8dSAndroid Build Coastguard Worker os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), 73*cda5da8dSAndroid Build Coastguard Worker "-latest", 74*cda5da8dSAndroid Build Coastguard Worker "-prerelease", 75*cda5da8dSAndroid Build Coastguard Worker "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", 76*cda5da8dSAndroid Build Coastguard Worker "-property", "installationPath", 77*cda5da8dSAndroid Build Coastguard Worker "-products", "*", 78*cda5da8dSAndroid Build Coastguard Worker ], encoding="mbcs", errors="strict").strip() 79*cda5da8dSAndroid Build Coastguard Worker except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): 80*cda5da8dSAndroid Build Coastguard Worker return None, None 81*cda5da8dSAndroid Build Coastguard Worker 82*cda5da8dSAndroid Build Coastguard Worker path = os.path.join(path, "VC", "Auxiliary", "Build") 83*cda5da8dSAndroid Build Coastguard Worker if os.path.isdir(path): 84*cda5da8dSAndroid Build Coastguard Worker return 15, path 85*cda5da8dSAndroid Build Coastguard Worker 86*cda5da8dSAndroid Build Coastguard Worker return None, None 87*cda5da8dSAndroid Build Coastguard Worker 88*cda5da8dSAndroid Build Coastguard WorkerPLAT_SPEC_TO_RUNTIME = { 89*cda5da8dSAndroid Build Coastguard Worker 'x86' : 'x86', 90*cda5da8dSAndroid Build Coastguard Worker 'x86_amd64' : 'x64', 91*cda5da8dSAndroid Build Coastguard Worker 'x86_arm' : 'arm', 92*cda5da8dSAndroid Build Coastguard Worker 'x86_arm64' : 'arm64' 93*cda5da8dSAndroid Build Coastguard Worker} 94*cda5da8dSAndroid Build Coastguard Worker 95*cda5da8dSAndroid Build Coastguard Workerdef _find_vcvarsall(plat_spec): 96*cda5da8dSAndroid Build Coastguard Worker # bpo-38597: Removed vcruntime return value 97*cda5da8dSAndroid Build Coastguard Worker _, best_dir = _find_vc2017() 98*cda5da8dSAndroid Build Coastguard Worker 99*cda5da8dSAndroid Build Coastguard Worker if not best_dir: 100*cda5da8dSAndroid Build Coastguard Worker best_version, best_dir = _find_vc2015() 101*cda5da8dSAndroid Build Coastguard Worker 102*cda5da8dSAndroid Build Coastguard Worker if not best_dir: 103*cda5da8dSAndroid Build Coastguard Worker log.debug("No suitable Visual C++ version found") 104*cda5da8dSAndroid Build Coastguard Worker return None, None 105*cda5da8dSAndroid Build Coastguard Worker 106*cda5da8dSAndroid Build Coastguard Worker vcvarsall = os.path.join(best_dir, "vcvarsall.bat") 107*cda5da8dSAndroid Build Coastguard Worker if not os.path.isfile(vcvarsall): 108*cda5da8dSAndroid Build Coastguard Worker log.debug("%s cannot be found", vcvarsall) 109*cda5da8dSAndroid Build Coastguard Worker return None, None 110*cda5da8dSAndroid Build Coastguard Worker 111*cda5da8dSAndroid Build Coastguard Worker return vcvarsall, None 112*cda5da8dSAndroid Build Coastguard Worker 113*cda5da8dSAndroid Build Coastguard Workerdef _get_vc_env(plat_spec): 114*cda5da8dSAndroid Build Coastguard Worker if os.getenv("DISTUTILS_USE_SDK"): 115*cda5da8dSAndroid Build Coastguard Worker return { 116*cda5da8dSAndroid Build Coastguard Worker key.lower(): value 117*cda5da8dSAndroid Build Coastguard Worker for key, value in os.environ.items() 118*cda5da8dSAndroid Build Coastguard Worker } 119*cda5da8dSAndroid Build Coastguard Worker 120*cda5da8dSAndroid Build Coastguard Worker vcvarsall, _ = _find_vcvarsall(plat_spec) 121*cda5da8dSAndroid Build Coastguard Worker if not vcvarsall: 122*cda5da8dSAndroid Build Coastguard Worker raise DistutilsPlatformError("Unable to find vcvarsall.bat") 123*cda5da8dSAndroid Build Coastguard Worker 124*cda5da8dSAndroid Build Coastguard Worker try: 125*cda5da8dSAndroid Build Coastguard Worker out = subprocess.check_output( 126*cda5da8dSAndroid Build Coastguard Worker 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec), 127*cda5da8dSAndroid Build Coastguard Worker stderr=subprocess.STDOUT, 128*cda5da8dSAndroid Build Coastguard Worker ).decode('utf-16le', errors='replace') 129*cda5da8dSAndroid Build Coastguard Worker except subprocess.CalledProcessError as exc: 130*cda5da8dSAndroid Build Coastguard Worker log.error(exc.output) 131*cda5da8dSAndroid Build Coastguard Worker raise DistutilsPlatformError("Error executing {}" 132*cda5da8dSAndroid Build Coastguard Worker .format(exc.cmd)) 133*cda5da8dSAndroid Build Coastguard Worker 134*cda5da8dSAndroid Build Coastguard Worker env = { 135*cda5da8dSAndroid Build Coastguard Worker key.lower(): value 136*cda5da8dSAndroid Build Coastguard Worker for key, _, value in 137*cda5da8dSAndroid Build Coastguard Worker (line.partition('=') for line in out.splitlines()) 138*cda5da8dSAndroid Build Coastguard Worker if key and value 139*cda5da8dSAndroid Build Coastguard Worker } 140*cda5da8dSAndroid Build Coastguard Worker 141*cda5da8dSAndroid Build Coastguard Worker return env 142*cda5da8dSAndroid Build Coastguard Worker 143*cda5da8dSAndroid Build Coastguard Workerdef _find_exe(exe, paths=None): 144*cda5da8dSAndroid Build Coastguard Worker """Return path to an MSVC executable program. 145*cda5da8dSAndroid Build Coastguard Worker 146*cda5da8dSAndroid Build Coastguard Worker Tries to find the program in several places: first, one of the 147*cda5da8dSAndroid Build Coastguard Worker MSVC program search paths from the registry; next, the directories 148*cda5da8dSAndroid Build Coastguard Worker in the PATH environment variable. If any of those work, return an 149*cda5da8dSAndroid Build Coastguard Worker absolute path that is known to exist. If none of them work, just 150*cda5da8dSAndroid Build Coastguard Worker return the original program name, 'exe'. 151*cda5da8dSAndroid Build Coastguard Worker """ 152*cda5da8dSAndroid Build Coastguard Worker if not paths: 153*cda5da8dSAndroid Build Coastguard Worker paths = os.getenv('path').split(os.pathsep) 154*cda5da8dSAndroid Build Coastguard Worker for p in paths: 155*cda5da8dSAndroid Build Coastguard Worker fn = os.path.join(os.path.abspath(p), exe) 156*cda5da8dSAndroid Build Coastguard Worker if os.path.isfile(fn): 157*cda5da8dSAndroid Build Coastguard Worker return fn 158*cda5da8dSAndroid Build Coastguard Worker return exe 159*cda5da8dSAndroid Build Coastguard Worker 160*cda5da8dSAndroid Build Coastguard Worker# A map keyed by get_platform() return values to values accepted by 161*cda5da8dSAndroid Build Coastguard Worker# 'vcvarsall.bat'. Always cross-compile from x86 to work with the 162*cda5da8dSAndroid Build Coastguard Worker# lighter-weight MSVC installs that do not include native 64-bit tools. 163*cda5da8dSAndroid Build Coastguard WorkerPLAT_TO_VCVARS = { 164*cda5da8dSAndroid Build Coastguard Worker 'win32' : 'x86', 165*cda5da8dSAndroid Build Coastguard Worker 'win-amd64' : 'x86_amd64', 166*cda5da8dSAndroid Build Coastguard Worker 'win-arm32' : 'x86_arm', 167*cda5da8dSAndroid Build Coastguard Worker 'win-arm64' : 'x86_arm64' 168*cda5da8dSAndroid Build Coastguard Worker} 169*cda5da8dSAndroid Build Coastguard Worker 170*cda5da8dSAndroid Build Coastguard Workerclass MSVCCompiler(CCompiler) : 171*cda5da8dSAndroid Build Coastguard Worker """Concrete class that implements an interface to Microsoft Visual C++, 172*cda5da8dSAndroid Build Coastguard Worker as defined by the CCompiler abstract class.""" 173*cda5da8dSAndroid Build Coastguard Worker 174*cda5da8dSAndroid Build Coastguard Worker compiler_type = 'msvc' 175*cda5da8dSAndroid Build Coastguard Worker 176*cda5da8dSAndroid Build Coastguard Worker # Just set this so CCompiler's constructor doesn't barf. We currently 177*cda5da8dSAndroid Build Coastguard Worker # don't use the 'set_executables()' bureaucracy provided by CCompiler, 178*cda5da8dSAndroid Build Coastguard Worker # as it really isn't necessary for this sort of single-compiler class. 179*cda5da8dSAndroid Build Coastguard Worker # Would be nice to have a consistent interface with UnixCCompiler, 180*cda5da8dSAndroid Build Coastguard Worker # though, so it's worth thinking about. 181*cda5da8dSAndroid Build Coastguard Worker executables = {} 182*cda5da8dSAndroid Build Coastguard Worker 183*cda5da8dSAndroid Build Coastguard Worker # Private class data (need to distinguish C from C++ source for compiler) 184*cda5da8dSAndroid Build Coastguard Worker _c_extensions = ['.c'] 185*cda5da8dSAndroid Build Coastguard Worker _cpp_extensions = ['.cc', '.cpp', '.cxx'] 186*cda5da8dSAndroid Build Coastguard Worker _rc_extensions = ['.rc'] 187*cda5da8dSAndroid Build Coastguard Worker _mc_extensions = ['.mc'] 188*cda5da8dSAndroid Build Coastguard Worker 189*cda5da8dSAndroid Build Coastguard Worker # Needed for the filename generation methods provided by the 190*cda5da8dSAndroid Build Coastguard Worker # base class, CCompiler. 191*cda5da8dSAndroid Build Coastguard Worker src_extensions = (_c_extensions + _cpp_extensions + 192*cda5da8dSAndroid Build Coastguard Worker _rc_extensions + _mc_extensions) 193*cda5da8dSAndroid Build Coastguard Worker res_extension = '.res' 194*cda5da8dSAndroid Build Coastguard Worker obj_extension = '.obj' 195*cda5da8dSAndroid Build Coastguard Worker static_lib_extension = '.lib' 196*cda5da8dSAndroid Build Coastguard Worker shared_lib_extension = '.dll' 197*cda5da8dSAndroid Build Coastguard Worker static_lib_format = shared_lib_format = '%s%s' 198*cda5da8dSAndroid Build Coastguard Worker exe_extension = '.exe' 199*cda5da8dSAndroid Build Coastguard Worker 200*cda5da8dSAndroid Build Coastguard Worker 201*cda5da8dSAndroid Build Coastguard Worker def __init__(self, verbose=0, dry_run=0, force=0): 202*cda5da8dSAndroid Build Coastguard Worker CCompiler.__init__ (self, verbose, dry_run, force) 203*cda5da8dSAndroid Build Coastguard Worker # target platform (.plat_name is consistent with 'bdist') 204*cda5da8dSAndroid Build Coastguard Worker self.plat_name = None 205*cda5da8dSAndroid Build Coastguard Worker self.initialized = False 206*cda5da8dSAndroid Build Coastguard Worker 207*cda5da8dSAndroid Build Coastguard Worker def initialize(self, plat_name=None): 208*cda5da8dSAndroid Build Coastguard Worker # multi-init means we would need to check platform same each time... 209*cda5da8dSAndroid Build Coastguard Worker assert not self.initialized, "don't init multiple times" 210*cda5da8dSAndroid Build Coastguard Worker if plat_name is None: 211*cda5da8dSAndroid Build Coastguard Worker plat_name = get_platform() 212*cda5da8dSAndroid Build Coastguard Worker # sanity check for platforms to prevent obscure errors later. 213*cda5da8dSAndroid Build Coastguard Worker if plat_name not in PLAT_TO_VCVARS: 214*cda5da8dSAndroid Build Coastguard Worker raise DistutilsPlatformError("--plat-name must be one of {}" 215*cda5da8dSAndroid Build Coastguard Worker .format(tuple(PLAT_TO_VCVARS))) 216*cda5da8dSAndroid Build Coastguard Worker 217*cda5da8dSAndroid Build Coastguard Worker # Get the vcvarsall.bat spec for the requested platform. 218*cda5da8dSAndroid Build Coastguard Worker plat_spec = PLAT_TO_VCVARS[plat_name] 219*cda5da8dSAndroid Build Coastguard Worker 220*cda5da8dSAndroid Build Coastguard Worker vc_env = _get_vc_env(plat_spec) 221*cda5da8dSAndroid Build Coastguard Worker if not vc_env: 222*cda5da8dSAndroid Build Coastguard Worker raise DistutilsPlatformError("Unable to find a compatible " 223*cda5da8dSAndroid Build Coastguard Worker "Visual Studio installation.") 224*cda5da8dSAndroid Build Coastguard Worker 225*cda5da8dSAndroid Build Coastguard Worker self._paths = vc_env.get('path', '') 226*cda5da8dSAndroid Build Coastguard Worker paths = self._paths.split(os.pathsep) 227*cda5da8dSAndroid Build Coastguard Worker self.cc = _find_exe("cl.exe", paths) 228*cda5da8dSAndroid Build Coastguard Worker self.linker = _find_exe("link.exe", paths) 229*cda5da8dSAndroid Build Coastguard Worker self.lib = _find_exe("lib.exe", paths) 230*cda5da8dSAndroid Build Coastguard Worker self.rc = _find_exe("rc.exe", paths) # resource compiler 231*cda5da8dSAndroid Build Coastguard Worker self.mc = _find_exe("mc.exe", paths) # message compiler 232*cda5da8dSAndroid Build Coastguard Worker self.mt = _find_exe("mt.exe", paths) # message compiler 233*cda5da8dSAndroid Build Coastguard Worker 234*cda5da8dSAndroid Build Coastguard Worker for dir in vc_env.get('include', '').split(os.pathsep): 235*cda5da8dSAndroid Build Coastguard Worker if dir: 236*cda5da8dSAndroid Build Coastguard Worker self.add_include_dir(dir.rstrip(os.sep)) 237*cda5da8dSAndroid Build Coastguard Worker 238*cda5da8dSAndroid Build Coastguard Worker for dir in vc_env.get('lib', '').split(os.pathsep): 239*cda5da8dSAndroid Build Coastguard Worker if dir: 240*cda5da8dSAndroid Build Coastguard Worker self.add_library_dir(dir.rstrip(os.sep)) 241*cda5da8dSAndroid Build Coastguard Worker 242*cda5da8dSAndroid Build Coastguard Worker self.preprocess_options = None 243*cda5da8dSAndroid Build Coastguard Worker # bpo-38597: Always compile with dynamic linking 244*cda5da8dSAndroid Build Coastguard Worker # Future releases of Python 3.x will include all past 245*cda5da8dSAndroid Build Coastguard Worker # versions of vcruntime*.dll for compatibility. 246*cda5da8dSAndroid Build Coastguard Worker self.compile_options = [ 247*cda5da8dSAndroid Build Coastguard Worker '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG', '/MD' 248*cda5da8dSAndroid Build Coastguard Worker ] 249*cda5da8dSAndroid Build Coastguard Worker 250*cda5da8dSAndroid Build Coastguard Worker self.compile_options_debug = [ 251*cda5da8dSAndroid Build Coastguard Worker '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' 252*cda5da8dSAndroid Build Coastguard Worker ] 253*cda5da8dSAndroid Build Coastguard Worker 254*cda5da8dSAndroid Build Coastguard Worker ldflags = [ 255*cda5da8dSAndroid Build Coastguard Worker '/nologo', '/INCREMENTAL:NO', '/LTCG' 256*cda5da8dSAndroid Build Coastguard Worker ] 257*cda5da8dSAndroid Build Coastguard Worker 258*cda5da8dSAndroid Build Coastguard Worker ldflags_debug = [ 259*cda5da8dSAndroid Build Coastguard Worker '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL' 260*cda5da8dSAndroid Build Coastguard Worker ] 261*cda5da8dSAndroid Build Coastguard Worker 262*cda5da8dSAndroid Build Coastguard Worker self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] 263*cda5da8dSAndroid Build Coastguard Worker self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1'] 264*cda5da8dSAndroid Build Coastguard Worker self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] 265*cda5da8dSAndroid Build Coastguard Worker self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] 266*cda5da8dSAndroid Build Coastguard Worker self.ldflags_static = [*ldflags] 267*cda5da8dSAndroid Build Coastguard Worker self.ldflags_static_debug = [*ldflags_debug] 268*cda5da8dSAndroid Build Coastguard Worker 269*cda5da8dSAndroid Build Coastguard Worker self._ldflags = { 270*cda5da8dSAndroid Build Coastguard Worker (CCompiler.EXECUTABLE, None): self.ldflags_exe, 271*cda5da8dSAndroid Build Coastguard Worker (CCompiler.EXECUTABLE, False): self.ldflags_exe, 272*cda5da8dSAndroid Build Coastguard Worker (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug, 273*cda5da8dSAndroid Build Coastguard Worker (CCompiler.SHARED_OBJECT, None): self.ldflags_shared, 274*cda5da8dSAndroid Build Coastguard Worker (CCompiler.SHARED_OBJECT, False): self.ldflags_shared, 275*cda5da8dSAndroid Build Coastguard Worker (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug, 276*cda5da8dSAndroid Build Coastguard Worker (CCompiler.SHARED_LIBRARY, None): self.ldflags_static, 277*cda5da8dSAndroid Build Coastguard Worker (CCompiler.SHARED_LIBRARY, False): self.ldflags_static, 278*cda5da8dSAndroid Build Coastguard Worker (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug, 279*cda5da8dSAndroid Build Coastguard Worker } 280*cda5da8dSAndroid Build Coastguard Worker 281*cda5da8dSAndroid Build Coastguard Worker self.initialized = True 282*cda5da8dSAndroid Build Coastguard Worker 283*cda5da8dSAndroid Build Coastguard Worker # -- Worker methods ------------------------------------------------ 284*cda5da8dSAndroid Build Coastguard Worker 285*cda5da8dSAndroid Build Coastguard Worker def object_filenames(self, 286*cda5da8dSAndroid Build Coastguard Worker source_filenames, 287*cda5da8dSAndroid Build Coastguard Worker strip_dir=0, 288*cda5da8dSAndroid Build Coastguard Worker output_dir=''): 289*cda5da8dSAndroid Build Coastguard Worker ext_map = { 290*cda5da8dSAndroid Build Coastguard Worker **{ext: self.obj_extension for ext in self.src_extensions}, 291*cda5da8dSAndroid Build Coastguard Worker **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions}, 292*cda5da8dSAndroid Build Coastguard Worker } 293*cda5da8dSAndroid Build Coastguard Worker 294*cda5da8dSAndroid Build Coastguard Worker output_dir = output_dir or '' 295*cda5da8dSAndroid Build Coastguard Worker 296*cda5da8dSAndroid Build Coastguard Worker def make_out_path(p): 297*cda5da8dSAndroid Build Coastguard Worker base, ext = os.path.splitext(p) 298*cda5da8dSAndroid Build Coastguard Worker if strip_dir: 299*cda5da8dSAndroid Build Coastguard Worker base = os.path.basename(base) 300*cda5da8dSAndroid Build Coastguard Worker else: 301*cda5da8dSAndroid Build Coastguard Worker _, base = os.path.splitdrive(base) 302*cda5da8dSAndroid Build Coastguard Worker if base.startswith((os.path.sep, os.path.altsep)): 303*cda5da8dSAndroid Build Coastguard Worker base = base[1:] 304*cda5da8dSAndroid Build Coastguard Worker try: 305*cda5da8dSAndroid Build Coastguard Worker # XXX: This may produce absurdly long paths. We should check 306*cda5da8dSAndroid Build Coastguard Worker # the length of the result and trim base until we fit within 307*cda5da8dSAndroid Build Coastguard Worker # 260 characters. 308*cda5da8dSAndroid Build Coastguard Worker return os.path.join(output_dir, base + ext_map[ext]) 309*cda5da8dSAndroid Build Coastguard Worker except LookupError: 310*cda5da8dSAndroid Build Coastguard Worker # Better to raise an exception instead of silently continuing 311*cda5da8dSAndroid Build Coastguard Worker # and later complain about sources and targets having 312*cda5da8dSAndroid Build Coastguard Worker # different lengths 313*cda5da8dSAndroid Build Coastguard Worker raise CompileError("Don't know how to compile {}".format(p)) 314*cda5da8dSAndroid Build Coastguard Worker 315*cda5da8dSAndroid Build Coastguard Worker return list(map(make_out_path, source_filenames)) 316*cda5da8dSAndroid Build Coastguard Worker 317*cda5da8dSAndroid Build Coastguard Worker 318*cda5da8dSAndroid Build Coastguard Worker def compile(self, sources, 319*cda5da8dSAndroid Build Coastguard Worker output_dir=None, macros=None, include_dirs=None, debug=0, 320*cda5da8dSAndroid Build Coastguard Worker extra_preargs=None, extra_postargs=None, depends=None): 321*cda5da8dSAndroid Build Coastguard Worker 322*cda5da8dSAndroid Build Coastguard Worker if not self.initialized: 323*cda5da8dSAndroid Build Coastguard Worker self.initialize() 324*cda5da8dSAndroid Build Coastguard Worker compile_info = self._setup_compile(output_dir, macros, include_dirs, 325*cda5da8dSAndroid Build Coastguard Worker sources, depends, extra_postargs) 326*cda5da8dSAndroid Build Coastguard Worker macros, objects, extra_postargs, pp_opts, build = compile_info 327*cda5da8dSAndroid Build Coastguard Worker 328*cda5da8dSAndroid Build Coastguard Worker compile_opts = extra_preargs or [] 329*cda5da8dSAndroid Build Coastguard Worker compile_opts.append('/c') 330*cda5da8dSAndroid Build Coastguard Worker if debug: 331*cda5da8dSAndroid Build Coastguard Worker compile_opts.extend(self.compile_options_debug) 332*cda5da8dSAndroid Build Coastguard Worker else: 333*cda5da8dSAndroid Build Coastguard Worker compile_opts.extend(self.compile_options) 334*cda5da8dSAndroid Build Coastguard Worker 335*cda5da8dSAndroid Build Coastguard Worker 336*cda5da8dSAndroid Build Coastguard Worker add_cpp_opts = False 337*cda5da8dSAndroid Build Coastguard Worker 338*cda5da8dSAndroid Build Coastguard Worker for obj in objects: 339*cda5da8dSAndroid Build Coastguard Worker try: 340*cda5da8dSAndroid Build Coastguard Worker src, ext = build[obj] 341*cda5da8dSAndroid Build Coastguard Worker except KeyError: 342*cda5da8dSAndroid Build Coastguard Worker continue 343*cda5da8dSAndroid Build Coastguard Worker if debug: 344*cda5da8dSAndroid Build Coastguard Worker # pass the full pathname to MSVC in debug mode, 345*cda5da8dSAndroid Build Coastguard Worker # this allows the debugger to find the source file 346*cda5da8dSAndroid Build Coastguard Worker # without asking the user to browse for it 347*cda5da8dSAndroid Build Coastguard Worker src = os.path.abspath(src) 348*cda5da8dSAndroid Build Coastguard Worker 349*cda5da8dSAndroid Build Coastguard Worker if ext in self._c_extensions: 350*cda5da8dSAndroid Build Coastguard Worker input_opt = "/Tc" + src 351*cda5da8dSAndroid Build Coastguard Worker elif ext in self._cpp_extensions: 352*cda5da8dSAndroid Build Coastguard Worker input_opt = "/Tp" + src 353*cda5da8dSAndroid Build Coastguard Worker add_cpp_opts = True 354*cda5da8dSAndroid Build Coastguard Worker elif ext in self._rc_extensions: 355*cda5da8dSAndroid Build Coastguard Worker # compile .RC to .RES file 356*cda5da8dSAndroid Build Coastguard Worker input_opt = src 357*cda5da8dSAndroid Build Coastguard Worker output_opt = "/fo" + obj 358*cda5da8dSAndroid Build Coastguard Worker try: 359*cda5da8dSAndroid Build Coastguard Worker self.spawn([self.rc] + pp_opts + [output_opt, input_opt]) 360*cda5da8dSAndroid Build Coastguard Worker except DistutilsExecError as msg: 361*cda5da8dSAndroid Build Coastguard Worker raise CompileError(msg) 362*cda5da8dSAndroid Build Coastguard Worker continue 363*cda5da8dSAndroid Build Coastguard Worker elif ext in self._mc_extensions: 364*cda5da8dSAndroid Build Coastguard Worker # Compile .MC to .RC file to .RES file. 365*cda5da8dSAndroid Build Coastguard Worker # * '-h dir' specifies the directory for the 366*cda5da8dSAndroid Build Coastguard Worker # generated include file 367*cda5da8dSAndroid Build Coastguard Worker # * '-r dir' specifies the target directory of the 368*cda5da8dSAndroid Build Coastguard Worker # generated RC file and the binary message resource 369*cda5da8dSAndroid Build Coastguard Worker # it includes 370*cda5da8dSAndroid Build Coastguard Worker # 371*cda5da8dSAndroid Build Coastguard Worker # For now (since there are no options to change this), 372*cda5da8dSAndroid Build Coastguard Worker # we use the source-directory for the include file and 373*cda5da8dSAndroid Build Coastguard Worker # the build directory for the RC file and message 374*cda5da8dSAndroid Build Coastguard Worker # resources. This works at least for win32all. 375*cda5da8dSAndroid Build Coastguard Worker h_dir = os.path.dirname(src) 376*cda5da8dSAndroid Build Coastguard Worker rc_dir = os.path.dirname(obj) 377*cda5da8dSAndroid Build Coastguard Worker try: 378*cda5da8dSAndroid Build Coastguard Worker # first compile .MC to .RC and .H file 379*cda5da8dSAndroid Build Coastguard Worker self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src]) 380*cda5da8dSAndroid Build Coastguard Worker base, _ = os.path.splitext(os.path.basename (src)) 381*cda5da8dSAndroid Build Coastguard Worker rc_file = os.path.join(rc_dir, base + '.rc') 382*cda5da8dSAndroid Build Coastguard Worker # then compile .RC to .RES file 383*cda5da8dSAndroid Build Coastguard Worker self.spawn([self.rc, "/fo" + obj, rc_file]) 384*cda5da8dSAndroid Build Coastguard Worker 385*cda5da8dSAndroid Build Coastguard Worker except DistutilsExecError as msg: 386*cda5da8dSAndroid Build Coastguard Worker raise CompileError(msg) 387*cda5da8dSAndroid Build Coastguard Worker continue 388*cda5da8dSAndroid Build Coastguard Worker else: 389*cda5da8dSAndroid Build Coastguard Worker # how to handle this file? 390*cda5da8dSAndroid Build Coastguard Worker raise CompileError("Don't know how to compile {} to {}" 391*cda5da8dSAndroid Build Coastguard Worker .format(src, obj)) 392*cda5da8dSAndroid Build Coastguard Worker 393*cda5da8dSAndroid Build Coastguard Worker args = [self.cc] + compile_opts + pp_opts 394*cda5da8dSAndroid Build Coastguard Worker if add_cpp_opts: 395*cda5da8dSAndroid Build Coastguard Worker args.append('/EHsc') 396*cda5da8dSAndroid Build Coastguard Worker args.append(input_opt) 397*cda5da8dSAndroid Build Coastguard Worker args.append("/Fo" + obj) 398*cda5da8dSAndroid Build Coastguard Worker args.extend(extra_postargs) 399*cda5da8dSAndroid Build Coastguard Worker 400*cda5da8dSAndroid Build Coastguard Worker try: 401*cda5da8dSAndroid Build Coastguard Worker self.spawn(args) 402*cda5da8dSAndroid Build Coastguard Worker except DistutilsExecError as msg: 403*cda5da8dSAndroid Build Coastguard Worker raise CompileError(msg) 404*cda5da8dSAndroid Build Coastguard Worker 405*cda5da8dSAndroid Build Coastguard Worker return objects 406*cda5da8dSAndroid Build Coastguard Worker 407*cda5da8dSAndroid Build Coastguard Worker 408*cda5da8dSAndroid Build Coastguard Worker def create_static_lib(self, 409*cda5da8dSAndroid Build Coastguard Worker objects, 410*cda5da8dSAndroid Build Coastguard Worker output_libname, 411*cda5da8dSAndroid Build Coastguard Worker output_dir=None, 412*cda5da8dSAndroid Build Coastguard Worker debug=0, 413*cda5da8dSAndroid Build Coastguard Worker target_lang=None): 414*cda5da8dSAndroid Build Coastguard Worker 415*cda5da8dSAndroid Build Coastguard Worker if not self.initialized: 416*cda5da8dSAndroid Build Coastguard Worker self.initialize() 417*cda5da8dSAndroid Build Coastguard Worker objects, output_dir = self._fix_object_args(objects, output_dir) 418*cda5da8dSAndroid Build Coastguard Worker output_filename = self.library_filename(output_libname, 419*cda5da8dSAndroid Build Coastguard Worker output_dir=output_dir) 420*cda5da8dSAndroid Build Coastguard Worker 421*cda5da8dSAndroid Build Coastguard Worker if self._need_link(objects, output_filename): 422*cda5da8dSAndroid Build Coastguard Worker lib_args = objects + ['/OUT:' + output_filename] 423*cda5da8dSAndroid Build Coastguard Worker if debug: 424*cda5da8dSAndroid Build Coastguard Worker pass # XXX what goes here? 425*cda5da8dSAndroid Build Coastguard Worker try: 426*cda5da8dSAndroid Build Coastguard Worker log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args)) 427*cda5da8dSAndroid Build Coastguard Worker self.spawn([self.lib] + lib_args) 428*cda5da8dSAndroid Build Coastguard Worker except DistutilsExecError as msg: 429*cda5da8dSAndroid Build Coastguard Worker raise LibError(msg) 430*cda5da8dSAndroid Build Coastguard Worker else: 431*cda5da8dSAndroid Build Coastguard Worker log.debug("skipping %s (up-to-date)", output_filename) 432*cda5da8dSAndroid Build Coastguard Worker 433*cda5da8dSAndroid Build Coastguard Worker 434*cda5da8dSAndroid Build Coastguard Worker def link(self, 435*cda5da8dSAndroid Build Coastguard Worker target_desc, 436*cda5da8dSAndroid Build Coastguard Worker objects, 437*cda5da8dSAndroid Build Coastguard Worker output_filename, 438*cda5da8dSAndroid Build Coastguard Worker output_dir=None, 439*cda5da8dSAndroid Build Coastguard Worker libraries=None, 440*cda5da8dSAndroid Build Coastguard Worker library_dirs=None, 441*cda5da8dSAndroid Build Coastguard Worker runtime_library_dirs=None, 442*cda5da8dSAndroid Build Coastguard Worker export_symbols=None, 443*cda5da8dSAndroid Build Coastguard Worker debug=0, 444*cda5da8dSAndroid Build Coastguard Worker extra_preargs=None, 445*cda5da8dSAndroid Build Coastguard Worker extra_postargs=None, 446*cda5da8dSAndroid Build Coastguard Worker build_temp=None, 447*cda5da8dSAndroid Build Coastguard Worker target_lang=None): 448*cda5da8dSAndroid Build Coastguard Worker 449*cda5da8dSAndroid Build Coastguard Worker if not self.initialized: 450*cda5da8dSAndroid Build Coastguard Worker self.initialize() 451*cda5da8dSAndroid Build Coastguard Worker objects, output_dir = self._fix_object_args(objects, output_dir) 452*cda5da8dSAndroid Build Coastguard Worker fixed_args = self._fix_lib_args(libraries, library_dirs, 453*cda5da8dSAndroid Build Coastguard Worker runtime_library_dirs) 454*cda5da8dSAndroid Build Coastguard Worker libraries, library_dirs, runtime_library_dirs = fixed_args 455*cda5da8dSAndroid Build Coastguard Worker 456*cda5da8dSAndroid Build Coastguard Worker if runtime_library_dirs: 457*cda5da8dSAndroid Build Coastguard Worker self.warn("I don't know what to do with 'runtime_library_dirs': " 458*cda5da8dSAndroid Build Coastguard Worker + str(runtime_library_dirs)) 459*cda5da8dSAndroid Build Coastguard Worker 460*cda5da8dSAndroid Build Coastguard Worker lib_opts = gen_lib_options(self, 461*cda5da8dSAndroid Build Coastguard Worker library_dirs, runtime_library_dirs, 462*cda5da8dSAndroid Build Coastguard Worker libraries) 463*cda5da8dSAndroid Build Coastguard Worker if output_dir is not None: 464*cda5da8dSAndroid Build Coastguard Worker output_filename = os.path.join(output_dir, output_filename) 465*cda5da8dSAndroid Build Coastguard Worker 466*cda5da8dSAndroid Build Coastguard Worker if self._need_link(objects, output_filename): 467*cda5da8dSAndroid Build Coastguard Worker ldflags = self._ldflags[target_desc, debug] 468*cda5da8dSAndroid Build Coastguard Worker 469*cda5da8dSAndroid Build Coastguard Worker export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])] 470*cda5da8dSAndroid Build Coastguard Worker 471*cda5da8dSAndroid Build Coastguard Worker ld_args = (ldflags + lib_opts + export_opts + 472*cda5da8dSAndroid Build Coastguard Worker objects + ['/OUT:' + output_filename]) 473*cda5da8dSAndroid Build Coastguard Worker 474*cda5da8dSAndroid Build Coastguard Worker # The MSVC linker generates .lib and .exp files, which cannot be 475*cda5da8dSAndroid Build Coastguard Worker # suppressed by any linker switches. The .lib files may even be 476*cda5da8dSAndroid Build Coastguard Worker # needed! Make sure they are generated in the temporary build 477*cda5da8dSAndroid Build Coastguard Worker # directory. Since they have different names for debug and release 478*cda5da8dSAndroid Build Coastguard Worker # builds, they can go into the same directory. 479*cda5da8dSAndroid Build Coastguard Worker build_temp = os.path.dirname(objects[0]) 480*cda5da8dSAndroid Build Coastguard Worker if export_symbols is not None: 481*cda5da8dSAndroid Build Coastguard Worker (dll_name, dll_ext) = os.path.splitext( 482*cda5da8dSAndroid Build Coastguard Worker os.path.basename(output_filename)) 483*cda5da8dSAndroid Build Coastguard Worker implib_file = os.path.join( 484*cda5da8dSAndroid Build Coastguard Worker build_temp, 485*cda5da8dSAndroid Build Coastguard Worker self.library_filename(dll_name)) 486*cda5da8dSAndroid Build Coastguard Worker ld_args.append ('/IMPLIB:' + implib_file) 487*cda5da8dSAndroid Build Coastguard Worker 488*cda5da8dSAndroid Build Coastguard Worker if extra_preargs: 489*cda5da8dSAndroid Build Coastguard Worker ld_args[:0] = extra_preargs 490*cda5da8dSAndroid Build Coastguard Worker if extra_postargs: 491*cda5da8dSAndroid Build Coastguard Worker ld_args.extend(extra_postargs) 492*cda5da8dSAndroid Build Coastguard Worker 493*cda5da8dSAndroid Build Coastguard Worker output_dir = os.path.dirname(os.path.abspath(output_filename)) 494*cda5da8dSAndroid Build Coastguard Worker self.mkpath(output_dir) 495*cda5da8dSAndroid Build Coastguard Worker try: 496*cda5da8dSAndroid Build Coastguard Worker log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args)) 497*cda5da8dSAndroid Build Coastguard Worker self.spawn([self.linker] + ld_args) 498*cda5da8dSAndroid Build Coastguard Worker except DistutilsExecError as msg: 499*cda5da8dSAndroid Build Coastguard Worker raise LinkError(msg) 500*cda5da8dSAndroid Build Coastguard Worker else: 501*cda5da8dSAndroid Build Coastguard Worker log.debug("skipping %s (up-to-date)", output_filename) 502*cda5da8dSAndroid Build Coastguard Worker 503*cda5da8dSAndroid Build Coastguard Worker def spawn(self, cmd): 504*cda5da8dSAndroid Build Coastguard Worker old_path = os.getenv('path') 505*cda5da8dSAndroid Build Coastguard Worker try: 506*cda5da8dSAndroid Build Coastguard Worker os.environ['path'] = self._paths 507*cda5da8dSAndroid Build Coastguard Worker return super().spawn(cmd) 508*cda5da8dSAndroid Build Coastguard Worker finally: 509*cda5da8dSAndroid Build Coastguard Worker os.environ['path'] = old_path 510*cda5da8dSAndroid Build Coastguard Worker 511*cda5da8dSAndroid Build Coastguard Worker # -- Miscellaneous methods ----------------------------------------- 512*cda5da8dSAndroid Build Coastguard Worker # These are all used by the 'gen_lib_options() function, in 513*cda5da8dSAndroid Build Coastguard Worker # ccompiler.py. 514*cda5da8dSAndroid Build Coastguard Worker 515*cda5da8dSAndroid Build Coastguard Worker def library_dir_option(self, dir): 516*cda5da8dSAndroid Build Coastguard Worker return "/LIBPATH:" + dir 517*cda5da8dSAndroid Build Coastguard Worker 518*cda5da8dSAndroid Build Coastguard Worker def runtime_library_dir_option(self, dir): 519*cda5da8dSAndroid Build Coastguard Worker raise DistutilsPlatformError( 520*cda5da8dSAndroid Build Coastguard Worker "don't know how to set runtime library search path for MSVC") 521*cda5da8dSAndroid Build Coastguard Worker 522*cda5da8dSAndroid Build Coastguard Worker def library_option(self, lib): 523*cda5da8dSAndroid Build Coastguard Worker return self.library_filename(lib) 524*cda5da8dSAndroid Build Coastguard Worker 525*cda5da8dSAndroid Build Coastguard Worker def find_library_file(self, dirs, lib, debug=0): 526*cda5da8dSAndroid Build Coastguard Worker # Prefer a debugging library if found (and requested), but deal 527*cda5da8dSAndroid Build Coastguard Worker # with it if we don't have one. 528*cda5da8dSAndroid Build Coastguard Worker if debug: 529*cda5da8dSAndroid Build Coastguard Worker try_names = [lib + "_d", lib] 530*cda5da8dSAndroid Build Coastguard Worker else: 531*cda5da8dSAndroid Build Coastguard Worker try_names = [lib] 532*cda5da8dSAndroid Build Coastguard Worker for dir in dirs: 533*cda5da8dSAndroid Build Coastguard Worker for name in try_names: 534*cda5da8dSAndroid Build Coastguard Worker libfile = os.path.join(dir, self.library_filename(name)) 535*cda5da8dSAndroid Build Coastguard Worker if os.path.isfile(libfile): 536*cda5da8dSAndroid Build Coastguard Worker return libfile 537*cda5da8dSAndroid Build Coastguard Worker else: 538*cda5da8dSAndroid Build Coastguard Worker # Oops, didn't find it in *any* of 'dirs' 539*cda5da8dSAndroid Build Coastguard Worker return None 540