aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Builtin-options.md1
-rw-r--r--docs/markdown/CMake-module.md5
-rw-r--r--docs/markdown/Release-notes-for-0.53.0.md24
-rw-r--r--docs/markdown/howtox.md4
-rw-r--r--docs/markdown/snippets/unitysize.md12
-rw-r--r--mesonbuild/backend/backends.py45
-rw-r--r--mesonbuild/cmake/executor.py96
-rw-r--r--mesonbuild/cmake/traceparser.py53
-rw-r--r--mesonbuild/coredata.py12
-rw-r--r--mesonbuild/dependencies/base.py6
-rw-r--r--mesonbuild/interpreter.py2
-rw-r--r--mesonbuild/linkers.py3
-rw-r--r--mesonbuild/mesonlib.py20
-rw-r--r--mesonbuild/mlog.py16
-rw-r--r--mesonbuild/optinterpreter.py5
-rwxr-xr-xrun_unittests.py4
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()