waf: moved header file handling into its own module
authorAndrew Tridgell <tridge@samba.org>
Thu, 3 Mar 2011 02:23:13 +0000 (13:23 +1100)
committerAndrew Tridgell <tridge@samba.org>
Tue, 15 Mar 2011 01:22:19 +0000 (12:22 +1100)
It is getting quite complex now, and shouldn't just be mixed in with
everything else

buildtools/wafsamba/samba_headers.py [new file with mode: 0644]
buildtools/wafsamba/wafsamba.py

diff --git a/buildtools/wafsamba/samba_headers.py b/buildtools/wafsamba/samba_headers.py
new file mode 100644 (file)
index 0000000..c3d1ade
--- /dev/null
@@ -0,0 +1,200 @@
+# specialist handling of header files for Samba
+
+import Build, re, Task, TaskGen
+from samba_utils import *
+
+
+def header_install_path(header, header_path):
+    '''find the installation path for a header, given a header_path option'''
+    if not header_path:
+        return ''
+    if not isinstance(header_path, list):
+        return header_path
+    for (p1, dir) in header_path:
+        for p2 in TO_LIST(p1):
+            if fnmatch.fnmatch(header, p2):
+                return dir
+    # default to current path
+    return ''
+
+
+re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
+class header_task(Task.Task):
+    """
+    The public headers (the one installed on the system) have both
+    different paths and contents, so the rename is not enough.
+
+    Intermediate .inst.h files are created because path manipulation
+    may be slow. The substitution is thus performed only once.
+    """
+
+    name = 'header'
+    color = 'PINK'
+    vars = ['INCLUDEDIR', 'HEADER_DEPS']
+
+    def run(self):
+        txt = self.inputs[0].read(self.env)
+
+        # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
+        txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
+
+        # use a regexp to substitute the #include lines in the files
+        map = self.generator.bld.hnodemap
+        dirnodes = self.generator.bld.hnodedirs
+        def repl(m):
+            if m.group(1):
+                s = m.group(1)
+
+                # pokemon headers: gotta catch'em all!
+                fin = s
+                if s.startswith('bin/default'):
+                    node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
+                    if not node:
+                        Logs.warn('could not find the public header for %r' % s)
+                    elif node.id in map:
+                        fin = map[node.id]
+                    else:
+                        Logs.warn('could not find the public header replacement for build header %r' % s)
+                else:
+                    # this part is more difficult since the path may be relative to anything
+                    for dirnode in dirnodes:
+                        node = dirnode.find_resource(s)
+                        if node:
+                             if node.id in map:
+                                 fin = map[node.id]
+                                 break
+                             else:
+                                 Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
+                    else:
+                        Logs.warn('-> could not find the public header for %r' % s)
+
+                return "#include <%s>" % fin
+            return ''
+
+        txt = re_header.sub(repl, txt)
+
+        # and write the output file
+        f = None
+        try:
+            f = open(self.outputs[0].abspath(self.env), 'w')
+            f.write(txt)
+        finally:
+            if f:
+                f.close()
+
+@TaskGen.feature('pubh')
+def make_public_headers(self):
+    """
+    collect the public headers to process and to install, then
+    create the substitutions (name and contents)
+    """
+
+    if not self.bld.is_install:
+        # install time only (lazy)
+        return
+
+    # keep two variables
+    #    hnodedirs: list of folders for searching the headers
+    #    hnodemap: node ids and replacement string (node objects are unique)
+    try:
+        self.bld.hnodedirs.append(self.path)
+    except AttributeError:
+        self.bld.hnodemap = {}
+        self.bld.hnodedirs = [self.bld.srcnode, self.path]
+
+        for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
+            node = self.bld.srcnode.find_dir(k)
+            if node:
+                self.bld.hnodedirs.append(node)
+
+    header_path = getattr(self, 'header_path', None) or ''
+
+    for x in self.to_list(self.headers):
+
+        inst_path = header_install_path(x, header_path)
+
+        dest = ''
+        name = x
+        if x.find(':') != -1:
+            s = x.split(':')
+            name = s[0]
+            dest = s[1]
+
+        inn = self.path.find_resource(name)
+
+        if not inn:
+            raise ValueError("could not find the public header %r in %r" % (name, self.path))
+        out = inn.change_ext('.inst.h')
+        self.create_task('header', inn, out)
+
+        if not dest:
+            dest = inn.name
+
+        if inst_path:
+            inst_path = inst_path + '/'
+        inst_path = inst_path + dest
+
+        self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
+
+        self.bld.hnodemap[inn.id] = inst_path
+
+    # create a hash (not md5) to make sure the headers are re-created if something changes
+    val = 0
+    lst = list(self.bld.hnodemap.keys())
+    lst.sort()
+    for k in lst:
+        val = hash((val, k, self.bld.hnodemap[k]))
+    self.bld.env.HEADER_DEPS = val
+
+
+
+def symlink_header(task):
+    '''symlink a header in the build tree'''
+    src = task.inputs[0].abspath(task.env)
+    tgt = task.outputs[0].bldpath(task.env)
+
+    if os.path.lexists(tgt):
+        if os.path.islink(tgt) and os.readlink(tgt) == src:
+            return
+        os.unlink(tgt)
+    os.symlink(src, tgt)
+
+
+def PUBLIC_HEADERS(bld, public_headers, header_path=None):
+    '''install some headers
+
+    header_path may either be a string that is added to the INCLUDEDIR,
+    or it can be a dictionary of wildcard patterns which map to destination
+    directories relative to INCLUDEDIR
+    '''
+    bld.SET_BUILD_GROUP('final')
+    ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
+
+    if bld.env.build_public_headers:
+        # when build_public_headers is set, symlink the headers into the include/public
+        # directory
+        for h in TO_LIST(public_headers):
+            inst_path = header_install_path(h, header_path)
+            if h.find(':') != -1:
+                s = h.split(":")
+                h_name =  s[0]
+                inst_name = s[1]
+            else:
+                h_name =  h
+                inst_name = os.path.basename(h)
+            relpath1 = os_path_relpath(bld.srcnode.abspath(), bld.curdir)
+            relpath2 = os_path_relpath(bld.curdir, bld.srcnode.abspath())
+            targetdir = os.path.normpath(os.path.join(relpath1, bld.env.build_public_headers, inst_path))
+            if not os.path.exists(os.path.join(bld.curdir, targetdir)):
+                raise Utils.WafError("missing source directory %s for public header %s" % (targetdir, inst_name))
+            target = os.path.join(targetdir, inst_name)
+            bld.SAMBA_GENERATOR('HEADER_%s/%s' % (relpath2, inst_name),
+                                rule=symlink_header,
+                                source=h_name,
+                                target=target)
+            if not bld.env.public_headers_list:
+                bld.env.public_headers_list = []
+            bld.env.public_headers_list.append(os.path.join(inst_path, inst_name))
+
+    return ret
+Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
index 1ad816e0b523df124c0e66bed345fec767a106e0..91cd2839db17a51aaf84c649eecdb04aa44537da 100644 (file)
@@ -21,6 +21,7 @@ from samba_bundled import *
 import samba_install
 import samba_conftests
 import samba_abi
