1 | # This file contains waf optimisations for Samba
|
---|
2 |
|
---|
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
|
---|
6 |
|
---|
7 | # overall this makes some build tasks quite a bit faster
|
---|
8 |
|
---|
9 | import os
|
---|
10 | import Build, Utils, Node
|
---|
11 | from TaskGen import feature, after, before
|
---|
12 | import preproc
|
---|
13 |
|
---|
14 | @feature('c', 'cc', 'cxx')
|
---|
15 | @after('apply_type_vars', 'apply_lib_vars', 'apply_core')
|
---|
16 | def apply_incpaths(self):
|
---|
17 | lst = []
|
---|
18 |
|
---|
19 | try:
|
---|
20 | kak = self.bld.kak
|
---|
21 | except AttributeError:
|
---|
22 | kak = self.bld.kak = {}
|
---|
23 |
|
---|
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]:
|
---|
27 | if not path in lst:
|
---|
28 | lst.append(path)
|
---|
29 | if preproc.go_absolute:
|
---|
30 | for path in preproc.standard_includes:
|
---|
31 | if not path in lst:
|
---|
32 | lst.append(path)
|
---|
33 |
|
---|
34 | for path in self.to_list(self.includes):
|
---|
35 | if not path in lst:
|
---|
36 | if preproc.go_absolute or path[0] != '/': # os.path.isabs(path):
|
---|
37 | lst.append(path)
|
---|
38 | else:
|
---|
39 | self.env.prepend_value('CPPPATH', path)
|
---|
40 |
|
---|
41 | for path in lst:
|
---|
42 | node = None
|
---|
43 | if path[0] == '/': # os.path.isabs(path):
|
---|
44 | if preproc.go_absolute:
|
---|
45 | node = self.bld.root.find_dir(path)
|
---|
46 | elif path[0] == '#':
|
---|
47 | node = self.bld.srcnode
|
---|
48 | if len(path) > 1:
|
---|
49 | try:
|
---|
50 | node = kak[path]
|
---|
51 | except KeyError:
|
---|
52 | kak[path] = node = node.find_dir(path[1:])
|
---|
53 | else:
|
---|
54 | try:
|
---|
55 | node = kak[(self.path.id, path)]
|
---|
56 | except KeyError:
|
---|
57 | kak[(self.path.id, path)] = node = self.path.find_dir(path)
|
---|
58 |
|
---|
59 | if node:
|
---|
60 | self.env.append_value('INC_PATHS', node)
|
---|
61 |
|
---|
62 | @feature('c', 'cc')
|
---|
63 | @after('apply_incpaths')
|
---|
64 | def apply_obj_vars_cc(self):
|
---|
65 | """after apply_incpaths for INC_PATHS"""
|
---|
66 | env = self.env
|
---|
67 | app = env.append_unique
|
---|
68 | cpppath_st = env['CPPPATH_ST']
|
---|
69 |
|
---|
70 | lss = env['_CCINCFLAGS']
|
---|
71 |
|
---|
72 | try:
|
---|
73 | cac = self.bld.cac
|
---|
74 | except AttributeError:
|
---|
75 | cac = self.bld.cac = {}
|
---|
76 |
|
---|
77 | # local flags come first
|
---|
78 | # set the user-defined includes paths
|
---|
79 | for i in env['INC_PATHS']:
|
---|
80 |
|
---|
81 | try:
|
---|
82 | lss.extend(cac[i.id])
|
---|
83 | except KeyError:
|
---|
84 |
|
---|
85 | cac[i.id] = [cpppath_st % i.bldpath(env), cpppath_st % i.srcpath(env)]
|
---|
86 | lss.extend(cac[i.id])
|
---|
87 |
|
---|
88 | env['_CCINCFLAGS'] = lss
|
---|
89 | # set the library include paths
|
---|
90 | for i in env['CPPPATH']:
|
---|
91 | app('_CCINCFLAGS', cpppath_st % i)
|
---|
92 |
|
---|
93 | import Node, Environment
|
---|
94 |
|
---|
95 | def vari(self):
|
---|
96 | return "default"
|
---|
97 | Environment.Environment.variant = vari
|
---|
98 |
|
---|
99 | def variant(self, env):
|
---|
100 | if not env: return 0
|
---|
101 | elif self.id & 3 == Node.FILE: return 0
|
---|
102 | else: return "default"
|
---|
103 | Node.Node.variant = variant
|
---|
104 |
|
---|
105 |
|
---|
106 | import TaskGen, Task
|
---|
107 |
|
---|
108 | def create_task(self, name, src=None, tgt=None):
|
---|
109 | task = Task.TaskBase.classes[name](self.env, generator=self)
|
---|
110 | if src:
|
---|
111 | task.set_inputs(src)
|
---|
112 | if tgt:
|
---|
113 | task.set_outputs(tgt)
|
---|
114 | return task
|
---|
115 | TaskGen.task_gen.create_task = create_task
|
---|
116 |
|
---|
117 | def hash_constraints(self):
|
---|
118 | a = self.attr
|
---|
119 | sum = hash((str(a('before', '')),
|
---|
120 | str(a('after', '')),
|
---|
121 | str(a('ext_in', '')),
|
---|
122 | str(a('ext_out', '')),
|
---|
123 | self.__class__.maxjobs))
|
---|
124 | return sum
|
---|
125 | Task.TaskBase.hash_constraints = hash_constraints
|
---|
126 |
|
---|
127 | def hash_env_vars(self, env, vars_lst):
|
---|
128 | idx = str(id(env)) + str(vars_lst)
|
---|
129 | try:
|
---|
130 | return self.cache_sig_vars[idx]
|
---|
131 | except KeyError:
|
---|
132 | pass
|
---|
133 |
|
---|
134 | m = Utils.md5()
|
---|
135 | m.update(''.join([str(env[a]) for a in vars_lst]))
|
---|
136 |
|
---|
137 | ret = self.cache_sig_vars[idx] = m.digest()
|
---|
138 | return ret
|
---|
139 | Build.BuildContext.hash_env_vars = hash_env_vars
|
---|
140 |
|
---|
141 |
|
---|
142 | def store_fast(self, filename):
|
---|
143 | file = open(filename, 'wb')
|
---|
144 | data = self.get_merged_dict()
|
---|
145 | try:
|
---|
146 | Build.cPickle.dump(data, file, -1)
|
---|
147 | finally:
|
---|
148 | file.close()
|
---|
149 | Environment.Environment.store_fast = store_fast
|
---|
150 |
|
---|
151 | def load_fast(self, filename):
|
---|
152 | file = open(filename, 'rb')
|
---|
153 | try:
|
---|
154 | data = Build.cPickle.load(file)
|
---|
155 | finally:
|
---|
156 | file.close()
|
---|
157 | self.table.update(data)
|
---|
158 | Environment.Environment.load_fast = load_fast
|
---|
159 |
|
---|
160 | def is_this_a_static_lib(self, name):
|
---|
161 | try:
|
---|
162 | cache = self.cache_is_this_a_static_lib
|
---|
163 | except AttributeError:
|
---|
164 | cache = self.cache_is_this_a_static_lib = {}
|
---|
165 | try:
|
---|
166 | return cache[name]
|
---|
167 | except KeyError:
|
---|
168 | ret = cache[name] = 'cstaticlib' in self.bld.get_tgen_by_name(name).features
|
---|
169 | return ret
|
---|
170 | TaskGen.task_gen.is_this_a_static_lib = is_this_a_static_lib
|
---|
171 |
|
---|
172 | def shared_ancestors(self):
|
---|
173 | try:
|
---|
174 | cache = self.cache_is_this_a_static_lib
|
---|
175 | except AttributeError:
|
---|
176 | cache = self.cache_is_this_a_static_lib = {}
|
---|
177 | try:
|
---|
178 | return cache[id(self)]
|
---|
179 | except KeyError:
|
---|
180 |
|
---|
181 | ret = []
|
---|
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
|
---|
187 | return ret
|
---|
188 | TaskGen.task_gen.shared_ancestors = shared_ancestors
|
---|
189 |
|
---|
190 | @feature('c', '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'"""
|
---|
195 |
|
---|
196 | # after 'apply_core' in case if 'cc' if there is no link
|
---|
197 |
|
---|
198 | env = self.env
|
---|
199 | app = env.append_value
|
---|
200 | seen_libpaths = set([])
|
---|
201 |
|
---|
202 | # OPTIMIZATION 1: skip uselib variables already added (700ms)
|
---|
203 | seen_uselib = set([])
|
---|
204 |
|
---|
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)
|
---|
209 |
|
---|
210 | seen = set([])
|
---|
211 | tmp = Utils.deque(names) # consume a copy of the list of names
|
---|
212 | while tmp:
|
---|
213 | lib_name = tmp.popleft()
|
---|
214 | # visit dependencies only once
|
---|
215 | if lib_name in seen:
|
---|
216 | continue
|
---|
217 |
|
---|
218 | y = self.get_tgen_by_name(lib_name)
|
---|
219 | if not y:
|
---|
220 | raise Utils.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name, self.name))
|
---|
221 | y.post()
|
---|
222 | seen.add(lib_name)
|
---|
223 |
|
---|
224 | # OPTIMIZATION 2: pre-compute ancestors shared libraries (100ms)
|
---|
225 | tmp.extend(y.shared_ancestors())
|
---|
226 |
|
---|
227 | # link task and flags
|
---|
228 | if getattr(y, 'link_task', None):
|
---|
229 |
|
---|
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)
|
---|
236 |
|
---|
237 | # the order
|
---|
238 | self.link_task.set_run_after(y.link_task)
|
---|
239 |
|
---|
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
|
---|
243 |
|
---|
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)
|
---|
252 |
|
---|
253 |
|
---|
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:
|
---|
257 | seen_uselib.add(v)
|
---|
258 | if not env['STATICLIB_' + v]:
|
---|
259 | if not v in self.uselib:
|
---|
260 | self.uselib.insert(0, v)
|
---|
261 |
|
---|
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]
|
---|
266 | if val:
|
---|
267 | self.env.append_value(v, val)
|
---|
268 |
|
---|
269 |
|
---|