jolt 0.9.172__py3-none-any.whl → 0.9.435__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.
Files changed (185) hide show
  1. jolt/__init__.py +80 -7
  2. jolt/__main__.py +9 -1
  3. jolt/bin/fstree-darwin-x86_64 +0 -0
  4. jolt/bin/fstree-linux-x86_64 +0 -0
  5. jolt/cache.py +596 -252
  6. jolt/chroot.py +36 -11
  7. jolt/cli.py +143 -130
  8. jolt/common_pb2.py +45 -45
  9. jolt/config.py +76 -40
  10. jolt/error.py +19 -4
  11. jolt/filesystem.py +2 -6
  12. jolt/graph.py +400 -82
  13. jolt/influence.py +110 -3
  14. jolt/loader.py +338 -174
  15. jolt/log.py +127 -31
  16. jolt/manifest.py +13 -46
  17. jolt/options.py +35 -11
  18. jolt/pkgs/abseil.py +42 -0
  19. jolt/pkgs/asio.py +25 -0
  20. jolt/pkgs/autoconf.py +41 -0
  21. jolt/pkgs/automake.py +41 -0
  22. jolt/pkgs/b2.py +31 -0
  23. jolt/pkgs/boost.py +111 -0
  24. jolt/pkgs/boringssl.py +32 -0
  25. jolt/pkgs/busybox.py +39 -0
  26. jolt/pkgs/bzip2.py +43 -0
  27. jolt/pkgs/cares.py +29 -0
  28. jolt/pkgs/catch2.py +36 -0
  29. jolt/pkgs/cbindgen.py +17 -0
  30. jolt/pkgs/cista.py +19 -0
  31. jolt/pkgs/clang.py +44 -0
  32. jolt/pkgs/cli11.py +24 -0
  33. jolt/pkgs/cmake.py +48 -0
  34. jolt/pkgs/cpython.py +196 -0
  35. jolt/pkgs/crun.py +29 -0
  36. jolt/pkgs/curl.py +38 -0
  37. jolt/pkgs/dbus.py +18 -0
  38. jolt/pkgs/double_conversion.py +24 -0
  39. jolt/pkgs/fastfloat.py +21 -0
  40. jolt/pkgs/ffmpeg.py +28 -0
  41. jolt/pkgs/flatbuffers.py +29 -0
  42. jolt/pkgs/fmt.py +27 -0
  43. jolt/pkgs/fstree.py +20 -0
  44. jolt/pkgs/gflags.py +18 -0
  45. jolt/pkgs/glib.py +18 -0
  46. jolt/pkgs/glog.py +25 -0
  47. jolt/pkgs/glslang.py +21 -0
  48. jolt/pkgs/golang.py +16 -11
  49. jolt/pkgs/googlebenchmark.py +18 -0
  50. jolt/pkgs/googletest.py +46 -0
  51. jolt/pkgs/gperf.py +15 -0
  52. jolt/pkgs/grpc.py +73 -0
  53. jolt/pkgs/hdf5.py +19 -0
  54. jolt/pkgs/help2man.py +14 -0
  55. jolt/pkgs/inja.py +28 -0
  56. jolt/pkgs/jsoncpp.py +31 -0
  57. jolt/pkgs/libarchive.py +43 -0
  58. jolt/pkgs/libcap.py +44 -0
  59. jolt/pkgs/libdrm.py +44 -0
  60. jolt/pkgs/libedit.py +42 -0
  61. jolt/pkgs/libevent.py +31 -0
  62. jolt/pkgs/libexpat.py +27 -0
  63. jolt/pkgs/libfastjson.py +21 -0
  64. jolt/pkgs/libffi.py +16 -0
  65. jolt/pkgs/libglvnd.py +30 -0
  66. jolt/pkgs/libogg.py +28 -0
  67. jolt/pkgs/libpciaccess.py +18 -0
  68. jolt/pkgs/libseccomp.py +21 -0
  69. jolt/pkgs/libtirpc.py +24 -0
  70. jolt/pkgs/libtool.py +42 -0
  71. jolt/pkgs/libunwind.py +35 -0
  72. jolt/pkgs/libva.py +18 -0
  73. jolt/pkgs/libvorbis.py +33 -0
  74. jolt/pkgs/libxml2.py +35 -0
  75. jolt/pkgs/libxslt.py +17 -0
  76. jolt/pkgs/libyajl.py +16 -0
  77. jolt/pkgs/llvm.py +81 -0
  78. jolt/pkgs/lua.py +54 -0
  79. jolt/pkgs/lz4.py +26 -0
  80. jolt/pkgs/m4.py +14 -0
  81. jolt/pkgs/make.py +17 -0
  82. jolt/pkgs/mesa.py +81 -0
  83. jolt/pkgs/meson.py +17 -0
  84. jolt/pkgs/mstch.py +28 -0
  85. jolt/pkgs/mysql.py +60 -0
  86. jolt/pkgs/nasm.py +49 -0
  87. jolt/pkgs/ncurses.py +30 -0
  88. jolt/pkgs/ng_log.py +25 -0
  89. jolt/pkgs/ninja.py +45 -0
  90. jolt/pkgs/nlohmann_json.py +25 -0
  91. jolt/pkgs/nodejs.py +19 -11
  92. jolt/pkgs/opencv.py +24 -0
  93. jolt/pkgs/openjdk.py +26 -0
  94. jolt/pkgs/openssl.py +103 -0
  95. jolt/pkgs/paho.py +76 -0
  96. jolt/pkgs/patchelf.py +16 -0
  97. jolt/pkgs/perl.py +42 -0
  98. jolt/pkgs/pkgconfig.py +64 -0
  99. jolt/pkgs/poco.py +39 -0
  100. jolt/pkgs/protobuf.py +77 -0
  101. jolt/pkgs/pugixml.py +27 -0
  102. jolt/pkgs/python.py +19 -0
  103. jolt/pkgs/qt.py +35 -0
  104. jolt/pkgs/rapidjson.py +26 -0
  105. jolt/pkgs/rapidyaml.py +28 -0
  106. jolt/pkgs/re2.py +30 -0
  107. jolt/pkgs/re2c.py +17 -0
  108. jolt/pkgs/readline.py +15 -0
  109. jolt/pkgs/rust.py +41 -0
  110. jolt/pkgs/sdl.py +28 -0
  111. jolt/pkgs/simdjson.py +27 -0
  112. jolt/pkgs/soci.py +46 -0
  113. jolt/pkgs/spdlog.py +29 -0
  114. jolt/pkgs/spirv_llvm.py +21 -0
  115. jolt/pkgs/spirv_tools.py +24 -0
  116. jolt/pkgs/sqlite.py +83 -0
  117. jolt/pkgs/ssl.py +12 -0
  118. jolt/pkgs/texinfo.py +15 -0
  119. jolt/pkgs/tomlplusplus.py +22 -0
  120. jolt/pkgs/wayland.py +26 -0
  121. jolt/pkgs/x11.py +58 -0
  122. jolt/pkgs/xerces_c.py +20 -0
  123. jolt/pkgs/xorg.py +360 -0
  124. jolt/pkgs/xz.py +29 -0
  125. jolt/pkgs/yamlcpp.py +30 -0
  126. jolt/pkgs/zeromq.py +47 -0
  127. jolt/pkgs/zlib.py +87 -0
  128. jolt/pkgs/zstd.py +33 -0
  129. jolt/plugins/alias.py +3 -0
  130. jolt/plugins/allure.py +2 -2
  131. jolt/plugins/autotools.py +66 -0
  132. jolt/plugins/cache.py +1 -1
  133. jolt/plugins/cmake.py +74 -6
  134. jolt/plugins/conan.py +238 -0
  135. jolt/plugins/cxxinfo.py +7 -0
  136. jolt/plugins/docker.py +76 -19
  137. jolt/plugins/email.xslt +141 -118
  138. jolt/plugins/environ.py +11 -0
  139. jolt/plugins/fetch.py +141 -0
  140. jolt/plugins/gdb.py +33 -14
  141. jolt/plugins/gerrit.py +0 -13
  142. jolt/plugins/git.py +248 -66
  143. jolt/plugins/googletest.py +1 -1
  144. jolt/plugins/http.py +1 -1
  145. jolt/plugins/libtool.py +63 -0
  146. jolt/plugins/linux.py +990 -0
  147. jolt/plugins/logstash.py +4 -4
  148. jolt/plugins/meson.py +61 -0
  149. jolt/plugins/ninja-compdb.py +96 -28
  150. jolt/plugins/ninja.py +424 -150
  151. jolt/plugins/paths.py +11 -1
  152. jolt/plugins/pkgconfig.py +219 -0
  153. jolt/plugins/podman.py +131 -87
  154. jolt/plugins/python.py +137 -0
  155. jolt/plugins/remote_execution/administration_pb2.py +27 -19
  156. jolt/plugins/remote_execution/log_pb2.py +12 -12
  157. jolt/plugins/remote_execution/scheduler_pb2.py +23 -23
  158. jolt/plugins/remote_execution/worker_pb2.py +19 -19
  159. jolt/plugins/report.py +7 -2
  160. jolt/plugins/rust.py +25 -0
  161. jolt/plugins/scheduler.py +135 -86
  162. jolt/plugins/selfdeploy/setup.py +6 -6
  163. jolt/plugins/selfdeploy.py +49 -31
  164. jolt/plugins/strings.py +35 -22
  165. jolt/plugins/symlinks.py +11 -4
  166. jolt/plugins/telemetry.py +1 -2
  167. jolt/plugins/timeline.py +13 -3
  168. jolt/scheduler.py +467 -165
  169. jolt/tasks.py +427 -111
  170. jolt/templates/timeline.html.template +44 -47
  171. jolt/timer.py +22 -0
  172. jolt/tools.py +527 -188
  173. jolt/utils.py +183 -3
  174. jolt/version.py +1 -1
  175. jolt/xmldom.py +12 -2
  176. {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/METADATA +97 -41
  177. jolt-0.9.435.dist-info/RECORD +207 -0
  178. {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/WHEEL +1 -1
  179. jolt/plugins/amqp.py +0 -855
  180. jolt/plugins/debian.py +0 -338
  181. jolt/plugins/repo.py +0 -253
  182. jolt/plugins/snap.py +0 -122
  183. jolt-0.9.172.dist-info/RECORD +0 -92
  184. {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/entry_points.txt +0 -0
  185. {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/top_level.txt +0 -0
jolt/plugins/ninja.py CHANGED
@@ -1,8 +1,11 @@
1
+ from collections import OrderedDict
1
2
  import contextlib
2
3
  import copy
3
4
  import functools
4
- import ninja_syntax as ninja
5
+ from ninja import ninja_syntax as ninja
5
6
  import os
7
+ import platform
8
+ import re
6
9
  import sys
7
10
 
8
11
  from jolt.tasks import Task, attributes as task_attributes
@@ -10,7 +13,6 @@ from jolt import config
10
13
  from jolt.influence import attribute as influence_attribute
11
14
  from jolt.influence import DirectoryInfluence, FileInfluence
12
15
  from jolt.influence import HashInfluenceProvider, TaskAttributeInfluence
13
- from jolt.loader import get_workspacedir
14
16
  from jolt.config import get_cachedir
15
17
  from jolt import log
16
18
  from jolt import utils
@@ -20,6 +22,12 @@ from jolt.error import raise_task_error_if
20
22
  from jolt.error import JoltError, JoltCommandError
21
23
 
22
24
 
25
+ c_standard_default = None
26
+ cxx_standard_default = None
27
+ c_standards_list = [90, 99, 11, 17, 23]
28
+ cxx_standards_list = [98, 11, 14, 17, 20, 23, 26]
29
+
30
+
23
31
  class CompileError(JoltError):
24
32
  def __init__(self, error):
25
33
  if error:
@@ -99,8 +107,8 @@ class attributes:
99
107
  self.info("Collecting coverage data into {covdatadir}")
100
108
 
101
109
  for _, artifact in deps.items():
102
- if str(artifact.paths.coverage_data):
103
- tools.copy(artifact.paths.coverage_data, self.covdatadir)
110
+ if artifact.paths.coverage_data:
111
+ tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
104
112
 
105
113
  with tools.environ(GCOV_PREFIX=self.covdatadir):
106
114
  yield
@@ -152,9 +160,9 @@ class attributes:
152
160
  The following class attributes may be set to control the behavior
153
161
  of lcov:
154
162
 
155
- - ``gcov_branches`` - Enable branch coverage.
163
+ - ``gcov_branches`` - Enable branch coverage.
156
164
  Passed as ``-b`` on the command line. Default: ``True``
157
- - ``gcov_demangle`` - Display demangled function names in output.
165
+ - ``gcov_demangle`` - Display demangled function names in output.
158
166
  Passed as ``-m`` on the command line. Default: ``True``
159
167
 
160
168
  The task artifact is annotated with
@@ -195,32 +203,31 @@ class attributes:
195
203
  if not hasattr(self, "covdatadir"):
196
204
  self.covdatadir = tools.builddir("coverage-data")
197
205
  for _, artifact in deps.items():
198
- if str(artifact.paths.coverage_data):
199
- tools.copy(artifact.paths.coverage_data, self.covdatadir)
206
+ if artifact.paths.coverage_data:
207
+ tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
200
208
 
201
209
  with tools.cwd(self.covdatadir):
202
210
  datafiles = tools.glob("**/*.gcda")
203
211
 
204
- with tools.cwd(tools.builddir("coverage-report-gcov")):
212
+ reportdir = tools.builddir("coverage-report-gcov")
213
+
214
+ with tools.cwd(tools.wsroot):
205
215
  for file in datafiles:
206
216
  infile = os.path.join(self.covdatadir, file)
207
217
  branchflag = "-b " if bool(getattr(self, "gcov_branches", branches)) else ""
208
218
  demangleflag = "-m " if bool(getattr(self, "gcov_demangle", demangle)) else ""
209
- tools.run("{} {}{}-p -s {covdatadir} {}",
210
- gcov, branchflag, demangleflag, infile, output_on_error=True)
211
-
212
- wsdir = get_workspacedir()
213
-
214
- for file in tools.glob("^#^#*.gcov"):
215
- # Patch paths in gcov files.
216
- tools.replace_in_file(file, "Source:../../", "Source:")
217
- tools.replace_in_file(file, self.covdatadir, "")
218
-
219
- # Demangle and rename files into a tree directory structure.
220
- newfile = file.replace("^", "..").replace("#", os.sep)
221
- newfile = tools.expand_relpath(newfile, wsdir)
222
- tools.mkdirname(newfile)
223
- tools.move(file, newfile)
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)
224
231
 
225
232
  @utils.cached.instance
226
233
  def publish_coverage_data(self, artifact, tools):
@@ -327,6 +334,19 @@ class attributes:
327
334
 
328
335
  def decorate(cls):
329
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
+
330
350
  def run_coverage_report_lcov(self, deps, tools):
331
351
  lcov = tools.getenv("LCOV", "lcov")
332
352
  if not tools.which(lcov):
@@ -346,13 +366,12 @@ class attributes:
346
366
  if not hasattr(self, "covdatadir"):
347
367
  self.covdatadir = tools.builddir("coverage-data")
348
368
  for _, artifact in deps.items():
349
- if str(artifact.paths.coverage_data):
350
- tools.copy(artifact.paths.coverage_data, self.covdatadir)
369
+ if artifact.paths.coverage_data:
370
+ tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
351
371
 
352
372
  reportdir = tools.builddir("coverage-report-lcov")
353
373
  htmldir = tools.builddir("coverage-report-lcov-html")
354
374
  cachedir = get_cachedir()
355
- wsdir = get_workspacedir()
356
375
 
357
376
  lcov_configs = list(getattr(self, "lcov_configs", []))
358
377
  lcov_excludes = list(getattr(self, "lcov_excludes", []))
@@ -360,7 +379,7 @@ class attributes:
360
379
  lcov_ignore_errors = list(getattr(self, "lcov_ignore_errors", ["empty", "mismatch", "source", "source", "unused"]))
361
380
  lcov_substitutes = list(getattr(self, "lcov_substitutes", []))
362
381
 
363
- lcov_html_flags = ["-p", wsdir]
382
+ lcov_html_flags = ["-p", tools.wsroot]
364
383
  if bool(getattr(self, "lcov_demangle", demangle)):
365
384
  lcov_html_flags.append("--demangle-cpp")
366
385
  lcov_html_flags.append(f"--rc demangle_cpp={cxxfilt}")
@@ -373,7 +392,7 @@ class attributes:
373
392
  lcov_configs.append("no_exception_branch=1")
374
393
 
375
394
  if lcov_excludes:
376
- lcov_excludes = ["--exclude " + exclude for exclude in lcov_excludes]
395
+ lcov_excludes = ["--exclude " + f"'{exclude}'" for exclude in lcov_excludes]
377
396
  lcov_info_flags.extend(lcov_excludes)
378
397
 
379
398
  if lcov_filters:
@@ -395,13 +414,22 @@ class attributes:
395
414
  lcov_html_flags.extend(lcov_substitutes)
396
415
 
397
416
  self.info("Generating LCOV code coverage report")
398
- tools.run("{} -c -d {covdatadir} -o {}/coverage.info --gcov-tool={} {}",
399
- lcov, reportdir, gcov, " ".join(lcov_info_flags), output_on_error=True)
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)
400
419
 
401
420
  reports = []
402
421
  for _, artifact in deps.items():
403
- if str(artifact.paths.coverage_report_lcov):
422
+ if artifact.paths.coverage_report_lcov:
404
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
+
405
433
  if reports:
406
434
  reports = ["-a " + report for report in reports]
407
435
  self.info("Merging LCOV code coverage reports")
@@ -409,13 +437,13 @@ class attributes:
409
437
  lcov, " ".join(reports), reportdir, gcov, " ".join(lcov_info_flags), output_on_error=True)
410
438
 
411
439
  with tools.cwd(reportdir):
412
- tools.replace_in_file("coverage.info", f"{wsdir}/", "")
440
+ tools.replace_in_file("coverage.info", f"{tools.wsroot}/", "")
413
441
  tools.replace_in_file("coverage.info", f"{cachedir}/", "{{cachedir}}/")
414
442
  tools.copy("coverage.info", "coverage.info.abs")
415
- tools.replace_in_file("coverage.info.abs", "SF:", f"SF:{wsdir}/")
416
- tools.replace_in_file("coverage.info.abs", f"SF:{wsdir}/" + "{{cachedir}}/", f"SF:{cachedir}/")
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}/")
417
445
 
418
- if tools.file_size("coverage.info") <= 0:
446
+ if tools.file_size("coverage.info") <= 0 or not self._cov_report_has_trace_data(tools.expand_path("coverage.info")):
419
447
  tools.unlink("coverage.info")
420
448
  self.warning("No coverage data records available, skipping HTML report generation")
421
449
  return
@@ -620,7 +648,7 @@ class Variable(HashInfluenceProvider):
620
648
 
621
649
  @staticmethod
622
650
  def __get_variables__(obj):
623
- variables = {}
651
+ variables = OrderedDict()
624
652
  for mro in reversed(obj.__class__.__mro__):
625
653
  for key, variable in getattr(mro, "__variable_list", {}).items():
626
654
  attr = getattr(obj.__class__, key)
@@ -631,7 +659,7 @@ class Variable(HashInfluenceProvider):
631
659
  def __set_name__(self, owner, name):
632
660
  self.name = name
633
661
  if "__variable_list" not in owner.__dict__:
634
- setattr(owner, "__variable_list", {})
662
+ setattr(owner, "__variable_list", OrderedDict())
635
663
  getattr(owner, "__variable_list")[name] = self
636
664
 
637
665
  def create(self, project, writer, deps, tools):
@@ -730,6 +758,54 @@ class ProjectVariable(Variable):
730
758
  return "PV: default={},attrib={}".format(self._default, self._attrib)
731
759
 
732
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
+
733
809
  class SharedLibraryVariable(Variable):
734
810
  def __init__(self, name=None, default=None):
735
811
  self.name = name
@@ -759,11 +835,11 @@ class GNUPCHVariables(Variable):
759
835
  "multiple precompiled headers found, only one is allowed")
760
836
 
761
837
  if len(pch) <= 0:
762
- writer.variable("pch_out", "$binary.dir/")
838
+ writer.variable("pch_out", tools.expand_relpath("{outdir}/{binary}.dir/", tools.wsroot))
763
839
  return
764
840
 
765
841
  project._pch = fs.path.basename(pch[0])
766
- project._pch_out = "$binary.dir/" + project._pch + self.gch_ext
842
+ project._pch_out = tools.expand_relpath("{outdir}/{binary}.dir/{_pch}" + self.gch_ext, tools.wsroot)
767
843
 
768
844
  writer.variable("pch", project._pch)
769
845
  writer.variable("pch_flags", "")
@@ -885,7 +961,7 @@ class Rule(HashInfluenceProvider):
885
961
  before any C++ file is compiled.
886
962
  """
887
963
  self.command = command
888
- self.variables = variables or {}
964
+ self.variables = OrderedDict([(key, value) for key, value in (variables or {}).items()])
889
965
  self.depfile = depfile
890
966
  self.deps = deps
891
967
  self.infiles = infiles or []
@@ -920,8 +996,8 @@ class Rule(HashInfluenceProvider):
920
996
  in_base, in_ext = fs.path.splitext(in_basename)
921
997
 
922
998
  if in_dirname and fs.path.isabs(in_dirname):
923
- in_dirname_outdir = fs.path.relpath(in_dirname, project.outdir)
924
- in_dirname = fs.path.relpath(in_dirname, project.joltdir)
999
+ in_dirname_outdir = fs.path.relpath(in_dirname, project.tools.wsroot)
1000
+ in_dirname = fs.path.relpath(in_dirname, project.tools.wsroot)
925
1001
 
926
1002
  result_files = []
927
1003
  for outfile in outfiles or self.outfiles:
@@ -938,7 +1014,7 @@ class Rule(HashInfluenceProvider):
938
1014
 
939
1015
  result_files.append(outfile.replace("..", "__"))
940
1016
 
941
- result_vars = {}
1017
+ result_vars = OrderedDict()
942
1018
  for key, val in self.variables.items():
943
1019
  result_vars[key] = project.tools.expand(
944
1020
  val,
@@ -964,17 +1040,17 @@ class Rule(HashInfluenceProvider):
964
1040
  def build(self, project, writer, infiles, implicit=None, implicit_outputs=None, order_only=None):
965
1041
  result = []
966
1042
  infiles = utils.as_list(infiles)
967
- infiles_rel = [fs.path.relpath(infile, project.outdir) for infile in infiles]
1043
+ infiles_rel = [fs.path.relpath(infile, project.tools.wsroot) for infile in infiles]
968
1044
  implicit = (self.implicit or []) + (implicit or [])
969
1045
  implicit_outputs = (self.implicit_outputs or []) + (implicit_outputs or [])
970
1046
  order_only = (self.order_only or []) + (order_only or [])
971
1047
 
972
1048
  if self.aggregate:
973
1049
  outfiles, variables = self._out(project, infiles[0])
974
- outfiles_rel = [fs.path.relpath(outfile, project.outdir) for outfile in outfiles]
1050
+ outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in outfiles]
975
1051
  if implicit_outputs:
976
1052
  implicit_outfiles, _ = self._out(project, infiles[0], implicit_outputs)
977
- implicit_outfiles_rel = [fs.path.relpath(outfile, project.outdir) for outfile in implicit_outfiles]
1053
+ implicit_outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in implicit_outfiles]
978
1054
  else:
979
1055
  implicit_outfiles_rel = []
980
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)
@@ -982,10 +1058,10 @@ class Rule(HashInfluenceProvider):
982
1058
  else:
983
1059
  for infile, infile_rel in zip(infiles, infiles_rel):
984
1060
  outfiles, variables = self._out(project, infile)
985
- outfiles_rel = [fs.path.relpath(outfile, project.outdir) for outfile in outfiles]
1061
+ outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in outfiles]
986
1062
  if implicit_outputs:
987
1063
  implicit_outfiles, _ = self._out(project, infile, implicit_outputs)
988
- implicit_outfiles_rel = [fs.path.relpath(outfile, project.outdir) for outfile in implicit_outfiles]
1064
+ implicit_outfiles_rel = [fs.path.relpath(outfile, project.tools.wsroot) for outfile in implicit_outfiles]
989
1065
  else:
990
1066
  implicit_outfiles_rel = []
991
1067
  writer.build(outfiles_rel, self.name, infile_rel, variables=variables, implicit=implicit, implicit_outputs=implicit_outfiles_rel, order_only=order_only)
@@ -1018,12 +1094,12 @@ class ProtobufCompiler(Rule):
1018
1094
  phony=True,
1019
1095
  variables=None,
1020
1096
  **kwargs):
1021
- variables_final = {
1022
- "desc": "[PROTOC] {in_base}{in_ext}",
1023
- "out_depfile": "{binary}.dir/{in_base}.pb.d",
1024
- "outdir_proto": os.path.dirname(outfiles[0]),
1025
- "in_path_outdir": "{in_path_outdir}",
1026
- }
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
+ ])
1027
1103
  variables_final.update(variables or {})
1028
1104
  super().__init__(
1029
1105
  command=command,
@@ -1064,8 +1140,8 @@ class GRPCProtobufCompiler(ProtobufCompiler):
1064
1140
  variables=None,
1065
1141
  **kwargs):
1066
1142
  variables_final = {
1067
- "out_depfile": "{binary}.dir/{in_base}.pb.d",
1068
- "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",
1069
1145
  }
1070
1146
  variables_final.update(variables or {})
1071
1147
  super().__init__(command=command, depfile=depfile, outfiles=outfiles, variables=variables_final, **kwargs)
@@ -1132,7 +1208,8 @@ class Skip(Rule):
1132
1208
 
1133
1209
  @task_attributes.system
1134
1210
  class MakeDirectory(Rule):
1135
- command_linux = "mkdir -p $out"
1211
+ command_darwin = "mkdir -p $out"
1212
+ command_linux = command_darwin
1136
1213
  command_windows = "if not exist $out mkdir $out"
1137
1214
 
1138
1215
  def __init__(self, name):
@@ -1207,7 +1284,9 @@ class FileListWriter(Rule):
1207
1284
  def build(self, project, writer, infiles, implicit=None, order_only=None):
1208
1285
  infiles = [fs.as_posix(infile) for infile in infiles] if self.posix else infiles
1209
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)
1210
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)
1211
1290
  data, digest = self._data(project, infiles)
1212
1291
  if not self._identical(file_list_path, file_list_hash_path, data, digest):
1213
1292
  self._write(file_list_path, file_list_hash_path, data, digest)
@@ -1290,11 +1369,12 @@ class GNUDepImporter(Rule):
1290
1369
  for name, artifact in deps.items():
1291
1370
  if artifact.cxxinfo.libpaths.items():
1292
1371
  sandbox = project.tools.sandbox(artifact, project.incremental)
1372
+ sandbox = project.tools.expand_relpath(sandbox, project.tools.wsroot)
1293
1373
  for lib in artifact.cxxinfo.libraries.items():
1294
1374
  name = "{0}{1}{2}".format(self.prefix, lib, self.suffix)
1295
1375
  for path in artifact.cxxinfo.libpaths.items():
1296
1376
  archive = fs.path.join(sandbox, path, name)
1297
- if fs.path.exists(archive):
1377
+ if fs.path.exists(os.path.join(project.tools.wsroot, archive)):
1298
1378
  archives.append(archive)
1299
1379
  return archives
1300
1380
 
@@ -1305,7 +1385,9 @@ class GNUDepImporter(Rule):
1305
1385
  if isinstance(project, CXXLibrary):
1306
1386
  imports += self._build_archives(project, writer, deps)
1307
1387
  if not project.shared and project.selfsustained:
1308
- writer.sources.extend(imports)
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)
1309
1391
  return imports
1310
1392
 
1311
1393
  def get_influence(self, task):
@@ -1318,7 +1400,7 @@ class Toolchain(object):
1318
1400
 
1319
1401
  @staticmethod
1320
1402
  def build_rules_and_vars(obj):
1321
- rule_map = {}
1403
+ rule_map = OrderedDict()
1322
1404
  rules, vars = Toolchain.all_rules_and_vars(obj)
1323
1405
  for name, rule in rules.items():
1324
1406
  rule.name = name
@@ -1390,18 +1472,18 @@ class IncludePaths(Variable):
1390
1472
  return tools.expand(path)
1391
1473
  if path[0] in ['-']:
1392
1474
  path = tools.expand_path(path[1:])
1393
- return tools.expand_relpath(path, project.outdir)
1475
+ return tools.expand_relpath(path, project.tools.wsroot)
1394
1476
 
1395
1477
  def expand_artifact(sandbox, path):
1396
1478
  if path[0] in ['=', fs.sep]:
1397
1479
  return path
1398
1480
  if path[0] in ['-']:
1399
1481
  path = fs.path.join(project.joltdir, path[1:])
1400
- return tools.expand_relpath(fs.path.join(sandbox, path), project.outdir)
1482
+ return tools.expand_relpath(fs.path.join(sandbox, path), project.tools.wsroot)
1401
1483
 
1402
1484
  incpaths = []
1403
1485
  if self.outdir:
1404
- incpaths += ["$binary.dir"]
1486
+ incpaths += [tools.expand_relpath("{outdir}/{binary}.dir", project.tools.wsroot)]
1405
1487
  if self.attrib:
1406
1488
  incpaths += [expand(path) for path in getattr(project, self.attrib)]
1407
1489
  if self.imported:
@@ -1430,12 +1512,13 @@ class LibraryPaths(Variable):
1430
1512
  return
1431
1513
  libpaths = []
1432
1514
  if self.attrib:
1433
- libpaths = [tools.expand_relpath(path, project.outdir) for path in getattr(project, self.attrib)]
1515
+ libpaths = [tools.expand_relpath(path, project.tools.wsroot) for path in getattr(project, self.attrib)]
1434
1516
  if self.imported:
1435
1517
  for _, artifact in deps.items():
1436
1518
  libs = artifact.cxxinfo.libpaths.items()
1437
1519
  if libs:
1438
1520
  sandbox = tools.sandbox(artifact, project.incremental)
1521
+ sandbox = tools.expand_relpath(sandbox, project.tools.wsroot)
1439
1522
  libpaths += [fs.path.join(sandbox, path) for path in libs]
1440
1523
  libpaths = ["{0}{1}".format(self.prefix, path) for path in libpaths]
1441
1524
  writer.variable(self.name, " ".join(libpaths))
@@ -1497,7 +1580,9 @@ class GNUToolchain(Toolchain):
1497
1580
  bin = Skip(infiles=[".dll", ".elf", ".exe", ".out", ".so"])
1498
1581
 
1499
1582
  joltdir = ProjectVariable()
1583
+ builddir = ProjectVariable(attrib="outdir")
1500
1584
  outdir = ProjectVariable()
1585
+ outdir_rel = ProjectVariable()
1501
1586
  binary = ProjectVariable()
1502
1587
 
1503
1588
  ar = ToolEnvironmentVariable(default="ar", abspath=True)
@@ -1510,7 +1595,17 @@ class GNUToolchain(Toolchain):
1510
1595
  cxxwrap = EnvironmentVariable(default="")
1511
1596
  flatc = ToolEnvironmentVariable(default="flatc", envname="FLATC", abspath=True)
1512
1597
  protoc = ToolEnvironmentVariable(default="protoc", envname="PROTOC", abspath=True)
1513
-
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
+ })
1514
1609
  asflags = EnvironmentVariable(default="")
1515
1610
  cflags = EnvironmentVariable(default="")
1516
1611
  cxxflags = EnvironmentVariable(default="")
@@ -1538,10 +1633,10 @@ class GNUToolchain(Toolchain):
1538
1633
  libpaths = LibraryPaths(prefix="-L")
1539
1634
  libraries = Libraries(prefix="-l")
1540
1635
 
1541
- mkdir_debug = MakeDirectory(name=".debug")
1636
+ mkdir_debug = MakeDirectory(name="$outdir_rel/.debug")
1542
1637
 
1543
1638
  compile_pch = GNUCompiler(
1544
- command="$cxxwrap $cxx -x c++-header $cxxflags $shared_flags $imported_cxxflags $extra_cxxflags $covflags $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",
1545
1640
  deps="gcc",
1546
1641
  depfile="$out.d",
1547
1642
  infiles=[GNUPCHVariables.pch_ext],
@@ -1550,7 +1645,7 @@ class GNUToolchain(Toolchain):
1550
1645
  variables={"desc": "[PCH] {in_base}{in_ext}"})
1551
1646
 
1552
1647
  compile_c = GNUCompiler(
1553
- command="$ccwrap $cc -x c $pch_flags $cflags $shared_flags $imported_cflags $extra_cflags $covflags $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",
1554
1649
  deps="gcc",
1555
1650
  depfile="$out.d",
1556
1651
  infiles=[".c"],
@@ -1560,7 +1655,7 @@ class GNUToolchain(Toolchain):
1560
1655
  implicit=["$cc_path"])
1561
1656
 
1562
1657
  compile_cxx = GNUCompiler(
1563
- command="$cxxwrap $cxx -x c++ $pch_flags $cxxflags $shared_flags $imported_cxxflags $extra_cxxflags $covflags $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",
1564
1659
  deps="gcc",
1565
1660
  depfile="$out.d",
1566
1661
  infiles=[".cc", ".cpp", ".cxx"],
@@ -1595,51 +1690,100 @@ class GNUToolchain(Toolchain):
1595
1690
 
1596
1691
  linker = GNULinker(
1597
1692
  command=" && ".join([
1598
- "$ld $ldflags $imported_ldflags $extra_ldflags $covflags $libpaths -Wl,--start-group @objects.list -Wl,--end-group -o $out -Wl,--start-group $libraries -Wl,--end-group",
1599
- "$objcopy_path --only-keep-debug $out .debug/$binary",
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",
1600
1695
  "$objcopy_path --strip-all $out",
1601
- "$objcopy_path --add-gnu-debuglink=.debug/$binary $out"
1696
+ "$objcopy_path --add-gnu-debuglink=$outdir_rel/.debug/$binary $out"
1602
1697
  ]),
1603
1698
  infiles=[".o", ".obj", ".a"],
1604
1699
  outfiles=["{outdir}/{binary}"],
1605
1700
  variables={"desc": "[LINK] {binary}"},
1606
- implicit=["$ld_path", "$objcopy_path", ".debug"])
1701
+ implicit=["$ld_path", "$objcopy_path", "$outdir_rel/.debug"])
1607
1702
 
1608
1703
  dynlinker = GNULinker(
1609
1704
  command=" && ".join([
1610
- "$ld $ldflags -shared $imported_ldflags $extra_ldflags $covflags $libpaths -Wl,--start-group @objects.list -Wl,--end-group -o $out -Wl,--start-group $libraries -Wl,--end-group",
1611
- "$objcopy_path --only-keep-debug $out .debug/lib$binary.so",
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",
1612
1707
  "$objcopy_path --strip-all $out",
1613
- "$objcopy_path --add-gnu-debuglink=.debug/lib$binary.so $out"
1708
+ "$objcopy_path --add-gnu-debuglink=$outdir_rel/.debug/lib$binary.so $out"
1614
1709
  ]),
1615
1710
  infiles=[".o", ".obj", ".a"],
1616
1711
  outfiles=["{outdir}/lib{binary}.so"],
1617
1712
  variables={"desc": "[LINK] {binary}"},
1618
- implicit=["$ld_path", "$objcopy_path", ".debug"])
1713
+ implicit=["$ld_path", "$objcopy_path", "$outdir_rel/.debug"])
1619
1714
 
1620
1715
  archiver = GNUArchiver(
1621
- command="$ar -M < objects.list && $ranlib $out",
1716
+ command="$ar -M < $outdir_rel/objects.list && $ranlib $out",
1622
1717
  infiles=[".o", ".obj", ".a"],
1623
1718
  outfiles=["{outdir}/lib{binary}.a"],
1624
1719
  variables={"desc": "[AR] lib{binary}.a"},
1625
- implicit=["$ld_path", "$ar_path"])
1720
+ implicit=["$ld_path", "$ar_path", "$ranlib_path"])
1626
1721
 
1627
1722
  depimport = GNUDepImporter(
1628
1723
  prefix="lib",
1629
1724
  suffix=".a")
1630
1725
 
1631
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
+
1632
1776
  class MinGWToolchain(GNUToolchain):
1633
1777
  linker = GNULinker(
1634
1778
  command=" && ".join([
1635
- "$ld $ldflags $imported_ldflags $extra_ldflags $libpaths -Wl,--start-group @objects.list -Wl,--end-group -o $out -Wl,--start-group $libraries -Wl,--end-group",
1636
- "$objcopy --only-keep-debug $out .debug/$binary.exe",
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",
1637
1781
  "$objcopy --strip-all $out",
1638
- "$objcopy --add-gnu-debuglink=.debug/$binary.exe $out"
1782
+ "$objcopy --add-gnu-debuglink=$outdir_rel/.debug/$binary.exe $out"
1639
1783
  ]),
1640
1784
  outfiles=["{outdir}/{binary}.exe"],
1641
1785
  variables={"desc": "[LINK] {binary}"},
1642
- implicit=["$ld_path", "$objcopy_path", ".debug"])
1786
+ implicit=["$ld_path", "$objcopy_path", "$outdir_rel/.debug"])
1643
1787
 
1644
1788
 
1645
1789
  class MSVCArchiver(Rule):
@@ -1657,6 +1801,62 @@ class MSVCArchiver(Rule):
1657
1801
  return "MSVCArchiver" + super().get_influence(task)
1658
1802
 
1659
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, "msvcrt"):
1842
+ crt = self._combine(project, crt, self._select_flag([str(dep.cxxinfo.msvcrt)]))
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, "msvcrt", 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 "MSVC-CRT"
1858
+
1859
+
1660
1860
  MSVCCompiler = GNUCompiler
1661
1861
  MSVCLinker = GNULinker
1662
1862
  MSVCDepImporter = GNUDepImporter
@@ -1667,7 +1867,9 @@ class MSVCToolchain(Toolchain):
1667
1867
  bin = Skip(infiles=[".dll", ".exe"])
1668
1868
 
1669
1869
  joltdir = ProjectVariable()
1870
+ builddir = ProjectVariable(attrib="outdir")
1670
1871
  outdir = ProjectVariable()
1872
+ outdir_rel = ProjectVariable()
1671
1873
  binary = ProjectVariable()
1672
1874
 
1673
1875
  cl = ToolEnvironmentVariable(default="cl", envname="cl_exe", abspath=True)
@@ -1676,13 +1878,25 @@ class MSVCToolchain(Toolchain):
1676
1878
  flatc = ToolEnvironmentVariable(default="flatc", envname="FLATC", abspath=True)
1677
1879
  protoc = ToolEnvironmentVariable(default="protoc", envname="PROTOC", abspath=True)
1678
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")
1679
1891
  asflags = EnvironmentVariable(default="")
1680
- cflags = EnvironmentVariable(default="/EHsc")
1681
- cxxflags = EnvironmentVariable(default="/EHsc")
1892
+ cflags = EnvironmentVariable(default="")
1893
+ cxxflags = EnvironmentVariable(default="")
1682
1894
  fbflags = EnvironmentVariable(default="")
1683
1895
  ldflags = EnvironmentVariable(default="")
1684
1896
  protoflags = EnvironmentVariable(default="")
1685
1897
 
1898
+ crt = MSVCCRT()
1899
+
1686
1900
  extra_asflags = ProjectVariable(attrib="asflags")
1687
1901
  extra_cflags = ProjectVariable(attrib="cflags")
1688
1902
  extra_cxxflags = ProjectVariable(attrib="cxxflags")
@@ -1697,26 +1911,26 @@ class MSVCToolchain(Toolchain):
1697
1911
  libraries = Libraries(suffix=".lib")
1698
1912
 
1699
1913
  compile_asm = MSVCCompiler(
1700
- 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",
1701
1915
  deps="msvc",
1702
1916
  infiles=[".asm", ".s", ".S"],
1703
- outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}.obj"],
1917
+ outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.obj"],
1704
1918
  variables={"desc": "[ASM] {in_base}{in_ext}"},
1705
1919
  implicit=["$cl_path"])
1706
1920
 
1707
1921
  compile_c = MSVCCompiler(
1708
- command="$cl /nologo /showIncludes $cxxflags $extra_cxxflags $macros $incpaths /c /Tc$in /Fo$out",
1922
+ command="$cl /nologo /showIncludes $cstd $crt $win32flags $optflag $cflags $extra_cflags $macros $incpaths /c /Tc$in /Fo$out",
1709
1923
  deps="msvc",
1710
1924
  infiles=[".c"],
1711
- outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}.obj"],
1925
+ outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.obj"],
1712
1926
  variables={"desc": "[C] {in_base}{in_ext}"},
1713
1927
  implicit=["$cl_path"])
1714
1928
 
1715
1929
  compile_cxx = MSVCCompiler(
1716
- 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",
1717
1931
  deps="msvc",
1718
1932
  infiles=[".cc", ".cpp", ".cxx"],
1719
- outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}.obj"],
1933
+ outfiles=["{outdir}/{binary}.dir/{in_path}/{in_base}{in_ext}.obj"],
1720
1934
  variables={"desc": "[CXX] {in_base}{in_ext}"},
1721
1935
  implicit=["$cl_path"])
1722
1936
 
@@ -1724,14 +1938,14 @@ class MSVCToolchain(Toolchain):
1724
1938
  compile_proto = ProtobufCompiler(generator="cpp")
1725
1939
 
1726
1940
  linker = MSVCLinker(
1727
- command="$link /nologo $ldflags $extra_ldflags $libpaths @objects.list $libraries /out:$out",
1941
+ command="$link /nologo $ldflags $extra_ldflags $libpaths @$outdir_rel/objects.list $libraries /out:$out",
1728
1942
  infiles=[".o", ".obj", ".lib"],
1729
1943
  outfiles=["{outdir}/{binary}.exe"],
1730
1944
  variables={"desc": "[LINK] {binary}"},
1731
1945
  implicit=["$link_path"])
1732
1946
 
1733
1947
  archiver = MSVCArchiver(
1734
- command="$lib /nologo /out:$out @objects.list",
1948
+ command="$lib /nologo /out:$out @$outdir_rel/objects.list",
1735
1949
  infiles=[".o", ".obj", ".lib"],
1736
1950
  outfiles=["{outdir}/{binary}.lib"],
1737
1951
  variables={"desc": "[LIB] {binary}"},
@@ -1744,11 +1958,15 @@ class MSVCToolchain(Toolchain):
1744
1958
 
1745
1959
  _toolchains = {
1746
1960
  GNUToolchain: GNUToolchain(),
1961
+ DarwinGNUToolchain: DarwinGNUToolchain(),
1747
1962
  MSVCToolchain: MSVCToolchain(),
1748
1963
  }
1749
1964
 
1750
- if os.name == "nt":
1965
+ _system = platform.system()
1966
+ if _system == "Windows":
1751
1967
  toolchain = _toolchains[MSVCToolchain]
1968
+ elif _system == "Darwin":
1969
+ toolchain = _toolchains[DarwinGNUToolchain]
1752
1970
  else:
1753
1971
  toolchain = _toolchains[GNUToolchain]
1754
1972
 
@@ -1788,9 +2006,23 @@ class CXXProject(Task):
1788
2006
  cflags = []
1789
2007
  """ A list of compiler flags used when compiling C files. """
1790
2008
 
2009
+ cstd = None
2010
+ """
2011
+ C language standard to use (int). Default: Compiler default
2012
+
2013
+ If the chosen standard is not supported, the nearest supported standard is selected.
2014
+ """
2015
+
1791
2016
  cxxflags = []
1792
2017
  """ A list of compiler flags used when compiling C++ files. """
1793
2018
 
2019
+ cxxstd = None
2020
+ """
2021
+ C++ language standard to use (int). Default: Compiler default
2022
+
2023
+ If the chosen standard is not supported, the nearest supported standard is selected.
2024
+ """
2025
+
1794
2026
  depimports = []
1795
2027
  """ List of implicit dependencies """
1796
2028
 
@@ -1809,6 +2041,18 @@ class CXXProject(Task):
1809
2041
  macros = []
1810
2042
  """ List of preprocessor macros to set """
1811
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
+
1812
2056
  sources = []
1813
2057
  """ A list of sources to compile.
1814
2058
 
@@ -1923,7 +2167,7 @@ class CXXProject(Task):
1923
2167
  self._init_rules_and_vars()
1924
2168
 
1925
2169
  def _init_rules_and_vars(self):
1926
- self._rules_by_ext = {}
2170
+ self._rules_by_ext = OrderedDict()
1927
2171
  self._rules = []
1928
2172
  self._variables = []
1929
2173
 
@@ -1961,22 +2205,26 @@ class CXXProject(Task):
1961
2205
  def _verify_influence(self, deps, artifact, tools):
1962
2206
  # Verify that listed sources and their dependencies are influencing
1963
2207
  sources = set(self.sources + getattr(self, "headers", []))
1964
- with tools.cwd(self.outdir):
2208
+ with tools.cwd(tools.wsroot):
1965
2209
  depfiles = [obj + ".d" for obj in getattr(self._writer, "_objects", [])]
1966
2210
  for depfile in depfiles:
1967
2211
  try:
1968
2212
  data = tools.read_file(depfile)
1969
2213
  except Exception:
1970
2214
  continue
1971
- data = data.split(":", 1)
1972
- if len(data) <= 1:
1973
- continue
1974
2215
 
1975
- depsrcs = data[1]
1976
- depsrcs = depsrcs.split()
1977
- depsrcs = [f.rstrip("\\").strip() for f in depsrcs]
1978
- depsrcs = [tools.expand_relpath(dep, self.joltdir) for dep in filter(lambda n: n, depsrcs)]
1979
- sources = sources.union(depsrcs)
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)
1980
2228
  super()._verify_influence(deps, artifact, tools, sources)
1981
2229
 
1982
2230
  def _expand_headers(self):
@@ -2010,10 +2258,11 @@ class CXXProject(Task):
2010
2258
  self.sources = sources
2011
2259
 
2012
2260
  def _write_ninja_file(self, basedir, deps, tools, filename="build.ninja"):
2013
- with open(fs.path.join(basedir, filename), "w") as fobj:
2261
+ with open(tools.expand_path(fs.path.join(basedir, filename)), "w") as fobj:
2014
2262
  writer = ninja.Writer(fobj)
2015
- writer.depimports = [tools.expand_relpath(dep, self.outdir)
2016
- for dep in self.depimports]
2263
+ writer.depimports = [
2264
+ tools.expand_relpath(dep, tools.wsroot)
2265
+ for dep in self.depimports]
2017
2266
  writer.objects = []
2018
2267
  writer.sources = copy.copy(self.sources)
2019
2268
  self._populate_rules_and_variables(writer, deps, tools)
@@ -2044,7 +2293,7 @@ def main():
2044
2293
  for object in objects:
2045
2294
  print(object)
2046
2295
  elif [arg for arg in sys.argv[1:] if arg == "-a"]:
2047
- subprocess.call(["ninja", "-v"])
2296
+ subprocess.call(["ninja", "-f", "{outdir}/build.ninja", "-v"])
2048
2297
  else:
2049
2298
  targets = []
2050
2299
  for arg in sys.argv[1:]:
@@ -2054,7 +2303,7 @@ def main():
2054
2303
  targets.extend(matches)
2055
2304
  if not targets:
2056
2305
  return
2057
- subprocess.call(["ninja", "-v"] + targets)
2306
+ subprocess.call(["ninja", "-f", "{outdir}/build.ninja", "-v"] + targets)
2058
2307
 
2059
2308
  if __name__ == "__main__":
2060
2309
  main()
@@ -2063,7 +2312,8 @@ if __name__ == "__main__":
2063
2312
  fobj.write(
2064
2313
  data.format(
2065
2314
  executable=sys.executable,
2066
- objects=[fs.path.relpath(o, self.outdir) for o in writer.objects]))
2315
+ objects=[fs.path.relpath(o, tools.wsroot) for o in writer.objects],
2316
+ outdir=self.outdir))
2067
2317
  tools.chmod(filepath, 0o777)
2068
2318
 
2069
2319
  def find_rule(self, ext):
@@ -2108,7 +2358,7 @@ if __name__ == "__main__":
2108
2358
  sources = [(tools.expand_path(source), origin) for source, origin in sources]
2109
2359
 
2110
2360
  # Aggregated list of sources for each rule
2111
- rule_source_list = {}
2361
+ rule_source_list = OrderedDict()
2112
2362
  while sources:
