Belle II Software light-2406-ragdoll
compilation_db.py
1# Adapted from
2# https://github.com/mongodb/mongo/blob/8dd6d4755734ed37c1b98dfdefce3ca6bc65f1f6/site_scons/site_tools/compilation_db.py
3
4# Copyright 2015 MongoDB Inc.
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18import json
19import SCons
20import itertools
21
22# Implements the ability for SCons to emit a compilation database for the MongoDB project. See
23# http://clang.llvm.org/docs/JSONCompilationDatabase.html for details on what a compilation
24# database is, and why you might want one. The only user visible entry point here is
25# 'env.CompilationDatabase'. This method takes an optional 'target' to name the file that
26# should hold the compilation database, otherwise, the file defaults to compile_commands.json,
27# which is the name that most clang tools search for by default.
28
29# TODO: Is there a better way to do this than this global? Right now this exists so that the
30# emitter we add can record all of the things it emits, so that the scanner for the top level
31# compilation database can access the complete list, and also so that the writer has easy
32# access to write all of the files. But it seems clunky. How can the emitter and the scanner
33# communicate more gracefully?
34__COMPILATION_DB_ENTRIES = []
35
36# Cribbed from Tool/cc.py and Tool/c++.py. It would be better if
37# we could obtain this from SCons.
38_CSuffixes = ['.c']
39if not SCons.Util.case_sensitive_suffixes('.c', '.C'):
40 _CSuffixes.append('.C')
41
42_CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++']
43if SCons.Util.case_sensitive_suffixes('.c', '.C'):
44 _CXXSuffixes.append('.C')
45
46
47# We make no effort to avoid rebuilding the entries. Someday, perhaps we could and even
48# integrate with the cache, but there doesn't seem to be much call for it.
49class __CompilationDbNode(SCons.Node.Python.Value):
50 def __init__(self, value):
51 SCons.Node.Python.Value.__init__(self, value)
52 self.Decider(changed_since_last_build_node)
53
54
55def changed_since_last_build_node(node, target, prev_ni, repo_node=None):
56 """ Dummy decider to force alwasy building"""
57 return True
58
59
60def makeEmitCompilationDbEntry(comstr):
61 """
62 Effectively this creates a lambda function to capture:
63 * command line
64 * source
65 * target
66 :param comstr: unevaluated command line
67 :return: an emitter which has captured the above
68 """
69 user_action = SCons.Action.Action(comstr)
70
71 def EmitCompilationDbEntry(target, source, env):
72 """
73 This emitter will be added to each c/c++ object build to capture the info needed
74 for clang tools
75 :param target: target node(s)
76 :param source: source node(s)
77 :param env: Environment for use building this node
78 :return: target(s), source(s)
79 """
80
81 dbtarget = __CompilationDbNode(source)
82
83 entry = env.__COMPILATIONDB_Entry(
84 target=dbtarget, source=[], __COMPILATIONDB_UTARGET=target,
85 __COMPILATIONDB_USOURCE=source, __COMPILATIONDB_UACTION=user_action,
86 __COMPILATIONDB_ENV=env)
87
88 # TODO: Technically, these next two lines should not be required: it should be fine to
89 # cache the entries. However, they don't seem to update properly. Since they are quick
90 # to re-generate disable caching and sidestep this problem.
91 env.AlwaysBuild(entry)
92 env.NoCache(entry)
93
94 __COMPILATION_DB_ENTRIES.append(dbtarget)
95
96 return target, source
97
98 return EmitCompilationDbEntry
99
100
101def CompilationDbEntryAction(target, source, env, **kw):
102 """
103 Create a dictionary with evaluated command line, target, source
104 and store that info as an attribute on the target
105 (Which has been stored in __COMPILATION_DB_ENTRIES array
106 :param target: target node(s)
107 :param source: source node(s)
108 :param env: Environment for use building this node
109 :param kw:
110 :return: None
111 """
112
113 command = env['__COMPILATIONDB_UACTION'].strfunction(
114 target=env['__COMPILATIONDB_UTARGET'],
115 source=env['__COMPILATIONDB_USOURCE'],
116 env=env['__COMPILATIONDB_ENV'],
117 )
118
119 entry = {
120 "directory": env.Dir('#').abspath, "command": command,
121 "file": str(env['__COMPILATIONDB_USOURCE'][0])
122 }
123
124 target[0].write(entry)
125
126
127def WriteCompilationDb(target, source, env):
128 entries = []
129
130 for s in __COMPILATION_DB_ENTRIES:
131 entries.append(s.read())
132
133 with open(str(target[0]), 'w') as target_file:
134 json.dump(entries, target_file, sort_keys=True, indent=4, separators=(',', ': '))
135
136
137def ScanCompilationDb(node, env, path):
138 return __COMPILATION_DB_ENTRIES
139
140
141def generate(env, **kwargs):
142
143 static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
144
145 env['COMPILATIONDB_COMSTR'] = kwargs.get('COMPILATIONDB_COMSTR',
146 'Building compilation database $TARGET')
147
148 components_by_suffix = itertools.chain(
149 itertools.product(_CSuffixes, [
150 (static_obj, SCons.Defaults.StaticObjectEmitter, '$CCCOM'),
151 (shared_obj, SCons.Defaults.SharedObjectEmitter, '$SHCCCOM'),
152 ]),
153 itertools.product(_CXXSuffixes, [
154 (static_obj, SCons.Defaults.StaticObjectEmitter, '$CXXCOM'),
155 (shared_obj, SCons.Defaults.SharedObjectEmitter, '$SHCXXCOM'),
156 ]),
157 )
158
159 for entry in components_by_suffix:
160 suffix = entry[0]
161 builder, base_emitter, command = entry[1]
162
163 # Assumes a dictionary emitter
164 emitter = builder.emitter[suffix]
165 builder.emitter[suffix] = SCons.Builder.ListEmitter([
166 emitter,
167 makeEmitCompilationDbEntry(command),
168 ])
169
170 env['BUILDERS']['__COMPILATIONDB_Entry'] = SCons.Builder.Builder(
171 action=SCons.Action.Action(CompilationDbEntryAction, None), )
172
173 env['BUILDERS']['__COMPILATIONDB_Database'] = SCons.Builder.Builder(
174 action=SCons.Action.Action(WriteCompilationDb, "$COMPILATIONDB_COMSTR"),
175 target_scanner=SCons.Scanner.Scanner(function=ScanCompilationDb, node_class=None))
176
177 def CompilationDatabase(env, target):
178 result = env.__COMPILATIONDB_Database(target=target, source=[])
179
180 env.AlwaysBuild(result)
181 env.NoCache(result)
182
183 return result
184
185 env.AddMethod(CompilationDatabase, 'CompilationDatabase')
186
187
188def exists(env):
189 return True