Please note:The SCons wiki is in read-only mode due to ongoing spam/DoS issues. Also, new account creation is currently disabled. We are looking into alternative wiki hosts.
Differences between revisions 16 and 17
Revision 16 as of 2006-01-11 07:44:17
Size: 3570
Editor: 69-212-77-18
Comment: removed porn spam
Revision 17 as of 2008-03-12 02:46:58
Size: 3570
Editor: localhost
Comment: converted to 1.6 markup
No differences found!

scons 0.96 treat dependencies on shared libraries that are generated in a simplistic manner, if the library is rebuilt, any programs that link against it are also rebuilt.

Most of the time it is not necessary to rebuild the programs, as changes are usually to the implementation of the source not interface changes. In the case of a shared library it is relatively easy to figure out if the change needs a relink by generating a signature based on the actual external symbols published and required by the library. This is in addition to the dependencies on the headers, which scons already determines automatically.

The following builder is a way of achieving this by separating changes to the implemention from changes to the interface. It uses a bunch of files to do this. There are probably better ways to achieve the same end, ideally scons would allow a custom signature technique to the plugged in for a node, typically by the builder.

The builder uses 2 common output directories for the libraries, #lib gets the latest builds of the shared libraries installed into it. The libraries in #linklib directory gets updated only when the interface changes. All programs get linked against the #linklibs directrory. The developer sets their LD_LIBRARY_PATH to the libraries in #lib when testing.

The builder sets up an indirect dependency between the library in each version, and uses a nm command extract the global symbols from the updated library, and stored this in a file that is used as the interface signature of the library.

Note it is also overriding the standard SharedLibrary() builder within the 'env' environment. However I am not convinced this is the best way to do this.

   1 ####################################################
   2 # override SharedLibrary to only update the libs in '#shlib/' if the symbols
   3 # change.  This is to avoid rebuilding binaries when a shared library has
   4 # changes.
   5 # This would be MUCH simpler to implement if we could override the
   6 # signature to used for the SharedLibrary node itself directly. That is
   7 # certainly possible, but would rely on the internal structure of SCons.
   8 
   9 def fasterSharedLibrary(env, library, sources, **args):
  10         # use the 'quicker' shallow copy method!
  11         envContentSig=env.Copy()
  12         envContentSig.TargetSignatures('content')
  13 
  14         cat=env.OriginalSharedLibrary(library, sources)
  15 
  16         # copy all the latest libraries to ONE directory..
  17         # for our convenience. Could modify the above to
  18         # build directly to this dir instead.
  19         catLib = env.Install('#lib', cat) #the CURRENT lib dir
  20 
  21         # now generate the 'interface' file, using the
  22         # content signature for its target
  23         catIF=envContentSig.Command('%s.if'%(library),
  24                 catLib,
  25                 'nm --extern-only $SOURCES | cut -c 12- | sort > $TARGET')
  26 
  27         # install command to copy lib to shlib, where the link
  28         # actually occurs.  Explicitly make this depend only on
  29         # the IF file, which has a target content signature.
  30         # ie only if the Global Symbol list changes, is copied and this the
  31         # Programs it relinked.
  32         catLink=env.Command('#linklib/${SHLIBPREFIX}%s${SHLIBSUFFIX}'%(library),
  33                 '',
  34                 Copy('$TARGET',
  35                 catLib))
  36 
  37         #Dir('#lib')
  38         envContentSig.Depends(catLink, catIF)
  39 
  40         global libs
  41         libs += catLib
  42 
  43         return cat
  44 
  45 # declaring OriginalSharedLibrary is a bit marginal.  Probably should use
  46 # a functor style object so we can store it in side the object?
  47 env['BUILDERS']['OriginalSharedLibrary'] = env['BUILDERS']['SharedLibrary']
  48 env['BUILDERS']['SharedLibrary'] = fasterSharedLibrary

SharedLibrarySignatureOverride (last edited 2008-03-12 02:46:58 by localhost)