jolt 0.9.76__py3-none-any.whl → 0.9.429__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jolt/__init__.py +88 -7
- jolt/__main__.py +9 -1
- jolt/bin/fstree-darwin-x86_64 +0 -0
- jolt/bin/fstree-linux-x86_64 +0 -0
- jolt/cache.py +839 -367
- jolt/chroot.py +156 -0
- jolt/cli.py +362 -143
- jolt/common_pb2.py +63 -0
- jolt/common_pb2_grpc.py +4 -0
- jolt/config.py +99 -42
- jolt/error.py +19 -4
- jolt/expires.py +2 -2
- jolt/filesystem.py +8 -6
- jolt/graph.py +705 -117
- jolt/hooks.py +63 -1
- jolt/influence.py +129 -6
- jolt/loader.py +369 -121
- jolt/log.py +225 -63
- jolt/manifest.py +28 -38
- jolt/options.py +35 -10
- jolt/pkgs/abseil.py +42 -0
- jolt/pkgs/asio.py +25 -0
- jolt/pkgs/autoconf.py +41 -0
- jolt/pkgs/automake.py +41 -0
- jolt/pkgs/b2.py +31 -0
- jolt/pkgs/boost.py +111 -0
- jolt/pkgs/boringssl.py +32 -0
- jolt/pkgs/busybox.py +39 -0
- jolt/pkgs/bzip2.py +43 -0
- jolt/pkgs/cares.py +29 -0
- jolt/pkgs/catch2.py +36 -0
- jolt/pkgs/cbindgen.py +17 -0
- jolt/pkgs/cista.py +19 -0
- jolt/pkgs/clang.py +44 -0
- jolt/pkgs/cli11.py +23 -0
- jolt/pkgs/cmake.py +48 -0
- jolt/pkgs/cpython.py +196 -0
- jolt/pkgs/crun.py +29 -0
- jolt/pkgs/curl.py +38 -0
- jolt/pkgs/dbus.py +18 -0
- jolt/pkgs/double_conversion.py +24 -0
- jolt/pkgs/fastfloat.py +21 -0
- jolt/pkgs/ffmpeg.py +28 -0
- jolt/pkgs/flatbuffers.py +29 -0
- jolt/pkgs/fmt.py +27 -0
- jolt/pkgs/fstree.py +20 -0
- jolt/pkgs/gflags.py +18 -0
- jolt/pkgs/glib.py +18 -0
- jolt/pkgs/glog.py +25 -0
- jolt/pkgs/glslang.py +21 -0
- jolt/pkgs/golang.py +16 -11
- jolt/pkgs/googlebenchmark.py +18 -0
- jolt/pkgs/googletest.py +46 -0
- jolt/pkgs/gperf.py +15 -0
- jolt/pkgs/grpc.py +73 -0
- jolt/pkgs/hdf5.py +19 -0
- jolt/pkgs/help2man.py +14 -0
- jolt/pkgs/inja.py +28 -0
- jolt/pkgs/jsoncpp.py +31 -0
- jolt/pkgs/libarchive.py +43 -0
- jolt/pkgs/libcap.py +44 -0
- jolt/pkgs/libdrm.py +44 -0
- jolt/pkgs/libedit.py +42 -0
- jolt/pkgs/libevent.py +31 -0
- jolt/pkgs/libexpat.py +27 -0
- jolt/pkgs/libfastjson.py +21 -0
- jolt/pkgs/libffi.py +16 -0
- jolt/pkgs/libglvnd.py +30 -0
- jolt/pkgs/libogg.py +28 -0
- jolt/pkgs/libpciaccess.py +18 -0
- jolt/pkgs/libseccomp.py +21 -0
- jolt/pkgs/libtirpc.py +24 -0
- jolt/pkgs/libtool.py +42 -0
- jolt/pkgs/libunwind.py +35 -0
- jolt/pkgs/libva.py +18 -0
- jolt/pkgs/libvorbis.py +33 -0
- jolt/pkgs/libxml2.py +35 -0
- jolt/pkgs/libxslt.py +17 -0
- jolt/pkgs/libyajl.py +16 -0
- jolt/pkgs/llvm.py +81 -0
- jolt/pkgs/lua.py +54 -0
- jolt/pkgs/lz4.py +26 -0
- jolt/pkgs/m4.py +14 -0
- jolt/pkgs/make.py +17 -0
- jolt/pkgs/mesa.py +81 -0
- jolt/pkgs/meson.py +17 -0
- jolt/pkgs/mstch.py +28 -0
- jolt/pkgs/mysql.py +60 -0
- jolt/pkgs/nasm.py +49 -0
- jolt/pkgs/ncurses.py +30 -0
- jolt/pkgs/ng_log.py +25 -0
- jolt/pkgs/ninja.py +45 -0
- jolt/pkgs/nlohmann_json.py +25 -0
- jolt/pkgs/nodejs.py +19 -11
- jolt/pkgs/opencv.py +24 -0
- jolt/pkgs/openjdk.py +26 -0
- jolt/pkgs/openssl.py +103 -0
- jolt/pkgs/paho.py +76 -0
- jolt/pkgs/patchelf.py +16 -0
- jolt/pkgs/perl.py +42 -0
- jolt/pkgs/pkgconfig.py +64 -0
- jolt/pkgs/poco.py +39 -0
- jolt/pkgs/protobuf.py +77 -0
- jolt/pkgs/pugixml.py +27 -0
- jolt/pkgs/python.py +19 -0
- jolt/pkgs/qt.py +35 -0
- jolt/pkgs/rapidjson.py +26 -0
- jolt/pkgs/rapidyaml.py +28 -0
- jolt/pkgs/re2.py +30 -0
- jolt/pkgs/re2c.py +17 -0
- jolt/pkgs/readline.py +15 -0
- jolt/pkgs/rust.py +41 -0
- jolt/pkgs/sdl.py +28 -0
- jolt/pkgs/simdjson.py +27 -0
- jolt/pkgs/soci.py +46 -0
- jolt/pkgs/spdlog.py +29 -0
- jolt/pkgs/spirv_llvm.py +21 -0
- jolt/pkgs/spirv_tools.py +24 -0
- jolt/pkgs/sqlite.py +83 -0
- jolt/pkgs/ssl.py +12 -0
- jolt/pkgs/texinfo.py +15 -0
- jolt/pkgs/tomlplusplus.py +22 -0
- jolt/pkgs/wayland.py +26 -0
- jolt/pkgs/x11.py +58 -0
- jolt/pkgs/xerces_c.py +20 -0
- jolt/pkgs/xorg.py +360 -0
- jolt/pkgs/xz.py +29 -0
- jolt/pkgs/yamlcpp.py +30 -0
- jolt/pkgs/zeromq.py +47 -0
- jolt/pkgs/zlib.py +69 -0
- jolt/pkgs/zstd.py +33 -0
- jolt/plugins/alias.py +3 -0
- jolt/plugins/allure.py +5 -2
- jolt/plugins/autotools.py +66 -0
- jolt/plugins/cache.py +133 -0
- jolt/plugins/cmake.py +74 -6
- jolt/plugins/conan.py +238 -0
- jolt/plugins/cxx.py +698 -0
- jolt/plugins/cxxinfo.py +7 -0
- jolt/plugins/dashboard.py +1 -1
- jolt/plugins/docker.py +91 -23
- jolt/plugins/email.py +5 -2
- jolt/plugins/email.xslt +144 -101
- jolt/plugins/environ.py +11 -0
- jolt/plugins/fetch.py +141 -0
- jolt/plugins/gdb.py +44 -21
- jolt/plugins/gerrit.py +1 -14
- jolt/plugins/git.py +316 -101
- jolt/plugins/googletest.py +522 -1
- jolt/plugins/http.py +36 -38
- jolt/plugins/libtool.py +63 -0
- jolt/plugins/linux.py +990 -0
- jolt/plugins/logstash.py +4 -4
- jolt/plugins/meson.py +61 -0
- jolt/plugins/ninja-compdb.py +107 -31
- jolt/plugins/ninja.py +929 -134
- jolt/plugins/paths.py +11 -1
- jolt/plugins/pkgconfig.py +219 -0
- jolt/plugins/podman.py +148 -91
- jolt/plugins/python.py +137 -0
- jolt/plugins/remote_execution/__init__.py +0 -0
- jolt/plugins/remote_execution/administration_pb2.py +46 -0
- jolt/plugins/remote_execution/administration_pb2_grpc.py +170 -0
- jolt/plugins/remote_execution/log_pb2.py +32 -0
- jolt/plugins/remote_execution/log_pb2_grpc.py +68 -0
- jolt/plugins/remote_execution/scheduler_pb2.py +41 -0
- jolt/plugins/remote_execution/scheduler_pb2_grpc.py +141 -0
- jolt/plugins/remote_execution/worker_pb2.py +38 -0
- jolt/plugins/remote_execution/worker_pb2_grpc.py +112 -0
- jolt/plugins/report.py +12 -2
- jolt/plugins/rust.py +25 -0
- jolt/plugins/scheduler.py +710 -0
- jolt/plugins/selfdeploy/setup.py +9 -4
- jolt/plugins/selfdeploy.py +138 -88
- jolt/plugins/strings.py +35 -22
- jolt/plugins/symlinks.py +26 -11
- jolt/plugins/telemetry.py +5 -2
- jolt/plugins/timeline.py +13 -3
- jolt/plugins/volume.py +46 -48
- jolt/scheduler.py +591 -191
- jolt/tasks.py +1783 -245
- jolt/templates/export.sh.template +12 -6
- jolt/templates/timeline.html.template +44 -47
- jolt/timer.py +22 -0
- jolt/tools.py +749 -302
- jolt/utils.py +245 -18
- jolt/version.py +1 -1
- jolt/version_utils.py +2 -2
- jolt/xmldom.py +12 -2
- {jolt-0.9.76.dist-info → jolt-0.9.429.dist-info}/METADATA +98 -38
- jolt-0.9.429.dist-info/RECORD +207 -0
- {jolt-0.9.76.dist-info → jolt-0.9.429.dist-info}/WHEEL +1 -1
- jolt/plugins/amqp.py +0 -834
- jolt/plugins/debian.py +0 -338
- jolt/plugins/ftp.py +0 -181
- jolt/plugins/ninja-cache.py +0 -64
- jolt/plugins/ninjacli.py +0 -271
- jolt/plugins/repo.py +0 -253
- jolt-0.9.76.dist-info/RECORD +0 -79
- {jolt-0.9.76.dist-info → jolt-0.9.429.dist-info}/entry_points.txt +0 -0
- {jolt-0.9.76.dist-info → jolt-0.9.429.dist-info}/top_level.txt +0 -0
jolt/plugins/ninja.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
from collections import OrderedDict
|
|
2
|
+
import contextlib
|
|
1
3
|
import copy
|
|
2
|
-
import
|
|
4
|
+
import functools
|
|
5
|
+
from ninja import ninja_syntax as ninja
|
|
3
6
|
import os
|
|
7
|
+
import platform
|
|
8
|
+
import re
|
|
4
9
|
import sys
|
|
5
10
|
|
|
6
11
|
from jolt.tasks import Task, attributes as task_attributes
|
|
@@ -8,16 +13,27 @@ from jolt import config
|
|
|
8
13
|
from jolt.influence import attribute as influence_attribute
|
|
9
14
|
from jolt.influence import DirectoryInfluence, FileInfluence
|
|
10
15
|
from jolt.influence import HashInfluenceProvider, TaskAttributeInfluence
|
|
16
|
+
from jolt.config import get_cachedir
|
|
11
17
|
from jolt import log
|
|
12
18
|
from jolt import utils
|
|
13
19
|
from jolt import filesystem as fs
|
|
20
|
+
from jolt.error import raise_task_error
|
|
14
21
|
from jolt.error import raise_task_error_if
|
|
15
22
|
from jolt.error import JoltError, JoltCommandError
|
|
16
23
|
|
|
17
24
|
|
|
25
|
+
c_standard_default = 17
|
|
26
|
+
cxx_standard_default = 17
|
|
27
|
+
c_standards_list = [90, 99, 11, 17, 23]
|
|
28
|
+
cxx_standards_list = [98, 11, 14, 17, 20, 23, 26]
|
|
29
|
+
|
|
30
|
+
|
|
18
31
|
class CompileError(JoltError):
|
|
19
|
-
def __init__(self):
|
|
20
|
-
|
|
32
|
+
def __init__(self, error):
|
|
33
|
+
if error:
|
|
34
|
+
super().__init__(f"{error.type}: {error.location}: {error.message}")
|
|
35
|
+
else:
|
|
36
|
+
super().__init__("Compilation failed")
|
|
21
37
|
|
|
22
38
|
|
|
23
39
|
class attributes:
|
|
@@ -34,6 +50,7 @@ class attributes:
|
|
|
34
50
|
Keywords are expanded.
|
|
35
51
|
prepend (boolean): Prepend the value of the alternative
|
|
36
52
|
attribute. Default: false (append).
|
|
53
|
+
|
|
37
54
|
"""
|
|
38
55
|
return utils.concat_attributes("asflags", attrib, prepend)
|
|
39
56
|
|
|
@@ -50,9 +67,438 @@ class attributes:
|
|
|
50
67
|
Keywords are expanded.
|
|
51
68
|
prepend (boolean): Prepend the value of the alternative
|
|
52
69
|
attribute. Default: false (append).
|
|
70
|
+
|
|
53
71
|
"""
|
|
54
72
|
return utils.concat_attributes("cflags", attrib, prepend)
|
|
55
73
|
|
|
74
|
+
@staticmethod
|
|
75
|
+
def coverage_data(publish=True):
|
|
76
|
+
"""Task decorator collecting coverage data files (.gcda) from instrumented executables.
|
|
77
|
+
|
|
78
|
+
The decorator sets the ``GCOV_PREFIX`` environment variable
|
|
79
|
+
during execution of the task. Data files generated by
|
|
80
|
+
instrumented executable are then collected into a dedicated
|
|
81
|
+
build directory and published upon completion of the task.
|
|
82
|
+
|
|
83
|
+
The decorator also republishes coverage note files found in
|
|
84
|
+
dependency artifacts.
|
|
85
|
+
|
|
86
|
+
The task artifact is annotated with
|
|
87
|
+
``artifact.paths.coverage_data`` which points out the path to
|
|
88
|
+
the data files within the artifact.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
publish (boolean): Publish coverage data with artifact.
|
|
92
|
+
Default: True.
|
|
93
|
+
|
|
94
|
+
Example:
|
|
95
|
+
|
|
96
|
+
.. literalinclude:: ../examples/code_coverage/coverage.jolt
|
|
97
|
+
:language: python
|
|
98
|
+
:caption: examples/code_coverage/coverage.jolt
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def decorate(cls):
|
|
103
|
+
class CoverageDataMixin(object):
|
|
104
|
+
@contextlib.contextmanager
|
|
105
|
+
def run_coverage_data(self, deps, tools):
|
|
106
|
+
self.covdatadir = tools.builddir("coverage-data")
|
|
107
|
+
self.info("Collecting coverage data into {covdatadir}")
|
|
108
|
+
|
|
109
|
+
for _, artifact in deps.items():
|
|
110
|
+
if artifact.paths.coverage_data:
|
|
111
|
+
tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
|
|
112
|
+
|
|
113
|
+
with tools.environ(GCOV_PREFIX=self.covdatadir):
|
|
114
|
+
yield
|
|
115
|
+
|
|
116
|
+
@utils.cached.instance
|
|
117
|
+
def publish_coverage_data(self, artifact, tools):
|
|
118
|
+
if not publish:
|
|
119
|
+
return
|
|
120
|
+
|
|
121
|
+
self.verbose("Publishing coverage data from {covdatadir}")
|
|
122
|
+
with tools.cwd(self.covdatadir):
|
|
123
|
+
if artifact.collect("**/*.gc*", "cov/"):
|
|
124
|
+
artifact.paths.coverage_data = "cov"
|
|
125
|
+
|
|
126
|
+
class CoverageData(cls, CoverageDataMixin):
|
|
127
|
+
@functools.wraps(cls.run)
|
|
128
|
+
def run(self, deps, tools):
|
|
129
|
+
with self.run_coverage_data(deps, tools):
|
|
130
|
+
super().run(deps, tools)
|
|
131
|
+
|
|
132
|
+
def publish_coverage_data(self, artifact, tools):
|
|
133
|
+
CoverageDataMixin.publish_coverage_data(self, artifact, tools)
|
|
134
|
+
|
|
135
|
+
@functools.wraps(cls.publish)
|
|
136
|
+
def publish(self, artifact, tools):
|
|
137
|
+
super().publish(artifact, tools)
|
|
138
|
+
if publish:
|
|
139
|
+
self.publish_coverage_data(artifact, tools)
|
|
140
|
+
|
|
141
|
+
CoverageData.__doc__ = cls.__doc__
|
|
142
|
+
CoverageData.__name__ = cls.__name__
|
|
143
|
+
return CoverageData
|
|
144
|
+
|
|
145
|
+
return decorate
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
def coverage_report_gcov(branches=True, demangle=True, coverage_data=False):
|
|
149
|
+
"""Decorator generating gcov reports from collected coverage data.
|
|
150
|
+
|
|
151
|
+
A gcov report file is generated for each instrumented source
|
|
152
|
+
file in the executable. The reports consists of plain-text
|
|
153
|
+
source code annotated with code coverage details.
|
|
154
|
+
|
|
155
|
+
The decorator can be used standalone or in combination with
|
|
156
|
+
:func:`coverage_data`. In either case, coverage data is
|
|
157
|
+
collected from dependency artifacts and processed together
|
|
158
|
+
with any data generated by the task itself.
|
|
159
|
+
|
|
160
|
+
The following class attributes may be set to control the behavior
|
|
161
|
+
of lcov:
|
|
162
|
+
|
|
163
|
+
- ``gcov_branches`` - Enable branch coverage.
|
|
164
|
+
Passed as ``-b`` on the command line. Default: ``True``
|
|
165
|
+
- ``gcov_demangle`` - Display demangled function names in output.
|
|
166
|
+
Passed as ``-m`` on the command line. Default: ``True``
|
|
167
|
+
|
|
168
|
+
The task artifact is annotated with
|
|
169
|
+
``artifact.paths.coverage_report_gcov`` which points out the
|
|
170
|
+
path to the gcov reports within the artifact.
|
|
171
|
+
|
|
172
|
+
A gcov executable must exist in PATH. Set the ``GCOV`` environment
|
|
173
|
+
variable to override its default name.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
branches (boolean): Enable branch coverage. Default: True.
|
|
177
|
+
Overridden by class attribute ``gcov_branches``, if set.
|
|
178
|
+
demangle (boolean): Display demangled function names in output. Default: True.
|
|
179
|
+
Overridden by class attribute ``gcov_demangle``, if set.
|
|
180
|
+
coverage_data (boolean): Republish coverage data found in
|
|
181
|
+
dependency artifacts. Default: ``False``
|
|
182
|
+
Overridden by class attribute ``gcov_coverage_data``, if set.
|
|
183
|
+
|
|
184
|
+
Example:
|
|
185
|
+
|
|
186
|
+
.. literalinclude:: ../examples/code_coverage/coverage.jolt
|
|
187
|
+
:language: python
|
|
188
|
+
:caption: examples/code_coverage/coverage.jolt
|
|
189
|
+
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
def decorate(cls):
|
|
193
|
+
class CoverageReportGcovMixin(object):
|
|
194
|
+
def run_coverage_report_gcov(self, deps, tools):
|
|
195
|
+
self.info("Generating GCOV code coverage report")
|
|
196
|
+
|
|
197
|
+
gcov = tools.getenv("GCOV", tools.getenv("CROSS_COMPILE", "") + "gcov")
|
|
198
|
+
if not tools.which(gcov):
|
|
199
|
+
raise_task_error(self, "gcov not found in PATH, cannot generate coverage report.")
|
|
200
|
+
|
|
201
|
+
# Assume data is already copied by coverage_data() if the covdatadir exists,
|
|
202
|
+
# otherwise copy it from dependency artifacts.
|
|
203
|
+
if not hasattr(self, "covdatadir"):
|
|
204
|
+
self.covdatadir = tools.builddir("coverage-data")
|
|
205
|
+
for _, artifact in deps.items():
|
|
206
|
+
if artifact.paths.coverage_data:
|
|
207
|
+
tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
|
|
208
|
+
|
|
209
|
+
with tools.cwd(self.covdatadir):
|
|
210
|
+
datafiles = tools.glob("**/*.gcda")
|
|
211
|
+
|
|
212
|
+
reportdir = tools.builddir("coverage-report-gcov")
|
|
213
|
+
|
|
214
|
+
with tools.cwd(tools.wsroot):
|
|
215
|
+
for file in datafiles:
|
|
216
|
+
infile = os.path.join(self.covdatadir, file)
|
|
217
|
+
branchflag = "-b " if bool(getattr(self, "gcov_branches", branches)) else ""
|
|
218
|
+
demangleflag = "-m " if bool(getattr(self, "gcov_demangle", demangle)) else ""
|
|
219
|
+
output = tools.run(
|
|
220
|
+
"{} {}{}-t -p -s {covdatadir} {}",
|
|
221
|
+
gcov, branchflag, demangleflag, infile, output_on_error=True)
|
|
222
|
+
output = output.replace(self.covdatadir, "")
|
|
223
|
+
source = re.search(r"0:Source:(.*)", output)
|
|
224
|
+
if not source:
|
|
225
|
+
self.warning(f"No source file found in gcov output for {file}")
|
|
226
|
+
continue
|
|
227
|
+
report = source.group(1) + ".gcov"
|
|
228
|
+
report_path = os.path.join(reportdir, report)
|
|
229
|
+
tools.mkdirname(report_path)
|
|
230
|
+
tools.write_file(report_path, output, expand=False)
|
|
231
|
+
|
|
232
|
+
@utils.cached.instance
|
|
233
|
+
def publish_coverage_data(self, artifact, tools):
|
|
234
|
+
if not bool(getattr(self, "gcov_coverage_data", coverage_data)):
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
self.verbose("Publishing coverage data from {covdatadir}")
|
|
238
|
+
with tools.cwd(self.covdatadir):
|
|
239
|
+
if artifact.collect("**/*.gc*", "cov/"):
|
|
240
|
+
artifact.paths.coverage_data = "cov"
|
|
241
|
+
|
|
242
|
+
def publish_coverage_report_gcov(self, artifact, tools):
|
|
243
|
+
with tools.cwd(tools.builddir("coverage-report-gcov")):
|
|
244
|
+
artifact.collect("*", "report/gcov/")
|
|
245
|
+
artifact.paths.coverage_report_gcov = "report/gcov"
|
|
246
|
+
|
|
247
|
+
class CoverageReportGcov(cls, CoverageReportGcovMixin):
|
|
248
|
+
@functools.wraps(cls.run)
|
|
249
|
+
def run(self, deps, tools):
|
|
250
|
+
super().run(deps, tools)
|
|
251
|
+
self.run_coverage_report_gcov(deps, tools)
|
|
252
|
+
|
|
253
|
+
def publish_coverage_data(self, artifact, tools):
|
|
254
|
+
CoverageReportGcovMixin.publish_coverage_data(self, artifact, tools)
|
|
255
|
+
|
|
256
|
+
@functools.wraps(cls.publish)
|
|
257
|
+
def publish(self, artifact, tools):
|
|
258
|
+
super().publish(artifact, tools)
|
|
259
|
+
self.publish_coverage_report_gcov(artifact, tools)
|
|
260
|
+
if bool(getattr(self, "gcov_coverage_data", coverage_data)):
|
|
261
|
+
self.publish_coverage_data(artifact, tools)
|
|
262
|
+
|
|
263
|
+
CoverageReportGcov.__doc__ = cls.__doc__
|
|
264
|
+
CoverageReportGcov.__name__ = cls.__name__
|
|
265
|
+
return CoverageReportGcov
|
|
266
|
+
|
|
267
|
+
return decorate
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def coverage_report_lcov(branches=True, demangle=True, html=True, coverage_data=False):
|
|
271
|
+
"""Decorator generating HTML reports from collected coverage data.
|
|
272
|
+
|
|
273
|
+
A single lcov coverage information file is always generated
|
|
274
|
+
and published. The corresponding HTML report is optional but
|
|
275
|
+
enabled by default. Disabling can save time if the coverage
|
|
276
|
+
information have to be merged with info from other tasks in
|
|
277
|
+
order for an HTML report to be useful.
|
|
278
|
+
|
|
279
|
+
The decorator can be used standalone or in combination with
|
|
280
|
+
:func:`coverage_data`. In either case, gcov coverage data as
|
|
281
|
+
well as lcov coverage data is collected from dependency
|
|
282
|
+
artifacts and processed together with data generated by the
|
|
283
|
+
task itself.
|
|
284
|
+
|
|
285
|
+
The following class attributes may be set to control the behavior
|
|
286
|
+
of lcov:
|
|
287
|
+
|
|
288
|
+
- ``lcov_branches`` - Enable branch coverage. Sets lcov configs
|
|
289
|
+
``branch_coverage=1`` and ``no_exception_branch=1``. Default: ``True``
|
|
290
|
+
- ``lcov_configs`` - List of lcov configs to set. Passed as ``--rc <config>``
|
|
291
|
+
on the command line. Default: ``[]``
|
|
292
|
+
- ``lcov_demangle`` - Display demangled function names in output.
|
|
293
|
+
Passed as ``--demangle-cpp`` on the command line. Default: ``True``
|
|
294
|
+
- ``lcov_exclude`` - List of files to exclude from the report.
|
|
295
|
+
Wildcards may be used. Passed as ``--exclude`` on the command line.
|
|
296
|
+
Default: ``[]``
|
|
297
|
+
- ``lcov_filters`` - List of filters. Passed as ``--filter`` on
|
|
298
|
+
the command line. Default: ``[brace, branch, range]``
|
|
299
|
+
- ``lcov_html`` - Enable/disable HTML report generation. Default: ``True``
|
|
300
|
+
- ``lcov_ignore_errors`` - List of errors to ignore.
|
|
301
|
+
Sets lcov config ``ignore_errors``. Default: ``[empty, mismatch, source, unused]``
|
|
302
|
+
- ``lcov_coverage_data`` - Republish raw gcov coverage data. Default: ``False``
|
|
303
|
+
|
|
304
|
+
The task artifact is annotated with:
|
|
305
|
+
|
|
306
|
+
- ``artifact.paths.coverage_report_lcov`` which points out the
|
|
307
|
+
path to the resulting coverage.info file in the artifact.
|
|
308
|
+
- ``artifact.paths.coverage_report_html`` which points out the
|
|
309
|
+
path to the resulting HTML files in the artifact.
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
A gcov and an lcov executable must exist in PATH. Set the ``GCOV``
|
|
313
|
+
and/or the ``LCOV`` environment variables to override their default names.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
branches (boolean): Enable branch coverage. Default: ``True``.
|
|
317
|
+
Overridden by class attribute ``lcov_branches``, if set.
|
|
318
|
+
demangle (boolean): Display demangled function names in output.
|
|
319
|
+
Default: ``True``. Overridden by class attribute ``lcov_demangle``,
|
|
320
|
+
if set.
|
|
321
|
+
html (boolean): Generate an HTML report. Default: ``True``.
|
|
322
|
+
Overridden by class attribute ``lcov_html``, if set.
|
|
323
|
+
coverage_data (boolean): Republish coverage data found in
|
|
324
|
+
dependency artifacts. Default: ``False``
|
|
325
|
+
Overridden by class attribute ``lcov_coverage_data``, if set.
|
|
326
|
+
|
|
327
|
+
Example:
|
|
328
|
+
|
|
329
|
+
.. literalinclude:: ../examples/code_coverage/coverage.jolt
|
|
330
|
+
:language: python
|
|
331
|
+
:caption: examples/code_coverage/coverage.jolt
|
|
332
|
+
|
|
333
|
+
"""
|
|
334
|
+
|
|
335
|
+
def decorate(cls):
|
|
336
|
+
class CoverageReportLcovMixin(object):
|
|
337
|
+
def _cov_report_has_trace_data(self, report):
|
|
338
|
+
"""
|
|
339
|
+
Check if a coverage report has trace data.
|
|
340
|
+
|
|
341
|
+
LCOV argument ``--ignore-errors=empty`` is not working correctly.
|
|
342
|
+
|
|
343
|
+
"""
|
|
344
|
+
with open(report, "r") as f:
|
|
345
|
+
for line in f:
|
|
346
|
+
if line.startswith("DA:") or line.startswith("BRDA:"):
|
|
347
|
+
return True
|
|
348
|
+
return False
|
|
349
|
+
|
|
350
|
+
def run_coverage_report_lcov(self, deps, tools):
|
|
351
|
+
lcov = tools.getenv("LCOV", "lcov")
|
|
352
|
+
if not tools.which(lcov):
|
|
353
|
+
raise_task_error(self, "lcov not found in PATH, cannot generate coverage report.")
|
|
354
|
+
|
|
355
|
+
gcov = tools.getenv("GCOV", tools.getenv("CROSS_COMPILE", "") + "gcov")
|
|
356
|
+
if not tools.which(gcov):
|
|
357
|
+
raise_task_error(self, "gcov not found in PATH, cannot generate coverage report.")
|
|
358
|
+
|
|
359
|
+
if bool(getattr(self, "lcov_demangle", demangle)):
|
|
360
|
+
cxxfilt = tools.getenv("CXXFILT", tools.getenv("CROSS_COMPILE", "") + "c++filt")
|
|
361
|
+
if not tools.which(cxxfilt):
|
|
362
|
+
raise_task_error(self, "c++filt not found in PATH, cannot generate coverage report.")
|
|
363
|
+
|
|
364
|
+
# Assume data is already copied by coverage_data() if the covdatadir exists,
|
|
365
|
+
# otherwise copy it from dependency artifacts.
|
|
366
|
+
if not hasattr(self, "covdatadir"):
|
|
367
|
+
self.covdatadir = tools.builddir("coverage-data")
|
|
368
|
+
for _, artifact in deps.items():
|
|
369
|
+
if artifact.paths.coverage_data:
|
|
370
|
+
tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
|
|
371
|
+
|
|
372
|
+
reportdir = tools.builddir("coverage-report-lcov")
|
|
373
|
+
htmldir = tools.builddir("coverage-report-lcov-html")
|
|
374
|
+
cachedir = get_cachedir()
|
|
375
|
+
|
|
376
|
+
lcov_configs = list(getattr(self, "lcov_configs", []))
|
|
377
|
+
lcov_excludes = list(getattr(self, "lcov_excludes", []))
|
|
378
|
+
lcov_filters = list(getattr(self, "lcov_filters", ["brace", "branch", "range"]))
|
|
379
|
+
lcov_ignore_errors = list(getattr(self, "lcov_ignore_errors", ["empty", "mismatch", "source", "source", "unused"]))
|
|
380
|
+
lcov_substitutes = list(getattr(self, "lcov_substitutes", []))
|
|
381
|
+
|
|
382
|
+
lcov_html_flags = ["-p", tools.wsroot]
|
|
383
|
+
if bool(getattr(self, "lcov_demangle", demangle)):
|
|
384
|
+
lcov_html_flags.append("--demangle-cpp")
|
|
385
|
+
lcov_html_flags.append(f"--rc demangle_cpp={cxxfilt}")
|
|
386
|
+
|
|
387
|
+
lcov_html_flags.extend(getattr(self, "lcov_html_flags", []))
|
|
388
|
+
lcov_info_flags = getattr(self, "lcov_info_flags", [])
|
|
389
|
+
|
|
390
|
+
if bool(getattr(self, "lcov_branches", branches)):
|
|
391
|
+
lcov_configs.append("branch_coverage=1")
|
|
392
|
+
lcov_configs.append("no_exception_branch=1")
|
|
393
|
+
|
|
394
|
+
if lcov_excludes:
|
|
395
|
+
lcov_excludes = ["--exclude " + f"'{exclude}'" for exclude in lcov_excludes]
|
|
396
|
+
lcov_info_flags.extend(lcov_excludes)
|
|
397
|
+
|
|
398
|
+
if lcov_filters:
|
|
399
|
+
lcov_info_flags.append("--rc filter=" + ",".join(lcov_filters))
|
|
400
|
+
lcov_html_flags.append("--rc filter=" + ",".join(lcov_filters))
|
|
401
|
+
|
|
402
|
+
if lcov_ignore_errors:
|
|
403
|
+
lcov_html_flags.append("--rc ignore_errors=" + ",".join(lcov_ignore_errors))
|
|
404
|
+
lcov_info_flags.append("--rc ignore_errors=" + ",".join(lcov_ignore_errors))
|
|
405
|
+
|
|
406
|
+
if lcov_configs:
|
|
407
|
+
lcov_configs = ["--rc " + option for option in lcov_configs]
|
|
408
|
+
lcov_html_flags.extend(lcov_configs)
|
|
409
|
+
lcov_info_flags.extend(lcov_configs)
|
|
410
|
+
|
|
411
|
+
if lcov_substitutes:
|
|
412
|
+
lcov_substitutes = [f"--substitute '{sub}'" for sub in lcov_substitutes]
|
|
413
|
+
lcov_substitutes = tools.expand(lcov_substitutes)
|
|
414
|
+
lcov_html_flags.extend(lcov_substitutes)
|
|
415
|
+
|
|
416
|
+
self.info("Generating LCOV code coverage report")
|
|
417
|
+
tools.run("{} -b {} -c -d {covdatadir} -o {}/coverage.info --gcov-tool={} {}",
|
|
418
|
+
lcov, tools.wsroot, reportdir, gcov, " ".join(lcov_info_flags), output_on_error=True)
|
|
419
|
+
|
|
420
|
+
reports = []
|
|
421
|
+
for _, artifact in deps.items():
|
|
422
|
+
if artifact.paths.coverage_report_lcov:
|
|
423
|
+
reports.append(str(artifact.paths.coverage_report_lcov))
|
|
424
|
+
if reports:
|
|
425
|
+
filtered_reports = []
|
|
426
|
+
for report in reports:
|
|
427
|
+
if not self._cov_report_has_trace_data(report):
|
|
428
|
+
self.warning(f"Coverage report {report} has no data records, excluding from merge")
|
|
429
|
+
else:
|
|
430
|
+
filtered_reports.append(report)
|
|
431
|
+
reports = filtered_reports
|
|
432
|
+
|
|
433
|
+
if reports:
|
|
434
|
+
reports = ["-a " + report for report in reports]
|
|
435
|
+
self.info("Merging LCOV code coverage reports")
|
|
436
|
+
tools.run("{} {} -o {}/coverage.info --gcov-tool={} {}",
|
|
437
|
+
lcov, " ".join(reports), reportdir, gcov, " ".join(lcov_info_flags), output_on_error=True)
|
|
438
|
+
|
|
439
|
+
with tools.cwd(reportdir):
|
|
440
|
+
tools.replace_in_file("coverage.info", f"{tools.wsroot}/", "")
|
|
441
|
+
tools.replace_in_file("coverage.info", f"{cachedir}/", "{{cachedir}}/")
|
|
442
|
+
tools.copy("coverage.info", "coverage.info.abs")
|
|
443
|
+
tools.replace_in_file("coverage.info.abs", "SF:", f"SF:{tools.wsroot}/")
|
|
444
|
+
tools.replace_in_file("coverage.info.abs", f"SF:{tools.wsroot}/" + "{{cachedir}}/", f"SF:{cachedir}/")
|
|
445
|
+
|
|
446
|
+
if tools.file_size("coverage.info") <= 0 or not self._cov_report_has_trace_data(tools.expand_path("coverage.info")):
|
|
447
|
+
tools.unlink("coverage.info")
|
|
448
|
+
self.warning("No coverage data records available, skipping HTML report generation")
|
|
449
|
+
return
|
|
450
|
+
|
|
451
|
+
if bool(getattr(self, "lcov_html", html)):
|
|
452
|
+
self.info("Generating HTML code coverage report")
|
|
453
|
+
tools.run("genhtml {}/coverage.info.abs --output-directory {} --title '{short_qualified_name}' {}",
|
|
454
|
+
reportdir, htmldir, " ".join(lcov_html_flags), output_on_error=True)
|
|
455
|
+
|
|
456
|
+
@utils.cached.instance
|
|
457
|
+
def publish_coverage_data(self, artifact, tools):
|
|
458
|
+
if not bool(getattr(self, "lcov_coverage_data", coverage_data)):
|
|
459
|
+
return
|
|
460
|
+
|
|
461
|
+
self.verbose("Publishing coverage data from {covdatadir}")
|
|
462
|
+
with tools.cwd(self.covdatadir):
|
|
463
|
+
if artifact.collect("**/*.gc*", "cov/"):
|
|
464
|
+
artifact.paths.coverage_data = "cov"
|
|
465
|
+
|
|
466
|
+
def publish_coverage_report_lcov_info(self, artifact, tools):
|
|
467
|
+
reportdir = tools.builddir("coverage-report-lcov")
|
|
468
|
+
with tools.cwd(reportdir):
|
|
469
|
+
if artifact.collect("coverage.info", "report/lcov/"):
|
|
470
|
+
artifact.paths.coverage_report_lcov = "report/lcov/coverage.info"
|
|
471
|
+
|
|
472
|
+
def publish_coverage_report_lcov_html(self, artifact, tools):
|
|
473
|
+
htmldir = tools.builddir("coverage-report-lcov-html")
|
|
474
|
+
with tools.cwd(htmldir):
|
|
475
|
+
if artifact.collect("*", "report/html/"):
|
|
476
|
+
artifact.paths.coverage_report_html = "report/html"
|
|
477
|
+
|
|
478
|
+
class CoverageReportLcov(cls, CoverageReportLcovMixin):
|
|
479
|
+
@functools.wraps(cls.run)
|
|
480
|
+
def run(self, deps, tools):
|
|
481
|
+
super().run(deps, tools)
|
|
482
|
+
self.run_coverage_report_lcov(deps, tools)
|
|
483
|
+
|
|
484
|
+
def publish_coverage_data(self, artifact, tools):
|
|
485
|
+
CoverageReportLcovMixin.publish_coverage_data(self, artifact, tools)
|
|
486
|
+
|
|
487
|
+
@functools.wraps(cls.publish)
|
|
488
|
+
def publish(self, artifact, tools):
|
|
489
|
+
super().publish(artifact, tools)
|
|
490
|
+
self.publish_coverage_report_lcov_info(artifact, tools)
|
|
491
|
+
if bool(getattr(self, "lcov_html", html)):
|
|
492
|
+
self.publish_coverage_report_lcov_html(artifact, tools)
|
|
493
|
+
if bool(getattr(self, "lcov_coverage_data", coverage_data)):
|
|
494
|
+
self.publish_coverage_data(artifact, tools)
|
|
495
|
+
|
|
496
|
+
CoverageReportLcov.__doc__ = cls.__doc__
|
|
497
|
+
CoverageReportLcov.__name__ = cls.__name__
|
|
498
|
+
return CoverageReportLcov
|
|
499
|
+
|
|
500
|
+
return decorate
|
|
501
|
+
|
|
56
502
|
@staticmethod
|
|
57
503
|
def cxxflags(attrib, prepend=False):
|
|
58
504
|
"""
|
|
@@ -69,6 +515,22 @@ class attributes:
|
|
|
69
515
|
"""
|
|
70
516
|
return utils.concat_attributes("cxxflags", attrib, prepend)
|
|
71
517
|
|
|
518
|
+
@staticmethod
|
|
519
|
+
def headers(attrib, prepend=False):
|
|
520
|
+
"""
|
|
521
|
+
Decorates a task with an alternative ``headers`` attribute.
|
|
522
|
+
|
|
523
|
+
The new attribute will be concatenated with the regular
|
|
524
|
+
``headers`` attribute.
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
attrib (str): Name of alternative attribute.
|
|
528
|
+
Keywords are expanded.
|
|
529
|
+
prepend (boolean): Prepend the value of the alternative
|
|
530
|
+
attribute. Default: false (append).
|
|
531
|
+
"""
|
|
532
|
+
return utils.concat_attributes("headers", attrib, prepend)
|
|
533
|
+
|
|
72
534
|
@staticmethod
|
|
73
535
|
def incpaths(attrib, prepend=False):
|
|
74
536
|
"""
|
|
@@ -186,7 +648,7 @@ class Variable(HashInfluenceProvider):
|
|
|
186
648
|
|
|
187
649
|
@staticmethod
|
|
188
650
|
def __get_variables__(obj):
|
|
189
|
-
variables =
|
|
651
|
+
variables = OrderedDict()
|
|
190
652
|
for mro in reversed(obj.__class__.__mro__):
|
|
191
653
|
for key, variable in getattr(mro, "__variable_list", {}).items():
|
|
192
654
|
attr = getattr(obj.__class__, key)
|
|
@@ -197,7 +659,7 @@ class Variable(HashInfluenceProvider):
|
|
|
197
659
|
def __set_name__(self, owner, name):
|
|
198
660
|
self.name = name
|
|
199
661
|
if "__variable_list" not in owner.__dict__:
|
|
200
|
-
setattr(owner, "__variable_list",
|
|
662
|
+
setattr(owner, "__variable_list", OrderedDict())
|
|
201
663
|
getattr(owner, "__variable_list")[name] = self
|
|
202
664
|
|
|
203
665
|
def create(self, project, writer, deps, tools):
|
|
@@ -287,7 +749,7 @@ class ProjectVariable(Variable):
|
|
|
287
749
|
|
|
288
750
|
def create(self, project, writer, deps, tools):
|
|
289
751
|
value = getattr(project, self._attrib or self.name, "")
|
|
290
|
-
if type(value)
|
|
752
|
+
if type(value) is list:
|
|
291
753
|
value = " ".join(value)
|
|
292
754
|
writer.variable(self.name, str(value))
|
|
293
755
|
|
|
@@ -296,6 +758,54 @@ class ProjectVariable(Variable):
|
|
|
296
758
|
return "PV: default={},attrib={}".format(self._default, self._attrib)
|
|
297
759
|
|
|
298
760
|
|
|
761
|
+
class StdVariable(Variable):
|
|
762
|
+
def __init__(self, lang, flagfmt, values, supported=None, default=None):
|
|
763
|
+
self._lang = lang
|
|
764
|
+
self._flagfmt = flagfmt
|
|
765
|
+
self._values = values
|
|
766
|
+
self._supported = supported or values
|
|
767
|
+
self._default = default
|
|
768
|
+
|
|
769
|
+
def create(self, project, writer, deps, tools):
|
|
770
|
+
value = getattr(project, self.name, self._default) or self._default
|
|
771
|
+
if not value:
|
|
772
|
+
return
|
|
773
|
+
raise_task_error_if(
|
|
774
|
+
type(value) is not int,
|
|
775
|
+
project,
|
|
776
|
+
f"Illegal {self._lang} language standard: '{value}'. Expected integer."
|
|
777
|
+
)
|
|
778
|
+
raise_task_error_if(
|
|
779
|
+
value not in self._values,
|
|
780
|
+
project,
|
|
781
|
+
f"Illegal {self._lang} language standard: '{value}'. Expected one of: {', '.join([str(v) for v in self._values])}"
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
if value not in self._supported:
|
|
785
|
+
new_value = min(self._supported, key=lambda n: abs(n - value))
|
|
786
|
+
project.warning(f"{self._lang}{value} is not supported. Using {self._lang}{new_value} instead.")
|
|
787
|
+
value = new_value
|
|
788
|
+
|
|
789
|
+
writer.variable(self.name, self._flagfmt.format(value))
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
class OptimizationVariable(Variable):
|
|
793
|
+
def __init__(self, default, values, name=None):
|
|
794
|
+
self.name = name
|
|
795
|
+
self._default = default
|
|
796
|
+
self._values = values
|
|
797
|
+
assert type(values) is dict, "Optimization values must be dict with compiler flag mapping"
|
|
798
|
+
|
|
799
|
+
def create(self, project, writer, deps, tools):
|
|
800
|
+
value = str(getattr(project, "optimize", self._default))
|
|
801
|
+
raise_task_error_if(
|
|
802
|
+
value not in self._values,
|
|
803
|
+
project,
|
|
804
|
+
f"Illegal value assigned to 'optimize' ({value}). Expected: 'none', 'debug', 'size', or 'release'."
|
|
805
|
+
)
|
|
806
|
+
writer.variable(self.name, self._values[value])
|
|
807
|
+
|
|
808
|
+
|
|
299
809
|
class SharedLibraryVariable(Variable):
|
|
300
810
|
def __init__(self, name=None, default=None):
|
|
301
811
|
self.name = name
|
|
@@ -325,11 +835,11 @@ class GNUPCHVariables(Variable):
|
|
|
325
835
|
"multiple precompiled headers found, only one is allowed")
|
|
326
836
|
|
|
327
837
|
if len(pch) <= 0:
|
|
328
|
-
writer.variable("pch_out", "
|
|
838
|
+
writer.variable("pch_out", tools.expand_relpath("{outdir}/{binary}.dir/", tools.wsroot))
|
|
329
839
|
return
|
|
330
840
|
|
|
331
841
|
project._pch = fs.path.basename(pch[0])
|
|
332
|
-
project._pch_out = "
|
|
842
|
+
project._pch_out = tools.expand_relpath("{outdir}/{binary}.dir/{_pch}" + self.gch_ext, tools.wsroot)
|
|
333
843
|
|
|
334
844
|
writer.variable("pch", project._pch)
|
|
335
845
|
writer.variable("pch_flags", "")
|
|
@@ -340,6 +850,14 @@ class GNUPCHVariables(Variable):
|
|
|
340
850
|
return "PCHV"
|
|
341
851
|
|
|
342
852
|
|
|
853
|
+
class GNUCoverageVariable(Variable):
|
|
854
|
+
def create(self, project, writer, deps, tools):
|
|
855
|
+
if bool(getattr(project, "coverage", False)):
|
|
856
|
+
writer.variable("covflags", "--coverage")
|
|
857
|
+
else:
|
|
858
|
+
writer.variable("covflags", "")
|
|
859
|
+
|
|
860
|
+
|
|
343
861
|
class Rule(HashInfluenceProvider):
|
|
344
862
|
""" A source transformation rule.
|
|
345
863
|
|
|
@@ -372,7 +890,7 @@ class Rule(HashInfluenceProvider):
|
|
|
372
890
|
|
|
373
891
|
"""
|
|
374
892
|
|
|
375
|
-
def __init__(self, command=None, infiles=None, outfiles=None, depfile=None, deps=None, variables=None, implicit=None, order_only=None, aggregate=False, phony=None):
|
|
893
|
+
def __init__(self, command=None, infiles=None, outfiles=None, depfile=None, deps=None, variables=None, implicit=None, implicit_outputs=None, order_only=None, aggregate=False, phony=None):
|
|
376
894
|
"""
|
|
377
895
|
Creates a new rule.
|
|
378
896
|
|
|
@@ -443,12 +961,13 @@ class Rule(HashInfluenceProvider):
|
|
|
443
961
|
before any C++ file is compiled.
|
|
444
962
|
"""
|
|
445
963
|
self.command = command
|
|
446
|
-
self.variables = variables or {}
|
|
964
|
+
self.variables = OrderedDict([(key, value) for key, value in (variables or {}).items()])
|
|
447
965
|
self.depfile = depfile
|
|
448
966
|
self.deps = deps
|
|
449
967
|
self.infiles = infiles or []
|
|
450
968
|
self.outfiles = utils.as_list(outfiles or [])
|
|
451
969
|
self.implicit = implicit or []
|
|
970
|
+
self.implicit_outputs = implicit_outputs or []
|
|
452
971
|
self.order_only = order_only or []
|
|
453
972
|
self.aggregate = aggregate
|
|
454
973
|
self.phony = phony
|
|
@@ -471,17 +990,17 @@ class Rule(HashInfluenceProvider):
|
|
|
471
990
|
setattr(owner, "__rule_list", {})
|
|
472
991
|
getattr(owner, "__rule_list")[name] = self
|
|
473
992
|
|
|
474
|
-
def _out(self, project, infile):
|
|
993
|
+
def _out(self, project, infile, outfiles=None):
|
|
475
994
|
in_dirname_outdir = None
|
|
476
995
|
in_dirname, in_basename = fs.path.split(infile)
|
|
477
996
|
in_base, in_ext = fs.path.splitext(in_basename)
|
|
478
997
|
|
|
479
998
|
if in_dirname and fs.path.isabs(in_dirname):
|
|
480
|
-
in_dirname_outdir = fs.path.relpath(in_dirname, project.
|
|
481
|
-
in_dirname = fs.path.relpath(in_dirname, project.
|
|
999
|
+
in_dirname_outdir = fs.path.relpath(in_dirname, project.tools.wsroot)
|
|
1000
|
+
in_dirname = fs.path.relpath(in_dirname, project.tools.wsroot)
|
|
482
1001
|
|
|
483
1002
|
result_files = []
|
|
484
|
-
for outfile in self.outfiles:
|
|
1003
|
+
for outfile in outfiles or self.outfiles:
|
|
485
1004
|
outfile = project.tools.expand(
|
|
486
1005
|
outfile,
|
|
487
1006
|
in_path=in_dirname,
|
|
@@ -495,7 +1014,7 @@ class Rule(HashInfluenceProvider):
|
|
|
495
1014
|
|
|
496
1015
|
result_files.append(outfile.replace("..", "__"))
|
|
497
1016
|
|
|
498
|
-
result_vars =
|
|
1017
|
+
result_vars = OrderedDict()
|
|
499
1018
|
for key, val in self.variables.items():
|
|
500
1019
|
result_vars[key] = project.tools.expand(
|
|
501
1020
|
val,
|
|
@@ -518,23 +1037,34 @@ class Rule(HashInfluenceProvider):
|
|
|
518
1037
|
outfiles, _ = self._out(project, utils.as_list(infiles)[0])
|
|
519
1038
|
return outfiles
|
|
520
1039
|
|
|
521
|
-
def build(self, project, writer, infiles, implicit=None, order_only=None):
|
|
1040
|
+
def build(self, project, writer, infiles, implicit=None, implicit_outputs=None, order_only=None):
|
|
522
1041
|
result = []
|
|
523
1042
|
infiles = utils.as_list(infiles)
|
|
524
|
-
infiles_rel = [fs.path.relpath(infile, project.
|
|
1043
|
+
infiles_rel = [fs.path.relpath(infile, project.tools.wsroot) for infile in infiles]
|
|
525
1044
|
implicit = (self.implicit or []) + (implicit or [])
|
|
1045
|
+
implicit_outputs = (self.implicit_outputs or []) + (implicit_outputs or [])
|
|
526
1046
|
order_only = (self.order_only or []) + (order_only or [])
|
|
527
1047
|
|
|
528
1048
|
if self.aggregate:
|
|
529
1049
|
outfiles, variables = self._out(project, infiles[0])
|
|
530
|
-
outfiles_rel = [fs.path.relpath(outfile, project.
|
|
531
|
-
|
|
1050
|
+
outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in outfiles]
|
|
1051
|
+
if implicit_outputs:
|
|
1052
|
+
implicit_outfiles, _ = self._out(project, infiles[0], implicit_outputs)
|
|
1053
|
+
implicit_outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in implicit_outfiles]
|
|
1054
|
+
else:
|
|
1055
|
+
implicit_outfiles_rel = []
|
|
1056
|
+
writer.build(outfiles_rel, self.name, infiles_rel, variables=variables, implicit=implicit, implicit_outputs=implicit_outfiles_rel, order_only=self.order_only + order_only)
|
|
532
1057
|
result.extend(outfiles)
|
|
533
1058
|
else:
|
|
534
1059
|
for infile, infile_rel in zip(infiles, infiles_rel):
|
|
535
1060
|
outfiles, variables = self._out(project, infile)
|
|
536
|
-
outfiles_rel = [fs.path.relpath(outfile, project.
|
|
537
|
-
|
|
1061
|
+
outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in outfiles]
|
|
1062
|
+
if implicit_outputs:
|
|
1063
|
+
implicit_outfiles, _ = self._out(project, infile, implicit_outputs)
|
|
1064
|
+
implicit_outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in implicit_outfiles]
|
|
1065
|
+
else:
|
|
1066
|
+
implicit_outfiles_rel = []
|
|
1067
|
+
writer.build(outfiles_rel, self.name, infile_rel, variables=variables, implicit=implicit, implicit_outputs=implicit_outfiles_rel, order_only=order_only)
|
|
538
1068
|
result.extend(outfiles)
|
|
539
1069
|
if self.phony:
|
|
540
1070
|
writer.build(self.phony, "phony", outfiles_rel)
|
|
@@ -564,12 +1094,12 @@ class ProtobufCompiler(Rule):
|
|
|
564
1094
|
phony=True,
|
|
565
1095
|
variables=None,
|
|
566
1096
|
**kwargs):
|
|
567
|
-
variables_final =
|
|
568
|
-
"desc"
|
|
569
|
-
"out_depfile"
|
|
570
|
-
"outdir_proto"
|
|
571
|
-
"in_path_outdir"
|
|
572
|
-
|
|
1097
|
+
variables_final = OrderedDict([
|
|
1098
|
+
("desc", "[PROTOC] {in_base}{in_ext}"),
|
|
1099
|
+
("out_depfile", "{outdir_rel}/{binary}.dir/{in_base}.pb.d"),
|
|
1100
|
+
("outdir_proto", "{outdir_rel}/{binary}.dir"),
|
|
1101
|
+
("in_path_outdir", "{in_path_outdir}"),
|
|
1102
|
+
])
|
|
573
1103
|
variables_final.update(variables or {})
|
|
574
1104
|
super().__init__(
|
|
575
1105
|
command=command,
|
|
@@ -583,8 +1113,8 @@ class ProtobufCompiler(Rule):
|
|
|
583
1113
|
**kwargs)
|
|
584
1114
|
self.generator = generator
|
|
585
1115
|
|
|
586
|
-
def _out(self, project, infile):
|
|
587
|
-
outfiles, variables = super()._out(project, infile)
|
|
1116
|
+
def _out(self, project, infile, outfiles=None):
|
|
1117
|
+
outfiles, variables = super()._out(project, infile, outfiles)
|
|
588
1118
|
variables["generator"] = project.tools.expand(self.generator)
|
|
589
1119
|
return outfiles, variables
|
|
590
1120
|
|
|
@@ -610,8 +1140,8 @@ class GRPCProtobufCompiler(ProtobufCompiler):
|
|
|
610
1140
|
variables=None,
|
|
611
1141
|
**kwargs):
|
|
612
1142
|
variables_final = {
|
|
613
|
-
"out_depfile": "{binary}.dir/{in_base}.pb.d",
|
|
614
|
-
"out_depfile_grpc": "{binary}.dir/{in_base}.grpc.pb.d",
|
|
1143
|
+
"out_depfile": "{outdir_rel}/{binary}.dir/{in_base}.pb.d",
|
|
1144
|
+
"out_depfile_grpc": "{outdir_rel}/{binary}.dir/{in_base}.grpc.pb.d",
|
|
615
1145
|
}
|
|
616
1146
|
variables_final.update(variables or {})
|
|
617
1147
|
super().__init__(command=command, depfile=depfile, outfiles=outfiles, variables=variables_final, **kwargs)
|
|
@@ -650,8 +1180,8 @@ class FlatbufferCompiler(Rule):
|
|
|
650
1180
|
**kwargs)
|
|
651
1181
|
self.generator = generator
|
|
652
1182
|
|
|
653
|
-
def _out(self, project, infile):
|
|
654
|
-
outfiles, variables = super()._out(project, infile)
|
|
1183
|
+
def _out(self, project, infile, outfiles=None):
|
|
1184
|
+
outfiles, variables = super()._out(project, infile, outfiles)
|
|
655
1185
|
variables["generator"] = project.tools.expand(self.generator)
|
|
656
1186
|
return outfiles, variables
|
|
657
1187
|
|
|
@@ -678,7 +1208,8 @@ class Skip(Rule):
|
|
|
678
1208
|
|
|
679
1209
|
@task_attributes.system
|
|
680
1210
|
class MakeDirectory(Rule):
|
|
681
|
-
|
|
1211
|
+
command_darwin = "mkdir -p $out"
|
|
1212
|
+
command_linux = command_darwin
|
|
682
1213
|
command_windows = "if not exist $out mkdir $out"
|
|
683
1214
|
|
|
684
1215
|
def __init__(self, name):
|
|
@@ -700,16 +1231,23 @@ class MakeDirectory(Rule):
|
|
|
700
1231
|
|
|
701
1232
|
class GNUCompiler(Rule):
|
|
702
1233
|
def __init__(self, *args, **kwargs):
|
|
1234
|
+
self.covfiles = kwargs.pop("covfiles", [])
|
|
703
1235
|
super(GNUCompiler, self).__init__(*args, **kwargs)
|
|
704
1236
|
|
|
705
1237
|
def create(self, project, writer, deps, tools):
|
|
706
1238
|
super().create(project, writer, deps, tools)
|
|
707
1239
|
|
|
708
|
-
def build(self, project, writer, infiles, implicit=None, order_only=None):
|
|
1240
|
+
def build(self, project, writer, infiles, implicit=None, implicit_outputs=None, order_only=None):
|
|
709
1241
|
implicit = implicit or []
|
|
1242
|
+
implicit_outputs = implicit_outputs or []
|
|
1243
|
+
|
|
1244
|
+
if getattr(project, "coverage", False) and self.covfiles:
|
|
1245
|
+
implicit_outputs.extend(self.covfiles)
|
|
1246
|
+
|
|
710
1247
|
if GNUPCHVariables.pch_ext not in self.infiles and project._pch_out is not None:
|
|
711
1248
|
implicit.append(project._pch_out)
|
|
712
|
-
|
|
1249
|
+
|
|
1250
|
+
return super().build(project, writer, infiles, implicit=implicit, implicit_outputs=implicit_outputs, order_only=order_only)
|
|
713
1251
|
|
|
714
1252
|
@utils.cached.instance
|
|
715
1253
|
def get_influence(self, task):
|
|
@@ -746,7 +1284,9 @@ class FileListWriter(Rule):
|
|
|
746
1284
|
def build(self, project, writer, infiles, implicit=None, order_only=None):
|
|
747
1285
|
infiles = [fs.as_posix(infile) for infile in infiles] if self.posix else infiles
|
|
748
1286
|
file_list_path = fs.path.join(project.outdir, "{0}.list".format(self.name))
|
|
1287
|
+
file_list_path = project.tools.expand_path(file_list_path)
|
|
749
1288
|
file_list_hash_path = fs.path.join(project.outdir, "{0}.hash".format(self.name))
|
|
1289
|
+
file_list_hash_path = project.tools.expand_path(file_list_hash_path)
|
|
750
1290
|
data, digest = self._data(project, infiles)
|
|
751
1291
|
if not self._identical(file_list_path, file_list_hash_path, data, digest):
|
|
752
1292
|
self._write(file_list_path, file_list_hash_path, data, digest)
|
|
@@ -829,11 +1369,12 @@ class GNUDepImporter(Rule):
|
|
|
829
1369
|
for name, artifact in deps.items():
|
|
830
1370
|
if artifact.cxxinfo.libpaths.items():
|
|
831
1371
|
sandbox = project.tools.sandbox(artifact, project.incremental)
|
|
1372
|
+
sandbox = project.tools.expand_relpath(sandbox, project.tools.wsroot)
|
|
832
1373
|
for lib in artifact.cxxinfo.libraries.items():
|
|
833
1374
|
name = "{0}{1}{2}".format(self.prefix, lib, self.suffix)
|
|
834
1375
|
for path in artifact.cxxinfo.libpaths.items():
|
|
835
1376
|
archive = fs.path.join(sandbox, path, name)
|
|
836
|
-
if fs.path.exists(archive):
|
|
1377
|
+
if fs.path.exists(os.path.join(project.tools.wsroot, archive)):
|
|
837
1378
|
archives.append(archive)
|
|
838
1379
|
return archives
|
|
839
1380
|
|
|
@@ -844,7 +1385,9 @@ class GNUDepImporter(Rule):
|
|
|
844
1385
|
if isinstance(project, CXXLibrary):
|
|
845
1386
|
imports += self._build_archives(project, writer, deps)
|
|
846
1387
|
if not project.shared and project.selfsustained:
|
|
847
|
-
|
|
1388
|
+
sources = [os.path.join(project.tools.wsroot, source) for source in imports]
|
|
1389
|
+
sources = [os.path.relpath(source, project.joltdir) for source in sources]
|
|
1390
|
+
writer.sources.extend(sources)
|
|
848
1391
|
return imports
|
|
849
1392
|
|
|
850
1393
|
def get_influence(self, task):
|
|
@@ -857,7 +1400,7 @@ class Toolchain(object):
|
|
|
857
1400
|
|
|
858
1401
|
@staticmethod
|
|
859
1402
|
def build_rules_and_vars(obj):
|
|
860
|
-
rule_map =
|
|
1403
|
+
rule_map = OrderedDict()
|
|
861
1404
|
rules, vars = Toolchain.all_rules_and_vars(obj)
|
|
862
1405
|
for name, rule in rules.items():
|
|
863
1406
|
rule.name = name
|
|
@@ -929,18 +1472,18 @@ class IncludePaths(Variable):
|
|
|
929
1472
|
return tools.expand(path)
|
|
930
1473
|
if path[0] in ['-']:
|
|
931
1474
|
path = tools.expand_path(path[1:])
|
|
932
|
-
return tools.expand_relpath(path, project.
|
|
1475
|
+
return tools.expand_relpath(path, project.tools.wsroot)
|
|
933
1476
|
|
|
934
1477
|
def expand_artifact(sandbox, path):
|
|
935
1478
|
if path[0] in ['=', fs.sep]:
|
|
936
1479
|
return path
|
|
937
1480
|
if path[0] in ['-']:
|
|
938
1481
|
path = fs.path.join(project.joltdir, path[1:])
|
|
939
|
-
return tools.expand_relpath(fs.path.join(sandbox, path), project.
|
|
1482
|
+
return tools.expand_relpath(fs.path.join(sandbox, path), project.tools.wsroot)
|
|
940
1483
|
|
|
941
1484
|
incpaths = []
|
|
942
1485
|
if self.outdir:
|
|
943
|
-
incpaths += ["
|
|
1486
|
+
incpaths += [tools.expand_relpath("{outdir}/{binary}.dir", project.tools.wsroot)]
|
|
944
1487
|
if self.attrib:
|
|
945
1488
|
incpaths += [expand(path) for path in getattr(project, self.attrib)]
|
|
946
1489
|
if self.imported:
|
|
@@ -969,12 +1512,13 @@ class LibraryPaths(Variable):
|
|
|
969
1512
|
return
|
|
970
1513
|
libpaths = []
|
|
971
1514
|
if self.attrib:
|
|
972
|
-
libpaths = [tools.expand_relpath(path, project.
|
|
1515
|
+
libpaths = [tools.expand_relpath(path, project.tools.wsroot) for path in getattr(project, self.attrib)]
|
|
973
1516
|
if self.imported:
|
|
974
1517
|
for _, artifact in deps.items():
|
|
975
1518
|
libs = artifact.cxxinfo.libpaths.items()
|
|
976
1519
|
if libs:
|
|
977
1520
|
sandbox = tools.sandbox(artifact, project.incremental)
|
|
1521
|
+
sandbox = tools.expand_relpath(sandbox, project.tools.wsroot)
|
|
978
1522
|
libpaths += [fs.path.join(sandbox, path) for path in libs]
|
|
979
1523
|
libpaths = ["{0}{1}".format(self.prefix, path) for path in libpaths]
|
|
980
1524
|
writer.variable(self.name, " ".join(libpaths))
|
|
@@ -1036,7 +1580,9 @@ class GNUToolchain(Toolchain):
|
|
|
1036
1580
|
bin = Skip(infiles=[".dll", ".elf", ".exe", ".out", ".so"])
|
|
1037
1581
|
|
|
1038
1582
|
joltdir = ProjectVariable()
|
|
1583
|
+
builddir = ProjectVariable(attrib="outdir")
|
|
1039
1584
|
outdir = ProjectVariable()
|
|
1585
|
+
outdir_rel = ProjectVariable()
|
|
1040
1586
|
binary = ProjectVariable()
|
|
1041
1587
|
|
|
1042
1588
|
ar = ToolEnvironmentVariable(default="ar", abspath=True)
|
|
@@ -1049,7 +1595,17 @@ class GNUToolchain(Toolchain):
|
|
|
1049
1595
|
cxxwrap = EnvironmentVariable(default="")
|
|
1050
1596
|
flatc = ToolEnvironmentVariable(default="flatc", envname="FLATC", abspath=True)
|
|
1051
1597
|
protoc = ToolEnvironmentVariable(default="protoc", envname="PROTOC", abspath=True)
|
|
1052
|
-
|
|
1598
|
+
strip = ToolEnvironmentVariable(default="strip", envname="STRIP", abspath=True)
|
|
1599
|
+
|
|
1600
|
+
cstd = StdVariable("C", "-std=c{}", values=c_standards_list, default=c_standard_default)
|
|
1601
|
+
cxxstd = StdVariable("C++", "-std=c++{}", values=cxx_standards_list, default=cxx_standard_default)
|
|
1602
|
+
optflag = OptimizationVariable(default="release", values={
|
|
1603
|
+
"none": "-O0",
|
|
1604
|
+
"debug": "-Og",
|
|
1605
|
+
"size": "-Os",
|
|
1606
|
+
"release": "-O2",
|
|
1607
|
+
None: "-O0",
|
|
1608
|
+
})
|
|
1053
1609
|
asflags = EnvironmentVariable(default="")
|
|
1054
1610
|
cflags = EnvironmentVariable(default="")
|
|
1055
1611
|
cxxflags = EnvironmentVariable(default="")
|
|
@@ -1065,6 +1621,8 @@ class GNUToolchain(Toolchain):
|
|
|
1065
1621
|
extra_cxxflags = ProjectVariable(attrib="cxxflags")
|
|
1066
1622
|
extra_ldflags = ProjectVariable(attrib="ldflags")
|
|
1067
1623
|
|
|
1624
|
+
covflags = GNUCoverageVariable()
|
|
1625
|
+
|
|
1068
1626
|
task_fbflags = ProjectVariable(attrib="fbflags")
|
|
1069
1627
|
task_protoflags = ProjectVariable(attrib="protoflags")
|
|
1070
1628
|
|
|
@@ -1075,31 +1633,34 @@ class GNUToolchain(Toolchain):
|
|
|
1075
1633
|
libpaths = LibraryPaths(prefix="-L")
|
|
1076
1634
|
libraries = Libraries(prefix="-l")
|
|
1077
1635
|
|
|
1078
|
-
mkdir_debug = MakeDirectory(name="
|
|
1636
|
+
mkdir_debug = MakeDirectory(name="$outdir_rel/.debug")
|
|
1079
1637
|
|
|
1080
1638
|
compile_pch = GNUCompiler(
|
|
1081
|
-
command="$cxxwrap $cxx -x c++-header $cxxflags $shared_flags $imported_cxxflags $extra_cxxflags $macros $incpaths -MMD -MF $out.d -c $in -o $out",
|
|
1639
|
+
command="$cxxwrap $cxx -x c++-header $cxxstd $optflag $cxxflags $shared_flags $imported_cxxflags $extra_cxxflags $covflags $macros $incpaths -MMD -MF $out.d -c $in -o $out",
|
|
1082
1640
|
deps="gcc",
|
|
1083
1641
|
depfile="$out.d",
|
|
1084
1642
|
infiles=[GNUPCHVariables.pch_ext],
|
|
1085
1643
|
outfiles=["{outdir}/{binary}.dir/{in_base}{in_ext}" + GNUPCHVariables.gch_ext],
|
|
1644
|
+
covfiles=["{outdir}/{binary}.dir/{in_base}{in_ext}.gcno"],
|
|
1086
1645
|
variables={"desc": "[PCH] {in_base}{in_ext}"})
|
|
1087
1646
|
|
|
1088
1647
|
compile_c = GNUCompiler(
|
|
1089
|
-
command="$ccwrap $cc -x c $pch_flags $cflags $shared_flags $imported_cflags $extra_cflags $macros $incpaths -MMD -MF $out.d -c $in -o $out",
|
|
1648
|
+
command="$ccwrap $cc -x c $cstd $pch_flags $optflag $cflags $shared_flags $imported_cflags $extra_cflags $covflags $macros $incpaths -MMD -MF $out.d -c $in -o $out",
|
|
1090
1649
|
deps="gcc",
|
|
1091
1650
|
depfile="$out.d",
|
|
1092
1651
|
infiles=[".c"],
|
|
1093
1652
|
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.o"],
|
|
1653
|
+
covfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.gcno"],
|
|
1094
1654
|
variables={"desc": "[C] {in_base}{in_ext}"},
|
|
1095
1655
|
implicit=["$cc_path"])
|
|
1096
1656
|
|
|
1097
1657
|
compile_cxx = GNUCompiler(
|
|
1098
|
-
command="$cxxwrap $cxx -x c++ $pch_flags $cxxflags $shared_flags $imported_cxxflags $extra_cxxflags $macros $incpaths -MMD -MF $out.d -c $in -o $out",
|
|
1658
|
+
command="$cxxwrap $cxx -x c++ $cxxstd $pch_flags $optflag $cxxflags $shared_flags $imported_cxxflags $extra_cxxflags $covflags $macros $incpaths -MMD -MF $out.d -c $in -o $out",
|
|
1099
1659
|
deps="gcc",
|
|
1100
1660
|
depfile="$out.d",
|
|
1101
1661
|
infiles=[".cc", ".cpp", ".cxx"],
|
|
1102
1662
|
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.o"],
|
|
1663
|
+
covfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.gcno"],
|
|
1103
1664
|
variables={"desc": "[CXX] {in_base}{in_ext}"},
|
|
1104
1665
|
implicit=["$cxx_path"])
|
|
1105
1666
|
|
|
@@ -1109,6 +1670,7 @@ class GNUToolchain(Toolchain):
|
|
|
1109
1670
|
depfile="$out.d",
|
|
1110
1671
|
infiles=[".s", ".asm"],
|
|
1111
1672
|
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.o"],
|
|
1673
|
+
covfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.gcno"],
|
|
1112
1674
|
variables={"desc": "[ASM] {in_base}{in_ext}"},
|
|
1113
1675
|
implicit=["$cc_path"])
|
|
1114
1676
|
|
|
@@ -1118,6 +1680,7 @@ class GNUToolchain(Toolchain):
|
|
|
1118
1680
|
depfile="$out.d",
|
|
1119
1681
|
infiles=[".S"],
|
|
1120
1682
|
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.o"],
|
|
1683
|
+
covfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.gcno"],
|
|
1121
1684
|
variables={"desc": "[ASM] {in_base}{in_ext}"},
|
|
1122
1685
|
implicit=["$cc_path"])
|
|
1123
1686
|
|
|
@@ -1127,51 +1690,100 @@ class GNUToolchain(Toolchain):
|
|
|
1127
1690
|
|
|
1128
1691
|
linker = GNULinker(
|
|
1129
1692
|
command=" && ".join([
|
|
1130
|
-
"$ld $ldflags $imported_ldflags $extra_ldflags $libpaths -Wl,--start-group
|
|
1131
|
-
"$objcopy_path --only-keep-debug $out
|
|
1693
|
+
"$ld $ldflags $imported_ldflags $extra_ldflags $covflags $libpaths -Wl,--start-group @$outdir_rel/objects.list -Wl,--end-group -o $out -Wl,--start-group $libraries -Wl,--end-group",
|
|
1694
|
+
"$objcopy_path --only-keep-debug $out $outdir_rel/.debug/$binary",
|
|
1132
1695
|
"$objcopy_path --strip-all $out",
|
|
1133
|
-
"$objcopy_path --add-gnu-debuglink
|
|
1696
|
+
"$objcopy_path --add-gnu-debuglink=$outdir_rel/.debug/$binary $out"
|
|
1134
1697
|
]),
|
|
1135
1698
|
infiles=[".o", ".obj", ".a"],
|
|
1136
1699
|
outfiles=["{outdir}/{binary}"],
|
|
1137
1700
|
variables={"desc": "[LINK] {binary}"},
|
|
1138
|
-
implicit=["$ld_path", "$objcopy_path", "
|
|
1701
|
+
implicit=["$ld_path", "$objcopy_path", "$outdir_rel/.debug"])
|
|
1139
1702
|
|
|
1140
1703
|
dynlinker = GNULinker(
|
|
1141
1704
|
command=" && ".join([
|
|
1142
|
-
"$ld $ldflags -shared $imported_ldflags $extra_ldflags $libpaths -Wl,--start-group
|
|
1143
|
-
"$objcopy_path --only-keep-debug $out
|
|
1705
|
+
"$ld $ldflags -shared $imported_ldflags $extra_ldflags $covflags $libpaths -Wl,--start-group @$outdir_rel/objects.list -Wl,--end-group -o $out -Wl,--start-group $libraries -Wl,--end-group",
|
|
1706
|
+
"$objcopy_path --only-keep-debug $out $outdir_rel/.debug/lib$binary.so",
|
|
1144
1707
|
"$objcopy_path --strip-all $out",
|
|
1145
|
-
"$objcopy_path --add-gnu-debuglink
|
|
1708
|
+
"$objcopy_path --add-gnu-debuglink=$outdir_rel/.debug/lib$binary.so $out"
|
|
1146
1709
|
]),
|
|
1147
1710
|
infiles=[".o", ".obj", ".a"],
|
|
1148
1711
|
outfiles=["{outdir}/lib{binary}.so"],
|
|
1149
1712
|
variables={"desc": "[LINK] {binary}"},
|
|
1150
|
-
implicit=["$ld_path", "$objcopy_path", "
|
|
1713
|
+
implicit=["$ld_path", "$objcopy_path", "$outdir_rel/.debug"])
|
|
1151
1714
|
|
|
1152
1715
|
archiver = GNUArchiver(
|
|
1153
|
-
command="$ar -M < objects.list && $ranlib $out",
|
|
1716
|
+
command="$ar -M < $outdir_rel/objects.list && $ranlib $out",
|
|
1154
1717
|
infiles=[".o", ".obj", ".a"],
|
|
1155
1718
|
outfiles=["{outdir}/lib{binary}.a"],
|
|
1156
1719
|
variables={"desc": "[AR] lib{binary}.a"},
|
|
1157
|
-
implicit=["$ld_path", "$ar_path"])
|
|
1720
|
+
implicit=["$ld_path", "$ar_path", "$ranlib_path"])
|
|
1158
1721
|
|
|
1159
1722
|
depimport = GNUDepImporter(
|
|
1160
1723
|
prefix="lib",
|
|
1161
1724
|
suffix=".a")
|
|
1162
1725
|
|
|
1163
1726
|
|
|
1727
|
+
class BSDArchiver(Rule):
|
|
1728
|
+
def __init__(self, *args, **kwargs):
|
|
1729
|
+
super(BSDArchiver, self).__init__(*args, aggregate=True, **kwargs)
|
|
1730
|
+
|
|
1731
|
+
def build(self, project, writer, infiles, implicit=None, order_only=None):
|
|
1732
|
+
writer._objects = infiles
|
|
1733
|
+
project._binaries, _ = self._out(project, project.binary)
|
|
1734
|
+
file_list = FileListWriter("objects", project._binaries)
|
|
1735
|
+
file_list.build(project, writer, infiles)
|
|
1736
|
+
super().build(project, writer, infiles, implicit=writer.depimports, order_only=order_only)
|
|
1737
|
+
|
|
1738
|
+
def get_influence(self, task):
|
|
1739
|
+
return "BSDArchiver" + super().get_influence(task)
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
class DarwinGNUToolchain(GNUToolchain):
|
|
1743
|
+
libtool = ToolEnvironmentVariable(default="libtool", envname="LIBTOOL", abspath=True)
|
|
1744
|
+
dsymutil = ToolEnvironmentVariable(default="dsymutil", envname="DSYMUTIL", abspath=True)
|
|
1745
|
+
|
|
1746
|
+
linker = GNULinker(
|
|
1747
|
+
command=" && ".join([
|
|
1748
|
+
"$ld $ldflags $imported_ldflags $extra_ldflags $covflags $libpaths @$outdir_rel/objects.list -o $out $libraries",
|
|
1749
|
+
"$dsymutil $out -o $outdir_rel/.debug/$binary.dSYM",
|
|
1750
|
+
"$strip $out",
|
|
1751
|
+
]),
|
|
1752
|
+
infiles=[".o", ".obj", ".a"],
|
|
1753
|
+
outfiles=["{outdir}/{binary}"],
|
|
1754
|
+
variables={"desc": "[LINK] {binary}"},
|
|
1755
|
+
implicit=["$ld_path", "$dsymutil_path", "$strip_path", "$outdir_rel/.debug"])
|
|
1756
|
+
|
|
1757
|
+
dynlinker = GNULinker(
|
|
1758
|
+
command=" && ".join([
|
|
1759
|
+
"$ld $ldflags -shared $imported_ldflags $extra_ldflags $covflags $libpaths @$outdir_rel/objects.list -o $out $libraries",
|
|
1760
|
+
"$dsymutil $out -o $outdir_rel/.debug/$binary.dSYM",
|
|
1761
|
+
"$strip $out",
|
|
1762
|
+
]),
|
|
1763
|
+
infiles=[".o", ".obj", ".a"],
|
|
1764
|
+
outfiles=["{outdir}/lib{binary}.so"],
|
|
1765
|
+
variables={"desc": "[LINK] {binary}"},
|
|
1766
|
+
implicit=["$ld_path", "$dsymutil_path", "$strip_path", "$outdir_rel/.debug"])
|
|
1767
|
+
|
|
1768
|
+
archiver = BSDArchiver(
|
|
1769
|
+
command="$libtool -static -o $out @$outdir_rel/objects.list && $ranlib $out",
|
|
1770
|
+
infiles=[".o", ".obj", ".a"],
|
|
1771
|
+
outfiles=["{outdir}/lib{binary}.a"],
|
|
1772
|
+
variables={"desc": "[AR] lib{binary}.a"},
|
|
1773
|
+
implicit=["$libtool_path", "$ranlib_path"])
|
|
1774
|
+
|
|
1775
|
+
|
|
1164
1776
|
class MinGWToolchain(GNUToolchain):
|
|
1165
1777
|
linker = GNULinker(
|
|
1166
1778
|
command=" && ".join([
|
|
1167
|
-
"$ld $ldflags $imported_ldflags $extra_ldflags $libpaths -Wl,--start-group
|
|
1168
|
-
"$objcopy --only-keep-debug $out
|
|
1779
|
+
"$ld $ldflags $imported_ldflags $extra_ldflags $libpaths -Wl,--start-group @$outdir_rel/objects.list -Wl,--end-group -o $out -Wl,--start-group $libraries -Wl,--end-group",
|
|
1780
|
+
"$objcopy --only-keep-debug $out $outdir_rel/.debug/$binary.exe",
|
|
1169
1781
|
"$objcopy --strip-all $out",
|
|
1170
|
-
"$objcopy --add-gnu-debuglink
|
|
1782
|
+
"$objcopy --add-gnu-debuglink=$outdir_rel/.debug/$binary.exe $out"
|
|
1171
1783
|
]),
|
|
1172
1784
|
outfiles=["{outdir}/{binary}.exe"],
|
|
1173
1785
|
variables={"desc": "[LINK] {binary}"},
|
|
1174
|
-
implicit=["$ld_path", "$objcopy_path", "
|
|
1786
|
+
implicit=["$ld_path", "$objcopy_path", "$outdir_rel/.debug"])
|
|
1175
1787
|
|
|
1176
1788
|
|
|
1177
1789
|
class MSVCArchiver(Rule):
|
|
@@ -1189,6 +1801,62 @@ class MSVCArchiver(Rule):
|
|
|
1189
1801
|
return "MSVCArchiver" + super().get_influence(task)
|
|
1190
1802
|
|
|
1191
1803
|
|
|
1804
|
+
class MSVCCRT(Variable):
|
|
1805
|
+
def __init__(self, default="/MD", flagsfn=None):
|
|
1806
|
+
self.default = default
|
|
1807
|
+
self.flagsfn = flagsfn
|
|
1808
|
+
|
|
1809
|
+
def _combine(self, project, crt1, crt2):
|
|
1810
|
+
if crt1 is None:
|
|
1811
|
+
return crt2
|
|
1812
|
+
if crt2 is None:
|
|
1813
|
+
return crt1
|
|
1814
|
+
raise_task_error_if(crt1 != crt2, project, "Mismatching Windows CRT library types (/MT vs /MD)")
|
|
1815
|
+
return crt1
|
|
1816
|
+
|
|
1817
|
+
def _select_flag(self, flags):
|
|
1818
|
+
""" Look for /Mxx flag in the list of flags """
|
|
1819
|
+
if flags is None:
|
|
1820
|
+
return None
|
|
1821
|
+
if "Static" in flags:
|
|
1822
|
+
return "/MT"
|
|
1823
|
+
if "StaticDebug" in flags:
|
|
1824
|
+
return "/MTd"
|
|
1825
|
+
if "Dynamic" in flags:
|
|
1826
|
+
return "/MD"
|
|
1827
|
+
if "DynamicDebug" in flags:
|
|
1828
|
+
return "/MDd"
|
|
1829
|
+
if "/MT" in flags:
|
|
1830
|
+
return "/MT"
|
|
1831
|
+
if "/MTd" in flags:
|
|
1832
|
+
return "/MTd"
|
|
1833
|
+
if "/MD" in flags:
|
|
1834
|
+
return "/MD"
|
|
1835
|
+
if "/MDd" in flags:
|
|
1836
|
+
return "/MDd"
|
|
1837
|
+
return None
|
|
1838
|
+
|
|
1839
|
+
def _select_dep_flags(self, project, dep):
|
|
1840
|
+
crt = self._select_flag(dep.cxxinfo.asflags.items())
|
|
1841
|
+
if hasattr(dep.cxxinfo, "crt"):
|
|
1842
|
+
crt = self._combine(project, crt, self._select_flag([str(dep.cxxinfo.crt)]))
|
|
1843
|
+
crt = self._combine(project, crt, self._select_flag(dep.cxxinfo.cflags.items()))
|
|
1844
|
+
return self._combine(project, crt, self._select_flag(dep.cxxinfo.cxxflags.items()))
|
|
1845
|
+
|
|
1846
|
+
def create(self, project, writer, deps, tools):
|
|
1847
|
+
crt = self._select_flag(getattr(project, "crt", None))
|
|
1848
|
+
crt = self._combine(project, crt, self._select_flag(project._asflags()))
|
|
1849
|
+
crt = self._combine(project, crt, self._select_flag(project._cflags()))
|
|
1850
|
+
crt = self._combine(project, crt, self._select_flag(project._cxxflags()))
|
|
1851
|
+
for _, artifact in deps.items():
|
|
1852
|
+
crt = self._combine(project, crt, self._select_dep_flags(project, artifact))
|
|
1853
|
+
writer.variable(self.name, crt or self.default)
|
|
1854
|
+
|
|
1855
|
+
@utils.cached.instance
|
|
1856
|
+
def get_influence(self, task):
|
|
1857
|
+
return "CRT"
|
|
1858
|
+
|
|
1859
|
+
|
|
1192
1860
|
MSVCCompiler = GNUCompiler
|
|
1193
1861
|
MSVCLinker = GNULinker
|
|
1194
1862
|
MSVCDepImporter = GNUDepImporter
|
|
@@ -1199,7 +1867,9 @@ class MSVCToolchain(Toolchain):
|
|
|
1199
1867
|
bin = Skip(infiles=[".dll", ".exe"])
|
|
1200
1868
|
|
|
1201
1869
|
joltdir = ProjectVariable()
|
|
1870
|
+
builddir = ProjectVariable(attrib="outdir")
|
|
1202
1871
|
outdir = ProjectVariable()
|
|
1872
|
+
outdir_rel = ProjectVariable()
|
|
1203
1873
|
binary = ProjectVariable()
|
|
1204
1874
|
|
|
1205
1875
|
cl = ToolEnvironmentVariable(default="cl", envname="cl_exe", abspath=True)
|
|
@@ -1208,13 +1878,25 @@ class MSVCToolchain(Toolchain):
|
|
|
1208
1878
|
flatc = ToolEnvironmentVariable(default="flatc", envname="FLATC", abspath=True)
|
|
1209
1879
|
protoc = ToolEnvironmentVariable(default="protoc", envname="PROTOC", abspath=True)
|
|
1210
1880
|
|
|
1881
|
+
cstd = StdVariable("C", "/std:c{}", values=c_standards_list, supported=[11, 17], default=c_standard_default)
|
|
1882
|
+
cxxstd = StdVariable("C++", "/std:c++{}", values=cxx_standards_list, supported=[14, 17, 20], default=cxx_standard_default)
|
|
1883
|
+
optflag = OptimizationVariable(default="speed", values={
|
|
1884
|
+
"none": "/Od",
|
|
1885
|
+
"debug": "/Od /Zi",
|
|
1886
|
+
"size": "/O1",
|
|
1887
|
+
"release": "/O2 /DNDEBUG",
|
|
1888
|
+
None: "/0d",
|
|
1889
|
+
})
|
|
1890
|
+
win32flags = Variable("/DWIN32 /D_WINDOWS /D_WIN32_WINNT=0x0601 /EHsc")
|
|
1211
1891
|
asflags = EnvironmentVariable(default="")
|
|
1212
|
-
cflags = EnvironmentVariable(default="
|
|
1213
|
-
cxxflags = EnvironmentVariable(default="
|
|
1892
|
+
cflags = EnvironmentVariable(default="")
|
|
1893
|
+
cxxflags = EnvironmentVariable(default="")
|
|
1214
1894
|
fbflags = EnvironmentVariable(default="")
|
|
1215
1895
|
ldflags = EnvironmentVariable(default="")
|
|
1216
1896
|
protoflags = EnvironmentVariable(default="")
|
|
1217
1897
|
|
|
1898
|
+
crt = MSVCCRT()
|
|
1899
|
+
|
|
1218
1900
|
extra_asflags = ProjectVariable(attrib="asflags")
|
|
1219
1901
|
extra_cflags = ProjectVariable(attrib="cflags")
|
|
1220
1902
|
extra_cxxflags = ProjectVariable(attrib="cxxflags")
|
|
@@ -1229,26 +1911,26 @@ class MSVCToolchain(Toolchain):
|
|
|
1229
1911
|
libraries = Libraries(suffix=".lib")
|
|
1230
1912
|
|
|
1231
1913
|
compile_asm = MSVCCompiler(
|
|
1232
|
-
command="$cl /nologo /showIncludes $asflags $extra_asflags $macros $incpaths /c /Tc$in /Fo$out",
|
|
1914
|
+
command="$cl /nologo /showIncludes $crt $win32flags $asflags $extra_asflags $macros $incpaths /c /Tc$in /Fo$out",
|
|
1233
1915
|
deps="msvc",
|
|
1234
1916
|
infiles=[".asm", ".s", ".S"],
|
|
1235
|
-
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}.obj"],
|
|
1917
|
+
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.obj"],
|
|
1236
1918
|
variables={"desc": "[ASM] {in_base}{in_ext}"},
|
|
1237
1919
|
implicit=["$cl_path"])
|
|
1238
1920
|
|
|
1239
1921
|
compile_c = MSVCCompiler(
|
|
1240
|
-
command="$cl /nologo /showIncludes $
|
|
1922
|
+
command="$cl /nologo /showIncludes $cstd $crt $win32flags $optflag $cflags $extra_cflags $macros $incpaths /c /Tc$in /Fo$out",
|
|
1241
1923
|
deps="msvc",
|
|
1242
1924
|
infiles=[".c"],
|
|
1243
|
-
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}.obj"],
|
|
1925
|
+
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.obj"],
|
|
1244
1926
|
variables={"desc": "[C] {in_base}{in_ext}"},
|
|
1245
1927
|
implicit=["$cl_path"])
|
|
1246
1928
|
|
|
1247
1929
|
compile_cxx = MSVCCompiler(
|
|
1248
|
-
command="$cl /nologo /showIncludes $cxxflags $extra_cxxflags $macros $incpaths /c /Tp$in /Fo$out",
|
|
1930
|
+
command="$cl /nologo /showIncludes $cxxstd $crt $win32flags $optflag $cxxflags $extra_cxxflags $macros $incpaths /c /Tp$in /Fo$out",
|
|
1249
1931
|
deps="msvc",
|
|
1250
1932
|
infiles=[".cc", ".cpp", ".cxx"],
|
|
1251
|
-
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}.obj"],
|
|
1933
|
+
outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.obj"],
|
|
1252
1934
|
variables={"desc": "[CXX] {in_base}{in_ext}"},
|
|
1253
1935
|
implicit=["$cl_path"])
|
|
1254
1936
|
|
|
@@ -1256,14 +1938,14 @@ class MSVCToolchain(Toolchain):
|
|
|
1256
1938
|
compile_proto = ProtobufCompiler(generator="cpp")
|
|
1257
1939
|
|
|
1258
1940
|
linker = MSVCLinker(
|
|
1259
|
-
command="$link /nologo $ldflags $extra_ldflags $libpaths
|
|
1941
|
+
command="$link /nologo $ldflags $extra_ldflags $libpaths @$outdir_rel/objects.list $libraries /out:$out",
|
|
1260
1942
|
infiles=[".o", ".obj", ".lib"],
|
|
1261
1943
|
outfiles=["{outdir}/{binary}.exe"],
|
|
1262
1944
|
variables={"desc": "[LINK] {binary}"},
|
|
1263
1945
|
implicit=["$link_path"])
|
|
1264
1946
|
|
|
1265
1947
|
archiver = MSVCArchiver(
|
|
1266
|
-
command="$lib /nologo /out:$out
|
|
1948
|
+
command="$lib /nologo /out:$out @$outdir_rel/objects.list",
|
|
1267
1949
|
infiles=[".o", ".obj", ".lib"],
|
|
1268
1950
|
outfiles=["{outdir}/{binary}.lib"],
|
|
1269
1951
|
variables={"desc": "[LIB] {binary}"},
|
|
@@ -1276,11 +1958,15 @@ class MSVCToolchain(Toolchain):
|
|
|
1276
1958
|
|
|
1277
1959
|
_toolchains = {
|
|
1278
1960
|
GNUToolchain: GNUToolchain(),
|
|
1961
|
+
DarwinGNUToolchain: DarwinGNUToolchain(),
|
|
1279
1962
|
MSVCToolchain: MSVCToolchain(),
|
|
1280
1963
|
}
|
|
1281
1964
|
|
|
1282
|
-
|
|
1965
|
+
_system = platform.system()
|
|
1966
|
+
if _system == "Windows":
|
|
1283
1967
|
toolchain = _toolchains[MSVCToolchain]
|
|
1968
|
+
elif _system == "Darwin":
|
|
1969
|
+
toolchain = _toolchains[DarwinGNUToolchain]
|
|
1284
1970
|
else:
|
|
1285
1971
|
toolchain = _toolchains[GNUToolchain]
|
|
1286
1972
|
|
|
@@ -1320,9 +2006,23 @@ class CXXProject(Task):
|
|
|
1320
2006
|
cflags = []
|
|
1321
2007
|
""" A list of compiler flags used when compiling C files. """
|
|
1322
2008
|
|
|
2009
|
+
cstd = None
|
|
2010
|
+
"""
|
|
2011
|
+
C language standard to use (int). Default: 17
|
|
2012
|
+
|
|
2013
|
+
If the chosen standard is not supported, the nearest supported standard is selected.
|
|
2014
|
+
"""
|
|
2015
|
+
|
|
1323
2016
|
cxxflags = []
|
|
1324
2017
|
""" A list of compiler flags used when compiling C++ files. """
|
|
1325
2018
|
|
|
2019
|
+
cxxstd = None
|
|
2020
|
+
"""
|
|
2021
|
+
C++ language standard to use (int). Default: 17
|
|
2022
|
+
|
|
2023
|
+
If the chosen standard is not supported, the nearest supported standard is selected.
|
|
2024
|
+
"""
|
|
2025
|
+
|
|
1326
2026
|
depimports = []
|
|
1327
2027
|
""" List of implicit dependencies """
|
|
1328
2028
|
|
|
@@ -1341,6 +2041,18 @@ class CXXProject(Task):
|
|
|
1341
2041
|
macros = []
|
|
1342
2042
|
""" List of preprocessor macros to set """
|
|
1343
2043
|
|
|
2044
|
+
optimize = "release"
|
|
2045
|
+
"""
|
|
2046
|
+
Compiler optimization level.
|
|
2047
|
+
|
|
2048
|
+
Supported values are:
|
|
2049
|
+
|
|
2050
|
+
- "none" / None
|
|
2051
|
+
- "debug"
|
|
2052
|
+
- "size"
|
|
2053
|
+
- "release"
|
|
2054
|
+
"""
|
|
2055
|
+
|
|
1344
2056
|
sources = []
|
|
1345
2057
|
""" A list of sources to compile.
|
|
1346
2058
|
|
|
@@ -1374,6 +2086,33 @@ class CXXProject(Task):
|
|
|
1374
2086
|
binary = None
|
|
1375
2087
|
""" Name of the target binary (defaults to canonical task name) """
|
|
1376
2088
|
|
|
2089
|
+
coverage = False
|
|
2090
|
+
"""Enable code coverage instrumentation.
|
|
2091
|
+
|
|
2092
|
+
Only implemented for GCC/Clang toolchains.
|
|
2093
|
+
|
|
2094
|
+
When set, the --coverage flag is passed to the compiler. The compiler
|
|
2095
|
+
instruments the generated machine code and outputs coverage note files
|
|
2096
|
+
(.gcno), one for each translation unit, which are collected into the
|
|
2097
|
+
task artifact. Upon running the executable, coverage data files are
|
|
2098
|
+
generated.
|
|
2099
|
+
|
|
2100
|
+
Use the :func:`attributes.coverage_data` decorator to
|
|
2101
|
+
automatically collect and publish data files in tasks that run
|
|
2102
|
+
instrumented binaries. The :func:`attributes.coverage_report_gcov`
|
|
2103
|
+
decorator can then be used to process the notes and data files
|
|
2104
|
+
into human readable coverage information. There is also a
|
|
2105
|
+
:func:`attributes.coverage_report_lcov` decorator that will
|
|
2106
|
+
generate and publish an HTML coverage report.
|
|
2107
|
+
|
|
2108
|
+
Example:
|
|
2109
|
+
|
|
2110
|
+
.. literalinclude:: ../examples/code_coverage/coverage.jolt
|
|
2111
|
+
:language: python
|
|
2112
|
+
:caption: examples/code_coverage/coverage.jolt
|
|
2113
|
+
|
|
2114
|
+
"""
|
|
2115
|
+
|
|
1377
2116
|
incremental = True
|
|
1378
2117
|
""" Compile incrementally.
|
|
1379
2118
|
|
|
@@ -1428,7 +2167,7 @@ class CXXProject(Task):
|
|
|
1428
2167
|
self._init_rules_and_vars()
|
|
1429
2168
|
|
|
1430
2169
|
def _init_rules_and_vars(self):
|
|
1431
|
-
self._rules_by_ext =
|
|
2170
|
+
self._rules_by_ext = OrderedDict()
|
|
1432
2171
|
self._rules = []
|
|
1433
2172
|
self._variables = []
|
|
1434
2173
|
|
|
@@ -1466,22 +2205,26 @@ class CXXProject(Task):
|
|
|
1466
2205
|
def _verify_influence(self, deps, artifact, tools):
|
|
1467
2206
|
# Verify that listed sources and their dependencies are influencing
|
|
1468
2207
|
sources = set(self.sources + getattr(self, "headers", []))
|
|
1469
|
-
with tools.cwd(
|
|
2208
|
+
with tools.cwd(tools.wsroot):
|
|
1470
2209
|
depfiles = [obj + ".d" for obj in getattr(self._writer, "_objects", [])]
|
|
1471
2210
|
for depfile in depfiles:
|
|
1472
2211
|
try:
|
|
1473
2212
|
data = tools.read_file(depfile)
|
|
1474
2213
|
except Exception:
|
|
1475
2214
|
continue
|
|
1476
|
-
data = data.split(":", 1)
|
|
1477
|
-
if len(data) <= 1:
|
|
1478
|
-
continue
|
|
1479
2215
|
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
2216
|
+
data = data.replace("\\\n", "")
|
|
2217
|
+
for depline in data.splitlines():
|
|
2218
|
+
depline = depline.strip()
|
|
2219
|
+
depline = depline.split(":", 1)
|
|
2220
|
+
if len(depline) <= 1:
|
|
2221
|
+
continue
|
|
2222
|
+
|
|
2223
|
+
inputs = depline[1]
|
|
2224
|
+
inputs = inputs.replace("\\ ", "\x00")
|
|
2225
|
+
inputs = [dep.strip().replace("\x00", " ") for dep in inputs.split()]
|
|
2226
|
+
inputs = [tools.expand_relpath(input, self.joltdir) for input in filter(lambda n: n, inputs)]
|
|
2227
|
+
sources = sources.union(inputs)
|
|
1485
2228
|
super()._verify_influence(deps, artifact, tools, sources)
|
|
1486
2229
|
|
|
1487
2230
|
def _expand_headers(self):
|
|
@@ -1515,10 +2258,11 @@ class CXXProject(Task):
|
|
|
1515
2258
|
self.sources = sources
|
|
1516
2259
|
|
|
1517
2260
|
def _write_ninja_file(self, basedir, deps, tools, filename="build.ninja"):
|
|
1518
|
-
with open(fs.path.join(basedir, filename), "w") as fobj:
|
|
2261
|
+
with open(tools.expand_path(fs.path.join(basedir, filename)), "w") as fobj:
|
|
1519
2262
|
writer = ninja.Writer(fobj)
|
|
1520
|
-
writer.depimports = [
|
|
1521
|
-
|
|
2263
|
+
writer.depimports = [
|
|
2264
|
+
tools.expand_relpath(dep, tools.wsroot)
|
|
2265
|
+
for dep in self.depimports]
|
|
1522
2266
|
writer.objects = []
|
|
1523
2267
|
writer.sources = copy.copy(self.sources)
|
|
1524
2268
|
self._populate_rules_and_variables(writer, deps, tools)
|
|
@@ -1526,12 +2270,6 @@ class CXXProject(Task):
|
|
|
1526
2270
|
writer.close()
|
|
1527
2271
|
return writer
|
|
1528
2272
|
|
|
1529
|
-
def _prepare_ninja_cache(self, deps, tools):
|
|
1530
|
-
""" Hooked from ninja-cache plugin """
|
|
1531
|
-
|
|
1532
|
-
def _write_ninja_cache(self, deps, tools):
|
|
1533
|
-
""" Hooked from ninja-cache plugin """
|
|
1534
|
-
|
|
1535
2273
|
def _write_shell_file(self, basedir, deps, tools, writer):
|
|
1536
2274
|
filepath = fs.path.join(basedir, "compile")
|
|
1537
2275
|
with open(filepath, "w") as fobj:
|
|
@@ -1555,7 +2293,7 @@ def main():
|
|
|
1555
2293
|
for object in objects:
|
|
1556
2294
|
print(object)
|
|
1557
2295
|
elif [arg for arg in sys.argv[1:] if arg == "-a"]:
|
|
1558
|
-
subprocess.call(["ninja", "-v"])
|
|
2296
|
+
subprocess.call(["ninja", "-f", "{outdir}/build.ninja", "-v"])
|
|
1559
2297
|
else:
|
|
1560
2298
|
targets = []
|
|
1561
2299
|
for arg in sys.argv[1:]:
|
|
@@ -1565,7 +2303,7 @@ def main():
|
|
|
1565
2303
|
targets.extend(matches)
|
|
1566
2304
|
if not targets:
|
|
1567
2305
|
return
|
|
1568
|
-
subprocess.call(["ninja", "-v"] + targets)
|
|
2306
|
+
subprocess.call(["ninja", "-f", "{outdir}/build.ninja", "-v"] + targets)
|
|
1569
2307
|
|
|
1570
2308
|
if __name__ == "__main__":
|
|
1571
2309
|
main()
|
|
@@ -1574,7 +2312,8 @@ if __name__ == "__main__":
|
|
|
1574
2312
|
fobj.write(
|
|
1575
2313
|
data.format(
|
|
1576
2314
|
executable=sys.executable,
|
|
1577
|
-
objects=[fs.path.relpath(o,
|
|
2315
|
+
objects=[fs.path.relpath(o, tools.wsroot) for o in writer.objects],
|
|
2316
|
+
outdir=self.outdir))
|
|
1578
2317
|
tools.chmod(filepath, 0o777)
|
|
1579
2318
|
|
|
1580
2319
|
def find_rule(self, ext):
|
|
@@ -1619,7 +2358,7 @@ if __name__ == "__main__":
|
|
|
1619
2358
|
sources = [(tools.expand_path(source), origin) for source, origin in sources]
|
|
1620
2359
|
|
|
1621
2360
|
# Aggregated list of sources for each rule
|
|
1622
|
-
rule_source_list =
|
|
2361
|
+
rule_source_list = OrderedDict()
|
|
1623
2362
|
while sources:
|
|
1624
2363
|
source, origin = sources.pop()
|
|
1625
2364
|
_, ext = fs.path.splitext(source)
|
|
@@ -1716,25 +2455,62 @@ if __name__ == "__main__":
|
|
|
1716
2455
|
incrementally. The behavior can be changed with the ``incremental``
|
|
1717
2456
|
class attribute.
|
|
1718
2457
|
"""
|
|
1719
|
-
|
|
1720
2458
|
self.outdir = tools.builddir("ninja", self.incremental)
|
|
2459
|
+
self.outdir_rel = self.tools.expand_relpath(self.outdir, tools.wsroot)
|
|
1721
2460
|
self._expand_headers()
|
|
1722
2461
|
self._expand_sources(deps, tools)
|
|
1723
|
-
self._prepare_ninja_cache(deps, tools)
|
|
1724
2462
|
self._writer = self._write_ninja_file(self.outdir, deps, tools)
|
|
1725
|
-
self._write_ninja_cache(deps, tools)
|
|
1726
2463
|
verbose = " -v" if log.is_verbose() else ""
|
|
1727
2464
|
threads = config.get("jolt", "threads", tools.getenv("JOLT_THREADS", None))
|
|
1728
2465
|
threads = " -j" + threads if threads else ""
|
|
2466
|
+
keep_going = " -k 0" if config.get_keep_going() else ""
|
|
1729
2467
|
depsfile = self._get_keepdepfile(tools)
|
|
1730
2468
|
try:
|
|
1731
|
-
tools.run(
|
|
2469
|
+
self.buildlog = tools.run(
|
|
2470
|
+
"ninja{3}{2}{5} -C {0} -f {4} {1}",
|
|
2471
|
+
tools.wsroot,
|
|
2472
|
+
verbose,
|
|
2473
|
+
threads,
|
|
2474
|
+
depsfile,
|
|
2475
|
+
fs.path.join(self.outdir, "build.ninja"),
|
|
2476
|
+
keep_going,
|
|
2477
|
+
output=True,
|
|
2478
|
+
)
|
|
2479
|
+
self._report_errors(self.buildlog)
|
|
1732
2480
|
except JoltCommandError as e:
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
2481
|
+
self.buildlog = "\n".join(e.stdout)
|
|
2482
|
+
report = self._report_errors(self.buildlog)
|
|
2483
|
+
error = self._first_reported_error(report)
|
|
2484
|
+
if error:
|
|
2485
|
+
raise CompileError(error)
|
|
2486
|
+
raise e
|
|
2487
|
+
|
|
2488
|
+
if bool(getattr(self, "coverage", False)):
|
|
2489
|
+
self.covdatadir = tools.builddir("coverage-data")
|
|
2490
|
+
with tools.cwd(tools.wsroot):
|
|
2491
|
+
for obj in getattr(self._writer, "_objects", []):
|
|
2492
|
+
obj, ext = os.path.splitext(obj)
|
|
2493
|
+
obj = obj + ".gcno"
|
|
2494
|
+
try:
|
|
2495
|
+
tools.copy(obj, os.path.join(self.covdatadir, tools.expand_relpath(obj, "/")))
|
|
2496
|
+
except FileNotFoundError:
|
|
2497
|
+
pass
|
|
2498
|
+
if self.selfsustained:
|
|
2499
|
+
for _, artifact in deps.items():
|
|
2500
|
+
if artifact.paths.coverage_data:
|
|
2501
|
+
tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
|
|
2502
|
+
|
|
2503
|
+
def publish(self, artifact, tools):
|
|
2504
|
+
if bool(getattr(self, "coverage", False)):
|
|
2505
|
+
self.publish_coverage_data(artifact, tools)
|
|
2506
|
+
|
|
2507
|
+
def publish_coverage_data(self, artifact, tools):
|
|
2508
|
+
""" Publishes code coverage data files. """
|
|
2509
|
+
with tools.cwd(self.covdatadir):
|
|
2510
|
+
if artifact.collect("**/*.gcno", "cov/"):
|
|
2511
|
+
artifact.paths.coverage_data = "cov"
|
|
1736
2512
|
|
|
1737
|
-
def
|
|
2513
|
+
def debugshell(self, deps, tools):
|
|
1738
2514
|
"""
|
|
1739
2515
|
Invoked to start a debug shell.
|
|
1740
2516
|
|
|
@@ -1751,41 +2527,58 @@ if __name__ == "__main__":
|
|
|
1751
2527
|
self._expand_headers()
|
|
1752
2528
|
self._expand_sources(deps, tools)
|
|
1753
2529
|
self.outdir = tools.builddir("ninja", self.incremental)
|
|
1754
|
-
self.
|
|
2530
|
+
self.outdir_rel = self.tools.expand_relpath(self.outdir, tools.wsroot)
|
|
1755
2531
|
writer = self._write_ninja_file(self.outdir, deps, tools)
|
|
1756
|
-
self._write_ninja_cache(deps, tools)
|
|
1757
2532
|
self._write_shell_file(self.outdir, deps, tools, writer)
|
|
1758
2533
|
pathenv = self.outdir + os.pathsep + tools.getenv("PATH")
|
|
1759
|
-
with tools.cwd(
|
|
2534
|
+
with tools.cwd(tools.wsroot), tools.environ(PATH=pathenv):
|
|
1760
2535
|
print()
|
|
1761
2536
|
print("Use the 'compile' command to build individual compilation targets")
|
|
1762
|
-
super(
|
|
1763
|
-
|
|
1764
|
-
def _report_errors(self,
|
|
1765
|
-
|
|
1766
|
-
report.
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
2537
|
+
super().debugshell(deps, tools)
|
|
2538
|
+
|
|
2539
|
+
def _report_errors(self, logbuffer):
|
|
2540
|
+
""" Parses the build log and reports errors. """
|
|
2541
|
+
with self.report() as report, utils.ignore_exception():
|
|
2542
|
+
# GCC style errors
|
|
2543
|
+
report.add_regex_errors_with_file(
|
|
2544
|
+
"Compiler Error",
|
|
2545
|
+
r"^(?P<location>(?P<file>.*?):(?P<line>[0-9]+):(?P<col>[0-9]+)): (?P<message>([^ ]*? )?(error:|[A-Z][0-9]*) .*)\n(?P<details>( ( |[0-9])*\| .*\n)+)?",
|
|
2546
|
+
logbuffer,
|
|
2547
|
+
self.outdir)
|
|
2548
|
+
|
|
2549
|
+
report.add_regex_errors_with_file(
|
|
2550
|
+
"Compiler Warning",
|
|
2551
|
+
r"^(?P<location>(?P<file>.*?):(?P<line>[0-9]+):(?P<col>[0-9]+)): (?P<message>([^ ]*? )?warning: .*)\n(?P<details>( ( |[0-9])*\| .*\n)+)?",
|
|
2552
|
+
logbuffer,
|
|
2553
|
+
self.outdir)
|
|
2554
|
+
|
|
2555
|
+
# MSVC compiler errors
|
|
2556
|
+
report.add_regex_errors_with_file(
|
|
2557
|
+
"Compiler Error",
|
|
2558
|
+
r"^(?P<location>(?P<file>.*?)\((?P<line>[0-9]+)\)): (?P<message>(fatal )?error( C[0-9]*?): .*)",
|
|
2559
|
+
logbuffer,
|
|
2560
|
+
self.outdir)
|
|
2561
|
+
|
|
2562
|
+
# Binutils/MSVC linker errors
|
|
2563
|
+
report.add_regex_errors(
|
|
2564
|
+
"Linker Error",
|
|
2565
|
+
r"^(?P<location>(?P<file>.*?)(:.*?)?)( )?: (?P<message>(( fatal)?error LNK|warning LNK|undefined reference|multiple definition).*)",
|
|
2566
|
+
logbuffer)
|
|
2567
|
+
|
|
2568
|
+
# LLVM linker errors
|
|
2569
|
+
report.add_regex_errors(
|
|
2570
|
+
"Linker Error",
|
|
2571
|
+
r"^(?P<location>(.*?)ld(\.lld)?): (error|warning): (?P<message>.*)",
|
|
2572
|
+
logbuffer)
|
|
2573
|
+
|
|
2574
|
+
return report
|
|
2575
|
+
|
|
2576
|
+
def _first_reported_error(self, report):
|
|
2577
|
+
""" Returns the first reported error or None if no errors were reported. """
|
|
2578
|
+
if report is None:
|
|
2579
|
+
return None
|
|
2580
|
+
for error in report.errors:
|
|
2581
|
+
return error
|
|
1789
2582
|
|
|
1790
2583
|
|
|
1791
2584
|
class CXXLibrary(CXXProject):
|
|
@@ -1860,6 +2653,7 @@ class CXXLibrary(CXXProject):
|
|
|
1860
2653
|
Include path metadata for this directory is automatically exported.
|
|
1861
2654
|
|
|
1862
2655
|
"""
|
|
2656
|
+
super().publish(artifact, tools)
|
|
1863
2657
|
|
|
1864
2658
|
with tools.cwd(self.outdir):
|
|
1865
2659
|
if not self.shared:
|
|
@@ -1945,6 +2739,7 @@ class CXXExecutable(CXXProject):
|
|
|
1945
2739
|
the executable to allow consumers to run it easily.
|
|
1946
2740
|
|
|
1947
2741
|
"""
|
|
2742
|
+
super().publish(artifact, tools)
|
|
1948
2743
|
|
|
1949
2744
|
with tools.cwd(self.outdir):
|
|
1950
2745
|
if os.name == "nt":
|