You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

337 lines
14 KiB

6 years ago
  1. """SCons.Tool.mslink
  2. Tool-specific initialization for the Microsoft linker.
  3. There normally shouldn't be any need to import this module directly.
  4. It will usually be imported through the generic SCons.Tool.Tool()
  5. selection method.
  6. """
  7. #
  8. # Copyright (c) 2001 - 2017 The SCons Foundation
  9. #
  10. # Permission is hereby granted, free of charge, to any person obtaining
  11. # a copy of this software and associated documentation files (the
  12. # "Software"), to deal in the Software without restriction, including
  13. # without limitation the rights to use, copy, modify, merge, publish,
  14. # distribute, sublicense, and/or sell copies of the Software, and to
  15. # permit persons to whom the Software is furnished to do so, subject to
  16. # the following conditions:
  17. #
  18. # The above copyright notice and this permission notice shall be included
  19. # in all copies or substantial portions of the Software.
  20. #
  21. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  22. # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  23. # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. #
  29. from __future__ import print_function
  30. __revision__ = "src/engine/SCons/Tool/mslink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
  31. import os.path
  32. import SCons.Action
  33. import SCons.Defaults
  34. import SCons.Errors
  35. import SCons.Platform.win32
  36. import SCons.Tool
  37. import SCons.Tool.msvc
  38. import SCons.Tool.msvs
  39. import SCons.Util
  40. from .MSCommon import msvc_setup_env_once, msvc_exists
  41. def pdbGenerator(env, target, source, for_signature):
  42. try:
  43. return ['/PDB:%s' % target[0].attributes.pdb, '/DEBUG']
  44. except (AttributeError, IndexError):
  45. return None
  46. def _dllTargets(target, source, env, for_signature, paramtp):
  47. listCmd = []
  48. dll = env.FindIxes(target, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp)
  49. if dll: listCmd.append("/out:%s"%dll.get_string(for_signature))
  50. implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
  51. if implib: listCmd.append("/implib:%s"%implib.get_string(for_signature))
  52. return listCmd
  53. def _dllSources(target, source, env, for_signature, paramtp):
  54. listCmd = []
  55. deffile = env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX")
  56. for src in source:
  57. # Check explicitly for a non-None deffile so that the __cmp__
  58. # method of the base SCons.Util.Proxy class used for some Node
  59. # proxies doesn't try to use a non-existent __dict__ attribute.
  60. if deffile and src == deffile:
  61. # Treat this source as a .def file.
  62. listCmd.append("/def:%s" % src.get_string(for_signature))
  63. else:
  64. # Just treat it as a generic source file.
  65. listCmd.append(src)
  66. return listCmd
  67. def windowsShlinkTargets(target, source, env, for_signature):
  68. return _dllTargets(target, source, env, for_signature, 'SHLIB')
  69. def windowsShlinkSources(target, source, env, for_signature):
  70. return _dllSources(target, source, env, for_signature, 'SHLIB')
  71. def _windowsLdmodTargets(target, source, env, for_signature):
  72. """Get targets for loadable modules."""
  73. return _dllTargets(target, source, env, for_signature, 'LDMODULE')
  74. def _windowsLdmodSources(target, source, env, for_signature):
  75. """Get sources for loadable modules."""
  76. return _dllSources(target, source, env, for_signature, 'LDMODULE')
  77. def _dllEmitter(target, source, env, paramtp):
  78. """Common implementation of dll emitter."""
  79. SCons.Tool.msvc.validate_vars(env)
  80. extratargets = []
  81. extrasources = []
  82. dll = env.FindIxes(target, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp)
  83. no_import_lib = env.get('no_import_lib', 0)
  84. if not dll:
  85. raise SCons.Errors.UserError('A shared library should have exactly one target with the suffix: %s' % env.subst('$%sSUFFIX' % paramtp))
  86. insert_def = env.subst("$WINDOWS_INSERT_DEF")
  87. if not insert_def in ['', '0', 0] and \
  88. not env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"):
  89. # append a def file to the list of sources
  90. extrasources.append(
  91. env.ReplaceIxes(dll,
  92. '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp,
  93. "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"))
  94. version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
  95. if version_num >= 8.0 and \
  96. (env.get('WINDOWS_INSERT_MANIFEST', 0) or env.get('WINDOWS_EMBED_MANIFEST', 0)):
  97. # MSVC 8 and above automatically generate .manifest files that must be installed
  98. extratargets.append(
  99. env.ReplaceIxes(dll,
  100. '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp,
  101. "WINDOWSSHLIBMANIFESTPREFIX", "WINDOWSSHLIBMANIFESTSUFFIX"))
  102. if 'PDB' in env and env['PDB']:
  103. pdb = env.arg2nodes('$PDB', target=target, source=source)[0]
  104. extratargets.append(pdb)
  105. target[0].attributes.pdb = pdb
  106. if version_num >= 11.0 and env.get('PCH', 0):
  107. # MSVC 11 and above need the PCH object file to be added to the link line,
  108. # otherwise you get link error LNK2011.
  109. pchobj = SCons.Util.splitext(str(env['PCH']))[0] + '.obj'
  110. # print "prog_emitter, version %s, appending pchobj %s"%(version_num, pchobj)
  111. if pchobj not in extrasources:
  112. extrasources.append(pchobj)
  113. if not no_import_lib and \
  114. not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
  115. # Append an import library to the list of targets.
  116. extratargets.append(
  117. env.ReplaceIxes(dll,
  118. '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp,
  119. "LIBPREFIX", "LIBSUFFIX"))
  120. # and .exp file is created if there are exports from a DLL
  121. extratargets.append(
  122. env.ReplaceIxes(dll,
  123. '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp,
  124. "WINDOWSEXPPREFIX", "WINDOWSEXPSUFFIX"))
  125. return (target+extratargets, source+extrasources)
  126. def windowsLibEmitter(target, source, env):
  127. return _dllEmitter(target, source, env, 'SHLIB')
  128. def ldmodEmitter(target, source, env):
  129. """Emitter for loadable modules.
  130. Loadable modules are identical to shared libraries on Windows, but building
  131. them is subject to different parameters (LDMODULE*).
  132. """
  133. return _dllEmitter(target, source, env, 'LDMODULE')
  134. def prog_emitter(target, source, env):
  135. SCons.Tool.msvc.validate_vars(env)
  136. extratargets = []
  137. extrasources = []
  138. exe = env.FindIxes(target, "PROGPREFIX", "PROGSUFFIX")
  139. if not exe:
  140. raise SCons.Errors.UserError("An executable should have exactly one target with the suffix: %s" % env.subst("$PROGSUFFIX"))
  141. version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
  142. if version_num >= 8.0 and \
  143. (env.get('WINDOWS_INSERT_MANIFEST', 0) or env.get('WINDOWS_EMBED_MANIFEST', 0)):
  144. # MSVC 8 and above automatically generate .manifest files that have to be installed
  145. extratargets.append(
  146. env.ReplaceIxes(exe,
  147. "PROGPREFIX", "PROGSUFFIX",
  148. "WINDOWSPROGMANIFESTPREFIX", "WINDOWSPROGMANIFESTSUFFIX"))
  149. if 'PDB' in env and env['PDB']:
  150. pdb = env.arg2nodes('$PDB', target=target, source=source)[0]
  151. extratargets.append(pdb)
  152. target[0].attributes.pdb = pdb
  153. if version_num >= 11.0 and env.get('PCH', 0):
  154. # MSVC 11 and above need the PCH object file to be added to the link line,
  155. # otherwise you get link error LNK2011.
  156. pchobj = SCons.Util.splitext(str(env['PCH']))[0] + '.obj'
  157. # print("prog_emitter, version %s, appending pchobj %s"%(version_num, pchobj))
  158. if pchobj not in extrasources:
  159. extrasources.append(pchobj)
  160. return (target+extratargets,source+extrasources)
  161. def RegServerFunc(target, source, env):
  162. if 'register' in env and env['register']:
  163. ret = regServerAction([target[0]], [source[0]], env)
  164. if ret:
  165. raise SCons.Errors.UserError("Unable to register %s" % target[0])
  166. else:
  167. print("Registered %s sucessfully" % target[0])
  168. return ret
  169. return 0
  170. # These are the actual actions run to embed the manifest.
  171. # They are only called from the Check versions below.
  172. embedManifestExeAction = SCons.Action.Action('$MTEXECOM')
  173. embedManifestDllAction = SCons.Action.Action('$MTSHLIBCOM')
  174. def embedManifestDllCheck(target, source, env):
  175. """Function run by embedManifestDllCheckAction to check for existence of manifest
  176. and other conditions, and embed the manifest by calling embedManifestDllAction if so."""
  177. if env.get('WINDOWS_EMBED_MANIFEST', 0):
  178. manifestSrc = target[0].get_abspath() + '.manifest'
  179. if os.path.exists(manifestSrc):
  180. ret = (embedManifestDllAction) ([target[0]],None,env)
  181. if ret:
  182. raise SCons.Errors.UserError("Unable to embed manifest into %s" % (target[0]))
  183. return ret
  184. else:
  185. print('(embed: no %s.manifest found; not embedding.)'%str(target[0]))
  186. return 0
  187. def embedManifestExeCheck(target, source, env):
  188. """Function run by embedManifestExeCheckAction to check for existence of manifest
  189. and other conditions, and embed the manifest by calling embedManifestExeAction if so."""
  190. if env.get('WINDOWS_EMBED_MANIFEST', 0):
  191. manifestSrc = target[0].get_abspath() + '.manifest'
  192. if os.path.exists(manifestSrc):
  193. ret = (embedManifestExeAction) ([target[0]],None,env)
  194. if ret:
  195. raise SCons.Errors.UserError("Unable to embed manifest into %s" % (target[0]))
  196. return ret
  197. else:
  198. print('(embed: no %s.manifest found; not embedding.)'%str(target[0]))
  199. return 0
  200. embedManifestDllCheckAction = SCons.Action.Action(embedManifestDllCheck, None)
  201. embedManifestExeCheckAction = SCons.Action.Action(embedManifestExeCheck, None)
  202. regServerAction = SCons.Action.Action("$REGSVRCOM", "$REGSVRCOMSTR")
  203. regServerCheck = SCons.Action.Action(RegServerFunc, None)
  204. shlibLinkAction = SCons.Action.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_SHLINK_SOURCES", "$SHLINKCOMSTR")}', '$SHLINKCOMSTR')
  205. compositeShLinkAction = shlibLinkAction + regServerCheck + embedManifestDllCheckAction
  206. ldmodLinkAction = SCons.Action.Action('${TEMPFILE("$LDMODULE $LDMODULEFLAGS $_LDMODULE_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_LDMODULE_SOURCES", "$LDMODULECOMSTR")}', '$LDMODULECOMSTR')
  207. compositeLdmodAction = ldmodLinkAction + regServerCheck + embedManifestDllCheckAction
  208. exeLinkAction = SCons.Action.Action('${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET.windows $_LIBDIRFLAGS $_LIBFLAGS $_PDB $SOURCES.windows", "$LINKCOMSTR")}', '$LINKCOMSTR')
  209. compositeLinkAction = exeLinkAction + embedManifestExeCheckAction
  210. def generate(env):
  211. """Add Builders and construction variables for ar to an Environment."""
  212. SCons.Tool.createSharedLibBuilder(env)
  213. SCons.Tool.createProgBuilder(env)
  214. env['SHLINK'] = '$LINK'
  215. env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll')
  216. env['_SHLINK_TARGETS'] = windowsShlinkTargets
  217. env['_SHLINK_SOURCES'] = windowsShlinkSources
  218. env['SHLINKCOM'] = compositeShLinkAction
  219. env.Append(SHLIBEMITTER = [windowsLibEmitter])
  220. env.Append(LDMODULEEMITTER = [windowsLibEmitter])
  221. env['LINK'] = 'link'
  222. env['LINKFLAGS'] = SCons.Util.CLVar('/nologo')
  223. env['_PDB'] = pdbGenerator
  224. env['LINKCOM'] = compositeLinkAction
  225. env.Append(PROGEMITTER = [prog_emitter])
  226. env['LIBDIRPREFIX']='/LIBPATH:'
  227. env['LIBDIRSUFFIX']=''
  228. env['LIBLINKPREFIX']=''
  229. env['LIBLINKSUFFIX']='$LIBSUFFIX'
  230. env['WIN32DEFPREFIX'] = ''
  231. env['WIN32DEFSUFFIX'] = '.def'
  232. env['WIN32_INSERT_DEF'] = 0
  233. env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}'
  234. env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}'
  235. env['WINDOWS_INSERT_DEF'] = '${WIN32_INSERT_DEF}'
  236. env['WIN32EXPPREFIX'] = ''
  237. env['WIN32EXPSUFFIX'] = '.exp'
  238. env['WINDOWSEXPPREFIX'] = '${WIN32EXPPREFIX}'
  239. env['WINDOWSEXPSUFFIX'] = '${WIN32EXPSUFFIX}'
  240. env['WINDOWSSHLIBMANIFESTPREFIX'] = ''
  241. env['WINDOWSSHLIBMANIFESTSUFFIX'] = '${SHLIBSUFFIX}.manifest'
  242. env['WINDOWSPROGMANIFESTPREFIX'] = ''
  243. env['WINDOWSPROGMANIFESTSUFFIX'] = '${PROGSUFFIX}.manifest'
  244. env['REGSVRACTION'] = regServerCheck
  245. env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
  246. env['REGSVRFLAGS'] = '/s '
  247. env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS ${TARGET.windows}'
  248. env['WINDOWS_EMBED_MANIFEST'] = 0
  249. env['MT'] = 'mt'
  250. #env['MTFLAGS'] = ['-hashupdate']
  251. env['MTFLAGS'] = SCons.Util.CLVar('/nologo')
  252. # Note: use - here to prevent build failure if no manifest produced.
  253. # This seems much simpler than a fancy system using a function action to see
  254. # if the manifest actually exists before trying to run mt with it.
  255. env['MTEXECOM'] = '-$MT $MTFLAGS -manifest ${TARGET}.manifest $_MANIFEST_SOURCES -outputresource:$TARGET;1'
  256. env['MTSHLIBCOM'] = '-$MT $MTFLAGS -manifest ${TARGET}.manifest $_MANIFEST_SOURCES -outputresource:$TARGET;2'
  257. # TODO Future work garyo 27-Feb-11
  258. env['_MANIFEST_SOURCES'] = None # _windowsManifestSources
  259. # Set-up ms tools paths
  260. msvc_setup_env_once(env)
  261. # Loadable modules are on Windows the same as shared libraries, but they
  262. # are subject to different build parameters (LDMODULE* variables).
  263. # Therefore LDMODULE* variables correspond as much as possible to
  264. # SHLINK*/SHLIB* ones.
  265. SCons.Tool.createLoadableModuleBuilder(env)
  266. env['LDMODULE'] = '$SHLINK'
  267. env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
  268. env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
  269. env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
  270. env['_LDMODULE_TARGETS'] = _windowsLdmodTargets
  271. env['_LDMODULE_SOURCES'] = _windowsLdmodSources
  272. env['LDMODULEEMITTER'] = [ldmodEmitter]
  273. env['LDMODULECOM'] = compositeLdmodAction
  274. def exists(env):
  275. return msvc_exists()
  276. # Local Variables:
  277. # tab-width:4
  278. # indent-tabs-mode:nil
  279. # End:
  280. # vim: set expandtab tabstop=4 shiftwidth=4: