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
9 import Build
, Utils
, Node
10 from TaskGen
import feature
, after
14 @after('apply_type_vars', 'apply_lib_vars', 'apply_core')
15 def apply_incpaths(self
):
20 except AttributeError:
21 kak
= self
.bld
.kak
= {}
23 # TODO move the uselib processing out of here
24 for lib
in self
.to_list(self
.uselib
):
25 for path
in self
.env
['CPPPATH_' + lib
]:
28 if preproc
.go_absolute
:
29 for path
in preproc
.standard_includes
:
33 for path
in self
.to_list(self
.includes
):
35 if preproc
.go_absolute
or path
[0] != '/': # os.path.isabs(path):
38 self
.env
.prepend_value('CPPPATH', path
)
42 if path
[0] == '/': # os.path.isabs(path):
43 if preproc
.go_absolute
:
44 node
= self
.bld
.root
.find_dir(path
)
46 node
= self
.bld
.srcnode
51 kak
[path
] = node
= node
.find_dir(path
[1:])
54 node
= kak
[(self
.path
.id, path
)]
56 kak
[(self
.path
.id, path
)] = node
= self
.path
.find_dir(path
)
59 self
.env
.append_value('INC_PATHS', node
)
62 @after('apply_incpaths')
63 def apply_obj_vars_cc(self
):
64 """after apply_incpaths for INC_PATHS"""
66 app
= env
.append_unique
67 cpppath_st
= env
['CPPPATH_ST']
69 lss
= env
['_CCINCFLAGS']
73 except AttributeError:
74 cac
= self
.bld
.cac
= {}
76 # local flags come first
77 # set the user-defined includes paths
78 for i
in env
['INC_PATHS']:
84 cac
[i
.id] = [cpppath_st
% i
.bldpath(env
), cpppath_st
% i
.srcpath(env
)]
87 env
['_CCINCFLAGS'] = lss
88 # set the library include paths
89 for i
in env
['CPPPATH']:
90 app('_CCINCFLAGS', cpppath_st
% i
)
92 import Node
, Environment
96 Environment
.Environment
.variant
= vari
98 def variant(self
, env
):
100 elif self
.id & 3 == Node
.FILE
: return 0
101 else: return "default"
102 Node
.Node
.variant
= variant
107 def create_task(self
, name
, src
=None, tgt
=None):
108 task
= Task
.TaskBase
.classes
[name
](self
.env
, generator
=self
)
112 task
.set_outputs(tgt
)
114 TaskGen
.task_gen
.create_task
= create_task
116 def hash_constraints(self
):
118 sum = hash((str(a('before', '')),
120 str(a('ext_in', '')),
121 str(a('ext_out', '')),
122 self
.__class
__.maxjobs
))
124 Task
.TaskBase
.hash_constraints
= hash_constraints
128 # from TaskGen import extension
131 # @extension(cc.EXT_CC)
132 # def c_hook(self, node):
133 # task = self.create_task('cc', node, node.change_ext('.o'))
135 # self.compiled_tasks.append(task)
136 # except AttributeError:
137 # raise Utils.WafError('Have you forgotten to set the feature "cc" on %s?' % str(self))
142 # except AttributeError:
145 # if task.outputs[0].id in dc:
146 # raise Utils.WafError('Samba, you are doing it wrong %r %s %s' % (task.outputs, task.generator, dc[task.outputs[0].id].generator))
148 # dc[task.outputs[0].id] = task
154 '''work around a problem with cc on solaris not handling module aliases
155 which have empty libs'''
156 if getattr(cls
, 'solaris_wrap', False):
158 cls
.solaris_wrap
= True
161 if self
.env
.CC_NAME
== "sun" and not self
.inputs
:
162 self
.env
= self
.env
.copy()
163 self
.env
.append_value('LINKFLAGS', '-')
166 suncc_wrap(Task
.TaskBase
.classes
['cc_link'])
170 def hash_env_vars(self
, env
, vars_lst
):
171 idx
= str(id(env
)) + str(vars_lst
)
173 return self
.cache_sig_vars
[idx
]
178 m
.update(''.join([str(env
[a
]) for a
in vars_lst
]))
180 ret
= self
.cache_sig_vars
[idx
] = m
.digest()
182 Build
.BuildContext
.hash_env_vars
= hash_env_vars
185 def store_fast(self
, filename
):
186 file = open(filename
, 'wb')
187 data
= self
.get_merged_dict()
189 Build
.cPickle
.dump(data
, file, -1)
192 Environment
.Environment
.store_fast
= store_fast
194 def load_fast(self
, filename
):
195 file = open(filename
, 'rb')
197 data
= Build
.cPickle
.load(file)
200 self
.table
.update(data
)
201 Environment
.Environment
.load_fast
= load_fast
203 def is_this_a_static_lib(self
, name
):
205 cache
= self
.cache_is_this_a_static_lib
206 except AttributeError:
207 cache
= self
.cache_is_this_a_static_lib
= {}
211 ret
= cache
[name
] = 'cstaticlib' in self
.bld
.name_to_obj(name
, self
.env
).features
213 TaskGen
.task_gen
.is_this_a_static_lib
= is_this_a_static_lib
215 def shared_ancestors(self
):
217 cache
= self
.cache_is_this_a_static_lib
218 except AttributeError:
219 cache
= self
.cache_is_this_a_static_lib
= {}
221 return cache
[id(self
)]
225 if 'cshlib' in self
.features
: # or 'cprogram' in self.features:
226 if getattr(self
, 'uselib_local', None):
227 lst
= self
.to_list(self
.uselib_local
)
228 ret
= [x
for x
in lst
if not self
.is_this_a_static_lib(x
)]
229 cache
[id(self
)] = ret
231 TaskGen
.task_gen
.shared_ancestors
= shared_ancestors
233 @feature('cc', 'cxx')
234 @after('apply_link', 'init_cc', 'init_cxx', 'apply_core')
235 def apply_lib_vars(self
):
236 """after apply_link because of 'link_task'
237 after default_cc because of the attribute 'uselib'"""
239 # after 'apply_core' in case if 'cc' if there is no link
242 app
= env
.append_value
243 seen_libpaths
= set([])
245 # OPTIMIZATION 1: skip uselib variables already added (700ms)
246 seen_uselib
= set([])
248 # 1. the case of the libs defined in the project (visit ancestors first)
249 # the ancestors external libraries (uselib) will be prepended
250 self
.uselib
= self
.to_list(self
.uselib
)
251 names
= self
.to_list(self
.uselib_local
)
254 tmp
= Utils
.deque(names
) # consume a copy of the list of names
256 lib_name
= tmp
.popleft()
257 # visit dependencies only once
261 y
= self
.name_to_obj(lib_name
)
263 raise Utils
.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name
, self
.name
))
267 # OPTIMIZATION 2: pre-compute ancestors shared libraries (100ms)
268 tmp
.extend(y
.shared_ancestors())
270 # link task and flags
271 if getattr(y
, 'link_task', None):
273 link_name
= y
.target
[y
.target
.rfind('/') + 1:]
274 if 'cstaticlib' in y
.features
:
275 app('STATICLIB', link_name
)
276 elif 'cshlib' in y
.features
or 'cprogram' in y
.features
:
277 # WARNING some linkers can link against programs
278 app('LIB', link_name
)
281 self
.link_task
.set_run_after(y
.link_task
)
283 # for the recompilation
284 dep_nodes
= getattr(self
.link_task
, 'dep_nodes', [])
285 self
.link_task
.dep_nodes
= dep_nodes
+ y
.link_task
.outputs
287 # OPTIMIZATION 3: reduce the amount of function calls
288 # add the link path too
289 par
= y
.link_task
.outputs
[0].parent
290 if id(par
) not in seen_libpaths
:
291 seen_libpaths
.add(id(par
))
292 tmp_path
= par
.bldpath(self
.env
)
293 if not tmp_path
in env
['LIBPATH']:
294 env
.prepend_value('LIBPATH', tmp_path
)
297 # add ancestors uselib too - but only propagate those that have no staticlib
298 for v
in self
.to_list(y
.uselib
):
299 if v
not in seen_uselib
:
301 if not env
['STATICLIB_' + v
]:
302 if not v
in self
.uselib
:
303 self
.uselib
.insert(0, v
)
305 # 2. the case of the libs defined outside
306 for x
in self
.uselib
:
307 for v
in self
.p_flag_vars
:
308 val
= self
.env
[v
+ '_' + x
]
310 self
.env
.append_value(v
, val
)