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
):
33 if "variable_prefix" in kw
:
34 var_prefix
= kw
["variable_prefix"]
38 do_symlinks
= env
.subst("$%sNOVERSIONSYMLINKS" % var_prefix
)
39 if do_symlinks
in ["1", "True", "true", True]:
42 shlibversion
= env
.subst("$%sVERSION" % var_prefix
)
45 print("shlib_symlink_emitter: %sVERSION=%s" % (var_prefix
, shlibversion
))
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
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
)
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
))
72 "_lib_emitter: symlinks={!r}".format(
74 ["%r->%r" % (k
, v
) for k
, v
in StringizeLibSymlinks(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
90 def _soversion(target
, source
, env
, for_signature
):
91 """Function to determine what to use for SOVERSION"""
93 if "SOVERSION" in env
:
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]
103 def _soname(target
, source
, env
, for_signature
) -> str:
105 # Now verify that SOVERSION is not also set as that is not allowed
106 if "SOVERSION" in env
:
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"])
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.
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
127 the library name without prefix/suffix
131 target_name
= str(target
.name
)
132 shlibprefix
= env
.subst("$SHLIBPREFIX")
133 shlibsuffix
= env
.subst("$_SHLIBSUFFIX")
135 if verbose
and not for_signature
:
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
,))
157 def _get_shlib_dir(target
, source
, env
, for_signature
: bool) -> str:
158 """Get the directory the shared library is in.
162 source: source node, not used
163 env: environment context, not used
164 for_signature: whether this is being done for signature generation
167 the directory the library will be in (empty string if '.')
171 if target
.dir and str(target
.dir) != ".":
173 print("_get_shlib_dir: target.dir:%s" % target
.dir)
175 return "%s/" % str(target
.dir)
180 def setup_shared_lib_logic(env
) -> None:
181 """Initialize an environment for shared library building.
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"