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.

236 lines
8.3 KiB

6 years ago
  1. """SCons.Tool.cyglink
  2. Customization of gnulink for Cygwin (http://www.cygwin.com/)
  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. from __future__ import absolute_import, print_function
  8. import re
  9. import os
  10. import SCons.Action
  11. import SCons.Util
  12. import SCons.Tool
  13. #MAYBE: from . import gnulink
  14. from . import gnulink
  15. from . import link
  16. def _lib_generator(target, source, env, for_signature, **kw):
  17. try: cmd = kw['cmd']
  18. except KeyError: cmd = SCons.Util.CLVar(['$SHLINK'])
  19. try: vp = kw['varprefix']
  20. except KeyError: vp = 'SHLIB'
  21. dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
  22. if dll: cmd.extend(['-o', dll])
  23. cmd.extend(['$SHLINKFLAGS', '$__%sVERSIONFLAGS' % vp, '$__RPATH'])
  24. implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
  25. if implib:
  26. cmd.extend([
  27. '-Wl,--out-implib='+implib.get_string(for_signature),
  28. '-Wl,--export-all-symbols',
  29. '-Wl,--enable-auto-import',
  30. '-Wl,--whole-archive', '$SOURCES',
  31. '-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS'
  32. ])
  33. else:
  34. cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
  35. return [cmd]
  36. def shlib_generator(target, source, env, for_signature):
  37. return _lib_generator(target, source, env, for_signature,
  38. varprefix='SHLIB',
  39. cmd = SCons.Util.CLVar(['$SHLINK']))
  40. def ldmod_generator(target, source, env, for_signature):
  41. return _lib_generator(target, source, env, for_signature,
  42. varprefix='LDMODULE',
  43. cmd = SCons.Util.CLVar(['$LDMODULE']))
  44. def _lib_emitter(target, source, env, **kw):
  45. Verbose = False
  46. if Verbose:
  47. print("_lib_emitter: target[0]=%r" % target[0].get_path())
  48. try: vp = kw['varprefix']
  49. except KeyError: vp = 'SHLIB'
  50. try: libtype = kw['libtype']
  51. except KeyError: libtype = 'ShLib'
  52. dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
  53. no_import_lib = env.get('no_import_lib', 0)
  54. if Verbose:
  55. print("_lib_emitter: dll=%r" % dll.get_path())
  56. if not dll or len(target) > 1:
  57. raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp))
  58. # Remove any "lib" after the prefix
  59. pre = env.subst('$%sPREFIX' % vp)
  60. if dll.name[len(pre):len(pre)+3] == 'lib':
  61. dll.name = pre + dll.name[len(pre)+3:]
  62. if Verbose:
  63. print("_lib_emitter: dll.name=%r" % dll.name)
  64. orig_target = target
  65. target = [env.fs.File(dll)]
  66. target[0].attributes.shared = 1
  67. if Verbose:
  68. print("_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path())
  69. # Append an import lib target
  70. if not no_import_lib:
  71. # Create list of target libraries as strings
  72. target_strings = env.ReplaceIxes(orig_target[0],
  73. '%sPREFIX' % vp, '%sSUFFIX' % vp,
  74. 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
  75. if Verbose:
  76. print("_lib_emitter: target_strings=%r" % target_strings)
  77. implib_target = env.fs.File(target_strings)
  78. if Verbose:
  79. print("_lib_emitter: implib_target=%r" % implib_target.get_path())
  80. implib_target.attributes.shared = 1
  81. target.append(implib_target)
  82. symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target,
  83. implib_libtype=libtype,
  84. generator_libtype=libtype+'ImpLib')
  85. if Verbose:
  86. print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
  87. if symlinks:
  88. SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0])
  89. implib_target.attributes.shliblinks = symlinks
  90. return (target, source)
  91. def shlib_emitter(target, source, env):
  92. return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib')
  93. def ldmod_emitter(target, source, env):
  94. return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod')
  95. def _versioned_lib_suffix(env, suffix, version):
  96. """Generate versioned shared library suffix from a unversioned one.
  97. If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'"""
  98. Verbose = False
  99. if Verbose:
  100. print("_versioned_lib_suffix: suffix= ", suffix)
  101. print("_versioned_lib_suffix: version= ", version)
  102. cygversion = re.sub('\.', '-', version)
  103. if not suffix.startswith('-' + cygversion):
  104. suffix = '-' + cygversion + suffix
  105. if Verbose:
  106. print("_versioned_lib_suffix: return suffix= ", suffix)
  107. return suffix
  108. def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw):
  109. return link._versioned_lib_name(env, libnode, version, prefix, suffix,
  110. SCons.Tool.ImpLibPrefixGenerator,
  111. SCons.Tool.ImpLibSuffixGenerator,
  112. implib_libtype=kw['libtype'])
  113. def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw):
  114. """Generate link names that should be created for a versioned shared library.
  115. Returns a list in the form [ (link, linktarget), ... ]
  116. """
  117. Verbose = False
  118. if Verbose:
  119. print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path())
  120. print("_versioned_implib_symlinks: version=%r" % version)
  121. try: libtype = kw['libtype']
  122. except KeyError: libtype = 'ShLib'
  123. linkdir = os.path.dirname(libnode.get_path())
  124. if Verbose:
  125. print("_versioned_implib_symlinks: linkdir=%r" % linkdir)
  126. name = SCons.Tool.ImpLibNameGenerator(env, libnode,
  127. implib_libtype=libtype,
  128. generator_libtype=libtype+'ImpLib')
  129. if Verbose:
  130. print("_versioned_implib_symlinks: name=%r" % name)
  131. major = version.split('.')[0]
  132. link0 = env.fs.File(os.path.join(linkdir, name))
  133. symlinks = [(link0, libnode)]
  134. if Verbose:
  135. print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
  136. return symlinks
  137. shlib_action = SCons.Action.Action(shlib_generator, generator=1)
  138. ldmod_action = SCons.Action.Action(ldmod_generator, generator=1)
  139. def generate(env):
  140. """Add Builders and construction variables for cyglink to an Environment."""
  141. gnulink.generate(env)
  142. env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined')
  143. env['SHLINKCOM'] = shlib_action
  144. env['LDMODULECOM'] = ldmod_action
  145. env.Append(SHLIBEMITTER = [shlib_emitter])
  146. env.Append(LDMODULEEMITTER = [ldmod_emitter])
  147. env['SHLIBPREFIX'] = 'cyg'
  148. env['SHLIBSUFFIX'] = '.dll'
  149. env['IMPLIBPREFIX'] = 'lib'
  150. env['IMPLIBSUFFIX'] = '.dll.a'
  151. # Variables used by versioned shared libraries
  152. env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
  153. env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
  154. # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
  155. # LINKCALLBACKS are NOT inherited from gnulink
  156. env['LINKCALLBACKS'] = {
  157. 'VersionedShLibSuffix' : _versioned_lib_suffix,
  158. 'VersionedLdModSuffix' : _versioned_lib_suffix,
  159. 'VersionedImpLibSuffix' : _versioned_lib_suffix,
  160. 'VersionedShLibName' : link._versioned_shlib_name,
  161. 'VersionedLdModName' : link._versioned_ldmod_name,
  162. 'VersionedShLibImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='ShLib'),
  163. 'VersionedLdModImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='LdMod'),
  164. 'VersionedShLibImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'),
  165. 'VersionedLdModImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'),
  166. }
  167. # these variables were set by gnulink but are not used in cyglink
  168. try: del env['_SHLIBSONAME']
  169. except KeyError: pass
  170. try: del env['_LDMODULESONAME']
  171. except KeyError: pass
  172. def exists(env):
  173. return gnulink.exists(env)
  174. # Local Variables:
  175. # tab-width:4
  176. # indent-tabs-mode:nil
  177. # End:
  178. # vim: set expandtab tabstop=4 shiftwidth=4: