3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
7 # Thomas Nagy, 2006-2015 (ita)
10 Instead of compiling object files one by one, c/c++ compilers are often able to compile at once:
11 cc -c ../file1.c ../file2.c ../file3.c
13 Files are output on the directory where the compiler is called, and dependencies are more difficult
14 to track (do not run the command on all source files if only one file changes)
15 As such, we do as if the files were compiled one by one, but no command is actually run:
16 replace each cc/cpp Task by a TaskSlave. A new task called TaskMaster collects the
17 signatures from each slave and finds out the command-line to run.
19 Just import this module to start using it:
21 bld.load('batched_cc')
23 Note that this is provided as an example, unity builds are recommended
24 for best performance results (fewer tasks and fewer jobs to execute).
25 See waflib/extras/unity.py.
28 from waflib import Task, Utils
29 from waflib.TaskGen import extension, feature, after_method
30 from waflib.Tools import c, cxx
34 c_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${tsk.batch_incpaths()} ${DEFINES_ST:DEFINES} -c ${SRCLST} ${CXX_TGT_F_BATCHED} ${CPPFLAGS}'
35 c_fun, _ = Task.compile_fun_noshell(c_str)
37 cxx_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${tsk.batch_incpaths()} ${DEFINES_ST:DEFINES} -c ${SRCLST} ${CXX_TGT_F_BATCHED} ${CPPFLAGS}'
38 cxx_fun, _ = Task.compile_fun_noshell(cxx_str)
41 class batch(Task.Task):
45 before = ['cprogram', 'cshlib', 'cstlib', 'cxxprogram', 'cxxshlib', 'cxxstlib']
48 return Utils.h_list([Task.Task.uid(self), self.generator.idx, self.generator.path.abspath(), self.generator.target])
51 return 'Batch compilation for %d slaves' % len(self.slaves)
53 def __init__(self, *k, **kw):
54 Task.Task.__init__(self, *k, **kw)
63 def add_slave(self, slave):
64 self.slaves.append(slave)
65 self.set_run_after(slave)
67 def runnable_status(self):
68 for t in self.run_after:
74 if t.hasrun != Task.SKIPPED:
80 return self.slaves[0].outputs[0].parent
82 def batch_incpaths(self):
83 st = self.env.CPPPATH_ST
84 return [st % node.abspath() for node in self.generator.includes_nodes]
92 if t.hasrun != Task.SKIPPED:
94 srclst.append(t.inputs[0].abspath())
96 self.env.SRCLST = srclst
98 if self.slaves[0].__class__.__name__ == 'c':
110 def n_hook(self, node):
112 ext = '.obj' if self.env.CC_NAME == 'msvc' else '.o'
116 basename = name[:k] + ext
118 basename = name + ext
120 outdir = node.parent.get_bld().make_node('%d' % self.idx)
122 out = outdir.find_or_declare(basename)
124 task = self.create_task(cls_type, node, out)
127 self.compiled_tasks.append(task)
128 except AttributeError:
129 self.compiled_tasks = [task]
131 if not getattr(self, 'masters', None):
136 if self.env.CC_NAME == 'msvc':
137 tsk.env.append_unique('CXX_TGT_F_BATCHED', '/Fo%s\\' % outdir.abspath())
139 if not node.parent in self.masters:
140 m = self.masters[node.parent] = self.master = self.create_task('batch')
142 self.allmasters.append(m)
144 m = self.masters[node.parent]
145 if len(m.slaves) > MAX_BATCH:
146 m = self.masters[node.parent] = self.master = self.create_task('batch')
148 self.allmasters.append(m)
153 extension('.c')(hook('c'))
154 extension('.cpp','.cc','.cxx','.C','.c++')(hook('cxx'))
156 @feature('cprogram', 'cshlib', 'cstaticlib', 'cxxprogram', 'cxxshlib', 'cxxstlib')
157 @after_method('apply_link')
158 def link_after_masters(self):
159 if getattr(self, 'allmasters', None):
160 for m in self.allmasters:
161 self.link_task.set_run_after(m)
163 # Modify the c and cxx task classes - in theory it would be best to
164 # create subclasses and to re-map the c/c++ extensions
165 for x in ('c', 'cxx'):
173 setattr(t, 'oldrun', getattr(t, 'run', None))
174 setattr(t, 'run', run)
175 setattr(t, 'old_post_run', t.post_run)
176 setattr(t, 'post_run', post_run)