+import samba_headers
 import tru64cc
 import irixcc
 import hpuxcc
@@ -737,202 +738,6 @@ def INSTALL_DIRS(bld, destdir, dirs):
 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
 
 
-def header_install_path(header, header_path):
-    '''find the installation path for a header, given a header_path option'''
-    if not header_path:
-        return ''
-    if not isinstance(header_path, list):
-        return header_path
-    for (p1, dir) in header_path:
-        for p2 in TO_LIST(p1):
-            if fnmatch.fnmatch(header, p2):
-                return dir
-    # default to current path
-    return ''
-
-
-re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
-class header_task(Task.Task):
-    """
-    The public headers (the one installed on the system) have both
-    different paths and contents, so the rename is not enough.
-
-    Intermediate .inst.h files are created because path manipulation
-    may be slow. The substitution is thus performed only once.
-    """
-
-    name = 'header'
-    color = 'PINK'
-    vars = ['INCLUDEDIR', 'HEADER_DEPS']
-
-    def run(self):
-        txt = self.inputs[0].read(self.env)
-
-        # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
-        txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
-
-        # use a regexp to substitute the #include lines in the files
-        map = self.generator.bld.hnodemap
-        dirnodes = self.generator.bld.hnodedirs
-        def repl(m):
-            if m.group(1):
-                s = m.group(1)
-
-                # pokemon headers: gotta catch'em all!
-                fin = s
-                if s.startswith('bin/default'):
-                    node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
-                    if not node:
-                        Logs.warn('could not find the public header for %r' % s)
-                    elif node.id in map:
-                        fin = map[node.id]
-                    else:
-                        Logs.warn('could not find the public header replacement for build header %r' % s)
-                else:
-                    # this part is more difficult since the path may be relative to anything
-                    for dirnode in dirnodes:
-                        node = dirnode.find_resource(s)
-                        if node:
-                             if node.id in map:
-                                 fin = map[node.id]
-                                 break
-                             else:
-                                 Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
-                    else:
-                        Logs.warn('-> could not find the public header for %r' % s)
-
-                return "#include <%s>" % fin
-            return ''
-
-        txt = re_header.sub(repl, txt)
-
-        # and write the output file
-        f = None
-        try:
-            f = open(self.outputs[0].abspath(self.env), 'w')
-            f.write(txt)
-        finally:
-            if f:
-                f.close()
-
-@TaskGen.feature('pubh')
-def make_public_headers(self):
-    """
-    collect the public headers to process and to install, then
-    create the substitutions (name and contents)
-    """
-
-    if not self.bld.is_install:
-        # install time only (lazy)
-        return
-
-    # keep two variables
-    #    hnodedirs: list of folders for searching the headers
-    #    hnodemap: node ids and replacement string (node objects are unique)
-    try:
-        self.bld.hnodedirs.append(self.path)
-    except AttributeError:
-        self.bld.hnodemap = {}
-        self.bld.hnodedirs = [self.bld.srcnode, self.path]
-
-        for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
-            node = self.bld.srcnode.find_dir(k)
-            if node:
-                self.bld.hnodedirs.append(node)
-
-    header_path = getattr(self, 'header_path', None) or ''
-
-    for x in self.to_list(self.headers):
-
-        inst_path = header_install_path(x, header_path)
-
-        dest = ''
-        name = x
-        if x.find(':') != -1:
-            s = x.split(':')
-            name = s[0]
-            dest = s[1]
-
-        inn = self.path.find_resource(name)
-
-        if not inn:
-            raise ValueError("could not find the public header %r in %r" % (name, self.path))
-        out = inn.change_ext('.inst.h')
-        self.create_task('header', inn, out)
-
-        if not dest:
-            dest = inn.name
-
-        if inst_path:
-            inst_path = inst_path + '/'
-        inst_path = inst_path + dest
-
-        self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
-
-        self.bld.hnodemap[inn.id] = inst_path
-
-    # create a hash (not md5) to make sure the headers are re-created if something changes
-    val = 0
-    lst = list(self.bld.hnodemap.keys())
-    lst.sort()
-    for k in lst:
-        val = hash((val, k, self.bld.hnodemap[k]))
-    self.bld.env.HEADER_DEPS = val
-
-
-
-def symlink_header(task):
-    '''symlink a header in the build tree'''
-    src = task.inputs[0].abspath(task.env)
-    tgt = task.outputs[0].bldpath(task.env)
-
-    if os.path.lexists(tgt):
-        if os.path.islink(tgt) and os.readlink(tgt) == src:
-            return
-        os.unlink(tgt)
-    os.symlink(src, tgt)
-
-
-def PUBLIC_HEADERS(bld, public_headers, header_path=None):
-    '''install some headers
-
-    header_path may either be a string that is added to the INCLUDEDIR,
-    or it can be a dictionary of wildcard patterns which map to destination
-    directories relative to INCLUDEDIR
-    '''
-    bld.SET_BUILD_GROUP('final')
-    ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
-
-    if bld.env.build_public_headers:
-        # when build_public_headers is set, symlink the headers into the include/public
-        # directory
-        for h in TO_LIST(public_headers):
-            inst_path = header_install_path(h, header_path)
-            if h.find(':') != -1:
-                s = h.split(":")
-                h_name =  s[0]
-                inst_name = s[1]
-            else:
-                h_name =  h
-                inst_name = os.path.basename(h)
-            relpath1 = os_path_relpath(bld.srcnode.abspath(), bld.curdir)
-            relpath2 = os_path_relpath(bld.curdir, bld.srcnode.abspath())
-            targetdir = os.path.normpath(os.path.join(relpath1, bld.env.build_public_headers, inst_path))
-            if not os.path.exists(os.path.join(bld.curdir, targetdir)):
-                raise Utils.WafError("missing source directory %s for public header %s" % (targetdir, inst_name))
-            target = os.path.join(targetdir, inst_name)
-            bld.SAMBA_GENERATOR('HEADER_%s/%s' % (relpath2, inst_name),
-                                rule=symlink_header,
-                                source=h_name,
-                                target=target)
-            if not bld.env.public_headers_list:
-                bld.env.public_headers_list = []
-            bld.env.public_headers_list.append(os.path.join(inst_path, inst_name))
-
-    return ret
-Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
-
-
 def MANPAGES(bld, manpages):
     '''build and install manual pages'''
     bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'