2113
2363
  source, origin = sources.pop()
2114
2364
  _, ext = fs.path.splitext(source)
@@ -2205,26 +2455,39 @@ if __name__ == "__main__":
2205
2455
  incrementally. The behavior can be changed with the ``incremental``
2206
2456
  class attribute.
2207
2457
  """
2208
-
2209
2458
  self.outdir = tools.builddir("ninja", self.incremental)
2459
+ self.outdir_rel = self.tools.expand_relpath(self.outdir, tools.wsroot)
2210
2460
  self._expand_headers()
2211
2461
  self._expand_sources(deps, tools)
2212
2462
  self._writer = self._write_ninja_file(self.outdir, deps, tools)
2213
2463
  verbose = " -v" if log.is_verbose() else ""
2214
2464
  threads = config.get("jolt", "threads", tools.getenv("JOLT_THREADS", None))
2215
2465
  threads = " -j" + threads if threads else ""
2466
+ keep_going = " -k 0" if config.get_keep_going() else ""
2216
2467
  depsfile = self._get_keepdepfile(tools)
2217
2468
  try:
2218
- tools.run("ninja{3}{2} -C {0} {1}", self.outdir, verbose, threads, depsfile)
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)
2219
2480
  except JoltCommandError as e:
2220
- with self.report() as report:
2221
- with utils.ignore_exception():
2222
- self._report_errors(report, "\n".join(e.stdout))
2223
- raise CompileError(self._first_reported_error(report))
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
2224
2487
 
2225
2488
  if bool(getattr(self, "coverage", False)):
2226
2489
  self.covdatadir = tools.builddir("coverage-data")
2227
- with tools.cwd(self.outdir):
2490
+ with tools.cwd(tools.wsroot):
2228
2491
  for obj in getattr(self._writer, "_objects", []):
2229
2492
  obj, ext = os.path.splitext(obj)
2230
2493
  obj = obj + ".gcno"
@@ -2234,14 +2497,15 @@ if __name__ == "__main__":
2234
2497
  pass
2235
2498
  if self.selfsustained:
2236
2499
  for _, artifact in deps.items():
2237
- if str(artifact.paths.coverage_data):
2238
- tools.copy(artifact.paths.coverage_data, self.covdatadir)
2500
+ if artifact.paths.coverage_data:
2501
+ tools.copy(str(artifact.paths.coverage_data), self.covdatadir)
2239
2502
 
2240
2503
  def publish(self, artifact, tools):
2241
2504
  if bool(getattr(self, "coverage", False)):
2242
2505
  self.publish_coverage_data(artifact, tools)
2243
2506
 
2244
2507
  def publish_coverage_data(self, artifact, tools):
2508
+ """ Publishes code coverage data files. """
2245
2509
  with tools.cwd(self.covdatadir):
2246
2510
  if artifact.collect("**/*.gcno", "cov/"):
2247
2511
  artifact.paths.coverage_data = "cov"
@@ -2263,46 +2527,56 @@ if __name__ == "__main__":
2263
2527
  self._expand_headers()
2264
2528
  self._expand_sources(deps, tools)
2265
2529
  self.outdir = tools.builddir("ninja", self.incremental)
2530
+ self.outdir_rel = self.tools.expand_relpath(self.outdir, tools.wsroot)
2266
2531
  writer = self._write_ninja_file(self.outdir, deps, tools)
2267
2532
  self._write_shell_file(self.outdir, deps, tools, writer)
2268
2533
  pathenv = self.outdir + os.pathsep + tools.getenv("PATH")
2269
- with tools.cwd(self.outdir), tools.environ(PATH=pathenv):
2534
+ with tools.cwd(tools.wsroot), tools.environ(PATH=pathenv):
2270
2535
  print()
2271
2536
  print("Use the 'compile' command to build individual compilation targets")
2272
2537
  super().debugshell(deps, tools)
2273
2538
 
2274
- def _report_errors(self, report, logbuffer):
2539
+ def _report_errors(self, logbuffer):
2275
2540
  """ Parses the build log and reports errors. """
2276
-
2277
- # GCC style errors
2278
- report.add_regex_errors_with_file(
2279
- "Compiler Error",
2280
- r"^(?P<location>(?P<file>.*?):(?P<line>[0-9]+):(?P<col>[0-9]+)): (?P<message>.*)",
2281
- logbuffer,
2282
- self.outdir,
2283
- lambda err: not err["message"].startswith("note:"))
2284
-
2285
- # MSVC compiler errors
2286
- report.add_regex_errors_with_file(
2287
- "Compiler Error",
2288
- r"^(?P<location>(?P<file>.*?)\((?P<line>[0-9]+)\)): (?P<message>(fatal )?error( C[0-9]*?): .*)",
2289
- logbuffer,
2290
- self.outdir)
2291
-
2292
- # Binutils/MSVC linker errors
2293
- report.add_regex_errors(
2294
- "Linker Error",
2295
- r"^(?P<location>(?P<file>.*?)(:.*?)?)( )?: (?P<message>(( fatal)?error LNK|warning LNK|undefined reference|multiple definition).*)",
2296
- logbuffer)
2297
-
2298
- # LLVM linker errors
2299
- report.add_regex_errors(
2300
- "Linker Error",
2301
- r"^(?P<location>ld(\.lld)?): (error|warning): (?P<message>.*)",
2302
- logbuffer)
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
2303
2575
 
2304
2576
  def _first_reported_error(self, report):
2305
2577
  """ Returns the first reported error or None if no errors were reported. """
2578
+ if report is None:
2579
+ return None
2306
2580
  for error in report.errors:
2307
2581
  return error
2308
2582