1 # specialist handling of header files for Samba
3 import Build
, re
, Task
, TaskGen
, shutil
, sys
, Logs
4 from samba_utils
import *
7 def header_install_path(header
, header_path
):
8 '''find the installation path for a header, given a header_path option'''
11 if not isinstance(header_path
, list):
13 for (p1
, dir) in header_path
:
14 for p2
in TO_LIST(p1
):
15 if fnmatch
.fnmatch(header
, p2
):
17 # default to current path
21 re_header
= re
.compile('^\s*#\s*include[ \t]*"([^"]+)"', re
.I | re
.M
)
23 # a dictionary mapping source header paths to public header paths
26 def find_suggested_header(hpath
):
27 '''find a suggested header path to use'''
28 base
= os
.path
.basename(hpath
)
31 if os
.path
.basename(h
) == base
:
32 ret
.append('<%s>' % header_map
[h
])
33 ret
.append('"%s"' % h
)
36 def create_public_header(task
):
37 '''create a public header from a private one, output within the build tree'''
38 src
= task
.inputs
[0].abspath(task
.env
)
39 tgt
= task
.outputs
[0].bldpath(task
.env
)
41 if os
.path
.exists(tgt
):
44 relsrc
= os_path_relpath(src
, task
.env
.TOPDIR
)
46 infile
= open(src
, mode
='r')
47 outfile
= open(tgt
, mode
='w')
50 search_paths
= [ '', task
.env
.RELPATH
]
51 for i
in task
.env
.EXTRA_INCLUDES
:
53 search_paths
.append(i
[1:])
58 # allow some straight substitutions
59 if task
.env
.public_headers_replace
and line
.strip() in task
.env
.public_headers_replace
:
60 outfile
.write(task
.env
.public_headers_replace
[line
.strip()] + '\n')
63 # see if its an include line
64 m
= re_header
.match(line
)
69 # its an include, get the header path
71 if hpath
.startswith("bin/default/"):
74 # some are always allowed
75 if task
.env
.public_headers_skip
and hpath
in task
.env
.public_headers_skip
:
79 # work out the header this refers to
81 for s
in search_paths
:
82 p
= os
.path
.normpath(os
.path
.join(s
, hpath
))
84 outfile
.write("#include <%s>\n" % header_map
[p
])
90 if task
.env
.public_headers_allow_broken
:
91 Logs
.warn("Broken public header include '%s' in '%s'" % (hpath
, relsrc
))
95 # try to be nice to the developer by suggesting an alternative
96 suggested
= find_suggested_header(hpath
)
99 sys
.stderr
.write("%s:%u:Error: unable to resolve public header %s (maybe try one of %s)\n" % (
100 os
.path
.relpath(src
, os
.getcwd()), linenumber
, hpath
, suggested
))
101 raise Utils
.WafError("Unable to resolve header path '%s' in public header '%s' in directory %s" % (
102 hpath
, relsrc
, task
.env
.RELPATH
))
107 def public_headers_simple(bld
, public_headers
, header_path
=None, public_headers_install
=True):
108 '''install some headers - simple version, no munging needed
110 if not public_headers_install
:
112 for h
in TO_LIST(public_headers
):
113 inst_path
= header_install_path(h
, header_path
)
114 if h
.find(':') != -1:
120 inst_name
= os
.path
.basename(h
)
121 bld
.INSTALL_FILES('${INCLUDEDIR}', h_name
, destname
=inst_name
)
124 def PUBLIC_HEADERS(bld
, public_headers
, header_path
=None, public_headers_install
=True):
125 '''install some headers
127 header_path may either be a string that is added to the INCLUDEDIR,
128 or it can be a dictionary of wildcard patterns which map to destination
129 directories relative to INCLUDEDIR
131 bld
.SET_BUILD_GROUP('final')
133 if not bld
.env
.build_public_headers
:
134 # in this case no header munging neeeded. Used for tdb, talloc etc
135 public_headers_simple(bld
, public_headers
, header_path
=header_path
,
136 public_headers_install
=public_headers_install
)
139 # create the public header in the given path
141 for h
in TO_LIST(public_headers
):
142 inst_path
= header_install_path(h
, header_path
)
143 if h
.find(':') != -1:
149 inst_name
= os
.path
.basename(h
)
150 relpath1
= os_path_relpath(bld
.srcnode
.abspath(), bld
.curdir
)
151 relpath2
= os_path_relpath(bld
.curdir
, bld
.srcnode
.abspath())
152 targetdir
= os
.path
.normpath(os
.path
.join(relpath1
, bld
.env
.build_public_headers
, inst_path
))
153 if not os
.path
.exists(os
.path
.join(bld
.curdir
, targetdir
)):
154 raise Utils
.WafError("missing source directory %s for public header %s" % (targetdir
, inst_name
))
155 target
= os
.path
.join(targetdir
, inst_name
)
157 # the source path of the header, relative to the top of the source tree
158 src_path
= os
.path
.normpath(os
.path
.join(relpath2
, h_name
))
160 # the install path of the header, relative to the public include directory
161 target_path
= os
.path
.normpath(os
.path
.join(inst_path
, inst_name
))
163 header_map
[src_path
] = target_path
165 t
= bld
.SAMBA_GENERATOR('HEADER_%s/%s/%s' % (relpath2
, inst_path
, inst_name
),
167 rule
=create_public_header
,
170 t
.env
.RELPATH
= relpath2
171 t
.env
.TOPDIR
= bld
.srcnode
.abspath()
172 if not bld
.env
.public_headers_list
:
173 bld
.env
.public_headers_list
= []
174 bld
.env
.public_headers_list
.append(os
.path
.join(inst_path
, inst_name
))
175 if public_headers_install
:
176 bld
.INSTALL_FILES('${INCLUDEDIR}',
178 destname
=os
.path
.join(inst_path
, inst_name
), flat
=True)
179 Build
.BuildContext
.PUBLIC_HEADERS
= PUBLIC_HEADERS