summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mensinger <daniel@mensinger-ka.de>2020-01-28 11:46:10 +0100
committerDaniel Mensinger <daniel@mensinger-ka.de>2020-02-12 20:58:37 +0100
commit796b4c120ab37a9e0e73e2067aaad7b8d929e227 (patch)
treeaa96aeda197afb0de6ed93dba4b62e6a2e8d28f7
parenta41a902f5e32d60ba3eb46979737274ca771fb6e (diff)
downloadmeson-796b4c120ab37a9e0e73e2067aaad7b8d929e227.tar.gz
cmake: Add support for the new JSON trace format
-rw-r--r--docs/markdown/CMake-module.md5
-rw-r--r--mesonbuild/cmake/traceparser.py53
2 files changed, 43 insertions, 15 deletions
diff --git a/docs/markdown/CMake-module.md b/docs/markdown/CMake-module.md
index 4cd62a5f7..a02139644 100644
--- a/docs/markdown/CMake-module.md
+++ b/docs/markdown/CMake-module.md
@@ -12,6 +12,11 @@ following functions will then be available as methods on the object
with the name `cmake`. You can, of course, replace the name `cmake`
with anything else.
+It is generally recommended to use the latest Meson version and
+CMake >=3.17 for best compatibility. CMake subprojects will
+usually also work with older CMake versions. However, this can
+lead to unexpected issues in rare cases.
+
## CMake subprojects
Using CMake subprojects is similar to using the "normal" meson
diff --git a/mesonbuild/cmake/traceparser.py b/mesonbuild/cmake/traceparser.py
index 4aa34f1cc..7b29c86df 100644
--- a/mesonbuild/cmake/traceparser.py
+++ b/mesonbuild/cmake/traceparser.py
@@ -24,6 +24,7 @@ import typing as T
from pathlib import Path
import re
import os
+import json
class CMakeTraceLine:
def __init__(self, file, line, func, args):
@@ -80,11 +81,12 @@ class CMakeTraceParser:
self.cmake_version = cmake_version # type: str
self.trace_file = 'cmake_trace.txt'
self.trace_file_path = Path(build_dir) / self.trace_file
- self.trace_format = 'human'
+ self.trace_format = 'json-v1' if version_compare(cmake_version, '>=3.17') else 'human'
def trace_args(self) -> T.List[str]:
arg_map = {
'human': ['--trace', '--trace-expand'],
+ 'json-v1': ['--trace-expand', '--trace-format=json-v1'],
}
base_args = ['--no-warn-unused-cli']
@@ -109,8 +111,10 @@ class CMakeTraceParser:
lexer1 = None
if self.trace_format == 'human':
lexer1 = self._lex_trace_human(trace)
+ elif self.trace_format == 'json-v1':
+ lexer1 = self._lex_trace_json(trace)
else:
- raise CMakeException('CMake: Internal error: Invalid trace format {}. Expected [human]'.format(self.trace_format))
+ raise CMakeException('CMake: Internal error: Invalid trace format {}. Expected [human, json-v1]'.format(self.trace_format))
# All supported functions
functions = {
@@ -421,21 +425,27 @@ class CMakeTraceParser:
# Neither of these is awesome for obvious reasons. I'm going to try
# option 1 first and fall back to 2, as 1 requires less code and less
# synchroniztion for cmake changes.
+ #
+ # With the JSON output format, introduced in CMake 3.17, spaces are
+ # handled properly and we don't have to do either options
arglist = [] # type: T.List[T.Tuple[str, T.List[str]]]
- name = args.pop(0)
- values = []
- prop_regex = re.compile(r'^[A-Z_]+$')
- for a in args:
- if prop_regex.match(a):
- if values:
- arglist.append((name, ' '.join(values).split(';')))
- name = a
- values = []
- else:
- values.append(a)
- if values:
- arglist.append((name, ' '.join(values).split(';')))
+ if self.trace_format == 'human':
+ name = args.pop(0)
+ values = []
+ prop_regex = re.compile(r'^[A-Z_]+$')
+ for a in args:
+ if prop_regex.match(a):
+ if values:
+ arglist.append((name, ' '.join(values).split(';')))
+ name = a
+ values = []
+ else:
+ values.append(a)
+ if values:
+ arglist.append((name, ' '.join(values).split(';')))
+ else:
+ arglist = [(x[0], x[1].split(';')) for x in zip(args[::2], args[1::2])]
for name, value in arglist:
for i in targets:
@@ -549,7 +559,20 @@ class CMakeTraceParser:
yield CMakeTraceLine(file, line, func, args)
+ def _lex_trace_json(self, trace: str):
+ lines = trace.splitlines(keepends=False)
+ lines.pop(0) # The first line is the version
+ for i in lines:
+ data = json.loads(i)
+ args = data['args']
+ args = [parse_generator_expressions(x) for x in args]
+ yield CMakeTraceLine(data['file'], data['line'], data['cmd'], args)
+
def _guess_files(self, broken_list: T.List[str]) -> T.List[str]:
+ # Nothing has to be done for newer formats
+ if self.trace_format != 'human':
+ return broken_list
+
# Try joining file paths that contain spaces
reg_start = re.compile(r'^([A-Za-z]:)?/.*/[^./]+$')