1 # specialist handling of header files for Samba
3 import os
, re
, sys
, fnmatch
4 from waflib
import Build
, Logs
, Utils
, Errors
5 from samba_utils
import TO_LIST
8 def header_install_path(header
, header_path
):
9 '''find the installation path for a header, given a header_path option'''
12 if not isinstance(header_path
, list):
14 for (p1
, dir) in header_path
:
15 for p2
in TO_LIST(p1
):
16 if fnmatch
.fnmatch(header
, p2
):
18 # default to current path
22 re_header
= re
.compile(r
'^\s*#\s*include[ \t]*"([^"]+)"', re
.I | re
.M
)
24 # a dictionary mapping source header paths to public header paths
27 def find_suggested_header(hpath
):
28 '''find a suggested header path to use'''
29 base
= os
.path
.basename(hpath
)
32 if os
.path
.basename(h
) == base
:
33 ret
.append('<%s>' % header_map
[h
])
34 ret
.append('"%s"' % h
)
37 def create_public_header(task
):
38 '''create a public header from a private one, output within the build tree'''
39 src
= task
.inputs
[0].abspath(task
.env
)
40 tgt
= task
.outputs
[0].bldpath(task
.env
)
42 if os
.path
.exists(tgt
):
45 relsrc
= os
.path
.relpath(src
, task
.env
.TOPDIR
)
47 infile
= open(src
, mode
='r')
48 outfile
= open(tgt
, mode
='w')
51 search_paths
= [ '', task
.env
.RELPATH
]
52 for i
in task
.env
.EXTRA_INCLUDES
:
54 search_paths
.append(i
[1:])
59 # allow some straight substitutions
60 if task
.env
.public_headers_replace
and line
.strip() in task
.env
.public_headers_replace
:
61 outfile
.write(task
.env
.public_headers_replace
[line
.strip()] + '\n')
64 # see if its an include line
65 m
= re_header
.match(line
)
70 # its an include, get the header path
72 if hpath
.startswith("bin/default/"):
75 # some are always allowed
76 if task
.env
.public_headers_skip
and hpath
in task
.env
.public_headers_skip
:
80 # work out the header this refers to
82 for s
in search_paths
:
83 p
= os
.path
.normpath(os
.path
.join(s
, hpath
))
85 outfile
.write("#include <%s>\n" % header_map
[p
])
91 if task
.env
.public_headers_allow_broken
:
92 Logs
.warn("Broken public header include '%s' in '%s'" % (hpath
, relsrc
))
96 # try to be nice to the developer by suggesting an alternative
97 suggested
= find_suggested_header(hpath
)
100 sys
.stderr
.write("%s:%u:Error: unable to resolve public header %s (maybe try one of %s)\n" % (
101 os
.path
.relpath(src
, os
.getcwd()), linenumber
, hpath
, suggested
))
102 raise Errors
.WafError("Unable to resolve header path '%s' in public header '%s' in directory %s" % (
103 hpath
, relsrc
, task
.env
.RELPATH
))
108 def public_headers_simple(bld
, public_headers
, header_path
=None, public_headers_install
=True):
109 '''install some headers - simple version, no munging needed
111 if not public_headers_install
:
113 for h
in TO_LIST(public_headers
):
114 inst_path
= header_install_path(h
, header_path
)
115 if h
.find(':') != -1:
121 inst_name
= os
.path
.basename(h
)
122 bld
.INSTALL_FILES('${INCLUDEDIR}', h_name
, destname
=inst_name
)
125 def PUBLIC_HEADERS(bld
, public_headers
, header_path
=None, public_headers_install
=True):
126 '''install some headers
128 header_path may either be a string that is added to the INCLUDEDIR,
129 or it can be a dictionary of wildcard patterns which map to destination
130 directories relative to INCLUDEDIR
132 bld
.SET_BUILD_GROUP('final')
134 if not bld
.env
.build_public_headers
:
135 # in this case no header munging needed. Used for tdb, talloc etc
136 public_headers_simple(bld
, public_headers
, header_path
=header_path
,
137 public_headers_install
=public_headers_install
)
140 # create the public header in the given path
142 for h
in TO_LIST(public_headers
):
143 inst_path
= header_install_path(h
, header_path
)
144 if h
.find(':') != -1:
150 inst_name
= os
.path
.basename(h
)
151 curdir
= bld
.path
.abspath()
152 relpath1
= os
.path
.relpath(bld
.srcnode
.abspath(), curdir
)
153 relpath2
= os
.path
.relpath(curdir
, bld
.srcnode
.abspath())
154 targetdir
= os
.path
.normpath(os
.path
.join(relpath1
, bld
.env
.build_public_headers
, inst_path
))
155 if not os
.path
.exists(os
.path
.join(curdir
, targetdir
)):
156 raise Errors
.WafError("missing source directory %s for public header %s" % (targetdir
, inst_name
))
157 target
= os
.path
.join(targetdir
, inst_name
)
159 # the source path of the header, relative to the top of the source tree
160 src_path
= os
.path
.normpath(os
.path
.join(relpath2
, h_name
))
162 # the install path of the header, relative to the public include directory
163 target_path
= os
.path
.normpath(os
.path
.join(inst_path
, inst_name
))
165 header_map
[src_path
] = target_path
167 t
= bld
.SAMBA_GENERATOR('HEADER_%s/%s/%s' % (relpath2
, inst_path
, inst_name
),
169 rule
=create_public_header
,
172 t
.env
.RELPATH
= relpath2
173 t
.env
.TOPDIR
= bld
.srcnode
.abspath()
174 if not bld
.env
.public_headers_list
:
175 bld
.env
.public_headers_list
= []
176 bld
.env
.public_headers_list
.append(os
.path
.join(inst_path
, inst_name
))
177 if public_headers_install
:
178 bld
.INSTALL_FILES('${INCLUDEDIR}',
180 destname
=os
.path
.join(inst_path
, inst_name
), flat
=True)
181 Build
.BuildContext
.PUBLIC_HEADERS
= PUBLIC_HEADERS