5 # Copyright The SCons Foundation
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
15 # The above copyright notice and this permission notice shall be included
16 # in all copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 Test that we can build shared libraries and link against shared
28 libraries that have non-standard library prefixes and suffixes.
35 test
= TestSCons
.TestSCons()
37 test
.write('SConstruct', """
39 isCygwin = sys.platform == 'cygwin'
40 isWindows = sys.platform == 'win32'
43 import SCons.Tool.MSCommon as msc
44 if not msc.msvc_exists():
45 # We can't seem to find any MSVC version, so we assume
46 # that MinGW is installed instead. Accordingly, we use the
47 # standard gcc/g++ conventions for lib prefixes and suffixes
52 DefaultEnvironment(tools=[]) # test speedup
55 # Make sure that the shared library can be located at runtime.
56 env.Append(RPATH=['.'])
57 env.Append(LIBPATH=['.'])
59 # We first bake the LIBSUFFIXES, so that it will not change as a
60 # side-effect of changing SHLIBSUFFIX.
61 env['LIBSUFFIXES'] = list(map( env.subst, env.get('LIBSUFFIXES', [])))
63 weird_prefixes = ['libXX', 'libYY']
66 weird_suffixes = ['.xxx', '.yyy', '.xxx.dll', '.yyy.dll']
67 env.Append(CCFLAGS = '/MD')
68 elif env['PLATFORM'] == 'darwin':
69 weird_suffixes = ['.xxx.dylib', '.yyy.dylib']
71 weird_suffixes = ['.xxx.so', '.yyy.so']
73 shlibprefix = env.subst('$SHLIBPREFIX')
74 shlibsuffix = env.subst('$SHLIBSUFFIX')
76 progprefix = env.subst('$PROGPREFIX')
77 progsuffix = env.subst('$PROGSUFFIX')
79 goo_obj = env.SharedObject(source='goo.c')
80 foo_obj = env.SharedObject(source='foo.c')
81 prog_obj = env.SharedObject(source='prog.c')
84 # The following functions define all the different ways that one can
85 # use to link against a shared library.
87 def nodeInSrc(source, lib, libname):
88 return (source+lib, '')
90 def pathInSrc(source, lib, libname):
91 return (source+list(map(str,lib)), '')
93 def nodeInLib(source, lib, libname):
96 def pathInLib(source, lib, libname):
97 return (source, list(map(str,lib)))
99 def nameInLib(source, lib, libname):
100 # NOTE: libname must contain both the proper prefix and suffix.
102 # When using non-standard prefixes and suffixes, one has to
103 # provide the full name of the library since scons can not know
104 # which of the non-standard extension to use.
106 # Note that this is not necessarily SHLIBPREFIX and
107 # SHLIBSUFFIX. These are the ixes of the target library, not the
108 # ixes of the library that we are linking against.
109 return (source, libname)
111 libmethods = [nodeInSrc, pathInSrc, nodeInLib, pathInLib]
112 # We skip the nameInLib test for MinGW and Cygwin...they would fail, due to
113 # the Tool's internal naming conventions
114 if not isMingw and not isCygwin:
115 libmethods.extend([nameInLib])
117 def buildAndlinkAgainst(builder, target, source, method, lib, libname, **kw):
118 '''Build a target using a given builder while linking against a given
119 library using a specified method for linking against the library.'''
121 # On Windows, we have to link against the .lib file.
124 if str(l)[-4:] == '.lib':
127 # If we use MinGW or Cygwin and create a SharedLibrary, we get two targets: a DLL,
128 # and the import lib created by the "--out-implib" parameter. We always
129 # want to link against the second one, in order to prevent naming issues
130 # for the linker command line...
131 if (isMingw or isCygwin) and len(lib) > 1:
134 # Apply the naming method to be tested and call the specified Builder.
135 (source, LIBS) = method(source, lib, libname)
136 #build = builder(target=target, source=source, LIBS=LIBS, **kw)
138 kw['target'] = target
139 kw['source'] = source
141 build = builder(**kw)
143 # Check that the build target depends on at least one of the
146 children = build[0].children()
152 "One of %s not found in %s, method=%s, libname=%s, shlibsuffix=%s" % \
153 (list(map(str,lib)), list(map(str, build[0].children())), method.__name__, libname, shlibsuffix)
157 goomethod, goolibprefix, goolibsuffix,
158 foomethod, foolibprefix, foolibsuffix):
161 The program links against a shared library foo which itself links
162 against a shared library goo. The libraries foo and goo can use
163 arbitrary library prefixes and suffixes.'''
165 goo_name = goolibprefix+'goo'+str(i)+goolibsuffix
166 foo_name = foolibprefix+'foo'+str(i)+foolibsuffix
167 prog_name = progprefix+'prog'+str(i)+progsuffix
169 print('Prog: %d, %s, %s, %s' % (i, goo_name, foo_name, prog_name))
171 # On Windows, we have to link against the .lib file.
173 goo_libname = goolibprefix+'goo'+str(i)+'.lib'
174 foo_libname = foolibprefix+'foo'+str(i)+'.lib'
176 goo_libname = goo_name
177 foo_libname = foo_name
179 goo_lib = env.SharedLibrary(
180 goo_name, goo_obj, SHLIBSUFFIX=goolibsuffix)
181 foo_lib = buildAndlinkAgainst(
182 env.SharedLibrary, foo_name, foo_obj,
183 goomethod, goo_lib, goo_libname, SHLIBSUFFIX=foolibsuffix)
184 prog = buildAndlinkAgainst(env.Program, prog_name, prog_obj,
185 foomethod, foo_lib, foo_libname)
189 # Create the list of all possible permutations to test.
193 prefixes = [shlibprefix] + weird_prefixes
194 suffixes = [shlibsuffix] + weird_suffixes
195 for foolibprefix in prefixes:
196 for foolibsuffix in suffixes:
197 for foomethod in libmethods:
198 for goolibprefix in prefixes:
199 for goolibsuffix in suffixes:
200 for goomethod in libmethods:
203 goomethod, goolibprefix, goolibsuffix,
204 foomethod, foolibprefix, foolibsuffix))
208 # Pseudo-randomly choose 200 tests to run out of the possible
209 # tests. (Testing every possible permutation would take too long.)
214 random.shuffle(tests)
215 except AttributeError:
223 test
.write('goo.c', r
"""
227 #define EXPORT __declspec( dllexport )
239 test
.write('foo.c', r
"""
245 #define EXPORT __declspec( dllexport )
258 test
.write('prog.c', r
"""
264 main(int argc, char *argv[])
273 test
.run(arguments
= '.',
274 stderr
=TestSCons
.noisy_ar
,
275 match
=TestSCons
.match_re_dotall
)
277 tests
= re
.findall(r
'Prog: (\d+), (\S+), (\S+), (\S+)', test
.stdout())
278 expected
= "goo.c\nfoo.c\nprog.c\n"
281 if sys
.platform
!= 'cygwin':
282 test
.must_exist(t
[1])
283 test
.must_exist(t
[2])
285 # Cygwin turns libFoo.xxx into cygFoo.xxx
287 test
.must_exist(re
.sub('^lib', 'cyg', f
))
289 test
.must_exist(t
[3])
290 test
.run(program
= test
.workpath(t
[3]), stdout
=expected
)
296 # indent-tabs-mode:nil
298 # vim: set expandtab tabstop=4 shiftwidth=4: