File indexing completed on 2025-05-11 08:24:54
0001
0002
0003
0004
0005 """
0006 Execute the tasks with gcc -MD, read the dependencies from the .d file
0007 and prepare the dependency calculation for the next run.
0008 This affects the cxx class, so make sure to load Qt5 after this tool.
0009
0010 Usage::
0011
0012 def options(opt):
0013 opt.load('compiler_cxx')
0014 def configure(conf):
0015 conf.load('compiler_cxx gccdeps')
0016 """
0017
0018 import os, re, threading
0019 from waflib import Task, Logs, Utils, Errors
0020 from waflib.Tools import asm, c, c_preproc, cxx
0021 from waflib.TaskGen import before_method, feature
0022
0023 lock = threading.Lock()
0024
0025 gccdeps_flags = ['-MD']
0026 if not c_preproc.go_absolute:
0027 gccdeps_flags = ['-MMD']
0028
0029
0030 supported_compilers = ['gas', 'gcc', 'icc', 'clang']
0031
0032 re_o = re.compile(r"\.o$")
0033 re_splitter = re.compile(r'(?<!\\)\s+')
0034
0035 def remove_makefile_rule_lhs(line):
0036
0037
0038
0039
0040 rulesep = ': '
0041
0042 sep_idx = line.find(rulesep)
0043 if sep_idx >= 0:
0044 return line[sep_idx + 2:]
0045 else:
0046 return line
0047
0048 def path_to_node(base_node, path, cached_nodes):
0049
0050
0051
0052 if getattr(path, '__hash__'):
0053 node_lookup_key = (base_node, path)
0054 else:
0055
0056 node_lookup_key = (base_node, os.path.sep.join(path))
0057
0058 try:
0059 node = cached_nodes[node_lookup_key]
0060 except KeyError:
0061
0062 with lock:
0063 try:
0064 node = cached_nodes[node_lookup_key]
0065 except KeyError:
0066 node = cached_nodes[node_lookup_key] = base_node.find_resource(path)
0067
0068 return node
0069
0070 def post_run(self):
0071 if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS:
0072 return super(self.derived_gccdeps, self).post_run()
0073
0074 deps_filename = self.outputs[0].abspath()
0075 deps_filename = re_o.sub('.d', deps_filename)
0076 try:
0077 deps_txt = Utils.readf(deps_filename)
0078 except EnvironmentError:
0079 Logs.error('Could not find a .d dependency file, are cflags/cxxflags overwritten?')
0080 raise
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 deps_txt = '\n'.join([remove_makefile_rule_lhs(line) for line in deps_txt.splitlines()])
0101
0102
0103 deps_txt = deps_txt.replace('\\\n', '')
0104
0105 dep_paths = deps_txt.strip()
0106 dep_paths = [x.replace('\\ ', ' ') for x in re_splitter.split(dep_paths) if x]
0107
0108 resolved_nodes = []
0109 unresolved_names = []
0110 bld = self.generator.bld
0111
0112
0113 try:
0114 cached_nodes = bld.cached_nodes
0115 except AttributeError:
0116 cached_nodes = bld.cached_nodes = {}
0117
0118 for path in dep_paths:
0119
0120 node = None
0121 if os.path.isabs(path):
0122 node = path_to_node(bld.root, path, cached_nodes)
0123 else:
0124
0125 base_node = getattr(bld, 'cwdx', bld.bldnode)
0126
0127 path = [k for k in Utils.split_path(path) if k and k != '.']
0128 while '..' in path:
0129 idx = path.index('..')
0130 if idx == 0:
0131 path = path[1:]
0132 base_node = base_node.parent
0133 else:
0134 del path[idx]
0135 del path[idx-1]
0136
0137 node = path_to_node(base_node, path, cached_nodes)
0138
0139 if not node:
0140 raise ValueError('could not find %r for %r' % (path, self))
0141
0142 if id(node) == id(self.inputs[0]):
0143
0144
0145 continue
0146
0147 resolved_nodes.append(node)
0148
0149 Logs.debug('deps: gccdeps for %s returned %s', self, resolved_nodes)
0150
0151 bld.node_deps[self.uid()] = resolved_nodes
0152 bld.raw_deps[self.uid()] = unresolved_names
0153
0154 try:
0155 del self.cache_sig
0156 except AttributeError:
0157 pass
0158
0159 Task.Task.post_run(self)
0160
0161 def scan(self):
0162 if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS:
0163 return super(self.derived_gccdeps, self).scan()
0164
0165 resolved_nodes = self.generator.bld.node_deps.get(self.uid(), [])
0166 unresolved_names = []
0167 return (resolved_nodes, unresolved_names)
0168
0169 def sig_implicit_deps(self):
0170 if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS:
0171 return super(self.derived_gccdeps, self).sig_implicit_deps()
0172 bld = self.generator.bld
0173
0174 try:
0175 return self.compute_sig_implicit_deps()
0176 except Errors.TaskNotReady:
0177 raise ValueError("Please specify the build order precisely with gccdeps (asm/c/c++ tasks)")
0178 except EnvironmentError:
0179
0180 for x in bld.node_deps.get(self.uid(), []):
0181 if not x.is_bld() and not x.exists():
0182 try:
0183 del x.parent.children[x.name]
0184 except KeyError:
0185 pass
0186
0187 key = self.uid()
0188 bld.node_deps[key] = []
0189 bld.raw_deps[key] = []
0190 return Utils.SIG_NIL
0191
0192 def wrap_compiled_task(classname):
0193 derived_class = type(classname, (Task.classes[classname],), {})
0194 derived_class.derived_gccdeps = derived_class
0195 derived_class.post_run = post_run
0196 derived_class.scan = scan
0197 derived_class.sig_implicit_deps = sig_implicit_deps
0198
0199 for k in ('asm', 'c', 'cxx'):
0200 if k in Task.classes:
0201 wrap_compiled_task(k)
0202
0203 @before_method('process_source')
0204 @feature('force_gccdeps')
0205 def force_gccdeps(self):
0206 self.env.ENABLE_GCCDEPS = ['asm', 'c', 'cxx']
0207
0208 def configure(conf):
0209
0210 if not getattr(conf.options, 'enable_gccdeps', True):
0211 return
0212
0213 global gccdeps_flags
0214 flags = conf.env.GCCDEPS_FLAGS or gccdeps_flags
0215 if conf.env.ASM_NAME in supported_compilers:
0216 try:
0217 conf.check(fragment='', features='asm force_gccdeps', asflags=flags, compile_filename='test.S', msg='Checking for asm flags %r' % ''.join(flags))
0218 except Errors.ConfigurationError:
0219 pass
0220 else:
0221 conf.env.append_value('ASFLAGS', flags)
0222 conf.env.append_unique('ENABLE_GCCDEPS', 'asm')
0223
0224 if conf.env.CC_NAME in supported_compilers:
0225 try:
0226 conf.check(fragment='int main() { return 0; }', features='c force_gccdeps', cflags=flags, msg='Checking for c flags %r' % ''.join(flags))
0227 except Errors.ConfigurationError:
0228 pass
0229 else:
0230 conf.env.append_value('CFLAGS', flags)
0231 conf.env.append_unique('ENABLE_GCCDEPS', 'c')
0232
0233 if conf.env.CXX_NAME in supported_compilers:
0234 try:
0235 conf.check(fragment='int main() { return 0; }', features='cxx force_gccdeps', cxxflags=flags, msg='Checking for cxx flags %r' % ''.join(flags))
0236 except Errors.ConfigurationError:
0237 pass
0238 else:
0239 conf.env.append_value('CXXFLAGS', flags)
0240 conf.env.append_unique('ENABLE_GCCDEPS', 'cxx')
0241
0242 def options(opt):
0243 raise ValueError('Do not load gccdeps options')
0244