summaryrefslogtreecommitdiff
path: root/buildtools/wafsamba
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2011-03-03 17:18:58 +1100
committerAndrew Tridgell <tridge@samba.org>2011-03-15 12:22:19 +1100
commitf8655f4621a0dbacb712d384565c590f057adbbf (patch)
treec36c5f12aa1bcd2296609dacab28d2eb59177ad0 /buildtools/wafsamba
parentc3f04a9f3520000b6347aaa6cd4c431e81976d40 (diff)
downloadsamba-f8655f4621a0dbacb712d384565c590f057adbbf.tar.gz
samba-f8655f4621a0dbacb712d384565c590f057adbbf.tar.bz2
samba-f8655f4621a0dbacb712d384565c590f057adbbf.zip
waf: always generate public headers in the build tree
this allows us to properly test our public headers before install
Diffstat (limited to 'buildtools/wafsamba')
-rw-r--r--buildtools/wafsamba/samba_headers.py283
-rw-r--r--buildtools/wafsamba/wafsamba.py6
2 files changed, 123 insertions, 166 deletions
diff --git a/buildtools/wafsamba/samba_headers.py b/buildtools/wafsamba/samba_headers.py
index c3d1ade710..cca8bbeeed 100644
--- a/buildtools/wafsamba/samba_headers.py
+++ b/buildtools/wafsamba/samba_headers.py
@@ -1,6 +1,6 @@
# specialist handling of header files for Samba
-import Build, re, Task, TaskGen
+import Build, re, Task, TaskGen, shutil, sys
from samba_utils import *
@@ -18,149 +18,88 @@ def header_install_path(header, header_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'''
+re_header = re.compile('^\s*#\s*include[ \t]*"([^"]+)"', re.I | re.M)
+
+# a dictionary mapping source header paths to public header paths
+header_map = {}
+
+def find_suggested_header(hpath):
+ '''find a suggested header path to use'''
+ base = os.path.basename(hpath)
+ ret = []
+ for h in header_map:
+ if os.path.basename(h) == base:
+ ret.append('<%s>' % header_map[h])
+ ret.append('"%s"' % h)
+ return ret
+
+def create_public_header(task):
+ '''create a public header from a private one, output within 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
+ if os.path.exists(tgt):
os.unlink(tgt)
- os.symlink(src, tgt)
+
+ relsrc = os_path_relpath(src, task.env.TOPDIR)
+
+ infile = open(src, mode='r')
+ outfile = open(tgt, mode='w')
+ linenumber = 0
+
+ search_paths = [ '', task.env.RELPATH ]
+ for i in task.env.EXTRA_INCLUDES:
+ if i.startswith('#'):
+ search_paths.append(i[1:])
+
+ for line in infile:
+ linenumber += 1
+
+ # allow some straight substitutions
+ if task.env.public_headers_replace and line.strip() in task.env.public_headers_replace:
+ outfile.write(task.env.public_headers_replace[line.strip()] + '\n')
+ continue
+
+ # see if its an include line
+ m = re_header.match(line)
+ if m is None:
+ outfile.write(line)
+ continue
+
+ # its an include, get the header path
+ hpath = m.group(1)
+ if hpath.startswith("bin/default/"):
+ hpath = hpath[12:]
+
+ # some are always allowed
+ if task.env.public_headers_skip and hpath in task.env.public_headers_skip:
+ outfile.write(line)
+ continue
+
+ # work out the header this refers to
+ found = False
+ for s in search_paths:
+ p = os.path.normpath(os.path.join(s, hpath))
+ if p in header_map:
+ outfile.write("#include <%s>\n" % header_map[p])
+ found = True
+ break
+ if found:
+ continue
+
+ # try to be nice to the developer by suggesting an alternative
+ suggested = find_suggested_header(hpath)
+ outfile.close()
+ os.unlink(tgt)
+ sys.stderr.write("%s:%u:Error: unable to resolve public header %s (maybe try one of %s)\n" % (
+ os.path.relpath(src, os.getcwd()), linenumber, hpath, suggested))
+ raise Utils.WafError("Unable to resolve header path '%s' in public header '%s' in directory %s" % (
+ hpath, relsrc, task.env.RELPATH))
+ infile.close()
+ outfile.close()
-def PUBLIC_HEADERS(bld, public_headers, header_path=None):
+def PUBLIC_HEADERS(bld, public_headers, header_path=None, public_headers_install=True):
'''install some headers
header_path may either be a string that is added to the INCLUDEDIR,
@@ -168,33 +107,47 @@ def PUBLIC_HEADERS(bld, public_headers, header_path=None):
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,
+ if not bld.env.build_public_headers:
+ bld.env.build_public_headers = ''
+
+ # create the public header in the given path
+ # in the build tree
+ 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)
+
+ # the source path of the header, relative to the top of the source tree
+ src_path = os.path.normpath(os.path.join(relpath2, h_name))
+
+ # the install path of the header, relative to the public include directory
+ target_path = os.path.normpath(os.path.join(inst_path, inst_name))
+
+ header_map[src_path] = target_path
+
+ t = bld.SAMBA_GENERATOR('HEADER_%s/%s/%s' % (relpath2, inst_path, inst_name),
+ group='prototypes',
+ rule=create_public_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
+ t.env.RELPATH = relpath2
+ t.env.TOPDIR = bld.srcnode.abspath()
+ 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))
+ if public_headers_install:
+ bld.INSTALL_FILES('${INCLUDEDIR}',
+ target,
+ destname=os.path.join(inst_path, inst_name), flat=True)
Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index 181bbae333..bf0c1b4548 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -98,6 +98,7 @@ def SAMBA_LIBRARY(bld, libname, source,
public_deps='',
includes='',
public_headers=None,
+ public_headers_install=True,
header_path=None,
pc_files=None,
vnum=None,
@@ -162,6 +163,7 @@ def SAMBA_LIBRARY(bld, libname, source,
public_deps = public_deps,
includes = includes,
public_headers = public_headers,
+ public_headers_install = public_headers_install,
header_path = header_path,
cflags = cflags,
group = subsystem_group,
@@ -459,6 +461,7 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
public_deps='',
includes='',
public_headers=None,
+ public_headers_install=True,
header_path=None,
cflags='',
cflags_end=None,
@@ -527,7 +530,8 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
if autoproto is not None:
bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
if public_headers is not None:
- bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
+ bld.PUBLIC_HEADERS(public_headers, header_path=header_path,
+ public_headers_install=public_headers_install)
return t