diff options
-rw-r--r-- | docs/markdown/Builtin-options.md | 1 | ||||
-rw-r--r-- | docs/markdown/CMake-module.md | 5 | ||||
-rw-r--r-- | docs/markdown/Release-notes-for-0.53.0.md | 24 | ||||
-rw-r--r-- | docs/markdown/howtox.md | 4 | ||||
-rw-r--r-- | docs/markdown/snippets/unitysize.md | 12 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 45 | ||||
-rw-r--r-- | mesonbuild/cmake/executor.py | 96 | ||||
-rw-r--r-- | mesonbuild/cmake/traceparser.py | 53 | ||||
-rw-r--r-- | mesonbuild/coredata.py | 12 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 6 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 2 | ||||
-rw-r--r-- | mesonbuild/linkers.py | 3 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 20 | ||||
-rw-r--r-- | mesonbuild/mlog.py | 16 | ||||
-rw-r--r-- | mesonbuild/optinterpreter.py | 5 | ||||
-rwxr-xr-x | run_unittests.py | 4 |
16 files changed, 200 insertions, 108 deletions
diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index 9eac371..067966f 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -82,6 +82,7 @@ Using the option as-is with no prefix affects all machines. For example: | stdsplit | true | Split stdout and stderr in test logs | no | | strip | false | Strip targets on install | no | | unity {on, off, subprojects} | off | Unity build | no | +| unity_size {>=2} | 4 | Unity file block size | no | | warning_level {0, 1, 2, 3} | 1 | Set the warning level. From 0 = none to 3 = highest | no | | werror | false | Treat warnings as errors | no | | wrap_mode {default, nofallback,<br>nodownload, forcefallback} | default | Wrap mode to use | no | diff --git a/docs/markdown/CMake-module.md b/docs/markdown/CMake-module.md index 4cd62a5..a021396 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/docs/markdown/Release-notes-for-0.53.0.md b/docs/markdown/Release-notes-for-0.53.0.md index 22db714..b29759f 100644 --- a/docs/markdown/Release-notes-for-0.53.0.md +++ b/docs/markdown/Release-notes-for-0.53.0.md @@ -74,15 +74,33 @@ flags passed via language flags and hoped things worked out. In meson 0.52.0 meson started detecting the linker and making intelligent decisions about using it. Unfortunately this broke choosing a non-default linker. -Now there is a generic mechanism for doing this, you may use the LD -environment variable (with normal meson environment variable rules), or add -the following to a cross or native file: +Now there is a generic mechanism for doing this. In 0.53.0, you can use the `LD` +environment variable. **In 0.53.1** this was changed to `<compiler_variable>_LD`, +such as `CC_LD`, `CXX_LD`, `D_LD`, etc due to regressions. The usual meson +[environment variable rules](https://mesonbuild.com/Running-Meson.html#environment-variables) +apply. Alternatively, you can add the following to a cross or native file: + +In 0.53.0: ```ini [binaries] ld = 'gold' ``` +**In 0.53.1 or newer**: + +```ini +[binaries] +c = 'gcc' +c_ld = 'gold' +``` + +```ini +[binaries] +c = 'clang' +c_ld = 'lld' +``` + And meson will select the linker if possible. ## `fortran_std` option diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md index 452da2c..f70ff47 100644 --- a/docs/markdown/howtox.md +++ b/docs/markdown/howtox.md @@ -31,11 +31,11 @@ native-files and the latter via the cross file only. *New in 0.53.0* Like the compiler, the linker is selected via the `<compiler variable>_LD` -environment variable, or through the `<compiler entry>ld` entry in a native +environment variable, or through the `<compiler entry>_ld` entry in a native or cross file. You must be aware of whether you're using a compiler that invokes the linker itself (most compilers including GCC and Clang) or a linker that is invoked directly (when using MSVC or compilers that act like -it, including Clang-Cl). With the former `cld` or `CC_LD` should be the value +it, including Clang-Cl). With the former `c_ld` or `CC_LD` should be the value to pass to the compiler's special argument (such as `-fuse-ld` with clang and gcc), with the latter it should be an executable, such as `lld-link.exe`. diff --git a/docs/markdown/snippets/unitysize.md b/docs/markdown/snippets/unitysize.md new file mode 100644 index 0000000..4919ce0 --- /dev/null +++ b/docs/markdown/snippets/unitysize.md @@ -0,0 +1,12 @@ +## Unity file block size is configurable + +Traditionally the unity files that Meson autogenerates contain all +source files that belong to a single target. This is the most +efficient setting for full builds but makes incremental builds slow. +This release adds a new option `unity_size` which specifies how many +source files should be put in each unity file. + +The default value for block size is 4. This means that if you have a +target that has eight source files, Meson will generate two unity +files each of which includes four source files. The old behaviour can +be replicated by setting `unity_size` to a large value, such as 10000. diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 5203323..a8f4789 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -243,19 +243,20 @@ class Backend: # target that the GeneratedList is used in return os.path.join(self.get_target_private_dir(target), src) - def get_unity_source_file(self, target, suffix): + def get_unity_source_file(self, target, suffix, number): # There is a potential conflict here, but it is unlikely that # anyone both enables unity builds and has a file called foo-unity.cpp. - osrc = target.name + '-unity.' + suffix + osrc = '{}-unity{}.{}'.format(target.name, number, suffix) return mesonlib.File.from_built_file(self.get_target_private_dir(target), osrc) def generate_unity_files(self, target, unity_src): abs_files = [] result = [] compsrcs = classify_unity_sources(target.compilers.values(), unity_src) + unity_size = self.get_option_for_target('unity_size', target) - def init_language_file(suffix): - unity_src = self.get_unity_source_file(target, suffix) + def init_language_file(suffix, unity_file_number): + unity_src = self.get_unity_source_file(target, suffix, unity_file_number) outfileabs = unity_src.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) outfileabs_tmp = outfileabs + '.tmp' @@ -266,11 +267,23 @@ class Backend: result.append(unity_src) return open(outfileabs_tmp, 'w') - # For each language, generate a unity source file and return the list + # For each language, generate unity source files and return the list for comp, srcs in compsrcs.items(): - with init_language_file(comp.get_default_suffix()) as ofile: - for src in srcs: - ofile.write('#include<%s>\n' % src) + files_in_current = unity_size + 1 + unity_file_number = 0 + ofile = None + for src in srcs: + if files_in_current >= unity_size: + if ofile: + ofile.close() + ofile = init_language_file(comp.get_default_suffix(), unity_file_number) + unity_file_number += 1 + files_in_current = 0 + ofile.write('#include<%s>\n' % src) + files_in_current += 1 + if ofile: + ofile.close() + [mesonlib.replace_if_different(x, x + '.tmp') for x in abs_files] return result @@ -489,16 +502,18 @@ class Backend: targetdir = self.get_target_private_dir(extobj.target) - # With unity builds, there's just one object that contains all the - # sources, and we only support extracting all the objects in this mode, - # so just return that. + # With unity builds, sources don't map directly to objects, + # we only support extracting all the objects in this mode, + # so just return all object files. if self.is_unity(extobj.target): compsrcs = classify_unity_sources(extobj.target.compilers.values(), sources) sources = [] - for comp in compsrcs.keys(): - osrc = self.get_unity_source_file(extobj.target, - comp.get_default_suffix()) - sources.append(osrc) + unity_size = self.get_option_for_target('unity_size', extobj.target) + for comp, srcs in compsrcs.items(): + for i in range(len(srcs) // unity_size + 1): + osrc = self.get_unity_source_file(extobj.target, + comp.get_default_suffix(), i) + sources.append(osrc) for osrc in sources: objname = self.object_filename_from_source(extobj.target, osrc) diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index c3303eb..7b9edf7 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -23,6 +23,7 @@ import re import os import shutil import ctypes +import textwrap from .. import mlog, mesonlib from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice @@ -264,9 +265,12 @@ class CMakeExecutor: if lang in compilers: exe_list = compilers[lang].get_exelist() else: - comp_obj = self.environment.compiler_from_language(lang, MachineChoice.BUILD) - if comp_obj is not None: - exe_list = comp_obj.get_exelist() + try: + comp_obj = self.environment.compiler_from_language(lang, MachineChoice.BUILD) + if comp_obj is not None: + exe_list = comp_obj.get_exelist() + except Exception: + pass if len(exe_list) == 1: return make_abs(exe_list[0], lang), '' @@ -278,10 +282,7 @@ class CMakeExecutor: c_comp, c_launcher = choose_compiler('c') cxx_comp, cxx_launcher = choose_compiler('cpp') - try: - fortran_comp, fortran_launcher = choose_compiler('fortran') - except Exception: - fortran_comp = fortran_launcher = '' + fortran_comp, fortran_launcher = choose_compiler('fortran') # on Windows, choose_compiler returns path with \ as separator - replace by / before writing to CMAKE file c_comp = c_comp.replace('\\', '/') @@ -302,47 +303,50 @@ class CMakeExecutor: cxx_comp_file = comp_dir / 'CMakeCXXCompiler.cmake' fortran_comp_file = comp_dir / 'CMakeFortranCompiler.cmake' - if not c_comp_file.is_file(): - c_comp_file.write_text('''# Fake CMake file to skip the boring and slow stuff -set(CMAKE_C_COMPILER "{}") # Should be a valid compiler for try_compile, etc. -set(CMAKE_C_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) -set(CMAKE_C_COMPILER_ID "GNU") # Pretend we have found GCC -set(CMAKE_COMPILER_IS_GNUCC 1) -set(CMAKE_C_COMPILER_LOADED 1) -set(CMAKE_C_COMPILER_WORKS TRUE) -set(CMAKE_C_ABI_COMPILED TRUE) -set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) -set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) -set(CMAKE_SIZEOF_VOID_P "{}") -'''.format(c_comp, c_launcher, ctypes.sizeof(ctypes.c_voidp))) - - if not cxx_comp_file.is_file(): - cxx_comp_file.write_text('''# Fake CMake file to skip the boring and slow stuff -set(CMAKE_CXX_COMPILER "{}") # Should be a valid compiler for try_compile, etc. -set(CMAKE_CXX_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) -set(CMAKE_CXX_COMPILER_ID "GNU") # Pretend we have found GCC -set(CMAKE_COMPILER_IS_GNUCXX 1) -set(CMAKE_CXX_COMPILER_LOADED 1) -set(CMAKE_CXX_COMPILER_WORKS TRUE) -set(CMAKE_CXX_ABI_COMPILED TRUE) -set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) -set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;mm;CPP) -set(CMAKE_SIZEOF_VOID_P "{}") -'''.format(cxx_comp, cxx_launcher, ctypes.sizeof(ctypes.c_voidp))) + if c_comp and not c_comp_file.is_file(): + c_comp_file.write_text(textwrap.dedent('''\ + # Fake CMake file to skip the boring and slow stuff + set(CMAKE_C_COMPILER "{}") # Should be a valid compiler for try_compile, etc. + set(CMAKE_C_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) + set(CMAKE_C_COMPILER_ID "GNU") # Pretend we have found GCC + set(CMAKE_COMPILER_IS_GNUCC 1) + set(CMAKE_C_COMPILER_LOADED 1) + set(CMAKE_C_COMPILER_WORKS TRUE) + set(CMAKE_C_ABI_COMPILED TRUE) + set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) + set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) + set(CMAKE_SIZEOF_VOID_P "{}") + '''.format(c_comp, c_launcher, ctypes.sizeof(ctypes.c_voidp)))) + + if cxx_comp and not cxx_comp_file.is_file(): + cxx_comp_file.write_text(textwrap.dedent('''\ + # Fake CMake file to skip the boring and slow stuff + set(CMAKE_CXX_COMPILER "{}") # Should be a valid compiler for try_compile, etc. + set(CMAKE_CXX_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) + set(CMAKE_CXX_COMPILER_ID "GNU") # Pretend we have found GCC + set(CMAKE_COMPILER_IS_GNUCXX 1) + set(CMAKE_CXX_COMPILER_LOADED 1) + set(CMAKE_CXX_COMPILER_WORKS TRUE) + set(CMAKE_CXX_ABI_COMPILED TRUE) + set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) + set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;mm;CPP) + set(CMAKE_SIZEOF_VOID_P "{}") + '''.format(cxx_comp, cxx_launcher, ctypes.sizeof(ctypes.c_voidp)))) if fortran_comp and not fortran_comp_file.is_file(): - fortran_comp_file.write_text('''# Fake CMake file to skip the boring and slow stuff -set(CMAKE_Fortran_COMPILER "{}") # Should be a valid compiler for try_compile, etc. -set(CMAKE_Fortran_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) -set(CMAKE_Fortran_COMPILER_ID "GNU") # Pretend we have found GCC -set(CMAKE_COMPILER_IS_GNUG77 1) -set(CMAKE_Fortran_COMPILER_LOADED 1) -set(CMAKE_Fortran_COMPILER_WORKS TRUE) -set(CMAKE_Fortran_ABI_COMPILED TRUE) -set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) -set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95) -set(CMAKE_SIZEOF_VOID_P "{}") -'''.format(fortran_comp, fortran_launcher, ctypes.sizeof(ctypes.c_voidp))) + fortran_comp_file.write_text(textwrap.dedent('''\ + # Fake CMake file to skip the boring and slow stuff + set(CMAKE_Fortran_COMPILER "{}") # Should be a valid compiler for try_compile, etc. + set(CMAKE_Fortran_COMPILER_LAUNCHER "{}") # The compiler launcher (if presentt) + set(CMAKE_Fortran_COMPILER_ID "GNU") # Pretend we have found GCC + set(CMAKE_COMPILER_IS_GNUG77 1) + set(CMAKE_Fortran_COMPILER_LOADED 1) + set(CMAKE_Fortran_COMPILER_WORKS TRUE) + set(CMAKE_Fortran_ABI_COMPILED TRUE) + set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) + set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95) + set(CMAKE_SIZEOF_VOID_P "{}") + '''.format(fortran_comp, fortran_launcher, ctypes.sizeof(ctypes.c_voidp)))) return self.call(args, build_dir, env) diff --git a/mesonbuild/cmake/traceparser.py b/mesonbuild/cmake/traceparser.py index 4aa34f1..7b29c86 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]:)?/.*/[^./]+$') diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index aea2d90..720d064 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -96,11 +96,12 @@ class UserBooleanOption(UserOption[bool]): raise MesonException('Value %s is not boolean (true or false).' % value) class UserIntegerOption(UserOption[int]): - def __init__(self, description, min_value, max_value, value, yielding=None): + def __init__(self, description, value, yielding=None): + min_value, max_value, default_value = value super().__init__(description, [True, False], yielding) self.min_value = min_value self.max_value = max_value - self.set_value(value) + self.set_value(default_value) c = [] if min_value is not None: c.append('>=' + str(min_value)) @@ -127,7 +128,7 @@ class UserIntegerOption(UserOption[int]): class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, int]]): def __init__(self, description, value, yielding=None): - super().__init__(description, 0, 0o777, value, yielding) + super().__init__(description, (0, 0o777, value), yielding) self.choices = ['preserve', '0000-0777'] def printable_value(self): @@ -525,7 +526,7 @@ class CoreData: UserIntegerOption( 'Maximum number of linker processes to run or 0 for no ' 'limit', - 0, None, 0) + (0, None, 0)) elif backend_name.startswith('vs'): self.backend_options['backend_startup_project'] = \ UserStringOption( @@ -967,7 +968,7 @@ class BuiltinOption(T.Generic[_T, _U]): """Class for a builtin option type. - Currently doesn't support UserIntegerOption, or a few other cases. + There are some cases that are not fully supported yet. """ def __init__(self, opt_type: T.Type[_U], description: str, default: T.Any, yielding: bool = True, *, @@ -1066,6 +1067,7 @@ builtin_options = OrderedDict([ ('stdsplit', BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)), ('strip', BuiltinOption(UserBooleanOption, 'Strip targets on install', False)), ('unity', BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])), + ('unity_size', BuiltinOption(UserIntegerOption, 'Unity block size', (2, None, 4))), ('warning_level', BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3'])), ('werror', BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False)), ('wrap_mode', BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback'])), diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index a83e3d6..6f8181d 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -388,7 +388,7 @@ class ConfigToolDependency(ExternalDependency): tools = None tool_name = None - __strip_version = re.compile(r'^[0-9.]*') + __strip_version = re.compile(r'^[0-9][0-9.]+') def __init__(self, name, environment, kwargs, language: T.Optional[str] = None): super().__init__('config-tool', environment, kwargs, language=language) @@ -1661,8 +1661,8 @@ class DubDependency(ExternalDependency): lib_file_name = os.path.basename(default_path) module_build_path = os.path.join(module_path, '.dub', 'build') - # If default_path is a path to lib file and - # directory of lib don't have subdir '.dub/build' + # If default_path is a path to lib file and + # directory of lib don't have subdir '.dub/build' if not os.path.isdir(module_build_path) and os.path.isfile(default_path): if folder_only: return module_path diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 09f7ff5..c29ed89 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -547,7 +547,7 @@ class ExternalProgramHolder(InterpreterObject, ObjectHolder): output = res.stdout.strip() if not output: output = res.stderr.strip() - match = re.search(r'([0-9\.]+)', output) + match = re.search(r'([0-9][0-9\.]+)', output) if not match: m = 'Could not find a version number in output of {!r}' raise InterpreterException(m.format(raw_cmd)) diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 9781813..dbd90b2 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -787,6 +787,9 @@ class VisualStudioLikeLinkerMixin: super().__init__(*args, **kwargs) self.machine = machine + def get_buildtype_args(self, buildtype: str) -> T.List[str]: + return mesonlib.listify([self._apply_prefix(a) for a in self._BUILDTYPE_ARGS[buildtype]]) + def invoked_by_compiler(self) -> bool: return not self.direct diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 891e7a1..e09d123 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -65,8 +65,7 @@ def git(cmd: T.List[str], workingdir: str, **kwargs) -> subprocess.CompletedProc # Sometimes git calls git recursively, such as `git submodule update # --recursive` which will be without the above workaround, so set the # console mode again just in case. - if platform.system().lower() == 'windows': - mlog._windows_ansi() + mlog.setup_console() return pc @@ -1080,11 +1079,20 @@ def Popen_safe(args: T.List[str], write: T.Optional[str] = None, **kwargs: T.Any) -> T.Tuple[subprocess.Popen, str, str]: import locale encoding = locale.getpreferredencoding() + # Redirect stdin to DEVNULL otherwise the command run by us here might mess + # up the console and ANSI colors will stop working on Windows. + if 'stdin' not in kwargs: + kwargs['stdin'] = subprocess.DEVNULL if sys.version_info < (3, 6) or not sys.stdout.encoding or encoding.upper() != 'UTF-8': - return Popen_safe_legacy(args, write=write, stdout=stdout, stderr=stderr, **kwargs) - p = subprocess.Popen(args, universal_newlines=True, close_fds=False, - stdout=stdout, stderr=stderr, **kwargs) - o, e = p.communicate(write) + p, o, e = Popen_safe_legacy(args, write=write, stdout=stdout, stderr=stderr, **kwargs) + else: + p = subprocess.Popen(args, universal_newlines=True, close_fds=False, + stdout=stdout, stderr=stderr, **kwargs) + o, e = p.communicate(write) + # Sometimes the command that we run will call another command which will be + # without the above stdin workaround, so set the console mode again just in + # case. + mlog.setup_console() return p, o, e def Popen_safe_legacy(args: T.List[str], write: T.Optional[str] = None, diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index a30d6b9..b28eca1 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -40,13 +40,15 @@ def _windows_ansi() -> bool: # original behavior return bool(kernel.SetConsoleMode(stdout, mode.value | 0x4) or os.environ.get('ANSICON')) -try: - if platform.system().lower() == 'windows': - colorize_console = os.isatty(sys.stdout.fileno()) and _windows_ansi() # type: bool - else: - colorize_console = os.isatty(sys.stdout.fileno()) and os.environ.get('TERM') != 'dumb' -except Exception: - colorize_console = False +def setup_console() -> bool: + try: + if platform.system().lower() == 'windows': + return os.isatty(sys.stdout.fileno()) and _windows_ansi() + return os.isatty(sys.stdout.fileno()) and os.environ.get('TERM') != 'dumb' + except Exception: + return False + +colorize_console = setup_console() log_dir = None # type: T.Optional[str] log_file = None # type: T.Optional[T.TextIO] log_fname = 'meson-log.txt' # type: str diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index 4d790b6..1a8a04a 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -90,10 +90,9 @@ def ComboParser(description, kwargs): def IntegerParser(description, kwargs): if 'value' not in kwargs: raise OptionException('Integer option must contain value argument.') + inttuple = (kwargs.get('min', None), kwargs.get('max', None), kwargs['value']) return coredata.UserIntegerOption(description, - kwargs.get('min', None), - kwargs.get('max', None), - kwargs['value'], + inttuple, kwargs.get('yield', coredata.default_yielding)) # FIXME: Cannot use FeatureNew while parsing options because we parse it before diff --git a/run_unittests.py b/run_unittests.py index c5ad499..7c2ae05 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -5305,9 +5305,9 @@ class LinuxlikeTests(BasePlatformTests): testdir = os.path.join(self.common_test_dir, '45 subproject') self.init(testdir, extra_args='--unity=subprojects') simpletest_id = Target.construct_id_from_path('subprojects/sublib', 'simpletest', '@exe') - self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', simpletest_id, 'simpletest-unity.c')) + self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', simpletest_id, 'simpletest-unity0.c')) sublib_id = Target.construct_id_from_path('subprojects/sublib', 'sublib', '@sha') - self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', sublib_id, 'sublib-unity.c')) + self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', sublib_id, 'sublib-unity0.c')) self.assertPathDoesNotExist(os.path.join(self.builddir, 'user@exe/user-unity.c')) self.build() |