build: split build and install libraries/binaries
authorAndrew Tridgell <tridge@samba.org>
Thu, 18 Mar 2010 12:47:48 +0000 (23:47 +1100)
committerAndrew Tridgell <tridge@samba.org>
Tue, 6 Apr 2010 10:26:52 +0000 (20:26 +1000)
we need to split these to avoid re-compilation on install
as install has different rpath settings

buildtools/wafsamba/samba_deps.py
buildtools/wafsamba/samba_utils.py
buildtools/wafsamba/wafsamba.py

index f20bccba067c37e5ba9f2b48ac545fdf90b92794..fa34cb8fcf765c7319ee618740938aa452bbd166 100644 (file)
@@ -15,7 +15,9 @@ def ADD_GLOBAL_DEPENDENCY(ctx, dep):
 def TARGET_ALIAS(bld, target, alias):
     '''define an alias for a target name'''
     cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
-    bld.ASSERT(alias not in cache, "Target alias %s already set" % alias)
+    if alias in cache:
+        print("Target alias %s already set to %s : newalias %s" % (alias, cache[alias], target))
+        raise
     cache[alias] = target
 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
 
@@ -173,9 +175,14 @@ def add_init_functions(self):
 
     subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
 
+    # cope with the separated object lists from BINARY and LIBRARY targets
+    sname = self.sname
+    if sname.endswith('.objlist'):
+        sname = sname[0:-8]
+
     modules = []
-    if self.sname in subsystems:
-        modules.append(self.sname)
+    if sname in subsystems:
+        modules.append(sname)
 
     m = getattr(self, 'samba_modules', None)
     if m is not None:
@@ -544,6 +551,9 @@ def calculate_final_deps(bld, tgt_list):
             for l in t.final_libs.copy():
                 t2 = bld.name_to_obj(l, bld.env)
                 if t.sname in t2.final_libs:
+                    # we could break this in either direction. If one of the libraries
+                    # has a version number, and will this be distributed publicly, then
+                    # we should make it the lower level library in the DAG
                     debug('deps: removing library loop %s<->%s', t.sname, l)
                     t2.final_libs.remove(t.sname)
                     loops[t2.sname] = t.sname;
@@ -702,6 +712,9 @@ def check_project_rules(bld):
         if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
             continue
         t = bld.name_to_obj(tgt, bld.env)
+        if t is None:
+            print "Target %s of type %s has no task generator" % (tgt, type)
+            raise
         tgt_list.append(t)
 
     add_samba_attributes(bld, tgt_list)
index 5fbb801ef62e2186d1557dfd70855eefbc7eccb7..a5d42e4f7fbbd3e48d0a46dc877e0e8957155b2b 100644 (file)
@@ -51,23 +51,18 @@ def runonce(function):
 
 
 
-################################################################
-# magic rpath handling
-#
-# we want a different rpath when installing and when building
-# Note that this should really check if rpath is available on this platform
-# and it should also honor an --enable-rpath option
 def set_rpath(bld):
-    if Options.is_install:
-        if bld.env['RPATH_ON_INSTALL']:
-            bld.env['RPATH'] = ['-Wl,-rpath=%s/lib' % bld.env.PREFIX]
-        else:
-            bld.env['RPATH'] = []
-    else:
-        rpath = os.path.normpath('%s/%s' % (bld.env['BUILD_DIRECTORY'], LIB_PATH))
-        bld.env.append_value('RPATH', '-Wl,-rpath=%s' % rpath)
+    '''setup the default rpath'''
+    rpath = os.path.normpath('%s/%s' % (bld.env['BUILD_DIRECTORY'], LIB_PATH))
+    bld.env.append_value('RPATH', '-Wl,-rpath=%s' % rpath)
 Build.BuildContext.set_rpath = set_rpath
 
+def install_rpath(bld):
+    '''the rpath value for installation'''
+    if bld.env['RPATH_ON_INSTALL']:
+        return ['-Wl,-rpath=%s/lib' % bld.env.PREFIX]
+    return []
+
 
 #############################################################
 # return a named build cache dictionary, used to store
