98b23f47fe469cad55cde3e2e18ecc59f5dbaf2f
[bbaumbach/samba-autobuild/.git] / third_party / waf / waflib / extras / pch.py
1 #! /usr/bin/env python
2 # encoding: utf-8
3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
4
5 #! /usr/bin/env python
6 # encoding: utf-8
7 # Alexander Afanasyev (UCLA), 2014
8
9 """
10 Enable precompiled C++ header support (currently only clang++ and g++ are supported)
11
12 To use this tool, wscript should look like:
13
14         def options(opt):
15                 opt.load('pch')
16                 # This will add `--with-pch` configure option.
17                 # Unless --with-pch during configure stage specified, the precompiled header support is disabled
18
19         def configure(conf):
20                 conf.load('pch')
21                 # this will set conf.env.WITH_PCH if --with-pch is specified and the supported compiler is used
22                 # Unless conf.env.WITH_PCH is set, the precompiled header support is disabled
23
24         def build(bld):
25                 bld(features='cxx pch',
26                         target='precompiled-headers',
27                         name='precompiled-headers',
28                         headers='a.h b.h c.h', # headers to pre-compile into `precompiled-headers`
29
30                         # Other parameters to compile precompiled headers
31                         # includes=...,
32                         # export_includes=...,
33                         # use=...,
34                         # ...
35
36                         # Exported parameters will be propagated even if precompiled headers are disabled
37                 )
38
39                 bld(
40                         target='test',
41                         features='cxx cxxprogram',
42                         source='a.cpp b.cpp d.cpp main.cpp',
43                         use='precompiled-headers',
44                 )
45
46                 # or
47
48                 bld(
49                         target='test',
50                         features='pch cxx cxxprogram',
51                         source='a.cpp b.cpp d.cpp main.cpp',
52                         headers='a.h b.h c.h',
53                 )
54
55 Note that precompiled header must have multiple inclusion guards.  If the guards are missing, any benefit of precompiled header will be voided and compilation may fail in some cases.
56 """
57
58 import os
59 from waflib import Task, TaskGen, Utils
60 from waflib.Tools import c_preproc, cxx
61
62
63 PCH_COMPILER_OPTIONS = {
64         'clang++': [['-include'], '.pch', ['-x', 'c++-header']],
65         'g++':     [['-include'], '.gch', ['-x', 'c++-header']],
66 }
67
68
69 def options(opt):
70         opt.add_option('--without-pch', action='store_false', default=True, dest='with_pch', help='''Try to use precompiled header to speed up compilation (only g++ and clang++)''')
71
72 def configure(conf):
73         if (conf.options.with_pch and conf.env['COMPILER_CXX'] in PCH_COMPILER_OPTIONS.keys()):
74                 conf.env.WITH_PCH = True
75                 flags = PCH_COMPILER_OPTIONS[conf.env['COMPILER_CXX']]
76                 conf.env.CXXPCH_F = flags[0]
77                 conf.env.CXXPCH_EXT = flags[1]
78                 conf.env.CXXPCH_FLAGS = flags[2]
79
80
81 @TaskGen.feature('pch')
82 @TaskGen.before('process_source')
83 def apply_pch(self):
84         if not self.env.WITH_PCH:
85                 return
86
87         if getattr(self.bld, 'pch_tasks', None) is None:
88                 self.bld.pch_tasks = {}
89
90         if getattr(self, 'headers', None) is None:
91                 return
92
93         self.headers = self.to_nodes(self.headers)
94
95         if getattr(self, 'name', None):
96                 try:
97                         task = self.bld.pch_tasks[self.name]
98                         self.bld.fatal("Duplicated 'pch' task with name %r" % self.name)
99                 except KeyError:
100                         pass
101
102         out = '%s.%d%s' % (self.target, self.idx, self.env['CXXPCH_EXT'])
103         out = self.path.find_or_declare(out)
104         task = self.create_task('gchx', self.headers, out)
105
106         # target should be an absolute path of `out`, but without precompiled header extension
107         task.target = out.abspath()[:-len(out.suffix())]
108
109         self.pch_task = task
110         if getattr(self, 'name', None):
111                 self.bld.pch_tasks[self.name] = task
112
113 @TaskGen.feature('cxx')
114 @TaskGen.after_method('process_source', 'propagate_uselib_vars')
115 def add_pch(self):
116         if not (self.env['WITH_PCH'] and getattr(self, 'use', None) and getattr(self, 'compiled_tasks', None) and getattr(self.bld, 'pch_tasks', None)):
117                 return
118
119         pch = None
120         # find pch task, if any
121
122         if getattr(self, 'pch_task', None):
123                 pch = self.pch_task
124         else:
125                 for use in Utils.to_list(self.use):
126                         try:
127                                 pch = self.bld.pch_tasks[use]
128                         except KeyError:
129                                 pass
130
131         if pch:
132                 for x in self.compiled_tasks:
133                         x.env.append_value('CXXFLAGS', self.env['CXXPCH_F'] + [pch.target])
134
135 class gchx(Task.Task):
136         run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CXXPCH_FLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXXPCH_F:SRC} ${CXX_SRC_F}${SRC[0].abspath()} ${CXX_TGT_F}${TGT[0].abspath()} ${CPPFLAGS}'
137         scan    = c_preproc.scan
138         color   = 'BLUE'
139         ext_out=['.h']
140
141         def runnable_status(self):
142                 try:
143                         node_deps = self.generator.bld.node_deps[self.uid()]
144                 except KeyError:
145                         node_deps = []
146                 ret = Task.Task.runnable_status(self)
147                 if ret == Task.SKIP_ME and self.env.CXX_NAME == 'clang':
148                         t = os.stat(self.outputs[0].abspath()).st_mtime
149                         for n in self.inputs + node_deps:
150                                 if os.stat(n.abspath()).st_mtime > t:
151                                         return Task.RUN_ME
152                 return ret