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 @after('apply_incpaths')
64 def apply_obj_vars_cc(self
):
65 """after apply_incpaths for INC_PATHS"""
67 app
= env
.append_unique
68 cpppath_st
= env
['CPPPATH_ST']
70 lss
= env
['_CCINCFLAGS']
74 except AttributeError:
75 cac
= self
.bld
.cac
= {}
77 # local flags come first
78 # set the user-defined includes paths
79 for i
in env
['INC_PATHS']:
85 cac
[i
.id] = [cpppath_st
% i
.bldpath(env
), cpppath_st
% i
.srcpath(env
)]
88 env
['_CCINCFLAGS'] = lss
89 # set the library include paths
90 for i
in env
['CPPPATH']:
91 app('_CCINCFLAGS', cpppath_st
% i
)
93 import Node
, Environment
97 Environment
.Environment
.variant
= vari
99 def variant(self
, env
):
101 elif self
.id & 3 == Node
.FILE
: return 0
102 else: return "default"
103 Node
.Node
.variant
= variant
108 def create_task(self
, name
, src
=None, tgt
=None):
109 task
= Task
.TaskBase
.classes
[name
](self
.env
, generator
=self
)
113 task
.set_outputs(tgt
)
115 TaskGen
.task_gen
.create_task
= create_task
117 def hash_constraints(self
):
119 sum = hash((str(a('before', '')),
121 str(a('ext_in', '')),
122 str(a('ext_out', '')),
123 self
.__class
__.maxjobs
))
125 Task
.TaskBase
.hash_constraints
= hash_constraints
127 def hash_env_vars(self
, env
, vars_lst
):
128 idx
= str(id(env
)) + str(vars_lst
)
130 return self
.cache_sig_vars
[idx
]
135 m
.update(''.join([str(env
[a
]) for a
in vars_lst
]))
137 ret
= self
.cache_sig_vars
[idx
] = m
.digest()
139 Build
.BuildContext
.hash_env_vars
= hash_env_vars
142 def store_fast(self
, filename
):
143 file = open(filename
, 'wb')
144 data
= self
.get_merged_dict()
146 Build
.cPickle
.dump(data
, file, -1)
149 Environment
.Environment
.store_fast
= store_fast
151 def load_fast(self
, filename
):
152 file = open(filename
, 'rb')
154 data
= Build
.cPickle
.load(file)
157 self
.table
.update(data
)
158 Environment
.Environment
.load_fast
= load_fast
160 def is_this_a_static_lib(self
, name
):
162 cache
= self
.cache_is_this_a_static_lib
163 except AttributeError:
164 cache
= self
.cache_is_this_a_static_lib
= {}
168 ret
= cache
[name
] = 'cstaticlib' in self
.bld
.name_to_obj(name
, self
.env
).features
170 TaskGen
.task_gen
.is_this_a_static_lib
= is_this_a_static_lib
172 def shared_ancestors(self
):
174 cache
= self
.cache_is_this_a_static_lib
175 except AttributeError:
176 cache
= self
.cache_is_this_a_static_lib
= {}
178 return cache
[id(self
)]
182 if 'cshlib' in self
.features
: # or 'cprogram' in self.features:
183 if getattr(self
, 'uselib_local', None):
184 lst
= self
.to_list(self
.uselib_local
)
185 ret
= [x
for x
in lst
if not self
.is_this_a_static_lib(x
)]
186 cache
[id(self
)] = ret
188 TaskGen
.task_gen
.shared_ancestors
= shared_ancestors
190 @feature('cc', 'cxx')
191 @after('apply_link', 'init_cc', 'init_cxx', 'apply_core')
192 def apply_lib_vars(self
):
193 """after apply_link because of 'link_task'
194 after default_cc because of the attribute 'uselib'"""
196 # after 'apply_core' in case if 'cc' if there is no link
199 app
= env
.append_value
200 seen_libpaths
= set([])
202 # OPTIMIZATION 1: skip uselib variables already added (700ms)
203 seen_uselib
= set([])
205 # 1. the case of the libs defined in the project (visit ancestors first)
206 # the ancestors external libraries (uselib) will be prepended
207 self
.uselib
= self
.to_list(self
.uselib
)
208 names
= self
.to_list(self
.uselib_local
)
211 tmp
= Utils
.deque(names
) # consume a copy of the list of names
213 lib_name
= tmp
.popleft()
214 # visit dependencies only once
218 y
= self
.name_to_obj(lib_name
)
220 raise Utils
.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name
, self
.name
))
224 # OPTIMIZATION 2: pre-compute ancestors shared libraries (100ms)
225 tmp
.extend(y
.shared_ancestors())
227 # link task and flags
228 if getattr(y
, 'link_task', None):
230 link_name
= y
.target
[y
.target
.rfind('/') + 1:]
231 if 'cstaticlib' in y
.features
:
232 app('STATICLIB', link_name
)
233 elif 'cshlib' in y
.features
or 'cprogram' in y
.features
:
234 # WARNING some linkers can link against programs
235 app('LIB', link_name
)
238 self
.link_task
.set_run_after(y
.link_task
)
240 # for the recompilation
241 dep_nodes
= getattr(self
.link_task
, 'dep_nodes', [])
242 self
.link_task
.dep_nodes
= dep_nodes
+ y
.link_task
.outputs
244 # OPTIMIZATION 3: reduce the amount of function calls
245 # add the link path too
246 par
= y
.link_task
.outputs
[0].parent
247 if id(par
) not in seen_libpaths
:
248 seen_libpaths
.add(id(par
))
249 tmp_path
= par
.bldpath(self
.env
)
250 if not tmp_path
in env
['LIBPATH']:
251 env
.prepend_value('LIBPATH', tmp_path
)
254 # add ancestors uselib too - but only propagate those that have no staticlib
255 for v
in self
.to_list(y
.uselib
):
256 if v
not in seen_uselib
:
258 if not env
['STATICLIB_' + v
]:
259 if not v
in self
.uselib
:
260 self
.uselib
.insert(0, v
)
262 # 2. the case of the libs defined outside
263 for x
in self
.uselib
:
264 for v
in self
.p_flag_vars
:
265 val
= self
.env
[v
+ '_' + x
]
267 self
.env
.append_value(v
, val
)
269 @feature('cprogram', 'cshlib', 'cstaticlib')
270 @after('apply_lib_vars')
271 @before('apply_obj_vars')
272 def samba_before_apply_obj_vars(self
):
273 """before apply_obj_vars for uselib, this removes the standard pathes"""
275 def is_standard_libpath(env
, path
):
276 for _path
in env
.STANDARD_LIBPATH
:
277 if _path
== os
.path
.normpath(path
):
284 if is_standard_libpath(v
, i
):
287 for i
in v
['LIBPATH']:
288 if is_standard_libpath(v
, i
):
289 v
['LIBPATH'].remove(i
)