Fixed ninja binary location logic to use ninja.BIN_DIR. Previous logic no longer...
[scons.git] / SCons / Tool / applelink.py
blob3dc744d465db9767461fd34ddcadab65442f5d47
1 """SCons.Tool.applelink
3 Tool-specific initialization for Apple's gnu-like linker.
5 There normally shouldn't be any need to import this module directly.
6 It will usually be imported through the generic SCons.Tool.Tool()
7 selection method.
9 """
12 # MIT License
14 # Copyright The SCons Foundation
16 # Permission is hereby granted, free of charge, to any person obtaining
17 # a copy of this software and associated documentation files (the
18 # "Software"), to deal in the Software without restriction, including
19 # without limitation the rights to use, copy, modify, merge, publish,
20 # distribute, sublicense, and/or sell copies of the Software, and to
21 # permit persons to whom the Software is furnished to do so, subject to
22 # the following conditions:
24 # The above copyright notice and this permission notice shall be included
25 # in all copies or substantial portions of the Software.
27 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
28 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
29 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 # Even though the Mac is based on the GNU toolchain, it doesn't understand
37 # the -rpath option, so we use the "link" tool instead of "gnulink".
38 from SCons.Util import CLVar
39 from SCons.Errors import UserError
40 from . import link
42 # User programmatically describes how SHLIBVERSION maps to values for compat/current.
43 _APPLELIB_MAX_VERSION_VALUES = (65535, 255, 255)
46 class AppleLinkInvalidCurrentVersionException(Exception):
47 pass
50 class AppleLinkInvalidCompatibilityVersionException(Exception):
51 pass
54 def _applelib_check_valid_version(version_string):
55 """
56 Check that the version # is valid.
57 X[.Y[.Z]]
58 where X 0-65535
59 where Y either not specified or 0-255
60 where Z either not specified or 0-255
61 :param version_string:
62 :return:
63 """
64 parts = version_string.split('.')
65 if len(parts) > 3:
66 return False, "Version string has too many periods [%s]" % version_string
67 if len(parts) <= 0:
68 return False, "Version string unspecified [%s]" % version_string
70 for (i, p) in enumerate(parts):
71 try:
72 p_i = int(p)
73 except ValueError:
74 return False, "Version component %s (from %s) is not a number" % (p, version_string)
75 if p_i < 0 or p_i > _APPLELIB_MAX_VERSION_VALUES[i]:
76 return False, "Version component %s (from %s) is not valid value should be between 0 and %d" % (
77 p, version_string, _APPLELIB_MAX_VERSION_VALUES[i])
79 return True, ""
82 def _applelib_currentVersionFromSoVersion(source, target, env, for_signature) -> str:
83 """
84 A generator function to create the -Wl,-current_version flag if needed.
85 If env['APPLELINK_NO_CURRENT_VERSION'] contains a true value no flag will be generated
86 Otherwise if APPLELINK_CURRENT_VERSION is not specified, env['SHLIBVERSION']
87 will be used.
89 :param source:
90 :param target:
91 :param env:
92 :param for_signature:
93 :return: A string providing the flag to specify the current_version of the shared library
94 """
95 if env.get('APPLELINK_NO_CURRENT_VERSION', False):
96 return ""
97 elif env.get('APPLELINK_CURRENT_VERSION', False):
98 version_string = env['APPLELINK_CURRENT_VERSION']
99 elif env.get('SHLIBVERSION', False):
100 version_string = env['SHLIBVERSION']
101 else:
102 return ""
104 version_string = ".".join(version_string.split('.')[:3])
106 valid, reason = _applelib_check_valid_version(version_string)
107 if not valid:
108 raise AppleLinkInvalidCurrentVersionException(reason)
110 return "-Wl,-current_version,%s" % version_string
113 def _applelib_compatVersionFromSoVersion(source, target, env, for_signature) -> str:
115 A generator function to create the -Wl,-compatibility_version flag if needed.
116 If env['APPLELINK_NO_COMPATIBILITY_VERSION'] contains a true value no flag will be generated
117 Otherwise if APPLELINK_COMPATIBILITY_VERSION is not specified
118 the first two parts of env['SHLIBVERSION'] will be used with a .0 appended.
120 :param source:
121 :param target:
122 :param env:
123 :param for_signature:
124 :return: A string providing the flag to specify the compatibility_version of the shared library
126 if env.get('APPLELINK_NO_COMPATIBILITY_VERSION', False):
127 return ""
128 elif env.get('APPLELINK_COMPATIBILITY_VERSION', False):
129 version_string = env['APPLELINK_COMPATIBILITY_VERSION']
130 elif env.get('SHLIBVERSION', False):
131 version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0'])
132 else:
133 return ""
135 if version_string is None:
136 return ""
138 valid, reason = _applelib_check_valid_version(version_string)
139 if not valid:
140 raise AppleLinkInvalidCompatibilityVersionException(reason)
142 return "-Wl,-compatibility_version,%s" % version_string
144 def _applelib_soname(target, source, env, for_signature) -> str:
146 Override default _soname() function from SCons.Tools.linkCommon.SharedLibrary.
147 Apple's file naming for versioned shared libraries puts the version string before
148 the shared library suffix (.dylib), instead of after.
150 if "SONAME" in env:
151 # Now verify that SOVERSION is not also set as that is not allowed
152 if "SOVERSION" in env:
153 raise UserError(
154 "Ambiguous library .so naming, both SONAME: %s and SOVERSION: %s are defined. "
155 "Only one can be defined for a target library."
156 % (env["SONAME"], env["SOVERSION"])
158 return "$SONAME"
159 else:
160 return "$SHLIBPREFIX$_get_shlib_stem$_SHLIBSOVERSION${SHLIBSUFFIX}"
163 def generate(env) -> None:
164 """Add Builders and construction variables for applelink to an
165 Environment."""
166 link.generate(env)
168 env['FRAMEWORKPATHPREFIX'] = '-F'
169 env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__, RDirs)}'
171 env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
172 env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
173 env['SHLINKFLAGS'] = CLVar('$LINKFLAGS -dynamiclib')
174 env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
176 env['_APPLELINK_CURRENT_VERSION'] = _applelib_currentVersionFromSoVersion
177 env['_APPLELINK_COMPATIBILITY_VERSION'] = _applelib_compatVersionFromSoVersion
178 env['_SHLIBVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
179 env['_LDMODULEVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
181 # override the default for loadable modules, which are different
182 # on OS X than dynamic shared libs. echoing what XCode does for
183 # pre/suffixes:
184 env['LDMODULEPREFIX'] = ''
185 env['LDMODULESUFFIX'] = ''
186 env['LDMODULEFLAGS'] = CLVar('$LINKFLAGS -bundle')
187 env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS' \
188 ' $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
190 # New stuff
192 env['_SHLIBSUFFIX'] = '${_SHLIBVERSION}${SHLIBSUFFIX}'
194 env['__SHLIBVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
195 '"SHLIBVERSION","_APPLELINK_CURRENT_VERSION", "_SHLIBVERSIONFLAGS")}'
196 env['__LDMODULEVERSIONFLAGS'] = '${__lib_either_version_flag(__env__,' \
197 '"LDMODULEVERSION","_APPLELINK_CURRENT_VERSION", "_LDMODULEVERSIONFLAGS")}'
199 env["_SHLIBSONAME"] = _applelib_soname
202 def exists(env):
203 return env['PLATFORM'] == 'darwin'
205 # Local Variables:
206 # tab-width:4
207 # indent-tabs-mode:nil
208 # End:
209 # vim: set expandtab tabstop=4 shiftwidth=4: