1 # This file contains waf optimisations for Samba
3 # most of these optimisations are possible because of the restricted build environment
4 # that Samba has. For example, Samba doesn't attempt to cope with Win32 paths during the
5 # build, and Samba doesn't need build varients
7 # overall this makes some build tasks quite a bit faster
10 import Build, Utils, Node
11 from TaskGen import feature, after, before
15 @after('apply_type_vars', 'apply_lib_vars', 'apply_core')
16 def apply_incpaths(self):
21 except AttributeError:
22 kak = self.bld.kak = {}
24 # TODO move the uselib processing out of here
25 for lib in self.to_list(self.uselib):
26 for path in self.env['CPPPATH_' + lib]:
29 if preproc.go_absolute:
30 for path in preproc.standard_includes:
34 for path in self.to_list(self.includes):
36 if preproc.go_absolute or path[0] != '/': # os.path.isabs(path):
39 self.env.prepend_value('CPPPATH', path)
43 if path[0] == '/': # os.path.isabs(path):
44 if preproc.go_absolute:
45 node = self.bld.root.find_dir(path)
47 node = self.bld.srcnode
52 kak[path] = node = node.find_dir(path[1:])
55 node = kak[(self.path.id, path)]
57 kak[(self.path.id, path)] = node = self.path.find_dir(path)
60 self.env.append_value('INC_PATHS', node)
63 @before('apply_incpaths')
64 def samba_stash_cppflags(self):
65 """Fix broken waf ordering of CPPFLAGS"""
66 self.env['SAVED_CPPFLAGS'] = self.env['CPPFLAGS']
67 self.env['CPPFLAGS'] = []
70 @after('apply_incpaths')
71 def apply_obj_vars_cc(self):
72 """after apply_incpaths for INC_PATHS"""
74 app = env.append_unique
75 cpppath_st = env['CPPPATH_ST']
77 lss = env['_CCINCFLAGS']
81 except AttributeError:
82 cac = self.bld.cac = {}
84 # local flags come first
85 # set the user-defined includes paths
86 for i in env['INC_PATHS']:
92 cac[i.id] = [cpppath_st % i.bldpath(env), cpppath_st % i.srcpath(env)]
95 env['_CCINCFLAGS'] = lss
96 # set the library include paths
97 for i in env['CPPPATH']:
98 app('_CCINCFLAGS', cpppath_st % i)
100 # append stashed user CPPFLAGS after our internally computed flags
101 app('_CCINCFLAGS', env['SAVED_CPPFLAGS'])
102 env['SAVED_CPPFLAGS'] = []
104 import Node, Environment
108 Environment.Environment.variant = vari
110 def variant(self, env):
112 elif self.id & 3 == Node.FILE: return 0
113 else: return "default"
114 Node.Node.variant = variant
119 def create_task(self, name, src=None, tgt=None):
120 task = Task.TaskBase.classes[name](self.env, generator=self)
124 task.set_outputs(tgt)
126 TaskGen.task_gen.create_task = create_task
128 def hash_constraints(self):
130 sum = hash((str(a('before', '')),
132 str(a('ext_in', '')),
133 str(a('ext_out', '')),
134 self.__class__.maxjobs))
136 Task.TaskBase.hash_constraints = hash_constraints
140 # from TaskGen import extension
143 # @extension(cc.EXT_CC)
144 # def c_hook(self, node):
145 # task = self.create_task('cc', node, node.change_ext('.o'))
147 # self.compiled_tasks.append(task)
148 # except AttributeError:
149 # raise Utils.WafError('Have you forgotten to set the feature "cc" on %s?' % str(self))
154 # except AttributeError:
157 # if task.outputs[0].id in dc:
158 # raise Utils.WafError('Samba, you are doing it wrong %r %s %s' % (task.outputs, task.generator, dc[task.outputs[0].id].generator))
160 # dc[task.outputs[0].id] = task
166 '''work around a problem with cc on solaris not handling module aliases
167 which have empty libs'''
168 if getattr(cls, 'solaris_wrap', False):
170 cls.solaris_wrap = True
173 if self.env.CC_NAME == "sun" and not self.inputs:
174 self.env = self.env.copy()
175 self.env.append_value('LINKFLAGS', '-')
178 suncc_wrap(Task.TaskBase.classes['cc_link'])
182 def hash_env_vars(self, env, vars_lst):
183 idx = str(id(env)) + str(vars_lst)
185 return self.cache_sig_vars[idx]
190 m.update(''.join([str(env[a]) for a in vars_lst]))
192 ret = self.cache_sig_vars[idx] = m.digest()
194 Build.BuildContext.hash_env_vars = hash_env_vars
197 def store_fast(self, filename):
198 file = open(filename, 'wb')
199 data = self.get_merged_dict()
201 Build.cPickle.dump(data, file, -1)
204 Environment.Environment.store_fast = store_fast
206 def load_fast(self, filename):
207 file = open(filename, 'rb')
209 data = Build.cPickle.load(file)
212 self.table.update(data)
213 Environment.Environment.load_fast = load_fast
215 def is_this_a_static_lib(self, name):
217 cache = self.cache_is_this_a_static_lib
218 except AttributeError:
219 cache = self.cache_is_this_a_static_lib = {}
223 ret = cache[name] = 'cstaticlib' in self.bld.name_to_obj(name, self.env).features
225 TaskGen.task_gen.is_this_a_static_lib = is_this_a_static_lib
227 def shared_ancestors(self):
229 cache = self.cache_is_this_a_static_lib
230 except AttributeError:
231 cache = self.cache_is_this_a_static_lib = {}
233 return cache[id(self)]
237 if 'cshlib' in self.features: # or 'cprogram' in self.features:
238 if getattr(self, 'uselib_local', None):
239 lst = self.to_list(self.uselib_local)
240 ret = [x for x in lst if not self.is_this_a_static_lib(x)]
241 cache[id(self)] = ret
243 TaskGen.task_gen.shared_ancestors = shared_ancestors
245 @feature('cc', 'cxx')
246 @after('apply_link', 'init_cc', 'init_cxx', 'apply_core')
247 def apply_lib_vars(self):
248 """after apply_link because of 'link_task'
249 after default_cc because of the attribute 'uselib'"""
251 # after 'apply_core' in case if 'cc' if there is no link
254 app = env.append_value
255 seen_libpaths = set([])
257 # OPTIMIZATION 1: skip uselib variables already added (700ms)
258 seen_uselib = set([])
260 # 1. the case of the libs defined in the project (visit ancestors first)
261 # the ancestors external libraries (uselib) will be prepended
262 self.uselib = self.to_list(self.uselib)
263 names = self.to_list(self.uselib_local)
266 tmp = Utils.deque(names) # consume a copy of the list of names
268 lib_name = tmp.popleft()
269 # visit dependencies only once
273 y = self.name_to_obj(lib_name)
275 raise Utils.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name, self.name))
279 # OPTIMIZATION 2: pre-compute ancestors shared libraries (100ms)
280 tmp.extend(y.shared_ancestors())
282 # link task and flags
283 if getattr(y, 'link_task', None):
285 link_name = y.target[y.target.rfind('/') + 1:]
286 if 'cstaticlib' in y.features:
287 app('STATICLIB', link_name)
288 elif 'cshlib' in y.features or 'cprogram' in y.features:
289 # WARNING some linkers can link against programs
290 app('LIB', link_name)
293 self.link_task.set_run_after(y.link_task)
295 # for the recompilation
296 dep_nodes = getattr(self.link_task, 'dep_nodes', [])
297 self.link_task.dep_nodes = dep_nodes + y.link_task.outputs
299 # OPTIMIZATION 3: reduce the amount of function calls
300 # add the link path too
301 par = y.link_task.outputs[0].parent
302 if id(par) not in seen_libpaths:
303 seen_libpaths.add(id(par))
304 tmp_path = par.bldpath(self.env)
305 if not tmp_path in env['LIBPATH']:
306 env.prepend_value('LIBPATH', tmp_path)
309 # add ancestors uselib too - but only propagate those that have no staticlib
310 for v in self.to_list(y.uselib):
311 if v not in seen_uselib:
313 if not env['STATICLIB_' + v]:
314 if not v in self.uselib:
315 self.uselib.insert(0, v)
317 # 2. the case of the libs defined outside
318 for x in self.uselib:
319 for v in self.p_flag_vars:
320 val = self.env[v + '_' + x]
322 self.env.append_value(v, val)
324 @feature('cprogram', 'cshlib', 'cstaticlib')
325 @after('apply_lib_vars')
326 @before('apply_obj_vars')
327 def samba_before_apply_obj_vars(self):
328 """before apply_obj_vars for uselib, this removes the standard pathes"""
330 def is_standard_libpath(env, path):
331 for _path in env.STANDARD_LIBPATH:
332 if _path == os.path.normpath(path):
339 if is_standard_libpath(v, i):
342 for i in v['LIBPATH']:
343 if is_standard_libpath(v, i):
344 v['LIBPATH'].remove(i)
346 @feature('cprogram', 'cshlib', 'cstaticlib')
347 @before('apply_obj_vars', 'add_extra_flags')
348 def samba_stash_linkflags(self):
349 """stash away LINKFLAGS in order to fix waf's broken ordering wrt or
352 self.env.SAVE_LINKFLAGS = self.env['LINKFLAGS']
353 self.env['LINKFLAGS'] = []
355 @feature('cprogram', 'cshlib', 'cstaticlib')
356 @after('apply_obj_vars', 'add_extra_flags')
357 def samba_pop_linkflags(self):
358 """after apply_obj_vars append saved LDFLAGS"""
360 self.env.append_value('LINKFLAGS', self.env.SAVE_LINKFLAGS)
361 self.env.SAVE_LINKFLAGS = []