renamed SCons.Tool.ninja -> SCons.Tool.ninja_tool and added alias in tool loading...
[scons.git] / SCons / Tool / cyglink.py
blob6a5ca99cf3bef2f6e2c6d6a4ad934c93d804caae
1 # MIT License
3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 """SCons.Tool.cyglink
26 Customization of gnulink for Cygwin (https://www.cygwin.com/)
28 There normally shouldn't be any need to import this module directly.
29 It will usually be imported through the generic SCons.Tool.Tool()
30 selection method.
32 """
34 from SCons.Tool.linkCommon import StringizeLibSymlinks, EmitLibSymlinks
35 from SCons.Util import CLVar, is_String
36 from . import gnulink
39 def cyglink_lib_emitter(target, source, env, **kw):
40 verbose = True
42 if 'variable_prefix' in kw:
43 var_prefix = kw['variable_prefix']
44 else:
45 var_prefix = 'SHLIB'
47 no_import_lib = env.get('no_import_lib', False)
49 if verbose:
50 print(f"cyglink_lib_emitter: target[0]={target[0].get_path()!r}")
52 if not no_import_lib:
53 # Specify import lib and add to targets
55 import_lib = env.subst('$%s_IMPLIBNAME' % var_prefix, target=target, source=source)
56 import_lib_target = env.fs.File(import_lib)
57 import_lib_target.attributes.shared = True
58 target.append(import_lib_target)
60 if verbose:
61 print(f"cyglink_lib_emitter: import_lib={import_lib}")
62 print("cyglink_lib_emitter: target=%s" % target)
64 for tgt in target:
65 if is_String(tgt):
66 tgt = env.File(tgt)
67 tgt.attributes.shared = True
69 return target, source
72 def cyglink_ldmodule_emitter(target, source, env, **kw):
73 return cyglink_lib_emitter(target, source, env, variable_prefix='LDMODULE')
76 def cyglink_shlib_symlink_emitter(target, source, env, **kw):
77 """
78 On cygwin, we only create a symlink from the non-versioned implib to the versioned implib.
79 We don't version the shared library itself.
80 :param target:
81 :param source:
82 :param env:
83 :param kw:
84 :return:
85 """
86 verbose = True
88 if 'variable_prefix' in kw:
89 var_prefix = kw['variable_prefix']
90 else:
91 var_prefix = 'SHLIB'
93 no_import_lib = env.get('no_import_lib', False)
94 if no_import_lib in ['1', 'True', 'true', True]:
95 if verbose:
96 print("cyglink_shlib_symlink_emitter: no_import_lib=%s" % no_import_lib)
97 return target, source
99 no_symlinks = env.subst('$%sNOVERSIONSYMLINKS' % var_prefix)
100 if no_symlinks in ['1', 'True', 'true', True]:
101 return target, source
103 shlibversion = env.subst('$%sVERSION' % var_prefix)
104 if shlibversion:
105 if verbose:
106 print("cyglink_shlib_symlink_emitter: %sVERSION=%s" % (var_prefix, shlibversion))
108 # The implib (added by the cyglink_lib_emitter)
109 imp_lib_node = target[1]
110 shlib_noversion_symlink = env.subst('$%s_NOVERSION_SYMLINK' % var_prefix, target=target[0], source=source)
112 if verbose:
113 print("cyglink_shlib_symlink_emitter: shlib_noversion_symlink :%s" % shlib_noversion_symlink)
114 print("cyglink_shlib_symlink_emitter: imp_lib_node :%s" % imp_lib_node)
116 symlinks = [(env.File(shlib_noversion_symlink), imp_lib_node)]
118 if verbose:
119 print("cyglink_shlib_symlink_emitter: symlinks={!r}".format(
120 ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)])
123 if symlinks:
124 # This does the actual symlinking
125 EmitLibSymlinks(env, symlinks, target[0])
127 # This saves the information so if the versioned shared library is installed
128 # it can faithfully reproduce the correct symlinks
129 target[0].attributes.shliblinks = symlinks
131 return target, source
134 def cyglink_ldmod_symlink_emitter(target, source, env, **kw):
135 return cyglink_shlib_symlink_emitter(target, source, env, variable_prefix='LDMODULE')
138 def cyglink_shlibversion(target, source, env, for_signature):
139 var_prefix = 'SHLIB'
140 var = '%sVERSION' % var_prefix
141 if var not in env:
142 return ''
144 version = env.subst("$%s" % var, target=target, source=source)
145 version = version.replace('.', '-')
146 return "." + version
149 def cyglink_ldmodule_version(target, source, env, for_signature):
150 var_prefix = 'LDMODULE'
151 var = '%sVERSION' % var_prefix
152 if var not in env:
153 return ''
155 version = env.subst("$%s" % var, target=target, source=source)
156 version = version.replace('.', '-')
157 return "." + version
160 def _implib_pre_flags(target, source, env, for_signature) -> str:
161 no_import_lib = env.get('no_import_lib', False)
162 if no_import_lib in ['1', 'True', 'true', True]:
163 return ''
164 else:
165 return '-Wl,--out-implib=${TARGETS[1]} -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive'
168 def _implib_post_flags(target, source, env, for_signature) -> str:
169 no_import_lib = env.get('no_import_lib', False)
170 if no_import_lib in ['1', 'True', 'true', True]:
171 return ''
172 else:
173 return '-Wl,--no-whole-archive'
176 def generate(env) -> None:
177 """Add Builders and construction variables for cyglink to an Environment."""
178 gnulink.generate(env)
180 env['LINKFLAGS'] = CLVar('-Wl,-no-undefined')
182 env['SHLIBPREFIX'] = 'cyg'
183 env['SHLIBSUFFIX'] = '.dll'
185 env['IMPLIBPREFIX'] = 'lib'
186 env['IMPLIBSUFFIX'] = '.dll.a'
188 # Variables used by versioned shared libraries
189 # SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
190 env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
191 env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
193 env['_IMPLIB_PRE_SOURCES'] = _implib_pre_flags
194 env['_IMPLIB_POST_SOURCES'] = _implib_post_flags
195 env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH ' \
196 '$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
197 env['LDMODULECOM'] = '$LDMODULE -o $TARGET $SHLINKFLAGS $__LDMODULEVERSIONFLAGS $__RPATH ' \
198 '$_IMPLIB_PRE_SOURCES $SOURCES $_IMPLIB_POST_SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
200 # Overwrite emitters. Cyglink does things differently when creating symlinks
201 env['SHLIBEMITTER'] = [cyglink_lib_emitter, cyglink_shlib_symlink_emitter]
202 env['LDMODULEEMITTER'] = [cyglink_ldmodule_emitter, cyglink_ldmod_symlink_emitter]
204 # This is the non versioned shlib filename
205 # If SHLIBVERSION is defined then this will symlink to $SHLIBNAME
206 env['SHLIB_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_shlib_stem${IMPLIBSUFFIX}'
207 env['LDMODULE_NOVERSION_SYMLINK'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${IMPLIBSUFFIX}'
209 env['SHLIB_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_shlib_stem${_SHLIB_IMPLIBSUFFIX}'
210 env['LDMODULE_IMPLIBNAME'] = '${IMPLIBPREFIX}$_get_ldmodule_stem${_LDMODULE_IMPLIBSUFFIX}'
212 env['_cyglink_shlibversion'] = cyglink_shlibversion
213 env['_SHLIB_IMPLIBSUFFIX'] = '${_cyglink_shlibversion}${IMPLIBSUFFIX}'
214 env['_SHLIBSUFFIX'] = '${_cyglink_shlibversion}${SHLIBSUFFIX}'
216 env['_cyglink_ldmodule_version'] = cyglink_ldmodule_version
218 env['_LDMODULESUFFIX'] = '${_cyglink_ldmodule_version}${LDMODULESUFFIX}'
219 env['_LDMODULE_IMPLIBSUFFIX'] = '${_cyglink_ldmodule_version}${IMPLIBSUFFIX}'
221 # Remove variables set by default initialization which aren't needed/used by cyglink
222 # these variables were set by gnulink but are not used in cyglink
223 for rv in ['_SHLIBSONAME', '_LDMODULESONAME']:
224 if rv in env:
225 del env[rv]
228 def exists(env):
229 return gnulink.exists(env)
231 # Local Variables:
232 # tab-width:4
233 # indent-tabs-mode:nil
234 # End:
235 # vim: set expandtab tabstop=4 shiftwidth=4: