cmake: Add support for the new JSON trace format

pull/6616/head
Daniel Mensinger 5 years ago
parent a41a902f5e
commit 796b4c120a
  1. 5
      docs/markdown/CMake-module.md
  2. 27
      mesonbuild/cmake/traceparser.py

@ -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 the name `cmake`. You can, of course, replace the name `cmake`
with anything else. 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 ## CMake subprojects
Using CMake subprojects is similar to using the "normal" meson Using CMake subprojects is similar to using the "normal" meson

@ -24,6 +24,7 @@ import typing as T
from pathlib import Path from pathlib import Path
import re import re
import os import os
import json
class CMakeTraceLine: class CMakeTraceLine:
def __init__(self, file, line, func, args): def __init__(self, file, line, func, args):
@ -80,11 +81,12 @@ class CMakeTraceParser:
self.cmake_version = cmake_version # type: str self.cmake_version = cmake_version # type: str
self.trace_file = 'cmake_trace.txt' self.trace_file = 'cmake_trace.txt'
self.trace_file_path = Path(build_dir) / self.trace_file 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]: def trace_args(self) -> T.List[str]:
arg_map = { arg_map = {
'human': ['--trace', '--trace-expand'], 'human': ['--trace', '--trace-expand'],
'json-v1': ['--trace-expand', '--trace-format=json-v1'],
} }
base_args = ['--no-warn-unused-cli'] base_args = ['--no-warn-unused-cli']
@ -109,8 +111,10 @@ class CMakeTraceParser:
lexer1 = None lexer1 = None
if self.trace_format == 'human': if self.trace_format == 'human':
lexer1 = self._lex_trace_human(trace) lexer1 = self._lex_trace_human(trace)
elif self.trace_format == 'json-v1':
lexer1 = self._lex_trace_json(trace)
else: 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 # All supported functions
functions = { functions = {
@ -421,8 +425,12 @@ class CMakeTraceParser:
# Neither of these is awesome for obvious reasons. I'm going to try # 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 # option 1 first and fall back to 2, as 1 requires less code and less
# synchroniztion for cmake changes. # 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]]] arglist = [] # type: T.List[T.Tuple[str, T.List[str]]]
if self.trace_format == 'human':
name = args.pop(0) name = args.pop(0)
values = [] values = []
prop_regex = re.compile(r'^[A-Z_]+$') prop_regex = re.compile(r'^[A-Z_]+$')
@ -436,6 +444,8 @@ class CMakeTraceParser:
values.append(a) values.append(a)
if values: if values:
arglist.append((name, ' '.join(values).split(';'))) 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 name, value in arglist:
for i in targets: for i in targets:
@ -549,7 +559,20 @@ class CMakeTraceParser:
yield CMakeTraceLine(file, line, func, args) 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]: 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 # Try joining file paths that contain spaces
reg_start = re.compile(r'^([A-Za-z]:)?/.*/[^./]+$') reg_start = re.compile(r'^([A-Za-z]:)?/.*/[^./]+$')

Loading…
Cancel
Save