index 6cdcc35dd47c6960d2860a0a803cc4cd6828baeb..c0d428e507b430062a0e73f348e6382f8d630dcf 100644 (file)
@@ -1,7 +1,7 @@
 # a waf tool to add autoconf-like macros to the configure section
 # and for SAMBA_ macros for building libraries, binaries etc
 
-import Build, os, Options, Task, Utils, cc
+import Build, os, Options, Task, Utils, cc, TaskGen
 from Configure import conf
 from Logs import debug
 
@@ -64,7 +64,14 @@ def SAMBA_LIBRARY(bld, libname, source,
                   autoproto=None,
                   group='main',
                   depends_on='',
-                  local_include=True):
+                  local_include=True,
+                  install_path=None,
+                  install=True,
+                  enabled=True):
+
+    if not enabled:
+        SET_TARGET_TYPE(bld, libname, 'DISABLED')
+        return
 
     # remember empty libraries, so we can strip the dependencies
     if (source == '') or (source == []):
@@ -74,26 +81,84 @@ def SAMBA_LIBRARY(bld, libname, source,
     if not SET_TARGET_TYPE(bld, libname, 'LIBRARY'):
         return
 
+    obj_target = libname + '.objlist'
+
+    # first create a target for building the object files for this library
+    # by separating in this way, we avoid recompiling the C files
+    # separately for the install library and the build library
+    bld.SAMBA_SUBSYSTEM(obj_target,
+                        source         = source,
+                        deps           = deps,
+                        public_deps    = public_deps,
+                        includes       = includes,
+                        public_headers = public_headers,
+                        cflags         = cflags,
+                        group          = group,
+                        autoproto      = autoproto,
+                        depends_on     = depends_on,
+                        local_include  = local_include)
+
+    # the library itself will depend on that object target
     deps += ' ' + public_deps
+    deps = TO_LIST(deps)
+    deps.append(obj_target)
 
-    # this print below should show that we're runnig this code
     bld.SET_BUILD_GROUP(group)
     t = bld(
         features        = 'cc cshlib symlink_lib',
-        source          = source,
+        source          = [],
         target          = libname,
         samba_cflags    = CURRENT_CFLAGS(bld, libname, cflags),
         depends_on      = depends_on,
-        samba_deps      = TO_LIST(deps),
+        samba_deps      = deps,
         samba_includes  = includes,
         local_include   = local_include,
-        vnum            = vnum
+        vnum            = vnum,
+        install_path    = None
         )
+
+    if install_path is None:
+        install_path = '${PREFIX}/lib'
+
+    if install:
+        # create a separate install library, which may have
+        # different rpath settings
+        SET_TARGET_TYPE(bld, libname + '.inst', 'LIBRARY')
+        t = bld(
+            features        = 'cc cshlib',
+            source          = [],
+            target          = libname + '.inst',
+            samba_cflags    = CURRENT_CFLAGS(bld, libname, cflags),
+            depends_on      = depends_on,
+            samba_deps      = deps,
+            samba_includes  = includes,
+            local_include   = local_include,
+            vnum            = vnum,
+            install_as     = libname,
+            install_path    = None,
+            )
+        t.env['RPATH'] = install_rpath(bld)
+
+        if vnum:
+            vnum_base = vnum.split('.')[0]
+            install_name = 'lib%s.so.%s' % (libname, vnum)
+            install_link = 'lib%s.so.%s' % (libname, vnum_base)
+        else:
+            install_name = 'lib%s.so' % libname
+            install_link = None
+
+        bld.install_as(os.path.join(install_path, install_name),
+                       'lib%s.inst.so' % libname)
+        if install_link:
+            bld.symlink_as(os.path.join(install_path, install_link), install_name)
+
+
     if autoproto is not None:
         bld.SAMBA_AUTOPROTO(autoproto, source)
 
 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
 
+
 #################################################################
 # define a Samba binary
 def SAMBA_BINARY(bld, binname, source,
@@ -111,29 +176,79 @@ def SAMBA_BINARY(bld, binname, source,
                  manpages=None,
                  local_include=True,
                  subsystem_name=None,
-                 needs_python=False):
+                 needs_python=False,
+                 install=True,
+                 install_path=None):
 
     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
         return
 
-    features = 'cc cprogram copy_bin'
+    features = 'cc cprogram'
     if needs_python:
         features += ' pyembed'
 
     bld.SET_BUILD_GROUP(group)
+
+    obj_target = binname + '.objlist'
+
+    # first create a target for building the object files for this binary
+    # by separating in this way, we avoid recompiling the C files
+    # separately for the install binary and the build binary
+    bld.SAMBA_SUBSYSTEM(obj_target,
+                        source         = source,
+                        deps           = deps,
+                        includes       = includes,
+                        cflags         = cflags,
+                        group          = group,
+                        autoproto      = autoproto,
+                        subsystem_name = subsystem_name,
+                        needs_python   = needs_python,
+                        local_include  = local_include)
+
+    # the library itself will depend on that object target
+    deps = TO_LIST(deps)
+    deps.append(obj_target)
+
     bld(
-        features       = features,
-        source         = source,
+        features       = features + ' symlink_bin',
+        source         = [],
         target         = binname,
         samba_cflags   = CURRENT_CFLAGS(bld, binname, cflags),
-        samba_deps     = TO_LIST(deps),
+        samba_deps     = deps,
         samba_includes = includes,
         local_include  = local_include,
         samba_modules  = modules,
         top            = True,
-        samba_subsystem= subsystem_name
+        samba_subsystem= subsystem_name,
+        install_path   = None
         )
 
+    if install_path is None:
+        install_path = '${PREFIX}/bin'
+
+    if install:
+        # we create a separate 'install' binary, which
+        # will have different rpath settings
+        SET_TARGET_TYPE(bld, binname + '.inst', 'BINARY')
+        t = bld(
+            features       = features,
+            source         = [],
+            target         = binname + '.inst',
+            samba_cflags   = CURRENT_CFLAGS(bld, binname, cflags),
+            samba_deps     = deps,
+            samba_includes = includes,
+            local_include  = local_include,
+            samba_modules  = modules,
+            top            = True,
+            samba_subsystem= subsystem_name,
+            install_path   = None
+            )
+        t.env['RPATH'] = install_rpath(bld)
+
+        bld.install_as(os.path.join(install_path, binname),
+                       binname + '.inst',
+                       chmod=0755)
+
     # setup the subsystem_name as an alias for the real
     # binary name, so it can be found when expanding
     # subsystem dependencies
@@ -223,7 +338,6 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
                     cflags='',
                     cflags_end=None,
                     group='main',
-                    config_option=None,
                     init_function_sentinal=None,
                     heimdal_autoproto=None,
                     heimdal_autoproto_options=None,
@@ -398,22 +512,21 @@ def symlink_lib(self):
     debug('task_gen: LINK for %s is %s -> %s',
           self.name, tsk.env.LINK_SOURCE, tsk.env.LINK_TARGET)
 
-# for binaries we need to copy the executable to avoid the rpath changing
-# in the local bin/ directory on install
-t = Task.simple_task_type('copy_bin', 'rm -f ${BIN_TARGET} && cp ${SRC} ${BIN_TARGET}', color='PINK',
-                          ext_in='.bin', shell=True)
+
+t = Task.simple_task_type('symlink_bin', 'ln -sf ${SRC} ${BIN_TARGET}',
+                          color='PINK', ext_in='.bin')
 t.quiet = True
 
-@feature('copy_bin')
+@feature('symlink_bin')
 @after('apply_link')
-def copy_bin(self):
+def symlink_bin(self):
     if Options.is_install:
         # we don't want to copy the install binary, as
         # that has the install rpath, not the build rpath
         # The rpath of the binaries in bin/default/foo/blah is different
         # during the install phase, as distros insist on not using rpath in installed binaries
         return
-    tsk = self.create_task('copy_bin', self.link_task.outputs[0])
+    tsk = self.create_task('symlink_bin', self.link_task.outputs[0])
 
     tsk.env.BIN_TARGET = self.target
     debug('task_gen: BIN_TARGET for %s is %s', self.name, tsk.env.BIN_TARGET)
@@ -446,9 +559,10 @@ def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
         tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
         mkdir_p(tgtdir)
         t = bld(features='copy_script',
-                source=s,
-                target = target,
-                always=True)
+                source       = s,
+                target       = target,
+                always       = True,
+                install_path = None)
         t.env.LINK_TARGET = target
 
 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT