build: separate out dependencies and python rules
[Samba/gebeck_regimport.git] / buildtools / wafsamba / samba_deps.py
blob41b786d6bfe2228046fd9f925559dada03490168
1 # Samba automatic dependency handling
3 from TaskGen import taskgen, before
4 import Build, os, string, Utils, re
5 from samba_utils import *
6 from samba_autoconf import *
8 @conf
9 def ADD_GLOBAL_DEPENDENCY(ctx, dep):
10 '''add a dependency for all binaries and libraries'''
11 if not 'GLOBAL_DEPENDENCIES' in ctx.env:
12 ctx.env.GLOBAL_DEPENDENCIES = []
13 ctx.env.GLOBAL_DEPENDENCIES.append(dep)
16 def TARGET_ALIAS(bld, target, alias):
17 '''define an alias for a target name'''
18 cache = LOCAL_CACHE(bld, 'TARGET_ALIAS')
19 bld.ASSERT(alias not in cache, "Target alias %s already set" % alias)
20 cache[alias] = target
21 Build.BuildContext.TARGET_ALIAS = TARGET_ALIAS
24 def EXPAND_ALIAS(bld, target):
25 '''expand a target name via an alias'''
26 aliases = LOCAL_CACHE(bld, 'TARGET_ALIAS')
27 if target in aliases:
28 return aliases[target]
29 return target
30 Build.BuildContext.EXPAND_ALIAS = EXPAND_ALIAS
33 def expand_dependencies(bld, dep, chain, path):
34 '''expand a dependency recursively
35 return a triple of (uselib, uselib_local, add_objects)
36 '''
38 dep = EXPAND_ALIAS(bld, dep)
40 t = bld.name_to_obj(dep, bld.env)
42 # check for a cached list
43 if t is not None:
44 expanded = getattr(t, 'expanded_dependencies', None)
45 if expanded is not None:
46 return expanded
48 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
50 uselib_local = []
51 uselib = []
52 add_objects = []
54 recurse = False
56 bld.ASSERT(dep in target_dict, "Dependency %s not found in %s" % (dep, path))
57 type = target_dict[dep]
58 if type == 'SYSLIB':
59 uselib.append(dep)
60 elif type == 'LIBRARY':
61 uselib_local.append(dep)
62 recurse = True
63 elif type == 'SUBSYSTEM':
64 add_objects.append(dep)
65 recurse = True
66 elif type == 'MODULE':
67 add_objects.append(dep)
68 recurse = True
69 elif type == 'PYTHON':
70 add_objects.append(dep)
71 recurse = True
72 elif type == 'ASN1':
73 add_objects.append(dep)
74 recurse = True
75 elif type == 'BINARY':
76 pass
77 elif type == 'EMPTY':
78 pass
79 elif type == 'DISABLED':
80 debug('deps: Ignoring dependency on disabled target %s: %s' % (dep, path))
81 else:
82 bld.ASSERT(False, "Unknown target type %s for %s" % (type, dep))
84 # for some types we have to build the list recursively
85 if recurse:
86 bld.ASSERT(t is not None, "Unable to find target %s" % dep)
87 rec_deps = getattr(t, 'samba_deps', None)
88 bld.ASSERT(rec_deps is not None, "Unable to find dependencies of target %s" % dep)
89 for d2 in rec_deps:
90 try:
91 bld.ASSERT(d2 not in chain, "Circular dependency for %s: %s->%s" % (dep, path, d2))
92 except:
93 print "Removing dependency %s from target %s" % (d2, dep)
94 rec_deps.remove(d2)
95 continue
96 c2 = chain.copy()
97 c2[d2] = True
98 (rec_uselib, rec_uselib_local,
99 rec_add_objects) = expand_dependencies(bld, d2, c2, "%s->%s" % (path, d2))
100 uselib.extend(rec_uselib)
101 uselib_local.extend(rec_uselib_local)
102 add_objects.extend(rec_add_objects)
104 if t is not None:
105 t.expanded_dependencies = (uselib, uselib_local, add_objects)
107 return (uselib, uselib_local, add_objects)
110 def expand_deplist(self):
111 '''return an expanded list of dependencies from the samba_deps attribute'''
113 if not getattr(self, 'samba_deps', None):
114 return ([], [], [])
116 bld = self.bld
117 deps = self.samba_deps
119 uselib_local = []
120 uselib = []
121 add_objects = []
123 for d in deps:
124 (u, ul, ao) = expand_dependencies(bld, d, { self.name:True }, self.name)
125 uselib.extend(u)
126 uselib_local.extend(ul)
127 add_objects.extend(ao)
129 return (uselib, uselib_local, add_objects)
133 @feature('cc', 'cshlib', 'cprogram')
134 @before('apply_lib_vars', 'apply_verif', 'apply_objdeps', 'apply_obj_vars', 'apply_incpaths', 'build_includes')
135 @after('default_cc')
136 def build_dependencies(self):
137 '''This builds the dependency list for a target. It runs after all the targets are declared
139 The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
140 the full dependency list for a target until we have all of the targets declared. So what we do is
141 add a samba_deps attribute on the task generator when we declare it, then
142 this rule runs after all the task generators are declared and maps the samba_deps attribute
143 to a set of uselib, uselib_local and add_objects dependencies
146 if getattr(self, 'build_dependencies_done', False):
147 return
148 self.build_dependencies_done = True
150 if getattr(self, 'samba_deps', None) is None:
151 return
153 target_dict = LOCAL_CACHE(self.bld, 'TARGET_TYPE')
155 # we only should add extra library and object deps on libraries and binaries
156 type = target_dict[self.name]
157 if type != 'LIBRARY' and type != 'BINARY':
158 return
160 (uselib, uselib_local, add_objects) = expand_deplist(self)
162 if 'GLOBAL_DEPENDENCIES' in self.bld.env:
163 add_objects.extend(self.bld.env.GLOBAL_DEPENDENCIES)
165 self.uselib = unique_list(uselib)
166 self.uselib_local = unique_list(uselib_local)
167 self.add_objects = unique_list(add_objects)
169 debug('deps: dependency counts for %s: uselib=%u uselib_local=%u add_objects=%u' % (
170 self.name, len(uselib), len(uselib_local), len(add_objects)))
174 @feature('cc', 'cshlib', 'cprogram')
175 @before('apply_lib_vars', 'apply_verif', 'apply_objdeps', 'apply_obj_vars', 'apply_incpaths', 'add_init_functions')
176 @after('build_dependencies')
177 def build_includes(self):
178 '''This builds the right set of includes for a target.
180 This is closely related to building the set of dependencies, and
181 calls into the same expand_dependencies() function to do the work.
183 One tricky part of this is that the includes= attribute for a
184 target needs to use paths which are relative to that targets
185 declaration directory (which we can get at via t.path).
187 The way this works is the includes list gets added as
188 samba_includes in the main build task declaration. Then this
189 function runs after all of the tasks are declared, and it
190 processes the samba_includes attribute to produce a includes=
191 attribute
194 if not getattr(self, 'build_dependencies_done', False):
195 build_dependencies(self)
196 if getattr(self, 'build_includes_done', False):
197 return
198 self.build_includes_done = True
200 if getattr(self, 'samba_includes', None) is None:
201 return
203 bld = self.bld
205 (uselib, uselib_local, add_objects) = expand_deplist(self)
207 # get the list of all dependencies
208 all_deps = []
209 # all_deps.extend(uselib)
210 all_deps.extend(uselib_local)
211 all_deps.extend(add_objects)
212 all_deps = unique_list(all_deps)
214 includes = []
216 # build a list of includes
217 if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
218 includes.append('.')
220 includes.extend(TO_LIST(self.samba_includes))
222 if 'EXTRA_INCLUDES' in bld.env:
223 includes.extend(bld.env['EXTRA_INCLUDES'])
225 includes.append('#')
227 mypath = self.path.abspath(bld.env)
229 for d in all_deps:
230 t = bld.name_to_obj(d, bld.env)
231 bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.name))
232 t.samba_used = True
233 samba_includes = getattr(t, 'samba_includes', None)
234 inclist = TO_LIST(samba_includes)
235 if getattr(t, 'local_include', True) == True:
236 inclist.append('.')
237 if inclist == []:
238 continue
239 tpath = t.path.abspath(bld.env)
240 relpath = os.path.relpath(tpath, mypath)
241 for inc in inclist:
242 includes.append(os.path.normpath(os.path.join(relpath, inc)))
244 if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
245 includes.append('.')
247 self.includes = unique_list(includes)
248 debug('deps: Target %s has includes=%s all_deps=%s' % (self.name, self.includes, all_deps))
251 @feature('cc', 'cshlib', 'cprogram')
252 @before('apply_lib_vars', 'apply_verif', 'apply_objdeps', 'apply_obj_vars', 'apply_incpaths')
253 @after('build_includes')
254 def add_init_functions(self):
255 '''This builds the right set of init functions'''
257 if not getattr(self, 'build_includes_done', False):
258 build_includes(self)
259 if getattr(self, 'add_init_functions_done', False):
260 return
261 self.add_init_functions_done = True
263 bld = self.bld
265 subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
267 modules = []
268 if self.name in subsystems:
269 modules.append(self.name)
271 m = getattr(self, 'samba_modules', None)
272 if m is not None:
273 modules.extend(TO_LIST(m))
275 m = getattr(self, 'samba_subsystem', None)
276 if m is not None:
277 modules.append(m)
279 if modules == []:
280 return
282 cflags = getattr(self, 'ccflags', [])
283 for m in modules:
284 if not m in subsystems:
285 print "subsystems: %s" % subsystems
286 bld.ASSERT(m in subsystems,
287 "No init_function defined for module '%s' in target '%s'" % (m, self.name))
288 cflags.append('-DSTATIC_%s_MODULES="%s"' % (m, ','.join(subsystems[m])))
289 self.ccflags = cflags
292 def check_orpaned_targets(bld):
293 '''check if any build targets are orphaned'''
295 target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
297 # make sure all the earlier functions have run
298 for t in bld.all_task_gen:
299 if not t.name in target_dict:
300 continue
301 if not getattr(t, 'add_init_functions_done', False):
302 add_init_functions(t)
304 for t in bld.all_task_gen:
305 if not t.name in target_dict:
306 continue
307 if getattr(t, 'samba_used', False) == True:
308 continue
309 type = target_dict[t.name]
310 if type != 'BINARY' and type != 'LIBRARY' and type != 'MODULE':
311 if re.search('^PIDL_', t.name) is None:
312 print "Target %s of type %s is unused by any other target" % (t.name, type)
315 def CHECK_ORPANED_TARGETS(bld):
316 bld.add_pre_fun(check_orpaned_targets)
317 Build.BuildContext.CHECK_ORPANED_TARGETS = CHECK_ORPANED_TARGETS
320 @feature('dfkj*')
321 def samba_post_process(self):
322 '''samba specific post processing of task'''
323 if getattr(self, 'meths', None) is None:
324 return
325 count = getattr(self, 'moved_to_end', 0)
326 if count < 10:
327 # there has got to be a better way!!
328 self.moved_to_end = count + 1
329 self.meths.append('samba_post_process')
330 return
332 samba_post = getattr(self, 'samba_post', None)
333 if samba_post is None:
334 return
335 (tgt, cmd) = samba_post
336 self.env.TARGET_DIRECTORY = self.path.abspath(self.env)
337 #print "cmd=%s tgt=%s" % (cmd, tgt)
338 cmd = Utils.subst_vars(cmd, self.env)
339 tgt = Utils.subst_vars(tgt, self.env)
340 if os.path.isfile(tgt):
341 debug('deps: post processing for %s: %s' % (self.name, cmd))
342 ret = os.system(cmd)
343 self.bld.ASSERT(ret == 0, "Post processing for %s failed (%d): %s" % (self.name, ret, cmd))
346 ##############################
347 # handle the creation of links for libraries and binaries
348 # note that we use a relative symlink path to allow the whole tree
349 # to me moved/copied elsewhere without breaking the links
350 t = Task.simple_task_type('symlink_lib', 'ln -sf ../${SRC} ${LINK_TARGET}', color='PINK',
351 ext_in='.bin')
352 t.quiet = True
354 @feature('symlink_lib')
355 @after('apply_link')
356 def symlink_lib(self):
357 tsk = self.create_task('symlink_lib', self.link_task.outputs[0])
359 # calculat the link target and put it in the environment
360 soext=""
361 vnum = getattr(self, 'vnum', None)
362 if vnum is not None:
363 soext = '.' + vnum.split('.')[0]
365 libname = self.target
366 tsk.env.LINK_TARGET = '%s/lib%s.so%s' % (LIB_PATH, libname, soext)
367 debug('task_gen: LINK_TARGET for %s is %s', self.name, tsk.env.LINK_TARGET)
370 # for binaries we need to copy the executable to avoid the rpath changing
371 # in the local bin/ directory on install
372 t = Task.simple_task_type('copy_bin', 'rm -f ${BIN_TARGET} && cp ${SRC} ${BIN_TARGET}', color='PINK',
373 ext_in='.bin', shell=True)
374 t.quiet = True
376 @feature('copy_bin')
377 @after('apply_link')
378 def copy_bin(self):
379 if Options.is_install:
380 # we don't want to copy the install binary, as
381 # that has the install rpath, not the build rpath
382 # The rpath of the binaries in bin/default/foo/blah is different
383 # during the install phase, as distros insist on not using rpath in installed binaries
384 return
385 tsk = self.create_task('copy_bin', self.link_task.outputs[0])
387 tsk.env.BIN_TARGET = self.target
388 debug('task_gen: BIN_TARGET for %s is %s', self.name, tsk.env.BIN_TARGET)