renamed SCons.Tool.ninja -> SCons.Tool.ninja_tool and added alias in tool loading...
[scons.git] / SCons / Tool / linkCommon / SharedLibrary.py
blob30170f8bb82b269a9c7bca3f4b559cecffb1b909
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 from SCons.Errors import UserError
25 from SCons.Tool import createSharedLibBuilder
26 from SCons.Util import CLVar
27 from . import lib_emitter, EmitLibSymlinks, StringizeLibSymlinks
30 def shlib_symlink_emitter(target, source, env, **kw):
31 verbose = False
33 if "variable_prefix" in kw:
34 var_prefix = kw["variable_prefix"]
35 else:
36 var_prefix = "SHLIB"
38 do_symlinks = env.subst("$%sNOVERSIONSYMLINKS" % var_prefix)
39 if do_symlinks in ["1", "True", "true", True]:
40 return target, source
42 shlibversion = env.subst("$%sVERSION" % var_prefix)
43 if shlibversion:
44 if verbose:
45 print("shlib_symlink_emitter: %sVERSION=%s" % (var_prefix, shlibversion))
47 libnode = target[0]
48 shlib_soname_symlink = env.subst(
49 "$%s_SONAME_SYMLINK" % var_prefix, target=target, source=source
51 shlib_noversion_symlink = env.subst(
52 "$%s_NOVERSION_SYMLINK" % var_prefix, target=target, source=source
55 if verbose:
56 print("shlib_soname_symlink :%s" % shlib_soname_symlink)
57 print("shlib_noversion_symlink :%s" % shlib_noversion_symlink)
58 print("libnode :%s" % libnode)
60 shlib_soname_symlink = env.File(shlib_soname_symlink)
61 shlib_noversion_symlink = env.File(shlib_noversion_symlink)
63 symlinks = []
64 if shlib_soname_symlink != libnode:
65 # If soname and library name machine, don't symlink them together
66 symlinks.append((env.File(shlib_soname_symlink), libnode))
68 symlinks.append((env.File(shlib_noversion_symlink), libnode))
70 if verbose:
71 print(
72 "_lib_emitter: symlinks={!r}".format(
73 ", ".join(
74 ["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)]
79 if symlinks:
80 # This does the actual symlinking
81 EmitLibSymlinks(env, symlinks, target[0])
83 # This saves the information so if the versioned shared library is installed
84 # it can faithfully reproduce the correct symlinks
85 target[0].attributes.shliblinks = symlinks
87 return target, source
90 def _soversion(target, source, env, for_signature):
91 """Function to determine what to use for SOVERSION"""
93 if "SOVERSION" in env:
94 return ".$SOVERSION"
95 elif "SHLIBVERSION" in env:
96 shlibversion = env.subst("$SHLIBVERSION")
97 # We use only the most significant digit of SHLIBVERSION
98 return "." + shlibversion.split(".")[0]
99 else:
100 return ""
103 def _soname(target, source, env, for_signature) -> str:
104 if "SONAME" in env:
105 # Now verify that SOVERSION is not also set as that is not allowed
106 if "SOVERSION" in env:
107 raise UserError(
108 "Ambiguous library .so naming, both SONAME: %s and SOVERSION: %s are defined. "
109 "Only one can be defined for a target library."
110 % (env["SONAME"], env["SOVERSION"])
112 return "$SONAME"
113 else:
114 return "$SHLIBPREFIX$_get_shlib_stem${SHLIBSUFFIX}$_SHLIBSOVERSION"
117 def _get_shlib_stem(target, source, env, for_signature: bool) -> str:
118 """Get the base name of a shared library.
120 Args:
121 target: target node containing the lib name
122 source: source node, not used
123 env: environment context for running subst
124 for_signature: whether this is being done for signature generation
126 Returns:
127 the library name without prefix/suffix
129 verbose = False
131 target_name = str(target.name)
132 shlibprefix = env.subst("$SHLIBPREFIX")
133 shlibsuffix = env.subst("$_SHLIBSUFFIX")
135 if verbose and not for_signature:
136 print(
137 "_get_shlib_stem: target_name:%s shlibprefix:%s shlibsuffix:%s"
138 % (target_name, shlibprefix, shlibsuffix)
142 if shlibsuffix and target_name.endswith(shlibsuffix):
143 target_name = target_name[: -len(shlibsuffix)]
145 if shlibprefix and target_name.startswith(shlibprefix):
146 # skip pathological case were target _is_ the prefix
147 if target_name != shlibprefix:
148 target_name = target_name[len(shlibprefix) :]
151 if verbose and not for_signature:
152 print("_get_shlib_stem: target_name:%s AFTER" % (target_name,))
154 return target_name
157 def _get_shlib_dir(target, source, env, for_signature: bool) -> str:
158 """Get the directory the shared library is in.
160 Args:
161 target: target node
162 source: source node, not used
163 env: environment context, not used
164 for_signature: whether this is being done for signature generation
166 Returns:
167 the directory the library will be in (empty string if '.')
169 verbose = False
171 if target.dir and str(target.dir) != ".":
172 if verbose:
173 print("_get_shlib_dir: target.dir:%s" % target.dir)
175 return "%s/" % str(target.dir)
176 else:
177 return ""
180 def setup_shared_lib_logic(env) -> None:
181 """Initialize an environment for shared library building.
183 Args:
184 env: environment to set up
186 createSharedLibBuilder(env)
188 env["_get_shlib_stem"] = _get_shlib_stem
189 env["_get_shlib_dir"] = _get_shlib_dir
190 env["_SHLIBSOVERSION"] = _soversion
191 env["_SHLIBSONAME"] = _soname
193 env["SHLIBNAME"] = "${_get_shlib_dir}${SHLIBPREFIX}$_get_shlib_stem${_SHLIBSUFFIX}"
195 # This is the non versioned shlib filename
196 # If SHLIBVERSION is defined then this will symlink to $SHLIBNAME
197 env["SHLIB_NOVERSION_SYMLINK"] = "${_get_shlib_dir}${SHLIBPREFIX}$_get_shlib_stem${SHLIBSUFFIX}"
199 # This is the sonamed file name
200 # If SHLIBVERSION is defined then this will symlink to $SHLIBNAME
201 env["SHLIB_SONAME_SYMLINK"] = "${_get_shlib_dir}$_SHLIBSONAME"
203 # Note this is gnu style
204 env["SHLIBSONAMEFLAGS"] = "-Wl,-soname=$_SHLIBSONAME"
205 env["_SHLIBVERSION"] = "${SHLIBVERSION and '.'+SHLIBVERSION or ''}"
206 env["_SHLIBVERSIONFLAGS"] = "$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME"
208 env["SHLIBEMITTER"] = [lib_emitter, shlib_symlink_emitter]
210 # If it's already set, then don't overwrite.
211 env["SHLIBPREFIX"] = env.get('SHLIBPREFIX', "lib")
212 env["_SHLIBSUFFIX"] = "${SHLIBSUFFIX}${_SHLIBVERSION}"
214 env["SHLINKFLAGS"] = CLVar("$LINKFLAGS -shared")
216 env["SHLINKCOM"] = "$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS"
218 env["SHLINK"] = "$LINK"