While you're making plans for 2013, would somebody please pay
attention to the continuing lack of out-of-the-box support for
versioned shared libraries?

I know of at least two projects that have rejected moving to SCons for this
reason.  It is quite a bit more important in the real world than 
(for example) D support.

Here, once again, is my custom builder code solving this problem.  If
someone on the core teanm is willing to integrate this properly, I'll write the 
documentation for it.

# Cope with scons's failure to set SONAME in its builtins.
# Inspired by Richard Levitte's (slightly buggy) code at
# http://markmail.org/message/spttz3o4xrsftofr

def VersionedSharedLibrary(env, libname, version, lib_objs=[], parse_flags=[]):
    platform = env.subst('$PLATFORM')
    shlib_pre_action = None
    shlib_suffix = env.subst('$SHLIBSUFFIX')
    shlib_post_action = None
    shlink_flags = SCons.Util.CLVar(env.subst('$SHLINKFLAGS'))

    if platform == 'posix':
        ilib_suffix = shlib_suffix + '.' + version
        (major, age, revision) = version.split(".")
        soname = "lib" + libname + shlib_suffix + "." + major
        shlink_flags += [ '-Wl,-Bsymbolic', '-Wl,-soname=%s' % soname ]
    elif platform == 'cygwin':
        ilib_suffix = shlib_suffix
        shlink_flags += [ '-Wl,-Bsymbolic',
                          '-Wl,--out-implib,${TARGET.base}.a' ]
    elif platform == 'darwin':
        ilib_suffix = '.' + version + shlib_suffix
        shlink_flags += [ '-current_version', '%s' % version,
                          '-compatibility_version', '%s' % version,
                          '-undefined', 'dynamic_lookup' ]

    ilib = env.SharedLibrary(libname,lib_objs,
                            SHLIBSUFFIX=ilib_suffix,
                            SHLINKFLAGS=shlink_flags, parse_flags=parse_flags)

    if platform == 'darwin':
        if version.count(".") != 2:
            # We need a library name in libfoo.x.y.z.dylib form to proceed
            raise ValueError
        lib = 'lib' + libname + '.' + version + '.dylib'
        lib_no_ver = 'lib' + libname + '.dylib'
        # Link libfoo.x.y.z.dylib to libfoo.dylib
        env.AddPostAction(ilib, 'rm -f %s; ln -s %s %s' % (
            lib_no_ver, lib, lib_no_ver))
        env.Clean(lib, lib_no_ver)
    elif platform == 'posix':
        if version.count(".") != 2:
            # We need a library name in libfoo.so.x.y.z form to proceed
            raise ValueError
        lib = "lib" + libname + ".so." + version
        suffix_re = '%s\\.[0-9\\.]*$' % re.escape(shlib_suffix)
        # For libfoo.so.x.y.z, links libfoo.so libfoo.so.x.y libfoo.so.x
        major_name = shlib_suffix + "." + lib.split(".")[2]
        minor_name = major_name + "." + lib.split(".")[3]
        for linksuffix in [shlib_suffix, major_name, minor_name]:
            linkname = re.sub(suffix_re, linksuffix, lib)
            env.AddPostAction(ilib, 'rm -f %s; ln -s %s %s' % (
                linkname, lib, linkname))
            env.Clean(lib, linkname)

    return ilib

def VersionedSharedLibraryInstall(env, destination, libs):
    platform = env.subst('$PLATFORM')
    shlib_suffix = env.subst('$SHLIBSUFFIX')
    ilibs = env.Install(destination, libs)
    if platform == 'posix':
        suffix_re = '%s\\.[0-9\\.]*$' % re.escape(shlib_suffix)
        for lib in map(str, libs):
            if lib.count(".") != 4:
                # We need a library name in libfoo.so.x.y.z form to proceed
                raise ValueError
            # For libfoo.so.x.y.z, links libfoo.so libfoo.so.x.y libfoo.so.x
            major_name = shlib_suffix + "." + lib.split(".")[2]
            minor_name = major_name + "." + lib.split(".")[3]
            for linksuffix in [shlib_suffix, major_name, minor_name]:
                linkname = re.sub(suffix_re, linksuffix, lib)
                env.AddPostAction(ilibs, 'cd %s; rm -f %s; ln -s %s %s' % 
(destination, linkname, lib, linkname))
            env.Clean(lib, linkname)
    return ilibs

if not env["shared"]:
    def Library(env, target, sources, version, parse_flags=[]):
        return env.StaticLibrary(target, sources, parse_flags=parse_flags)
    LibraryInstall = lambda env, libdir, sources: env.Install(libdir, sources)
else:
    def Library(env, target, sources, version, parse_flags=[]):
        return VersionedSharedLibrary(env=env,
                                     libname=target,
                                     version=version,
                                     lib_objs=sources,
                                     parse_flags=parse_flags)
    LibraryInstall = lambda env, libdir, sources: \
                     VersionedSharedLibraryInstall(env, libdir, sources)

# Klugery to handle sonames ends


-- 
                <a href="http://www.catb.org/~esr/";>Eric S. Raymond</a>
_______________________________________________
Scons-dev mailing list
[email protected]
http://two.pairlist.net/mailman/listinfo/scons-dev

Reply via email to