msvccompiler.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. """distutils.msvccompiler
  2. Contains MSVCCompiler, an implementation of the abstract CCompiler class
  3. for the Microsoft Visual Studio.
  4. """
  5. # Written by Perry Stoll
  6. # hacked by Robin Becker and Thomas Heller to do a better job of
  7. # finding DevStudio (through the registry)
  8. import sys
  9. import os
  10. import warnings
  11. from distutils.errors import (
  12. DistutilsExecError,
  13. DistutilsPlatformError,
  14. CompileError,
  15. LibError,
  16. LinkError,
  17. )
  18. from distutils.ccompiler import CCompiler, gen_lib_options
  19. from distutils import log
  20. _can_read_reg = False
  21. try:
  22. import winreg
  23. _can_read_reg = True
  24. hkey_mod = winreg
  25. RegOpenKeyEx = winreg.OpenKeyEx
  26. RegEnumKey = winreg.EnumKey
  27. RegEnumValue = winreg.EnumValue
  28. RegError = winreg.error
  29. except ImportError:
  30. try:
  31. import win32api
  32. import win32con
  33. _can_read_reg = True
  34. hkey_mod = win32con
  35. RegOpenKeyEx = win32api.RegOpenKeyEx
  36. RegEnumKey = win32api.RegEnumKey
  37. RegEnumValue = win32api.RegEnumValue
  38. RegError = win32api.error
  39. except ImportError:
  40. log.info(
  41. "Warning: Can't read registry to find the "
  42. "necessary compiler setting\n"
  43. "Make sure that Python modules winreg, "
  44. "win32api or win32con are installed."
  45. )
  46. pass
  47. if _can_read_reg:
  48. HKEYS = (
  49. hkey_mod.HKEY_USERS,
  50. hkey_mod.HKEY_CURRENT_USER,
  51. hkey_mod.HKEY_LOCAL_MACHINE,
  52. hkey_mod.HKEY_CLASSES_ROOT,
  53. )
  54. warnings.warn(
  55. "msvccompiler is deprecated and slated to be removed "
  56. "in the future. Please discontinue use or file an issue "
  57. "with pypa/distutils describing your use case.",
  58. DeprecationWarning,
  59. )
  60. def read_keys(base, key):
  61. """Return list of registry keys."""
  62. try:
  63. handle = RegOpenKeyEx(base, key)
  64. except RegError:
  65. return None
  66. L = []
  67. i = 0
  68. while True:
  69. try:
  70. k = RegEnumKey(handle, i)
  71. except RegError:
  72. break
  73. L.append(k)
  74. i += 1
  75. return L
  76. def read_values(base, key):
  77. """Return dict of registry keys and values.
  78. All names are converted to lowercase.
  79. """
  80. try:
  81. handle = RegOpenKeyEx(base, key)
  82. except RegError:
  83. return None
  84. d = {}
  85. i = 0
  86. while True:
  87. try:
  88. name, value, type = RegEnumValue(handle, i)
  89. except RegError:
  90. break
  91. name = name.lower()
  92. d[convert_mbcs(name)] = convert_mbcs(value)
  93. i += 1
  94. return d
  95. def convert_mbcs(s):
  96. dec = getattr(s, "decode", None)
  97. if dec is not None:
  98. try:
  99. s = dec("mbcs")
  100. except UnicodeError:
  101. pass
  102. return s
  103. class MacroExpander:
  104. def __init__(self, version):
  105. self.macros = {}
  106. self.load_macros(version)
  107. def set_macro(self, macro, path, key):
  108. for base in HKEYS:
  109. d = read_values(base, path)
  110. if d:
  111. self.macros["$(%s)" % macro] = d[key]
  112. break
  113. def load_macros(self, version):
  114. vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
  115. self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
  116. self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
  117. net = r"Software\Microsoft\.NETFramework"
  118. self.set_macro("FrameworkDir", net, "installroot")
  119. try:
  120. if version > 7.0:
  121. self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
  122. else:
  123. self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
  124. except KeyError:
  125. raise DistutilsPlatformError(
  126. """Python was built with Visual Studio 2003;
  127. extensions must be built with a compiler than can generate compatible binaries.
  128. Visual Studio 2003 was not found on this system. If you have Cygwin installed,
  129. you can try compiling with MingW32, by passing "-c mingw32" to setup.py."""
  130. )
  131. p = r"Software\Microsoft\NET Framework Setup\Product"
  132. for base in HKEYS:
  133. try:
  134. h = RegOpenKeyEx(base, p)
  135. except RegError:
  136. continue
  137. key = RegEnumKey(h, 0)
  138. d = read_values(base, r"{}\{}".format(p, key))
  139. self.macros["$(FrameworkVersion)"] = d["version"]
  140. def sub(self, s):
  141. for k, v in self.macros.items():
  142. s = s.replace(k, v)
  143. return s
  144. def get_build_version():
  145. """Return the version of MSVC that was used to build Python.
  146. For Python 2.3 and up, the version number is included in
  147. sys.version. For earlier versions, assume the compiler is MSVC 6.
  148. """
  149. prefix = "MSC v."
  150. i = sys.version.find(prefix)
  151. if i == -1:
  152. return 6
  153. i = i + len(prefix)
  154. s, rest = sys.version[i:].split(" ", 1)
  155. majorVersion = int(s[:-2]) - 6
  156. if majorVersion >= 13:
  157. # v13 was skipped and should be v14
  158. majorVersion += 1
  159. minorVersion = int(s[2:3]) / 10.0
  160. # I don't think paths are affected by minor version in version 6
  161. if majorVersion == 6:
  162. minorVersion = 0
  163. if majorVersion >= 6:
  164. return majorVersion + minorVersion
  165. # else we don't know what version of the compiler this is
  166. return None
  167. def get_build_architecture():
  168. """Return the processor architecture.
  169. Possible results are "Intel" or "AMD64".
  170. """
  171. prefix = " bit ("
  172. i = sys.version.find(prefix)
  173. if i == -1:
  174. return "Intel"
  175. j = sys.version.find(")", i)
  176. return sys.version[i + len(prefix) : j]
  177. def normalize_and_reduce_paths(paths):
  178. """Return a list of normalized paths with duplicates removed.
  179. The current order of paths is maintained.
  180. """
  181. # Paths are normalized so things like: /a and /a/ aren't both preserved.
  182. reduced_paths = []
  183. for p in paths:
  184. np = os.path.normpath(p)
  185. # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
  186. if np not in reduced_paths:
  187. reduced_paths.append(np)
  188. return reduced_paths
  189. class MSVCCompiler(CCompiler):
  190. """Concrete class that implements an interface to Microsoft Visual C++,
  191. as defined by the CCompiler abstract class."""
  192. compiler_type = 'msvc'
  193. # Just set this so CCompiler's constructor doesn't barf. We currently
  194. # don't use the 'set_executables()' bureaucracy provided by CCompiler,
  195. # as it really isn't necessary for this sort of single-compiler class.
  196. # Would be nice to have a consistent interface with UnixCCompiler,
  197. # though, so it's worth thinking about.
  198. executables = {}
  199. # Private class data (need to distinguish C from C++ source for compiler)
  200. _c_extensions = ['.c']
  201. _cpp_extensions = ['.cc', '.cpp', '.cxx']
  202. _rc_extensions = ['.rc']
  203. _mc_extensions = ['.mc']
  204. # Needed for the filename generation methods provided by the
  205. # base class, CCompiler.
  206. src_extensions = _c_extensions + _cpp_extensions + _rc_extensions + _mc_extensions
  207. res_extension = '.res'
  208. obj_extension = '.obj'
  209. static_lib_extension = '.lib'
  210. shared_lib_extension = '.dll'
  211. static_lib_format = shared_lib_format = '%s%s'
  212. exe_extension = '.exe'
  213. def __init__(self, verbose=0, dry_run=0, force=0):
  214. super().__init__(verbose, dry_run, force)
  215. self.__version = get_build_version()
  216. self.__arch = get_build_architecture()
  217. if self.__arch == "Intel":
  218. # x86
  219. if self.__version >= 7:
  220. self.__root = r"Software\Microsoft\VisualStudio"
  221. self.__macros = MacroExpander(self.__version)
  222. else:
  223. self.__root = r"Software\Microsoft\Devstudio"
  224. self.__product = "Visual Studio version %s" % self.__version
  225. else:
  226. # Win64. Assume this was built with the platform SDK
  227. self.__product = "Microsoft SDK compiler %s" % (self.__version + 6)
  228. self.initialized = False
  229. def initialize(self):
  230. self.__paths = []
  231. if (
  232. "DISTUTILS_USE_SDK" in os.environ
  233. and "MSSdk" in os.environ
  234. and self.find_exe("cl.exe")
  235. ):
  236. # Assume that the SDK set up everything alright; don't try to be
  237. # smarter
  238. self.cc = "cl.exe"
  239. self.linker = "link.exe"
  240. self.lib = "lib.exe"
  241. self.rc = "rc.exe"
  242. self.mc = "mc.exe"
  243. else:
  244. self.__paths = self.get_msvc_paths("path")
  245. if len(self.__paths) == 0:
  246. raise DistutilsPlatformError(
  247. "Python was built with %s, "
  248. "and extensions need to be built with the same "
  249. "version of the compiler, but it isn't installed." % self.__product
  250. )
  251. self.cc = self.find_exe("cl.exe")
  252. self.linker = self.find_exe("link.exe")
  253. self.lib = self.find_exe("lib.exe")
  254. self.rc = self.find_exe("rc.exe") # resource compiler
  255. self.mc = self.find_exe("mc.exe") # message compiler
  256. self.set_path_env_var('lib')
  257. self.set_path_env_var('include')
  258. # extend the MSVC path with the current path
  259. try:
  260. for p in os.environ['path'].split(';'):
  261. self.__paths.append(p)
  262. except KeyError:
  263. pass
  264. self.__paths = normalize_and_reduce_paths(self.__paths)
  265. os.environ['path'] = ";".join(self.__paths)
  266. self.preprocess_options = None
  267. if self.__arch == "Intel":
  268. self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GX', '/DNDEBUG']
  269. self.compile_options_debug = [
  270. '/nologo',
  271. '/Od',
  272. '/MDd',
  273. '/W3',
  274. '/GX',
  275. '/Z7',
  276. '/D_DEBUG',
  277. ]
  278. else:
  279. # Win64
  280. self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GS-', '/DNDEBUG']
  281. self.compile_options_debug = [
  282. '/nologo',
  283. '/Od',
  284. '/MDd',
  285. '/W3',
  286. '/GS-',
  287. '/Z7',
  288. '/D_DEBUG',
  289. ]
  290. self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
  291. if self.__version >= 7:
  292. self.ldflags_shared_debug = ['/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG']
  293. else:
  294. self.ldflags_shared_debug = [
  295. '/DLL',
  296. '/nologo',
  297. '/INCREMENTAL:no',
  298. '/pdb:None',
  299. '/DEBUG',
  300. ]
  301. self.ldflags_static = ['/nologo']
  302. self.initialized = True
  303. # -- Worker methods ------------------------------------------------
  304. def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
  305. # Copied from ccompiler.py, extended to return .res as 'object'-file
  306. # for .rc input file
  307. if output_dir is None:
  308. output_dir = ''
  309. obj_names = []
  310. for src_name in source_filenames:
  311. (base, ext) = os.path.splitext(src_name)
  312. base = os.path.splitdrive(base)[1] # Chop off the drive
  313. base = base[os.path.isabs(base) :] # If abs, chop off leading /
  314. if ext not in self.src_extensions:
  315. # Better to raise an exception instead of silently continuing
  316. # and later complain about sources and targets having
  317. # different lengths
  318. raise CompileError("Don't know how to compile %s" % src_name)
  319. if strip_dir:
  320. base = os.path.basename(base)
  321. if ext in self._rc_extensions:
  322. obj_names.append(os.path.join(output_dir, base + self.res_extension))
  323. elif ext in self._mc_extensions:
  324. obj_names.append(os.path.join(output_dir, base + self.res_extension))
  325. else:
  326. obj_names.append(os.path.join(output_dir, base + self.obj_extension))
  327. return obj_names
  328. def compile( # noqa: C901
  329. self,
  330. sources,
  331. output_dir=None,
  332. macros=None,
  333. include_dirs=None,
  334. debug=0,
  335. extra_preargs=None,
  336. extra_postargs=None,
  337. depends=None,
  338. ):
  339. if not self.initialized:
  340. self.initialize()
  341. compile_info = self._setup_compile(
  342. output_dir, macros, include_dirs, sources, depends, extra_postargs
  343. )
  344. macros, objects, extra_postargs, pp_opts, build = compile_info
  345. compile_opts = extra_preargs or []
  346. compile_opts.append('/c')
  347. if debug:
  348. compile_opts.extend(self.compile_options_debug)
  349. else:
  350. compile_opts.extend(self.compile_options)
  351. for obj in objects:
  352. try:
  353. src, ext = build[obj]
  354. except KeyError:
  355. continue
  356. if debug:
  357. # pass the full pathname to MSVC in debug mode,
  358. # this allows the debugger to find the source file
  359. # without asking the user to browse for it
  360. src = os.path.abspath(src)
  361. if ext in self._c_extensions:
  362. input_opt = "/Tc" + src
  363. elif ext in self._cpp_extensions:
  364. input_opt = "/Tp" + src
  365. elif ext in self._rc_extensions:
  366. # compile .RC to .RES file
  367. input_opt = src
  368. output_opt = "/fo" + obj
  369. try:
  370. self.spawn([self.rc] + pp_opts + [output_opt] + [input_opt])
  371. except DistutilsExecError as msg:
  372. raise CompileError(msg)
  373. continue
  374. elif ext in self._mc_extensions:
  375. # Compile .MC to .RC file to .RES file.
  376. # * '-h dir' specifies the directory for the
  377. # generated include file
  378. # * '-r dir' specifies the target directory of the
  379. # generated RC file and the binary message resource
  380. # it includes
  381. #
  382. # For now (since there are no options to change this),
  383. # we use the source-directory for the include file and
  384. # the build directory for the RC file and message
  385. # resources. This works at least for win32all.
  386. h_dir = os.path.dirname(src)
  387. rc_dir = os.path.dirname(obj)
  388. try:
  389. # first compile .MC to .RC and .H file
  390. self.spawn([self.mc] + ['-h', h_dir, '-r', rc_dir] + [src])
  391. base, _ = os.path.splitext(os.path.basename(src))
  392. rc_file = os.path.join(rc_dir, base + '.rc')
  393. # then compile .RC to .RES file
  394. self.spawn([self.rc] + ["/fo" + obj] + [rc_file])
  395. except DistutilsExecError as msg:
  396. raise CompileError(msg)
  397. continue
  398. else:
  399. # how to handle this file?
  400. raise CompileError(
  401. "Don't know how to compile {} to {}".format(src, obj)
  402. )
  403. output_opt = "/Fo" + obj
  404. try:
  405. self.spawn(
  406. [self.cc]
  407. + compile_opts
  408. + pp_opts
  409. + [input_opt, output_opt]
  410. + extra_postargs
  411. )
  412. except DistutilsExecError as msg:
  413. raise CompileError(msg)
  414. return objects
  415. def create_static_lib(
  416. self, objects, output_libname, output_dir=None, debug=0, target_lang=None
  417. ):
  418. if not self.initialized:
  419. self.initialize()
  420. (objects, output_dir) = self._fix_object_args(objects, output_dir)
  421. output_filename = self.library_filename(output_libname, output_dir=output_dir)
  422. if self._need_link(objects, output_filename):
  423. lib_args = objects + ['/OUT:' + output_filename]
  424. if debug:
  425. pass # XXX what goes here?
  426. try:
  427. self.spawn([self.lib] + lib_args)
  428. except DistutilsExecError as msg:
  429. raise LibError(msg)
  430. else:
  431. log.debug("skipping %s (up-to-date)", output_filename)
  432. def link( # noqa: C901
  433. self,
  434. target_desc,
  435. objects,
  436. output_filename,
  437. output_dir=None,
  438. libraries=None,
  439. library_dirs=None,
  440. runtime_library_dirs=None,
  441. export_symbols=None,
  442. debug=0,
  443. extra_preargs=None,
  444. extra_postargs=None,
  445. build_temp=None,
  446. target_lang=None,
  447. ):
  448. if not self.initialized:
  449. self.initialize()
  450. (objects, output_dir) = self._fix_object_args(objects, output_dir)
  451. fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
  452. (libraries, library_dirs, runtime_library_dirs) = fixed_args
  453. if runtime_library_dirs:
  454. self.warn(
  455. "I don't know what to do with 'runtime_library_dirs': "
  456. + str(runtime_library_dirs)
  457. )
  458. lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries)
  459. if output_dir is not None:
  460. output_filename = os.path.join(output_dir, output_filename)
  461. if self._need_link(objects, output_filename):
  462. if target_desc == CCompiler.EXECUTABLE:
  463. if debug:
  464. ldflags = self.ldflags_shared_debug[1:]
  465. else:
  466. ldflags = self.ldflags_shared[1:]
  467. else:
  468. if debug:
  469. ldflags = self.ldflags_shared_debug
  470. else:
  471. ldflags = self.ldflags_shared
  472. export_opts = []
  473. for sym in export_symbols or []:
  474. export_opts.append("/EXPORT:" + sym)
  475. ld_args = (
  476. ldflags + lib_opts + export_opts + objects + ['/OUT:' + output_filename]
  477. )
  478. # The MSVC linker generates .lib and .exp files, which cannot be
  479. # suppressed by any linker switches. The .lib files may even be
  480. # needed! Make sure they are generated in the temporary build
  481. # directory. Since they have different names for debug and release
  482. # builds, they can go into the same directory.
  483. if export_symbols is not None:
  484. (dll_name, dll_ext) = os.path.splitext(
  485. os.path.basename(output_filename)
  486. )
  487. implib_file = os.path.join(
  488. os.path.dirname(objects[0]), self.library_filename(dll_name)
  489. )
  490. ld_args.append('/IMPLIB:' + implib_file)
  491. if extra_preargs:
  492. ld_args[:0] = extra_preargs
  493. if extra_postargs:
  494. ld_args.extend(extra_postargs)
  495. self.mkpath(os.path.dirname(output_filename))
  496. try:
  497. self.spawn([self.linker] + ld_args)
  498. except DistutilsExecError as msg:
  499. raise LinkError(msg)
  500. else:
  501. log.debug("skipping %s (up-to-date)", output_filename)
  502. # -- Miscellaneous methods -----------------------------------------
  503. # These are all used by the 'gen_lib_options() function, in
  504. # ccompiler.py.
  505. def library_dir_option(self, dir):
  506. return "/LIBPATH:" + dir
  507. def runtime_library_dir_option(self, dir):
  508. raise DistutilsPlatformError(
  509. "don't know how to set runtime library search path for MSVC++"
  510. )
  511. def library_option(self, lib):
  512. return self.library_filename(lib)
  513. def find_library_file(self, dirs, lib, debug=0):
  514. # Prefer a debugging library if found (and requested), but deal
  515. # with it if we don't have one.
  516. if debug:
  517. try_names = [lib + "_d", lib]
  518. else:
  519. try_names = [lib]
  520. for dir in dirs:
  521. for name in try_names:
  522. libfile = os.path.join(dir, self.library_filename(name))
  523. if os.path.exists(libfile):
  524. return libfile
  525. else:
  526. # Oops, didn't find it in *any* of 'dirs'
  527. return None
  528. # Helper methods for using the MSVC registry settings
  529. def find_exe(self, exe):
  530. """Return path to an MSVC executable program.
  531. Tries to find the program in several places: first, one of the
  532. MSVC program search paths from the registry; next, the directories
  533. in the PATH environment variable. If any of those work, return an
  534. absolute path that is known to exist. If none of them work, just
  535. return the original program name, 'exe'.
  536. """
  537. for p in self.__paths:
  538. fn = os.path.join(os.path.abspath(p), exe)
  539. if os.path.isfile(fn):
  540. return fn
  541. # didn't find it; try existing path
  542. for p in os.environ['Path'].split(';'):
  543. fn = os.path.join(os.path.abspath(p), exe)
  544. if os.path.isfile(fn):
  545. return fn
  546. return exe
  547. def get_msvc_paths(self, path, platform='x86'):
  548. """Get a list of devstudio directories (include, lib or path).
  549. Return a list of strings. The list will be empty if unable to
  550. access the registry or appropriate registry keys not found.
  551. """
  552. if not _can_read_reg:
  553. return []
  554. path = path + " dirs"
  555. if self.__version >= 7:
  556. key = r"{}\{:0.1f}\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories".format(
  557. self.__root,
  558. self.__version,
  559. )
  560. else:
  561. key = (
  562. r"%s\6.0\Build System\Components\Platforms"
  563. r"\Win32 (%s)\Directories" % (self.__root, platform)
  564. )
  565. for base in HKEYS:
  566. d = read_values(base, key)
  567. if d:
  568. if self.__version >= 7:
  569. return self.__macros.sub(d[path]).split(";")
  570. else:
  571. return d[path].split(";")
  572. # MSVC 6 seems to create the registry entries we need only when
  573. # the GUI is run.
  574. if self.__version == 6:
  575. for base in HKEYS:
  576. if read_values(base, r"%s\6.0" % self.__root) is not None:
  577. self.warn(
  578. "It seems you have Visual Studio 6 installed, "
  579. "but the expected registry settings are not present.\n"
  580. "You must at least run the Visual Studio GUI once "
  581. "so that these entries are created."
  582. )
  583. break
  584. return []
  585. def set_path_env_var(self, name):
  586. """Set environment variable 'name' to an MSVC path type value.
  587. This is equivalent to a SET command prior to execution of spawned
  588. commands.
  589. """
  590. if name == "lib":
  591. p = self.get_msvc_paths("library")
  592. else:
  593. p = self.get_msvc_paths(name)
  594. if p:
  595. os.environ[name] = ';'.join(p)
  596. if get_build_version() >= 8.0:
  597. log.debug("Importing new compiler from distutils.msvc9compiler")
  598. OldMSVCCompiler = MSVCCompiler
  599. from distutils.msvc9compiler import MSVCCompiler
  600. # get_build_architecture not really relevant now we support cross-compile
  601. from distutils.msvc9compiler import MacroExpander # noqa: F811