mirror of
https://github.com/Relintai/scons_gd.git
synced 2025-02-14 17:00:20 +01:00
299 lines
8.6 KiB
Python
299 lines
8.6 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# __COPYRIGHT__
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
#
|
|
|
|
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
|
|
|
"""
|
|
Test that we can build shared libraries and link against shared
|
|
libraries that have non-standard library prefixes and suffixes.
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
import TestSCons
|
|
|
|
test = TestSCons.TestSCons()
|
|
|
|
test.write('SConstruct', """
|
|
import sys
|
|
isCygwin = sys.platform == 'cygwin'
|
|
isWindows = sys.platform == 'win32'
|
|
isMingw = False
|
|
if isWindows:
|
|
import SCons.Tool.MSCommon as msc
|
|
if not msc.msvc_exists():
|
|
# We can't seem to find any MSVC version, so we assume
|
|
# that MinGW is installed instead. Accordingly, we use the
|
|
# standard gcc/g++ conventions for lib prefixes and suffixes
|
|
# in the following...
|
|
isWindows = False
|
|
isMingw = True
|
|
|
|
env = Environment()
|
|
|
|
# Make sure that the shared library can be located at runtime.
|
|
env.Append(RPATH=['.'])
|
|
env.Append(LIBPATH=['.'])
|
|
|
|
# We first bake the LIBSUFFIXES, so that it will not change as a
|
|
# side-effect of changing SHLIBSUFFIX.
|
|
env['LIBSUFFIXES'] = list(map( env.subst, env.get('LIBSUFFIXES', [])))
|
|
|
|
weird_prefixes = ['libXX', 'libYY']
|
|
|
|
if isWindows:
|
|
weird_suffixes = ['.xxx', '.yyy', '.xxx.dll', '.yyy.dll']
|
|
env.Append(CCFLAGS = '/MD')
|
|
elif env['PLATFORM'] == 'darwin':
|
|
weird_suffixes = ['.xxx.dylib', '.yyy.dylib']
|
|
else:
|
|
weird_suffixes = ['.xxx.so', '.yyy.so']
|
|
|
|
shlibprefix = env.subst('$SHLIBPREFIX')
|
|
shlibsuffix = env.subst('$SHLIBSUFFIX')
|
|
|
|
progprefix = env.subst('$PROGPREFIX')
|
|
progsuffix = env.subst('$PROGSUFFIX')
|
|
|
|
goo_obj = env.SharedObject(source='goo.c')
|
|
foo_obj = env.SharedObject(source='foo.c')
|
|
prog_obj = env.SharedObject(source='prog.c')
|
|
|
|
#
|
|
# The following functions define all the different ways that one can
|
|
# use to link against a shared library.
|
|
#
|
|
def nodeInSrc(source, lib, libname):
|
|
return (source+lib, '')
|
|
|
|
def pathInSrc(source, lib, libname):
|
|
return (source+list(map(str,lib)), '')
|
|
|
|
def nodeInLib(source, lib, libname):
|
|
return (source, lib)
|
|
|
|
def pathInLib(source, lib, libname):
|
|
return (source, list(map(str,lib)))
|
|
|
|
def nameInLib(source, lib, libname):
|
|
# NOTE: libname must contain both the proper prefix and suffix.
|
|
#
|
|
# When using non-standard prefixes and suffixes, one has to
|
|
# provide the full name of the library since scons can not know
|
|
# which of the non-standard extension to use.
|
|
#
|
|
# Note that this is not necessarily SHLIBPREFIX and
|
|
# SHLIBSUFFIX. These are the ixes of the target library, not the
|
|
# ixes of the library that we are linking against.
|
|
return (source, libname)
|
|
|
|
libmethods = [nodeInSrc, pathInSrc, nodeInLib, pathInLib]
|
|
# We skip the nameInLib test for MinGW and Cygwin...they would fail, due to
|
|
# the Tool's internal naming conventions
|
|
if not isMingw and not isCygwin:
|
|
libmethods.extend([nameInLib])
|
|
|
|
def buildAndlinkAgainst(builder, target, source, method, lib, libname, **kw):
|
|
'''Build a target using a given builder while linking against a given
|
|
library using a specified method for linking against the library.'''
|
|
|
|
# On Windows, we have to link against the .lib file.
|
|
if isWindows:
|
|
for l in lib:
|
|
if str(l)[-4:] == '.lib':
|
|
lib = [l]
|
|
break
|
|
# If we use MinGW or Cygwin and create a SharedLibrary, we get two targets: a DLL,
|
|
# and the import lib created by the "--out-implib" parameter. We always
|
|
# want to link against the second one, in order to prevent naming issues
|
|
# for the linker command line...
|
|
if (isMingw or isCygwin) and len(lib) > 1:
|
|
lib = lib[1:]
|
|
|
|
# Apply the naming method to be tested and call the specified Builder.
|
|
(source, LIBS) = method(source, lib, libname)
|
|
#build = builder(target=target, source=source, LIBS=LIBS, **kw)
|
|
kw = kw.copy()
|
|
kw['target'] = target
|
|
kw['source'] = source
|
|
kw['LIBS'] = LIBS
|
|
build = builder(**kw)
|
|
|
|
# Check that the build target depends on at least one of the
|
|
# library target.
|
|
found_dep = False
|
|
children = build[0].children()
|
|
for l in lib:
|
|
if l in children:
|
|
found_dep = True
|
|
break;
|
|
assert found_dep, \
|
|
"One of %s not found in %s, method=%s, libname=%s, shlibsuffix=%s" % \
|
|
(list(map(str,lib)), list(map(str, build[0].children())), method.__name__, libname, shlibsuffix)
|
|
return build
|
|
|
|
def prog(i,
|
|
goomethod, goolibprefix, goolibsuffix,
|
|
foomethod, foolibprefix, foolibsuffix):
|
|
'''Build a program
|
|
|
|
The program links against a shared library foo which itself links
|
|
against a shared library goo. The libraries foo and goo can use
|
|
arbitrary library prefixes and suffixes.'''
|
|
|
|
goo_name = goolibprefix+'goo'+str(i)+goolibsuffix
|
|
foo_name = foolibprefix+'foo'+str(i)+foolibsuffix
|
|
prog_name = progprefix+'prog'+str(i)+progsuffix
|
|
|
|
print('Prog: %d, %s, %s, %s' % (i, goo_name, foo_name, prog_name))
|
|
|
|
# On Windows, we have to link against the .lib file.
|
|
if isWindows:
|
|
goo_libname = goolibprefix+'goo'+str(i)+'.lib'
|
|
foo_libname = foolibprefix+'foo'+str(i)+'.lib'
|
|
else:
|
|
goo_libname = goo_name
|
|
foo_libname = foo_name
|
|
|
|
goo_lib = env.SharedLibrary(
|
|
goo_name, goo_obj, SHLIBSUFFIX=goolibsuffix)
|
|
foo_lib = buildAndlinkAgainst(
|
|
env.SharedLibrary, foo_name, foo_obj,
|
|
goomethod, goo_lib, goo_libname, SHLIBSUFFIX=foolibsuffix)
|
|
prog = buildAndlinkAgainst(env.Program, prog_name, prog_obj,
|
|
foomethod, foo_lib, foo_libname)
|
|
|
|
|
|
#
|
|
# Create the list of all possible permutations to test.
|
|
#
|
|
i = 0
|
|
tests = []
|
|
prefixes = [shlibprefix] + weird_prefixes
|
|
suffixes = [shlibsuffix] + weird_suffixes
|
|
for foolibprefix in prefixes:
|
|
for foolibsuffix in suffixes:
|
|
for foomethod in libmethods:
|
|
for goolibprefix in prefixes:
|
|
for goolibsuffix in suffixes:
|
|
for goomethod in libmethods:
|
|
tests.append(
|
|
(i,
|
|
goomethod, goolibprefix, goolibsuffix,
|
|
foomethod, foolibprefix, foolibsuffix))
|
|
i = i + 1
|
|
|
|
#
|
|
# Pseudo-randomly choose 200 tests to run out of the possible
|
|
# tests. (Testing every possible permutation would take too long.)
|
|
#
|
|
import random
|
|
random.seed(123456)
|
|
try:
|
|
random.shuffle(tests)
|
|
except AttributeError:
|
|
pass
|
|
|
|
for i in range(200):
|
|
prog(*tests[i])
|
|
|
|
""")
|
|
|
|
test.write('goo.c', r"""
|
|
#include <stdio.h>
|
|
|
|
#ifdef _WIN32
|
|
#define EXPORT __declspec( dllexport )
|
|
#else
|
|
#define EXPORT
|
|
#endif
|
|
|
|
EXPORT void
|
|
goo(void)
|
|
{
|
|
printf("goo.c\n");
|
|
}
|
|
""")
|
|
|
|
test.write('foo.c', r"""
|
|
#include <stdio.h>
|
|
|
|
void goo(void);
|
|
|
|
#ifdef _WIN32
|
|
#define EXPORT __declspec( dllexport )
|
|
#else
|
|
#define EXPORT
|
|
#endif
|
|
|
|
EXPORT void
|
|
foo(void)
|
|
{
|
|
goo();
|
|
printf("foo.c\n");
|
|
}
|
|
""")
|
|
|
|
test.write('prog.c', r"""
|
|
#include <stdio.h>
|
|
|
|
void foo(void);
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
argv[argc++] = "--";
|
|
foo();
|
|
printf("prog.c\n");
|
|
return 0;
|
|
}
|
|
""")
|
|
|
|
test.run(arguments = '.',
|
|
stderr=TestSCons.noisy_ar,
|
|
match=TestSCons.match_re_dotall)
|
|
|
|
tests = re.findall(r'Prog: (\d+), (\S+), (\S+), (\S+)', test.stdout())
|
|
expected = "goo.c\nfoo.c\nprog.c\n"
|
|
|
|
for t in tests:
|
|
if sys.platform != 'cygwin':
|
|
test.must_exist(t[1])
|
|
test.must_exist(t[2])
|
|
else:
|
|
# Cygwin turns libFoo.xxx into cygFoo.xxx
|
|
for f in t[1:2]:
|
|
test.must_exist(re.sub('^lib', 'cyg', f))
|
|
|
|
test.must_exist(t[3])
|
|
test.run(program = test.workpath(t[3]), stdout=expected)
|
|
|
|
test.pass_test()
|
|
|
|
# Local Variables:
|
|
# tab-width:4
|
|
# indent-tabs-mode:nil
|
|
# End:
|
|
# vim: set expandtab tabstop=4 shiftwidth=4:
|