aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci/travis_install.sh4
-rw-r--r--docs/markdown/Cross-compilation.md7
-rw-r--r--docs/markdown/Reference-manual.md19
-rw-r--r--docs/markdown/howtox.md10
-rw-r--r--docs/markdown/snippets/can_run_host_binaries.md5
-rw-r--r--docs/markdown/snippets/d-lang_n_debug.md4
-rw-r--r--docs/markdown/snippets/exe_wrapper_for_cross_built_tests.md9
-rw-r--r--docs/markdown/snippets/rpath_behavior.md7
-rw-r--r--mesonbuild/backend/backends.py58
-rw-r--r--mesonbuild/backend/ninjabackend.py11
-rw-r--r--mesonbuild/backend/vs2010backend.py7
-rw-r--r--mesonbuild/build.py2
-rw-r--r--mesonbuild/cmake/interpreter.py8
-rw-r--r--mesonbuild/compilers/c.py5
-rw-r--r--mesonbuild/compilers/compilers.py13
-rw-r--r--mesonbuild/compilers/cpp.py9
-rw-r--r--mesonbuild/compilers/cuda.py7
-rw-r--r--mesonbuild/compilers/d.py25
-rw-r--r--mesonbuild/compilers/fortran.py2
-rw-r--r--mesonbuild/compilers/mixins/arm.py16
-rw-r--r--mesonbuild/compilers/mixins/clang.py9
-rw-r--r--mesonbuild/compilers/mixins/clike.py3
-rw-r--r--mesonbuild/compilers/mixins/islinker.py4
-rw-r--r--mesonbuild/compilers/objc.py2
-rw-r--r--mesonbuild/compilers/objcpp.py2
-rw-r--r--mesonbuild/coredata.py6
-rw-r--r--mesonbuild/dependencies/boost.py8
-rw-r--r--mesonbuild/environment.py26
-rw-r--r--mesonbuild/interpreter.py14
-rw-r--r--mesonbuild/interpreterbase.py26
-rw-r--r--mesonbuild/linkers.py49
-rw-r--r--mesonbuild/minstall.py2
-rw-r--r--mesonbuild/modules/__init__.py11
-rw-r--r--mesonbuild/modules/gnome.py10
-rw-r--r--mesonbuild/mtest.py43
-rw-r--r--mesonbuild/scripts/depfixer.py32
-rw-r--r--mesonbuild/scripts/symbolextractor.py24
-rw-r--r--msi/createmsi.py2
-rwxr-xr-xrun_project_tests.py1
-rwxr-xr-xrun_unittests.py347
-rw-r--r--test cases/common/36 tryrun/meson.build2
-rw-r--r--test cases/common/93 selfbuilt custom/meson.build2
-rw-r--r--test cases/failing/34 dependency not-required then required/test.json2
-rw-r--r--test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.c124
-rw-r--r--test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h21
-rw-r--r--test cases/frameworks/7 gnome/gir/dep1/dep3/meson.build22
-rw-r--r--test cases/frameworks/7 gnome/gir/dep1/meson.build5
-rw-r--r--test cases/frameworks/7 gnome/gir/meson.build2
-rw-r--r--test cases/frameworks/7 gnome/test.json4
-rw-r--r--test cases/unit/36 exe_wrapper behaviour/meson.build2
-rw-r--r--test cases/unit/40 external, internal library rpath/built library/meson.build5
-rw-r--r--test cases/unit/40 external, internal library rpath/external library/meson.build6
-rwxr-xr-xtest cases/unit/72 cross test passed/exewrapper.py24
-rw-r--r--test cases/unit/72 cross test passed/meson.build19
-rw-r--r--test cases/unit/72 cross test passed/meson_options.txt5
-rw-r--r--test cases/unit/72 cross test passed/script.py7
-rw-r--r--test cases/unit/72 cross test passed/src/main.c6
-rw-r--r--test cases/unit/73 summary/meson.build (renamed from test cases/unit/72 summary/meson.build)0
-rw-r--r--test cases/unit/73 summary/subprojects/sub/meson.build (renamed from test cases/unit/72 summary/subprojects/sub/meson.build)0
-rw-r--r--test cases/unit/73 summary/subprojects/sub2/meson.build (renamed from test cases/unit/72 summary/subprojects/sub2/meson.build)0
-rw-r--r--test cases/unit/74 wrap file url/meson.build (renamed from test cases/unit/73 wrap file url/meson.build)0
-rw-r--r--test cases/unit/74 wrap file url/subprojects/foo-patch.tar.xz (renamed from test cases/unit/73 wrap file url/subprojects/foo-patch.tar.xz)bin228 -> 228 bytes
-rw-r--r--test cases/unit/74 wrap file url/subprojects/foo.tar.xz (renamed from test cases/unit/73 wrap file url/subprojects/foo.tar.xz)bin216 -> 216 bytes
-rw-r--r--test cases/unit/75 dep files/foo.c (renamed from test cases/unit/74 dep files/foo.c)0
-rw-r--r--test cases/unit/75 dep files/meson.build (renamed from test cases/unit/74 dep files/meson.build)0
-rw-r--r--test cases/unit/76 pkgconfig prefixes/client/client.c8
-rw-r--r--test cases/unit/76 pkgconfig prefixes/client/meson.build3
-rw-r--r--test cases/unit/76 pkgconfig prefixes/val1/meson.build5
-rw-r--r--test cases/unit/76 pkgconfig prefixes/val1/val1.c3
-rw-r--r--test cases/unit/76 pkgconfig prefixes/val1/val1.h1
-rw-r--r--test cases/unit/76 pkgconfig prefixes/val2/meson.build8
-rw-r--r--test cases/unit/76 pkgconfig prefixes/val2/val2.c4
-rw-r--r--test cases/unit/76 pkgconfig prefixes/val2/val2.h1
-rw-r--r--test cases/unit/76 subdir libdir/meson.build (renamed from test cases/unit/75 subdir libdir/meson.build)0
-rw-r--r--test cases/unit/76 subdir libdir/subprojects/flub/meson.build (renamed from test cases/unit/75 subdir libdir/subprojects/flub/meson.build)0
-rw-r--r--test cases/unit/77 global-rpath/meson.build3
-rw-r--r--test cases/unit/77 global-rpath/rpathified.cpp6
-rw-r--r--test cases/unit/77 global-rpath/yonder/meson.build5
-rw-r--r--test cases/unit/77 global-rpath/yonder/yonder.cpp3
-rw-r--r--test cases/unit/77 global-rpath/yonder/yonder.h1
-rw-r--r--test cases/warning/1 version for string div/test.json2
81 files changed, 923 insertions, 237 deletions
diff --git a/ci/travis_install.sh b/ci/travis_install.sh
index 5d191f1..d9d308a 100755
--- a/ci/travis_install.sh
+++ b/ci/travis_install.sh
@@ -7,9 +7,11 @@ msg() { echo -e "\x1b[1;32mINFO: \x1b[37m$*\x1b[0m"; }
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
msg "Running OSX setup"
brew update
+ # Run one macOS build with pkg-config available (pulled in by qt), and the
+ # other (unity=on) without pkg-config
brew install qt ldc llvm ninja
if [[ "$MESON_ARGS" =~ .*unity=on.* ]]; then
- which pkg-config || brew install pkg-config
+ which pkg-config && rm -f $(which pkg-config)
fi
python3 -m pip install jsonschema
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md
index 4c4b7bf..1c53dcf 100644
--- a/docs/markdown/Cross-compilation.md
+++ b/docs/markdown/Cross-compilation.md
@@ -231,13 +231,10 @@ The main *meson* object provides two functions to determine cross
compilation status.
```meson
-meson.is_cross_build() # returns true when cross compiling
-meson.has_exe_wrapper() # returns true if an exe wrapper has been defined
+meson.is_cross_build() # returns true when cross compiling
+meson.can_run_host_binaries() # returns true if the host binaries can be run, either with a wrapper or natively
```
-Note that the latter gives undefined return value when doing a native
-build.
-
You can run system checks on both the system compiler or the cross
compiler. You just have to specify which one to use.
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 97d3e83..9b5d657 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -1613,6 +1613,13 @@ object](#build-target-object) returned by
object](#external-program-object) returned by
[`find_program()`](#find_program).
+*Since 0.55.0* When cross compiling, if an exe_wrapper is needed and defined
+the environment variable `MESON_EXE_WRAPPER` will be set to the string value
+of that wrapper (implementation detail: using `mesonlib.join_args`). Test
+scripts may use this to run cross built binaries. If your test needs
+`MESON_EXE_WRAPPER` in cross build situations it is your responsibility to
+return code 77 to tell the harness to report "skip"
+
By default, environment variable
[`MALLOC_PERTURB_`](http://man7.org/linux/man-pages/man3/mallopt.3.html)
is automatically set by `meson test` to a random value between 1..255.
@@ -1836,10 +1843,14 @@ the following methods.
If `native: false` or not specified, variable is retrieved from the
cross-file if cross-compiling, and from the native-file when not cross-compiling.
-- `has_exe_wrapper()` returns true when doing a cross build if there
- is a wrapper command that can be used to execute cross built
- binaries (for example when cross compiling from Linux to Windows,
- one can use `wine` as the wrapper).
+- `can_run_host_binaries()` returns true if the build machine can run
+ binaries compiled for the host. This returns true unless you are
+ cross compiling, need a helper to run host binaries, and don't have one.
+ For example when cross compiling from Linux to Windows, one can use `wine`
+ as the helper. *New in 0.55.0*
+
+- `has_exe_wrapper()` alias of `can_run_host_binaries`
+ *Deprecated since 0.55.0*
- `install_dependency_manifest(output_name)` installs a manifest file
containing a list of all subprojects, their versions and license
diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md
index abf7519..84546b7 100644
--- a/docs/markdown/howtox.md
+++ b/docs/markdown/howtox.md
@@ -271,6 +271,7 @@ This can be used in cases where you want a default value, but might override it
later.
```meson
+# Not needed on Windows!
my_dep = dependency('', required : false)
if host_machine.system() in ['freebsd', 'netbsd', 'openbsd', 'dragonfly']
my_dep = dependency('some dep', required : false)
@@ -278,8 +279,9 @@ elif host_machine.system() == 'linux'
my_dep = dependency('some other dep', required : false)
endif
-# Last ditch effort!
-if no my_dep.found()
- my_dep = meson.get_compiler('c').find_library('dep')
-endif
+executable(
+ 'myexe',
+ my_sources,
+ deps : [my_dep]
+)
```
diff --git a/docs/markdown/snippets/can_run_host_binaries.md b/docs/markdown/snippets/can_run_host_binaries.md
new file mode 100644
index 0000000..0108184
--- /dev/null
+++ b/docs/markdown/snippets/can_run_host_binaries.md
@@ -0,0 +1,5 @@
+## Rename has_exe_wrapper -> can_run_host_binaries
+
+The old name was confusing as it didn't really match the behavior of the
+function. The old name remains as an alias (the behavior hasn't changed), but
+is now deprecated.
diff --git a/docs/markdown/snippets/d-lang_n_debug.md b/docs/markdown/snippets/d-lang_n_debug.md
new file mode 100644
index 0000000..59f09e4
--- /dev/null
+++ b/docs/markdown/snippets/d-lang_n_debug.md
@@ -0,0 +1,4 @@
+## b_ndebug support for D language compilers
+
+D Language compilers will now set -release/--release/-frelease (depending on
+the compiler) when the b_ndebug flag is set.
diff --git a/docs/markdown/snippets/exe_wrapper_for_cross_built_tests.md b/docs/markdown/snippets/exe_wrapper_for_cross_built_tests.md
new file mode 100644
index 0000000..ebdd8a7
--- /dev/null
+++ b/docs/markdown/snippets/exe_wrapper_for_cross_built_tests.md
@@ -0,0 +1,9 @@
+## Test scripts are given the exe wrapper if needed
+
+Meson will now set the `MESON_EXE_WRAPPER` as the properly wrapped and joined
+representation. For Unix-like OSes this means python's shelx.join, on Windows
+an implementation that attempts to properly quote windows argument is used.
+This allow wrapper scripts to run test binaries, instead of just skipping.
+
+for example, if the wrapper is `['emulator', '--script']`, it will be passed
+as `MESON_EXE_WRAPPER="emulator --script"`.
diff --git a/docs/markdown/snippets/rpath_behavior.md b/docs/markdown/snippets/rpath_behavior.md
new file mode 100644
index 0000000..c46f0c2
--- /dev/null
+++ b/docs/markdown/snippets/rpath_behavior.md
@@ -0,0 +1,7 @@
+## rpath removal now more careful
+
+On Linux-like systems, meson adds rpath entries to allow running apps
+in the build tree, and then removes those build-time-only
+rpath entries when installing. Rpath entries may also come
+in via LDFLAGS and via .pc files. Meson used to remove those
+latter rpath entries by accident, but is now more careful.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 7f7c434..840c9a3 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -90,12 +90,13 @@ class InstallData:
self.mesonintrospect = mesonintrospect
class TargetInstallData:
- def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install_rpath, install_mode, optional=False):
+ def __init__(self, fname, outdir, aliases, strip, install_name_mappings, rpath_dirs_to_remove, install_rpath, install_mode, optional=False):
self.fname = fname
self.outdir = outdir
self.aliases = aliases
self.strip = strip
self.install_name_mappings = install_name_mappings
+ self.rpath_dirs_to_remove = rpath_dirs_to_remove
self.install_rpath = install_rpath
self.install_mode = install_mode
self.optional = optional
@@ -118,7 +119,8 @@ class TestSerialisation:
needs_exe_wrapper: bool, is_parallel: bool, cmd_args: T.List[str],
env: build.EnvironmentVariables, should_fail: bool,
timeout: T.Optional[int], workdir: T.Optional[str],
- extra_paths: T.List[str], protocol: TestProtocol, priority: int):
+ extra_paths: T.List[str], protocol: TestProtocol, priority: int,
+ cmd_is_built: bool):
self.name = name
self.project_name = project
self.suite = suite
@@ -137,6 +139,8 @@ class TestSerialisation:
self.protocol = protocol
self.priority = priority
self.needs_exe_wrapper = needs_exe_wrapper
+ self.cmd_is_built = cmd_is_built
+
def get_backend_from_name(backend: str, build: T.Optional[build.Build] = None, interpreter: T.Optional['Interpreter'] = None) -> T.Optional['Backend']:
if backend == 'ninja':
@@ -258,7 +262,7 @@ class Backend:
return self.build_to_src
def get_target_private_dir(self, target):
- return os.path.join(self.get_target_dir(target), target.get_id())
+ return os.path.join(self.get_target_filename(target) + '.p')
def get_target_private_dir_abs(self, target):
return os.path.join(self.environment.get_build_dir(), self.get_target_private_dir(target))
@@ -443,6 +447,21 @@ class Backend:
return True
return False
+ def get_external_rpath_dirs(self, target):
+ dirs = set()
+ args = []
+ # FIXME: is there a better way?
+ for lang in ['c', 'cpp']:
+ try:
+ args.extend(self.environment.coredata.get_external_link_args(target.for_machine, lang))
+ except Exception:
+ pass
+ for arg in args:
+ if arg.startswith('-Wl,-rpath='):
+ for dir in arg.replace('-Wl,-rpath=','').split(':'):
+ dirs.add(dir)
+ return dirs
+
def rpaths_for_bundled_shared_libraries(self, target, exclude_system=True):
paths = []
for dep in target.external_deps:
@@ -457,6 +476,9 @@ class Backend:
if exclude_system and self._libdir_is_system(libdir, target.compilers, self.environment):
# No point in adding system paths.
continue
+ # Don't remove rpaths specified in LDFLAGS.
+ if libdir in self.get_external_rpath_dirs(target):
+ continue
# Windows doesn't support rpaths, but we use this function to
# emulate rpaths by setting PATH, so also accept DLLs here
if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']:
@@ -476,6 +498,7 @@ class Backend:
result = OrderedSet()
result.add('meson-out')
result.update(self.rpaths_for_bundled_shared_libraries(target))
+ target.rpath_dirs_to_remove.update([d.encode('utf8') for d in result])
return tuple(result)
def object_filename_from_source(self, target, source):
@@ -768,6 +791,15 @@ class Backend:
# E.g. an external verifier or simulator program run on a generated executable.
# Can always be run without a wrapper.
test_for_machine = MachineChoice.BUILD
+
+ # we allow passing compiled executables to tests, which may be cross built.
+ # We need to consider these as well when considering whether the target is cross or not.
+ for a in t.cmd_args:
+ if isinstance(a, build.BuildTarget):
+ if a.for_machine is MachineChoice.HOST:
+ test_for_machine = MachineChoice.HOST
+ break
+
is_cross = self.environment.is_cross_build(test_for_machine)
if is_cross and self.environment.need_exe_wrapper():
exe_wrapper = self.environment.get_exe_wrapper()
@@ -781,6 +813,7 @@ class Backend:
extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps)
else:
extra_paths = []
+
cmd_args = []
for a in unholder(t.cmd_args):
if isinstance(a, build.BuildTarget):
@@ -790,6 +823,11 @@ class Backend:
cmd_args.append(a)
elif isinstance(a, str):
cmd_args.append(a)
+ elif isinstance(a, build.Executable):
+ p = self.construct_target_rel_path(a, t.workdir)
+ if p == a.get_filename():
+ p = './' + p
+ cmd_args.append(p)
elif isinstance(a, build.Target):
cmd_args.append(self.construct_target_rel_path(a, t.workdir))
else:
@@ -798,7 +836,8 @@ class Backend:
exe_wrapper, self.environment.need_exe_wrapper(),
t.is_parallel, cmd_args, t.env,
t.should_fail, t.timeout, t.workdir,
- extra_paths, t.protocol, t.priority)
+ extra_paths, t.protocol, t.priority,
+ isinstance(exe, build.Executable))
arr.append(ts)
return arr
@@ -1140,6 +1179,7 @@ class Backend:
mappings = t.get_link_deps_mapping(d.prefix, self.environment)
i = TargetInstallData(self.get_target_filename(t), outdirs[0],
t.get_aliases(), should_strip, mappings,
+ t.rpath_dirs_to_remove,
t.install_rpath, install_mode)
d.targets.append(i)
@@ -1157,14 +1197,14 @@ class Backend:
implib_install_dir = self.environment.get_import_lib_dir()
# Install the import library; may not exist for shared modules
i = TargetInstallData(self.get_target_filename_for_linking(t),
- implib_install_dir, {}, False, {}, '', install_mode,
+ implib_install_dir, {}, False, {}, set(), '', install_mode,
optional=isinstance(t, build.SharedModule))
d.targets.append(i)
if not should_strip and t.get_debug_filename():
debug_file = os.path.join(self.get_target_dir(t), t.get_debug_filename())
i = TargetInstallData(debug_file, outdirs[0],
- {}, False, {}, '',
+ {}, False, {}, set(), '',
install_mode, optional=True)
d.targets.append(i)
# Install secondary outputs. Only used for Vala right now.
@@ -1174,7 +1214,7 @@ class Backend:
if outdir is False:
continue
f = os.path.join(self.get_target_dir(t), output)
- i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode)
+ i = TargetInstallData(f, outdir, {}, False, {}, set(), None, install_mode)
d.targets.append(i)
elif isinstance(t, build.CustomTarget):
# If only one install_dir is specified, assume that all
@@ -1187,7 +1227,7 @@ class Backend:
if num_outdirs == 1 and num_out > 1:
for output in t.get_outputs():
f = os.path.join(self.get_target_dir(t), output)
- i = TargetInstallData(f, outdirs[0], {}, False, {}, None, install_mode,
+ i = TargetInstallData(f, outdirs[0], {}, False, {}, set(), None, install_mode,
optional=not t.build_by_default)
d.targets.append(i)
else:
@@ -1196,7 +1236,7 @@ class Backend:
if outdir is False:
continue
f = os.path.join(self.get_target_dir(t), output)
- i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode,
+ i = TargetInstallData(f, outdir, {}, False, {}, set(), None, install_mode,
optional=not t.build_by_default)
d.targets.append(i)
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 9b895c9..7300aaf 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -570,7 +570,7 @@ int dummy;
generated_source_files.append(raw_src)
elif self.environment.is_object(rel_src):
obj_list.append(rel_src)
- elif self.environment.is_library(rel_src):
+ elif self.environment.is_library(rel_src) or modules.is_module_library(rel_src):
pass
else:
# Assume anything not specifically a source file is a header. This is because
@@ -585,7 +585,7 @@ int dummy;
o = self.generate_llvm_ir_compile(target, src)
else:
o = self.generate_single_compile(target, src, True,
- header_deps=header_deps)
+ order_deps=header_deps)
obj_list.append(o)
use_pch = self.environment.coredata.base_options.get('b_pch', False)
@@ -1348,7 +1348,8 @@ int dummy;
self.get_target_dir(target))
else:
target_slashname_workaround_dir = self.get_target_dir(target)
- rpath_args = rustc.build_rpath_args(self.environment,
+ (rpath_args, target.rpath_dirs_to_remove) = \
+ rustc.build_rpath_args(self.environment,
self.environment.get_build_dir(),
target_slashname_workaround_dir,
self.determine_rpath_dirs(target),
@@ -2580,12 +2581,14 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
self.get_target_dir(target))
else:
target_slashname_workaround_dir = self.get_target_dir(target)
- commands += linker.build_rpath_args(self.environment,
+ (rpath_args, target.rpath_dirs_to_remove) = \
+ linker.build_rpath_args(self.environment,
self.environment.get_build_dir(),
target_slashname_workaround_dir,
self.determine_rpath_dirs(target),
target.build_rpath,
target.install_rpath)
+ commands += rpath_args
# Add libraries generated by custom targets
custom_target_libraries = self.get_custom_target_provided_libraries(target)
commands += extra_args
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index b5803bf..6965c42 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -98,6 +98,9 @@ class Vs2010Backend(backends.Backend):
self.subdirs = {}
self.handled_target_deps = {}
+ def get_target_private_dir(self, target):
+ return os.path.join(self.get_target_dir(target), target.get_id())
+
def generate_custom_generator_commands(self, target, parent_node):
generator_output_files = []
custom_target_include_dirs = []
@@ -821,12 +824,12 @@ class Vs2010Backend(backends.Backend):
clconf = ET.SubElement(compiles, 'ClCompile')
# CRT type; debug or release
if vscrt_type.value == 'from_buildtype':
- if self.buildtype == 'debug' or self.buildtype == 'debugoptimized':
+ if self.buildtype == 'debug':
ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL'
else:
ET.SubElement(type_config, 'UseDebugLibraries').text = 'false'
- ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreaded'
+ ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDLL'
elif vscrt_type.value == 'mdd':
ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL'
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index fdfca73..360285e 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -512,6 +512,8 @@ class BuildTarget(Target):
self.d_features = {}
self.pic = False
self.pie = False
+ # Track build_rpath entries so we can remove them at install time
+ self.rpath_dirs_to_remove = set()
# Sources can be:
# 1. Pre-existing source files in the source tree
# 2. Pre-existing sources generated by configure_file in the build tree
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
index 0a452d1..35eb17c 100644
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -290,10 +290,12 @@ class ConverterTarget:
m = ConverterTarget.std_regex.match(j)
if m:
std = m.group(2)
- if std not in self._all_lang_stds(i):
+ supported = self._all_lang_stds(i)
+ if std not in supported:
mlog.warning(
- 'Unknown {}_std "{}" -> Ingoring. Try setting the project'
- 'level {}_std if build errors occur.'.format(i, std),
+ 'Unknown {0}_std "{1}" -> Ignoring. Try setting the project-'
+ 'level {0}_std if build errors occur. Known '
+ '{0}_stds are: {2}'.format(i, std, ' '.join(supported)),
once=True
)
continue
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 1bc9e84..aac99b4 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -86,9 +86,10 @@ class ClangCCompiler(ClangCompiler, CCompiler):
_C18_VERSION = '>=8.0.0'
def __init__(self, exelist, version, for_machine: MachineChoice,
- is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
+ is_cross, info: 'MachineInfo', exe_wrapper=None,
+ defines: T.Optional[T.List[str]] = None, **kwargs):
CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs)
- ClangCompiler.__init__(self)
+ ClangCompiler.__init__(self, defines)
default_warn_args = ['-Wall', '-Winvalid-pch']
self.warn_args = {'0': [],
'1': default_warn_args,
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 385ef5e..f3c171f 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -186,7 +186,7 @@ rust_buildtype_args = {'plain': [],
d_gdc_buildtype_args = {'plain': [],
'debug': [],
'debugoptimized': ['-finline-functions'],
- 'release': ['-frelease', '-finline-functions'],
+ 'release': ['-finline-functions'],
'minsize': [],
'custom': [],
}
@@ -194,7 +194,7 @@ d_gdc_buildtype_args = {'plain': [],
d_ldc_buildtype_args = {'plain': [],
'debug': [],
'debugoptimized': ['-enable-inlining', '-Hkeep-all-bodies'],
- 'release': ['-release', '-enable-inlining', '-Hkeep-all-bodies'],
+ 'release': ['-enable-inlining', '-Hkeep-all-bodies'],
'minsize': [],
'custom': [],
}
@@ -202,7 +202,7 @@ d_ldc_buildtype_args = {'plain': [],
d_dmd_buildtype_args = {'plain': [],
'debug': [],
'debugoptimized': ['-inline'],
- 'release': ['-release', '-inline'],
+ 'release': ['-inline'],
'minsize': [],
'custom': [],
}
@@ -320,7 +320,7 @@ def get_base_compile_args(options, compiler):
if (options['b_ndebug'].value == 'true' or
(options['b_ndebug'].value == 'if-release' and
options['buildtype'].value in {'release', 'plain'})):
- args += ['-DNDEBUG']
+ args += compiler.get_disable_assert_args()
except KeyError:
pass
# This does not need a try...except
@@ -1077,7 +1077,7 @@ class Compiler:
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
return self.linker.build_rpath_args(
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
@@ -1204,6 +1204,9 @@ class Compiler:
def get_coverage_link_args(self) -> T.List[str]:
return self.linker.get_coverage_args()
+ def get_disable_assert_args(self) -> T.List[str]:
+ return []
+
def get_largefile_args(compiler):
'''
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index d30017f..478a68c 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -155,10 +155,11 @@ class CPPCompiler(CLikeCompiler, Compiler):
class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice,
- is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
+ is_cross, info: 'MachineInfo', exe_wrapper=None,
+ defines : T.Optional[T.List[str]] = None, **kwargs):
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross,
info, exe_wrapper, **kwargs)
- ClangCompiler.__init__(self)
+ ClangCompiler.__init__(self, defines)
default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor']
self.warn_args = {'0': [],
'1': default_warn_args,
@@ -238,7 +239,9 @@ class EmscriptenCPPCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCPPCompile
class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice,
is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
- CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs)
+ CPPCompiler.__init__(self, exelist=exelist, version=version,
+ for_machine=for_machine, is_cross=is_cross,
+ info=info, exe_wrapper=exe_wrapper, **kwargs)
ArmclangCompiler.__init__(self)
default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor']
self.warn_args = {'0': [],
diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py
index e839f53..4e89f5d 100644
--- a/mesonbuild/compilers/cuda.py
+++ b/mesonbuild/compilers/cuda.py
@@ -271,9 +271,10 @@ class CudaCompiler(Compiler):
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
- return self._cook_link_args(self.host_compiler.build_rpath_args(
- env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath))
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ (rpath_args, rpath_dirs_to_remove) = self.host_compiler.build_rpath_args(
+ env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
+ return (self._cook_link_args(rpath_args), rpath_dirs_to_remove)
def linker_to_compiler_args(self, args):
return args
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index a83e221..777fa19 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -220,7 +220,7 @@ class DmdLikeCompilerMixin:
def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
if self.info.is_windows():
- return []
+ return ([], set())
# GNU ld, solaris ld, and lld acting like GNU ld
if self.linker.id.startswith('ld'):
@@ -228,15 +228,16 @@ class DmdLikeCompilerMixin:
# do directly, each argument -rpath and the value to rpath, need to be
# split into two separate arguments both prefaced with the -L=.
args = []
- for r in super().build_rpath_args(
- env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
+ (rpath_args, rpath_dirs_to_remove) = super().build_rpath_args(
+ env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
+ for r in rpath_args:
if ',' in r:
a, b = r.split(',', maxsplit=1)
args.append(a)
args.append(self.LINKER_PREFIX + b)
else:
args.append(r)
- return args
+ return (args, rpath_dirs_to_remove)
return super().build_rpath_args(
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
@@ -645,7 +646,8 @@ class GnuDCompiler(GnuCompiler, DCompiler):
'1': default_warn_args,
'2': default_warn_args + ['-Wextra'],
'3': default_warn_args + ['-Wextra', '-Wpedantic']}
- self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic', 'b_vscrt', 'b_coverage']
+ self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic',
+ 'b_vscrt', 'b_coverage', 'b_pgo', 'b_ndebug']
self._has_color_support = version_compare(self.version, '>=4.9')
# dependencies were implemented before, but broken - support was fixed in GCC 7.1+
@@ -684,6 +686,9 @@ class GnuDCompiler(GnuCompiler, DCompiler):
return args
return args + ['-shared-libphobos']
+ def get_disable_assert_args(self):
+ return ['-frelease']
+
class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler):
@@ -691,7 +696,7 @@ class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler):
info: 'MachineInfo', arch, **kwargs):
DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs)
self.id = 'llvm'
- self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt']
+ self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug']
def get_colorout_args(self, colortype):
if colortype == 'always':
@@ -733,6 +738,9 @@ class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler):
return args
return args + ['-link-defaultlib-shared']
+ def get_disable_assert_args(self) -> T.List[str]:
+ return ['--release']
+
class DmdDCompiler(DmdLikeCompilerMixin, DCompiler):
@@ -740,7 +748,7 @@ class DmdDCompiler(DmdLikeCompilerMixin, DCompiler):
info: 'MachineInfo', arch, **kwargs):
DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs)
self.id = 'dmd'
- self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt']
+ self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug']
def get_colorout_args(self, colortype):
if colortype == 'always':
@@ -803,3 +811,6 @@ class DmdDCompiler(DmdLikeCompilerMixin, DCompiler):
if self.info.is_windows():
return args
return args + ['-defaultlib=phobos2', '-debuglib=phobos2']
+
+ def get_disable_assert_args(self) -> T.List[str]:
+ return ['-release']
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index c155b5b..af83c0e56 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -424,7 +424,7 @@ class FlangFortranCompiler(ClangCompiler, FortranCompiler):
**kwargs):
FortranCompiler.__init__(self, exelist, version, for_machine,
is_cross, info, exe_wrapper, **kwargs)
- ClangCompiler.__init__(self)
+ ClangCompiler.__init__(self, [])
self.id = 'flang'
default_warn_args = ['-Minform=inform']
self.warn_args = {'0': [],
diff --git a/mesonbuild/compilers/mixins/arm.py b/mesonbuild/compilers/mixins/arm.py
index aa5d15d..2e2ed94 100644
--- a/mesonbuild/compilers/mixins/arm.py
+++ b/mesonbuild/compilers/mixins/arm.py
@@ -27,10 +27,10 @@ if T.TYPE_CHECKING:
arm_buildtype_args = {
'plain': [],
- 'debug': ['-O0', '--debug'],
- 'debugoptimized': ['-O1', '--debug'],
- 'release': ['-O3', '-Otime'],
- 'minsize': ['-O3', '-Ospace'],
+ 'debug': [],
+ 'debugoptimized': [],
+ 'release': [],
+ 'minsize': [],
'custom': [],
} # type: T.Dict[str, T.List[str]]
@@ -38,9 +38,9 @@ arm_optimization_args = {
'0': ['-O0'],
'g': ['-g'],
'1': ['-O1'],
- '2': ['-O2'],
- '3': ['-O3'],
- 's': [],
+ '2': [], # Compiler defaults to -O2
+ '3': ['-O3', '-Otime'],
+ 's': ['-O3'], # Compiler defaults to -Ospace
} # type: T.Dict[str, T.List[str]]
armclang_buildtype_args = {
@@ -181,7 +181,7 @@ class ArmclangCompiler:
# Override CCompiler.get_dependency_gen_args
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
- return []
+ return ['-MD', '-MT', outtarget, '-MF', outfile]
def get_optimization_args(self, optimization_level: str) -> T.List[str]:
return armclang_optimization_args[optimization_level]
diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py
index 1c0ee45..0ee10ad 100644
--- a/mesonbuild/compilers/mixins/clang.py
+++ b/mesonbuild/compilers/mixins/clang.py
@@ -42,9 +42,10 @@ clang_optimization_args = {
} # type: T.Dict[str, T.List[str]]
class ClangCompiler(GnuLikeCompiler):
- def __init__(self):
+ def __init__(self, defines: T.Optional[T.Dict[str, str]]):
super().__init__()
self.id = 'clang'
+ self.defines = defines or {}
self.base_options.append('b_colorout')
# TODO: this really should be part of the linker base_options, but
# linkers don't have base_options.
@@ -56,6 +57,12 @@ class ClangCompiler(GnuLikeCompiler):
def get_colorout_args(self, colortype: str) -> T.List[str]:
return clang_color_args[colortype][:]
+ def has_builtin_define(self, define: str) -> bool:
+ return define in self.defines
+
+ def get_builtin_define(self, define: str) -> T.Optional[str]:
+ return self.defines.get(define)
+
def get_optimization_args(self, optimization_level: str) -> T.List[str]:
return clang_optimization_args[optimization_level]
diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py
index e7b0cd2..01c984d 100644
--- a/mesonbuild/compilers/mixins/clike.py
+++ b/mesonbuild/compilers/mixins/clike.py
@@ -1137,3 +1137,6 @@ class CLikeCompiler:
return self.compiles(self.attribute_check_func(name), env,
extra_args=self.get_has_func_attribute_extra_args(name))
+
+ def get_disable_assert_args(self) -> T.List[str]:
+ return ['-DNDEBUG']
diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py
index 681c816..bf1d339 100644
--- a/mesonbuild/compilers/mixins/islinker.py
+++ b/mesonbuild/compilers/mixins/islinker.py
@@ -107,8 +107,8 @@ class BasicLinkerIsCompilerMixin:
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
- return []
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
def get_linker_debug_crt_args(self) -> T.List[str]:
return []
diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py
index 52d258d..d351c88 100644
--- a/mesonbuild/compilers/objc.py
+++ b/mesonbuild/compilers/objc.py
@@ -86,7 +86,7 @@ class ClangObjCCompiler(ClangCompiler, ObjCCompiler):
**kwargs):
ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross,
info, exe_wrapper, **kwargs)
- ClangCompiler.__init__(self)
+ ClangCompiler.__init__(self, [])
default_warn_args = ['-Wall', '-Winvalid-pch']
self.warn_args = {'0': [],
'1': default_warn_args,
diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py
index c8b422b..10555b4 100644
--- a/mesonbuild/compilers/objcpp.py
+++ b/mesonbuild/compilers/objcpp.py
@@ -84,7 +84,7 @@ class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler):
is_cross, info: 'MachineInfo', exe_wrapper=None,
**kwargs):
ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs)
- ClangCompiler.__init__(self)
+ ClangCompiler.__init__(self, [])
default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor']
self.warn_args = {'0': [],
'1': default_warn_args,
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 754be1d..8774b80 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -384,8 +384,8 @@ class CoreData:
self.compiler_check_cache = OrderedDict()
# Only to print a warning if it changes between Meson invocations.
self.config_files = self.__load_config_files(options, scratch_dir, 'native')
+ self.builtin_options_libdir_cross_fixup()
self.init_builtins('')
- self.libdir_cross_fixup()
@staticmethod
def __load_config_files(options: argparse.Namespace, scratch_dir: str, ftype: str) -> T.List[str]:
@@ -445,12 +445,12 @@ class CoreData:
raise MesonException('Cannot find specified {} file: {}'.format(ftype, f))
return real
- def libdir_cross_fixup(self):
+ def builtin_options_libdir_cross_fixup(self):
# By default set libdir to "lib" when cross compiling since
# getting the "system default" is always wrong on multiarch
# platforms as it gets a value like lib/x86_64-linux-gnu.
if self.cross_files:
- self.builtins['libdir'].value = 'lib'
+ builtin_options['libdir'].default = 'lib'
def sanitize_prefix(self, prefix):
prefix = os.path.expanduser(prefix)
diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py
index 2e84820..6e85c53 100644
--- a/mesonbuild/dependencies/boost.py
+++ b/mesonbuild/dependencies/boost.py
@@ -605,6 +605,12 @@ class BoostDependency(ExternalDependency):
roots += paths
return roots # Do not add system paths if BOOST_ROOT is present
+ # Add roots from system paths
+ inc_paths = [Path(x) for x in self.clib_compiler.get_default_include_dirs()]
+ inc_paths = [x.parent for x in inc_paths if x.exists()]
+ inc_paths = [x.resolve() for x in inc_paths]
+ roots += inc_paths
+
# Add system paths
if self.env.machines[self.for_machine].is_windows():
# Where boost built from source actually installs it
@@ -626,8 +632,6 @@ class BoostDependency(ExternalDependency):
roots += [x for x in candidates if x.name.lower().startswith('boost') and x.is_dir()]
else:
tmp = [] # type: T.List[Path]
- # Add unix paths
- tmp += [Path(x).parent for x in self.clib_compiler.get_default_include_dirs()]
# Homebrew
brew_boost = Path('/usr/local/Cellar/boost')
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 8fad628..cb6ae7d 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -726,6 +726,28 @@ class Environment:
minor = defines.get('__LCC_MINOR__', '0')
return dot.join((generation, major, minor))
+ @staticmethod
+ def get_clang_compiler_defines(compiler):
+ """
+ Get the list of Clang pre-processor defines
+ """
+ args = compiler + ['-E', '-dM', '-']
+ p, output, error = Popen_safe(args, write='', stdin=subprocess.PIPE)
+ if p.returncode != 0:
+ raise EnvironmentException('Unable to get clang pre-processor defines:\n' + output + error)
+ defines = {}
+ for line in output.split('\n'):
+ if not line:
+ continue
+ d, *rest = line.split(' ', 2)
+ if d != '#define':
+ continue
+ if len(rest) == 1:
+ defines[rest] = True
+ if len(rest) == 2:
+ defines[rest[0]] = rest[1]
+ return defines
+
def _get_compilers(self, lang, for_machine):
'''
The list of compilers is detected in the exact same way for
@@ -1043,6 +1065,8 @@ class Environment:
if 'clang' in out:
linker = None
+ defines = self.get_clang_compiler_defines(compiler)
+
# Even if the for_machine is darwin, we could be using vanilla
# clang.
if 'Apple' in out:
@@ -1063,7 +1087,7 @@ class Environment:
return cls(
ccache + compiler, version, for_machine, is_cross, info,
- exe_wrap, full_version=full_version, linker=linker)
+ exe_wrap, defines, full_version=full_version, linker=linker)
if 'Intel(R) C++ Intel(R)' in err:
version = search_version(err)
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 7901e5a..8c7a82c 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1873,6 +1873,7 @@ class MesonMain(InterpreterObject):
self.methods.update({'get_compiler': self.get_compiler_method,
'is_cross_build': self.is_cross_build_method,
'has_exe_wrapper': self.has_exe_wrapper_method,
+ 'can_run_host_binaries': self.can_run_host_binaries_method,
'is_unity': self.is_unity_method,
'is_subproject': self.is_subproject_method,
'current_source_dir': self.current_source_dir_method,
@@ -2023,9 +2024,16 @@ class MesonMain(InterpreterObject):
@noPosargs
@permittedKwargs({})
- def has_exe_wrapper_method(self, args, kwargs):
- if self.is_cross_build_method(None, None) and \
- self.build.environment.need_exe_wrapper():
+ @FeatureDeprecated('meson.has_exe_wrapper', '0.55.0', 'use meson.can_run_host_binaries instead.')
+ def has_exe_wrapper_method(self, args: T.Tuple[object, ...], kwargs: T.Dict[str, object]) -> bool:
+ return self.can_run_host_binaries_method(args, kwargs)
+
+ @noPosargs
+ @permittedKwargs({})
+ @FeatureNew('meson.can_run_host_binaries', '0.55.0')
+ def can_run_host_binaries_method(self, args: T.Tuple[object, ...], kwargs: T.Dict[str, object]) -> bool:
+ if (self.is_cross_build_method(None, None) and
+ self.build.environment.need_exe_wrapper()):
if self.build.environment.exe_wrapper is None:
return False
# We return True when exe_wrap is defined, when it's not needed, and
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
index 82d16f1..af9018b 100644
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -220,9 +220,10 @@ class FeatureCheckBase(metaclass=abc.ABCMeta):
# This will be overwritten by the subclasses by necessity
feature_registry = {} # type: T.ClassVar[T.Dict[str, T.Dict[str, T.Set[str]]]]
- def __init__(self, feature_name: str, version: str):
+ def __init__(self, feature_name: str, version: str, extra_message: T.Optional[str] = None):
self.feature_name = feature_name # type: str
self.feature_version = version # type: str
+ self.extra_message = extra_message or '' # type: str
@staticmethod
def get_target_version(subproject: str) -> str:
@@ -302,8 +303,15 @@ class FeatureNew(FeatureCheckBase):
return 'Project specifies a minimum meson_version \'{}\' but uses features which were added in newer versions:'.format(tv)
def log_usage_warning(self, tv: str) -> None:
- mlog.warning('Project targeting \'{}\' but tried to use feature introduced '
- 'in \'{}\': {}'.format(tv, self.feature_version, self.feature_name))
+ args = [
+ 'Project targeting', "'{}'".format(tv),
+ 'but tried to use feature introduced in',
+ "'{}':".format(self.feature_version),
+ '{}.'.format(self.feature_name),
+ ]
+ if self.extra_message:
+ args.append(self.extra_message)
+ mlog.warning(*args)
class FeatureDeprecated(FeatureCheckBase):
"""Checks for deprecated features"""
@@ -323,9 +331,15 @@ class FeatureDeprecated(FeatureCheckBase):
return 'Deprecated features used:'
def log_usage_warning(self, tv: str) -> None:
- mlog.deprecation('Project targeting \'{}\' but tried to use feature '
- 'deprecated since \'{}\': {}'
- ''.format(tv, self.feature_version, self.feature_name))
+ args = [
+ 'Project targeting', "'{}'".format(tv),
+ 'but tried to use feature deprecated since',
+ "'{}':".format(self.feature_version),
+ '{}.'.format(self.feature_name),
+ ]
+ if self.extra_message:
+ args.append(self.extra_message)
+ mlog.warning(*args)
class FeatureCheckKwargsBase:
diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py
index db735e7..f02c297 100644
--- a/mesonbuild/linkers.py
+++ b/mesonbuild/linkers.py
@@ -56,8 +56,8 @@ class StaticLinker:
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
- return []
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
def thread_link_flags(self, env: 'Environment') -> T.List[str]:
return []
@@ -444,8 +444,8 @@ class DynamicLinker(LinkerEnvVarsMixin, metaclass=abc.ABCMeta):
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
- return []
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
@@ -551,12 +551,12 @@ class GnuLikeDynamicLinkerMixin:
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
m = env.machines[self.for_machine]
if m.is_windows() or m.is_cygwin():
- return []
+ return ([], set())
if not rpath_paths and not install_rpath and not build_rpath:
- return []
+ return ([], set())
args = []
origin_placeholder = '$ORIGIN'
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
@@ -564,9 +564,14 @@ class GnuLikeDynamicLinkerMixin:
# is *very* allergic to duplicate -delete_rpath arguments
# when calling depfixer on installation.
all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
+ rpath_dirs_to_remove = set()
+ for p in all_paths:
+ rpath_dirs_to_remove.add(p.encode('utf8'))
# Build_rpath is used as-is (it is usually absolute).
if build_rpath != '':
all_paths.add(build_rpath)
+ for p in build_rpath.split(':'):
+ rpath_dirs_to_remove.add(p.encode('utf8'))
# TODO: should this actually be "for (dragonfly|open)bsd"?
if mesonlib.is_dragonflybsd() or mesonlib.is_openbsd():
@@ -590,7 +595,7 @@ class GnuLikeDynamicLinkerMixin:
# TODO: should this actually be "for solaris/sunos"?
if mesonlib.is_sunos():
- return args
+ return (args, rpath_dirs_to_remove)
# Rpaths to use while linking must be absolute. These are not
# written to the binary. Needed only with GNU ld:
@@ -610,7 +615,7 @@ class GnuLikeDynamicLinkerMixin:
for p in rpath_paths:
args.extend(self._apply_prefix('-rpath-link,' + os.path.join(build_dir, p)))
- return args
+ return (args, rpath_dirs_to_remove)
class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
@@ -676,9 +681,9 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
if not rpath_paths and not install_rpath and not build_rpath:
- return []
+ return ([], set())
# Ensure that there is enough space for install_name_tool in-place
# editing of large RPATHs
args = self._apply_prefix('-headerpad_max_install_names')
@@ -692,7 +697,7 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
for rp in all_paths:
args.extend(self._apply_prefix('-rpath,' + rp))
- return args
+ return (args, set())
class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
@@ -763,8 +768,8 @@ class WASMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dyna
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
- return []
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
class CcrxDynamicLinker(DynamicLinker):
@@ -839,8 +844,8 @@ class Xc16DynamicLinker(DynamicLinker):
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
- return []
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
class C2000DynamicLinker(DynamicLinker):
@@ -938,10 +943,10 @@ class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
if not env.machines[self.for_machine].is_windows():
- return ['-R' + os.path.join(build_dir, p) for p in rpath_paths]
- return []
+ return (['-R' + os.path.join(build_dir, p) for p in rpath_paths], set())
+ return ([], set())
class PGIStaticLinker(StaticLinker):
@@ -1091,9 +1096,9 @@ class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
- install_rpath: str) -> T.List[str]:
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
if not rpath_paths and not install_rpath and not build_rpath:
- return []
+ return ([], set())
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths])
if build_rpath != '':
@@ -1108,7 +1113,7 @@ class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
paths = padding
else:
paths = paths + ':' + padding
- return self._apply_prefix('-rpath,{}'.format(paths))
+ return (self._apply_prefix('-rpath,{}'.format(paths)), set())
def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
index 9c64429..0be01fe 100644
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -512,7 +512,7 @@ class Installer:
if file_copied:
self.did_install_something = True
try:
- depfixer.fix_rpath(outname, install_rpath, final_path,
+ depfixer.fix_rpath(outname, t.rpath_dirs_to_remove, install_rpath, final_path,
install_name_mappings, verbose=False)
except SystemExit as e:
if isinstance(e.code, int) and e.code == 0:
diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py
index dc86a1b..47be039 100644
--- a/mesonbuild/modules/__init__.py
+++ b/mesonbuild/modules/__init__.py
@@ -57,6 +57,17 @@ def get_include_args(include_dirs, prefix='-I'):
return dirs_str
+def is_module_library(fname):
+ '''
+ Check if the file is a library-like file generated by a module-specific
+ target, such as GirTarget or TypelibTarget
+ '''
+ if hasattr(fname, 'fname'):
+ fname = fname.fname
+ suffix = fname.split('.')[-1]
+ return suffix in ('gir', 'typelib')
+
+
class ModuleReturnValue:
def __init__(self, return_value, new_objects):
self.return_value = return_value
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index a97fffa..01acb37 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -695,11 +695,10 @@ class GnomeModule(ExtensionModule):
source.get_subdir())
if subdir not in typelib_includes:
typelib_includes.append(subdir)
- elif isinstance(dep, PkgConfigDependency):
- girdir = dep.get_pkgconfig_variable("girdir", {'default': ''})
+ if isinstance(dep, Dependency):
+ girdir = dep.get_variable(pkgconfig='girdir', internal='girdir', default_value='')
if girdir and girdir not in typelib_includes:
typelib_includes.append(girdir)
-
return typelib_includes
def _get_external_args_for_langs(self, state, langs):
@@ -769,7 +768,6 @@ class GnomeModule(ExtensionModule):
external_ldflags += list(self._get_scanner_ldflags(dep_external_ldflags))
girtargets_inc_dirs = self._get_gir_targets_inc_dirs(girtargets)
inc_dirs = self._scan_inc_dirs(kwargs)
- gi_includes.update(gir_inc_dirs + inc_dirs)
scan_command = [giscanner]
scan_command += ['--no-libtool']
@@ -790,7 +788,7 @@ class GnomeModule(ExtensionModule):
scan_command += cflags
scan_command += ['--cflags-end']
scan_command += get_include_args(inc_dirs)
- scan_command += get_include_args(list(gi_includes), prefix='--add-include-path=')
+ scan_command += get_include_args(list(gi_includes) + gir_inc_dirs + inc_dirs, prefix='--add-include-path=')
scan_command += list(internal_ldflags)
scan_command += self._scan_gir_targets(state, girtargets)
scan_command += self._scan_langs(state, [lc[0] for lc in langs_compilers])
@@ -804,7 +802,7 @@ class GnomeModule(ExtensionModule):
typelib_output = '%s-%s.typelib' % (ns, nsversion)
typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
- typelib_cmd += get_include_args(list(gi_includes), prefix='--includedir=')
+ typelib_cmd += get_include_args(gir_inc_dirs, prefix='--includedir=')
for incdir in typelib_includes:
typelib_cmd += ["--includedir=" + incdir]
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 4592c90..4aafe62 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -42,7 +42,7 @@ from . import build
from . import environment
from . import mlog
from .dependencies import ExternalProgram
-from .mesonlib import MesonException, get_wine_shortpath, split_args
+from .mesonlib import MesonException, get_wine_shortpath, split_args, join_args
from .backend.backends import TestProtocol
if T.TYPE_CHECKING:
@@ -311,7 +311,7 @@ class TAPParser:
yield self.Version(version=version)
continue
- if len(line) == 0:
+ if not line:
continue
yield self.Error('unexpected input at line {}'.format((lineno,)))
@@ -609,20 +609,20 @@ class SingleTestRunner:
return ['java', '-jar'] + self.test.fname
elif not self.test.is_cross_built and run_with_mono(self.test.fname[0]):
return ['mono'] + self.test.fname
- else:
- if self.test.is_cross_built and self.test.needs_exe_wrapper:
- if self.test.exe_runner is None:
- # Can not run test on cross compiled executable
- # because there is no execute wrapper.
- return None
- else:
- if not self.test.exe_runner.found():
- msg = 'The exe_wrapper defined in the cross file {!r} was not ' \
- 'found. Please check the command and/or add it to PATH.'
- raise TestException(msg.format(self.test.exe_runner.name))
- return self.test.exe_runner.get_command() + self.test.fname
- else:
- return self.test.fname
+ elif self.test.cmd_is_built and self.test.needs_exe_wrapper:
+ if self.test.exe_runner is None:
+ # Can not run test on cross compiled executable
+ # because there is no execute wrapper.
+ return None
+ elif self.test.cmd_is_built:
+ # If the command is not built (ie, its a python script),
+ # then we don't check for the exe-wrapper
+ if not self.test.exe_runner.found():
+ msg = ('The exe_wrapper defined in the cross file {!r} was not '
+ 'found. Please check the command and/or add it to PATH.')
+ raise TestException(msg.format(self.test.exe_runner.name))
+ return self.test.exe_runner.get_command() + self.test.fname
+ return self.test.fname
def run(self) -> TestRun:
cmd = self._get_cmd()
@@ -638,7 +638,7 @@ class SingleTestRunner:
def _run_cmd(self, cmd: T.List[str]) -> TestRun:
starttime = time.time()
- if len(self.test.extra_paths) > 0:
+ if self.test.extra_paths:
self.env['PATH'] = os.pathsep.join(self.test.extra_paths + ['']) + self.env['PATH']
winecmd = []
for c in cmd:
@@ -867,6 +867,9 @@ class TestHarness:
env = os.environ.copy()
test_env = test.env.get_env(env)
env.update(test_env)
+ if (test.is_cross_built and test.needs_exe_wrapper and
+ test.exe_runner and test.exe_runner.found()):
+ env['MESON_EXE_WRAPPER'] = join_args(test.exe_runner.get_command())
return SingleTestRunner(test, test_env, env, options)
def process_test_result(self, result: TestRun) -> None:
@@ -941,7 +944,7 @@ class TestHarness:
self.junit.write()
def print_collected_logs(self) -> None:
- if len(self.collected_logs) > 0:
+ if self.collected_logs:
if len(self.collected_logs) > 10:
print('\nThe output from 10 first failed tests:\n')
else:
@@ -1023,7 +1026,7 @@ class TestHarness:
print('No tests defined.')
return []
- if len(self.options.include_suites) or len(self.options.exclude_suites):
+ if self.options.include_suites or self.options.exclude_suites:
tests = []
for tst in self.tests:
if self.test_suitable(tst):
@@ -1085,7 +1088,7 @@ class TestHarness:
if len(self.suites) > 1 and test.suite:
rv = TestHarness.split_suite_string(test.suite[0])[0]
s = "+".join(TestHarness.split_suite_string(s)[1] for s in test.suite)
- if len(s):
+ if s:
rv += ":"
return rv + s + " / " + test.name
else:
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py
index 5ba3a97..a3a3eff 100644
--- a/mesonbuild/scripts/depfixer.py
+++ b/mesonbuild/scripts/depfixer.py
@@ -290,13 +290,13 @@ class Elf(DataSizes):
self.bf.seek(offset)
self.bf.write(newname)
- def fix_rpath(self, new_rpath):
+ def fix_rpath(self, rpath_dirs_to_remove, new_rpath):
# The path to search for can be either rpath or runpath.
# Fix both of them to be sure.
- self.fix_rpathtype_entry(new_rpath, DT_RPATH)
- self.fix_rpathtype_entry(new_rpath, DT_RUNPATH)
+ self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RPATH)
+ self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RUNPATH)
- def fix_rpathtype_entry(self, new_rpath, entrynum):
+ def fix_rpathtype_entry(self, rpath_dirs_to_remove, new_rpath, entrynum):
if isinstance(new_rpath, str):
new_rpath = new_rpath.encode('utf8')
rp_off = self.get_entry_offset(entrynum)
@@ -305,7 +305,23 @@ class Elf(DataSizes):
print('File does not have rpath. It should be a fully static executable.')
return
self.bf.seek(rp_off)
+
old_rpath = self.read_str()
+ new_rpaths = []
+ if new_rpath:
+ new_rpaths.append(new_rpath)
+ if old_rpath:
+ # Filter out build-only rpath entries
+ # added by get_link_dep_subdirs() or
+ # specified by user with build_rpath.
+ for dir in old_rpath.split(b':'):
+ if not (dir in rpath_dirs_to_remove or
+ dir == (b'X' * len(dir))):
+ new_rpaths.append(dir)
+
+ # Prepend user-specified new entries while preserving the ones that came from pkgconfig etc.
+ new_rpath = b':'.join(new_rpaths)
+
if len(old_rpath) < len(new_rpath):
sys.exit("New rpath must not be longer than the old one.")
# The linker does read-only string deduplication. If there is a
@@ -343,13 +359,13 @@ class Elf(DataSizes):
entry.write(self.bf)
return None
-def fix_elf(fname, new_rpath, verbose=True):
+def fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose=True):
with Elf(fname, verbose) as e:
if new_rpath is None:
e.print_rpath()
e.print_runpath()
else:
- e.fix_rpath(new_rpath)
+ e.fix_rpath(rpath_dirs_to_remove, new_rpath)
def get_darwin_rpaths_to_remove(fname):
out = subprocess.check_output(['otool', '-l', fname],
@@ -430,7 +446,7 @@ def fix_jar(fname):
f.truncate()
subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF'])
-def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True):
+def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_mappings, verbose=True):
global INSTALL_NAME_TOOL
# Static libraries, import libraries, debug information, headers, etc
# never have rpaths
@@ -441,7 +457,7 @@ def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True)
if fname.endswith('.jar'):
fix_jar(fname)
return
- fix_elf(fname, new_rpath, verbose)
+ fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose)
return
except SystemExit as e:
if isinstance(e.code, int) and e.code == 0:
diff --git a/mesonbuild/scripts/symbolextractor.py b/mesonbuild/scripts/symbolextractor.py
index d393f93..41cca26 100644
--- a/mesonbuild/scripts/symbolextractor.py
+++ b/mesonbuild/scripts/symbolextractor.py
@@ -113,7 +113,10 @@ def gnu_syms(libfilename: str, outfilename: str):
continue
line_split = line.split()
entry = line_split[0:2]
- if len(line_split) >= 4:
+ # Store the size of symbols pointing to data objects so we relink
+ # when those change, which is needed because of copy relocations
+ # https://github.com/mesonbuild/meson/pull/7132#issuecomment-628353702
+ if line_split[1].upper() in ('B', 'G', 'D') and len(line_split) >= 4:
entry += [line_split[3]]
result += [' '.join(entry)]
write_if_changed('\n'.join(result) + '\n', outfilename)
@@ -139,6 +142,23 @@ def osx_syms(libfilename: str, outfilename: str):
result += [' '.join(x.split()[0:2]) for x in output.split('\n')]
write_if_changed('\n'.join(result) + '\n', outfilename)
+def openbsd_syms(libfilename: str, outfilename: str):
+ # Get the name of the library
+ output = call_tool('readelf', ['-d', libfilename])
+ if not output:
+ dummy_syms(outfilename)
+ return
+ result = [x for x in output.split('\n') if 'SONAME' in x]
+ assert(len(result) <= 1)
+ # Get a list of all symbols exported
+ output = call_tool('nm', ['-D', '-P', '-g', libfilename])
+ if not output:
+ dummy_syms(outfilename)
+ return
+ # U = undefined (cope with the lack of --defined-only option)
+ result += [' '.join(x.split()[0:2]) for x in output.split('\n') if x and not x.endswith('U ')]
+ write_if_changed('\n'.join(result) + '\n', outfilename)
+
def cygwin_syms(impfilename: str, outfilename: str):
# Get the name of the library
output = call_tool('dlltool', ['-I', impfilename])
@@ -234,6 +254,8 @@ def gen_symbols(libfilename: str, impfilename: str, outfilename: str, cross_host
gnu_syms(libfilename, outfilename)
elif mesonlib.is_osx():
osx_syms(libfilename, outfilename)
+ elif mesonlib.is_openbsd():
+ openbsd_syms(libfilename, outfilename)
elif mesonlib.is_windows():
if os.path.isfile(impfilename):
windows_syms(impfilename, outfilename)
diff --git a/msi/createmsi.py b/msi/createmsi.py
index f80d1dc..4d03593 100644
--- a/msi/createmsi.py
+++ b/msi/createmsi.py
@@ -153,6 +153,7 @@ class PackageGenerator:
if os.path.exists(sdir):
shutil.rmtree(sdir)
main_stage, ninja_stage = self.staging_dirs
+ dep_data_dir = 'mesonbuild/dependencies/data'
modules = self.get_all_modules_from_dir('mesonbuild/modules')
modules += self.get_all_modules_from_dir('mesonbuild/scripts')
modules += self.get_more_modules()
@@ -174,6 +175,7 @@ class PackageGenerator:
pyinst_cmd += ['meson.py']
subprocess.check_call(pyinst_cmd)
shutil.move(pyinstaller_tmpdir + '/meson', main_stage)
+ shutil.copytree(dep_data_dir, main_stage + '/mesonbuild/dependencies/data')
if not os.path.exists(os.path.join(main_stage, 'meson.exe')):
sys.exit('Meson exe missing from staging dir.')
os.mkdir(ninja_stage)
diff --git a/run_project_tests.py b/run_project_tests.py
index f372436..22c0205 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -417,6 +417,7 @@ def _compare_output(expected: T.List[T.Dict[str, str]], output: str, desc: str)
match = bool(re.match(expected, actual))
else:
match = (expected == actual)
+ print(actual)
if match:
how, expected = next_expected(i)
diff --git a/run_unittests.py b/run_unittests.py
index d6f7911..7e5dffc 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -40,6 +40,7 @@ from contextlib import contextmanager
from glob import glob
from pathlib import (PurePath, Path)
from distutils.dir_util import copy_tree
+import typing
import mesonbuild.mlog
import mesonbuild.depfile
@@ -56,7 +57,7 @@ from mesonbuild.mesonlib import (
BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows,
is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos,
windows_proof_rmtree, python_command, version_compare, split_args,
- quote_arg, relpath
+ quote_arg, relpath, is_linux
)
from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException
@@ -1468,14 +1469,14 @@ class DataTests(unittest.TestCase):
class BasePlatformTests(unittest.TestCase):
+ prefix = '/usr'
+ libdir = 'lib'
def setUp(self):
super().setUp()
self.maxDiff = None
src_root = os.path.dirname(__file__)
src_root = os.path.join(os.getcwd(), src_root)
self.src_root = src_root
- self.prefix = '/usr'
- self.libdir = 'lib'
# Get the backend
# FIXME: Extract this from argv?
self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja'))
@@ -1588,8 +1589,9 @@ class BasePlatformTests(unittest.TestCase):
extra_args = [extra_args]
args = [srcdir, self.builddir]
if default_args:
- args += ['--prefix', self.prefix,
- '--libdir', self.libdir]
+ args += ['--prefix', self.prefix]
+ if self.libdir:
+ args += ['--libdir', self.libdir]
if self.meson_native_file:
args += ['--native-file', self.meson_native_file]
if self.meson_cross_file:
@@ -2448,9 +2450,12 @@ class AllPlatformTests(BasePlatformTests):
# Check include order for 'someexe'
incs = [a for a in split_args(execmd) if a.startswith("-I")]
self.assertEqual(len(incs), 9)
- # target private dir
- someexe_id = Target.construct_id_from_path("sub4", "someexe", "@exe")
- self.assertPathEqual(incs[0], "-I" + os.path.join("sub4", someexe_id))
+ # Need to run the build so the private dir is created.
+ self.build()
+ pdirs = glob(os.path.join(self.builddir, 'sub4/someexe*.p'))
+ self.assertEqual(len(pdirs), 1)
+ privdir = pdirs[0][len(self.builddir)+1:]
+ self.assertPathEqual(incs[0], "-I" + privdir)
# target build subdir
self.assertPathEqual(incs[1], "-Isub4")
# target source subdir
@@ -2471,7 +2476,10 @@ class AllPlatformTests(BasePlatformTests):
incs = [a for a in split_args(fxecmd) if a.startswith('-I')]
self.assertEqual(len(incs), 9)
# target private dir
- self.assertPathEqual(incs[0], '-Isomefxe@exe')
+ pdirs = glob(os.path.join(self.builddir, 'somefxe*.p'))
+ self.assertEqual(len(pdirs), 1)
+ privdir = pdirs[0][len(self.builddir)+1:]
+ self.assertPathEqual(incs[0], '-I' + privdir)
# target build dir
self.assertPathEqual(incs[1], '-I.')
# target source dir
@@ -3419,67 +3427,6 @@ int main(int argc, char **argv) {
f.write('public class Foo { public static void main() {} }')
self._run(self.meson_command + ['init', '-b'], workdir=tmpdir)
- # The test uses mocking and thus requires that
- # the current process is the one to run the Meson steps.
- # If we are using an external test executable (most commonly
- # in Debian autopkgtests) then the mocking won't work.
- @unittest.skipIf('MESON_EXE' in os.environ, 'MESON_EXE is defined, can not use mocking.')
- def test_cross_file_system_paths(self):
- if is_windows():
- raise unittest.SkipTest('system crossfile paths not defined for Windows (yet)')
- if is_sunos():
- cc = 'gcc'
- else:
- cc = 'cc'
-
- testdir = os.path.join(self.common_test_dir, '1 trivial')
- cross_content = textwrap.dedent("""\
- [binaries]
- c = '/usr/bin/{}'
- ar = '/usr/bin/ar'
- strip = '/usr/bin/ar'
-
- [properties]
-
- [host_machine]
- system = 'linux'
- cpu_family = 'x86'
- cpu = 'i686'
- endian = 'little'
- """.format(cc))
-
- with tempfile.TemporaryDirectory() as d:
- dir_ = os.path.join(d, 'meson', 'cross')
- os.makedirs(dir_)
- with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
- f.write(cross_content)
- name = os.path.basename(f.name)
-
- with mock.patch.dict(os.environ, {'XDG_DATA_HOME': d}):
- self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
- self.wipe()
-
- with mock.patch.dict(os.environ, {'XDG_DATA_DIRS': d}):
- os.environ.pop('XDG_DATA_HOME', None)
- self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
- self.wipe()
-
- with tempfile.TemporaryDirectory() as d:
- dir_ = os.path.join(d, '.local', 'share', 'meson', 'cross')
- os.makedirs(dir_)
- with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
- f.write(cross_content)
- name = os.path.basename(f.name)
-
- # If XDG_DATA_HOME is set in the environment running the
- # tests this test will fail, os mock the environment, pop
- # it, then test
- with mock.patch.dict(os.environ):
- os.environ.pop('XDG_DATA_HOME', None)
- with mock.patch('mesonbuild.coredata.os.path.expanduser', lambda x: x.replace('~', d)):
- self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
- self.wipe()
-
def test_compiler_run_command(self):
'''
The test checks that the compiler object can be passed to
@@ -4535,7 +4482,7 @@ recommended as it is not supported on some platforms''')
self._run(self.mconf_command + [self.builddir])
def test_summary(self):
- testdir = os.path.join(self.unit_test_dir, '72 summary')
+ testdir = os.path.join(self.unit_test_dir, '73 summary')
out = self.init(testdir)
expected = textwrap.dedent(r'''
Some Subproject 2.0
@@ -4589,7 +4536,7 @@ recommended as it is not supported on some platforms''')
self.assertPathDoesNotExist(os.path.join(self.builddir, prog))
def test_spurious_reconfigure_built_dep_file(self):
- testdir = os.path.join(self.unit_test_dir, '74 dep files')
+ testdir = os.path.join(self.unit_test_dir, '75 dep files')
# Regression test: Spurious reconfigure was happening when build
# directory is inside source directory.
@@ -5576,6 +5523,10 @@ class LinuxlikeTests(BasePlatformTests):
self.assertRegex('\n'.join(mesonlog),
r'Run-time dependency qt5 \(modules: Core\) found: YES .* \((qmake|qmake-qt5)\)\n')
+ def glob_sofiles_without_privdir(self, g):
+ files = glob(g)
+ return [f for f in files if not f.endswith('.p')]
+
def _test_soname_impl(self, libpath, install):
if is_cygwin() or is_osx():
raise unittest.SkipTest('Test only applicable to ELF and linuxlike sonames')
@@ -5591,28 +5542,28 @@ class LinuxlikeTests(BasePlatformTests):
self.assertPathExists(nover)
self.assertFalse(os.path.islink(nover))
self.assertEqual(get_soname(nover), 'libnover.so')
- self.assertEqual(len(glob(nover[:-3] + '*')), 1)
+ self.assertEqual(len(self.glob_sofiles_without_privdir(nover[:-3] + '*')), 1)
# File with version set
verset = os.path.join(libpath, 'libverset.so')
self.assertPathExists(verset + '.4.5.6')
self.assertEqual(os.readlink(verset), 'libverset.so.4')
self.assertEqual(get_soname(verset), 'libverset.so.4')
- self.assertEqual(len(glob(verset[:-3] + '*')), 3)
+ self.assertEqual(len(self.glob_sofiles_without_privdir(verset[:-3] + '*')), 3)
# File with soversion set
soverset = os.path.join(libpath, 'libsoverset.so')
self.assertPathExists(soverset + '.1.2.3')
self.assertEqual(os.readlink(soverset), 'libsoverset.so.1.2.3')
self.assertEqual(get_soname(soverset), 'libsoverset.so.1.2.3')
- self.assertEqual(len(glob(soverset[:-3] + '*')), 2)
+ self.assertEqual(len(self.glob_sofiles_without_privdir(soverset[:-3] + '*')), 2)
# File with version and soversion set to same values
settosame = os.path.join(libpath, 'libsettosame.so')
self.assertPathExists(settosame + '.7.8.9')
self.assertEqual(os.readlink(settosame), 'libsettosame.so.7.8.9')
self.assertEqual(get_soname(settosame), 'libsettosame.so.7.8.9')
- self.assertEqual(len(glob(settosame[:-3] + '*')), 2)
+ self.assertEqual(len(self.glob_sofiles_without_privdir(settosame[:-3] + '*')), 2)
# File with version and soversion set to different values
bothset = os.path.join(libpath, 'libbothset.so')
@@ -5620,7 +5571,7 @@ class LinuxlikeTests(BasePlatformTests):
self.assertEqual(os.readlink(bothset), 'libbothset.so.1.2.3')
self.assertEqual(os.readlink(bothset + '.1.2.3'), 'libbothset.so.4.5.6')
self.assertEqual(get_soname(bothset), 'libbothset.so.1.2.3')
- self.assertEqual(len(glob(bothset[:-3] + '*')), 3)
+ self.assertEqual(len(self.glob_sofiles_without_privdir(bothset[:-3] + '*')), 3)
def test_soname(self):
self._test_soname_impl(self.builddir, False)
@@ -5740,10 +5691,12 @@ class LinuxlikeTests(BasePlatformTests):
def test_unity_subproj(self):
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-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-unity0.c'))
+ pdirs = glob(os.path.join(self.builddir, 'subprojects/sublib/simpletest*.p'))
+ self.assertEqual(len(pdirs), 1)
+ self.assertPathExists(os.path.join(pdirs[0], 'simpletest-unity0.c'))
+ sdirs = glob(os.path.join(self.builddir, 'subprojects/sublib/*sublib*.p'))
+ self.assertEqual(len(sdirs), 1)
+ self.assertPathExists(os.path.join(sdirs[0], 'sublib-unity0.c'))
self.assertPathDoesNotExist(os.path.join(self.builddir, 'user@exe/user-unity.c'))
self.build()
@@ -6079,6 +6032,39 @@ class LinuxlikeTests(BasePlatformTests):
install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/progcxx'))
self.assertEqual(install_rpath, 'baz')
+ def test_global_rpath(self):
+ if is_cygwin():
+ raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH')
+ if is_osx():
+ raise unittest.SkipTest('Global RPATHs via LDFLAGS not yet supported on MacOS (does anybody need it?)')
+
+ testdir = os.path.join(self.unit_test_dir, '77 global-rpath')
+ oldinstalldir = self.installdir
+
+ # Build and install an external library without DESTDIR.
+ # The external library generates a .pc file without an rpath.
+ yonder_dir = os.path.join(testdir, 'yonder')
+ yonder_prefix = os.path.join(oldinstalldir, 'yonder')
+ yonder_libdir = os.path.join(yonder_prefix, self.libdir)
+ self.prefix = yonder_prefix
+ self.installdir = yonder_prefix
+ self.init(yonder_dir)
+ self.build()
+ self.install(use_destdir=False)
+ self.new_builddir()
+
+ # Build an app that uses that installed library.
+ # Supply the rpath to the installed library via LDFLAGS
+ # (as systems like buildroot and guix are wont to do)
+ # and verify install preserves that rpath.
+ env = {'LDFLAGS': '-Wl,-rpath=' + yonder_libdir,
+ 'PKG_CONFIG_PATH': os.path.join(yonder_libdir, 'pkgconfig')}
+ self.init(testdir, override_envvars=env)
+ self.build()
+ self.install(use_destdir=False)
+ got_rpath = get_rpath(os.path.join(yonder_prefix, 'bin/rpathified'))
+ self.assertEqual(got_rpath, yonder_libdir)
+
@skip_if_not_base_option('b_sanitize')
def test_pch_with_address_sanitizer(self):
if is_cygwin():
@@ -6390,13 +6376,15 @@ class LinuxlikeTests(BasePlatformTests):
self.build(override_envvars=env)
# test uninstalled
self.run_tests(override_envvars=env)
- if not is_osx():
- # Rest of the workflow only works on macOS
+ if not (is_osx() or is_linux()):
return
# test running after installation
self.install(use_destdir=False)
prog = os.path.join(self.installdir, 'bin', 'prog')
self._run([prog])
+ if not is_osx():
+ # Rest of the workflow only works on macOS
+ return
out = self._run(['otool', '-L', prog])
self.assertNotIn('@rpath', out)
## New builddir for testing that DESTDIR is not added to install_name
@@ -6413,6 +6401,57 @@ class LinuxlikeTests(BasePlatformTests):
# Ensure that the otool output does not contain self.installdir
self.assertNotRegex(out, self.installdir + '.*dylib ')
+ @skipIfNoPkgconfig
+ def test_usage_pkgconfig_prefixes(self):
+ '''
+ Build and install two external libraries, to different prefixes,
+ then build and install a client program that finds them via pkgconfig,
+ and verify the installed client program runs.
+ '''
+ oldinstalldir = self.installdir
+
+ # Build and install both external libraries without DESTDIR
+ val1dir = os.path.join(self.unit_test_dir, '76 pkgconfig prefixes', 'val1')
+ val1prefix = os.path.join(oldinstalldir, 'val1')
+ self.prefix = val1prefix
+ self.installdir = val1prefix
+ self.init(val1dir)
+ self.build()
+ self.install(use_destdir=False)
+ self.new_builddir()
+
+ env1 = {}
+ env1['PKG_CONFIG_PATH'] = os.path.join(val1prefix, self.libdir, 'pkgconfig')
+ val2dir = os.path.join(self.unit_test_dir, '76 pkgconfig prefixes', 'val2')
+ val2prefix = os.path.join(oldinstalldir, 'val2')
+ self.prefix = val2prefix
+ self.installdir = val2prefix
+ self.init(val2dir, override_envvars=env1)
+ self.build()
+ self.install(use_destdir=False)
+ self.new_builddir()
+
+ # Build, install, and run the client program
+ env2 = {}
+ env2['PKG_CONFIG_PATH'] = os.path.join(val2prefix, self.libdir, 'pkgconfig')
+ testdir = os.path.join(self.unit_test_dir, '76 pkgconfig prefixes', 'client')
+ testprefix = os.path.join(oldinstalldir, 'client')
+ self.prefix = testprefix
+ self.installdir = testprefix
+ self.init(testdir, override_envvars=env2)
+ self.build()
+ self.install(use_destdir=False)
+ prog = os.path.join(self.installdir, 'bin', 'client')
+ env3 = {}
+ if is_cygwin():
+ env3['PATH'] = os.path.join(val1prefix, 'bin') + \
+ os.pathsep + \
+ os.path.join(val2prefix, 'bin') + \
+ os.pathsep + os.environ['PATH']
+ out = self._run([prog], override_envvars=env3).strip()
+ # Expected output is val1 + val2 = 3
+ self.assertEqual(out, '3')
+
def install_subdir_invalid_symlinks(self, testdir, subdir_path):
'''
Test that installation of broken symlinks works fine.
@@ -6603,7 +6642,7 @@ c = ['{0}']
return hashlib.sha256(f.read()).hexdigest()
def test_wrap_with_file_url(self):
- testdir = os.path.join(self.unit_test_dir, '73 wrap file url')
+ testdir = os.path.join(self.unit_test_dir, '74 wrap file url')
source_filename = os.path.join(testdir, 'subprojects', 'foo.tar.xz')
patch_filename = os.path.join(testdir, 'subprojects', 'foo-patch.tar.xz')
wrap_filename = os.path.join(testdir, 'subprojects', 'foo.wrap')
@@ -6634,11 +6673,17 @@ c = ['{0}']
os.unlink(wrap_filename)
+class BaseLinuxCrossTests(BasePlatformTests):
+ # Don't pass --libdir when cross-compiling. We have tests that
+ # check whether meson auto-detects it correctly.
+ libdir = None
+
+
def should_run_cross_arm_tests():
return shutil.which('arm-linux-gnueabihf-gcc') and not platform.machine().lower().startswith('arm')
@unittest.skipUnless(not is_windows() and should_run_cross_arm_tests(), "requires ability to cross compile to ARM")
-class LinuxCrossArmTests(BasePlatformTests):
+class LinuxCrossArmTests(BaseLinuxCrossTests):
'''
Tests that cross-compilation to Linux/ARM works
'''
@@ -6688,7 +6733,7 @@ class LinuxCrossArmTests(BasePlatformTests):
def test_cross_libdir_subproject(self):
# Guard against a regression where calling "subproject"
# would reset the value of libdir to its default value.
- testdir = os.path.join(self.unit_test_dir, '75 subdir libdir')
+ testdir = os.path.join(self.unit_test_dir, '76 subdir libdir')
self.init(testdir, extra_args=['--libdir=fuf'])
for i in self.introspect('--buildoptions'):
if i['name'] == 'libdir':
@@ -6719,7 +6764,7 @@ def should_run_cross_mingw_tests():
return shutil.which('x86_64-w64-mingw32-gcc') and not (is_windows() or is_cygwin())
@unittest.skipUnless(not is_windows() and should_run_cross_mingw_tests(), "requires ability to cross compile with MinGW")
-class LinuxCrossMingwTests(BasePlatformTests):
+class LinuxCrossMingwTests(BaseLinuxCrossTests):
'''
Tests that cross-compilation to Windows/MinGW works
'''
@@ -7513,6 +7558,134 @@ class CrossFileTests(BasePlatformTests):
This is mainly aimed to testing overrides from cross files.
"""
+ def _cross_file_generator(self, *, needs_exe_wrapper: bool = False,
+ exe_wrapper: typing.Optional[typing.List[str]] = None) -> str:
+ if is_windows():
+ raise unittest.SkipTest('Cannot run this test on non-mingw/non-cygwin windows')
+ if is_sunos():
+ cc = 'gcc'
+ else:
+ cc = 'cc'
+
+ return textwrap.dedent("""\
+ [binaries]
+ c = '/usr/bin/{}'
+ ar = '/usr/bin/ar'
+ strip = '/usr/bin/ar'
+ {}
+
+ [properties]
+ needs_exe_wrapper = {}
+
+ [host_machine]
+ system = 'linux'
+ cpu_family = 'x86'
+ cpu = 'i686'
+ endian = 'little'
+ """.format(cc,
+ 'exe_wrapper = {}'.format(str(exe_wrapper)) if exe_wrapper is not None else '',
+ needs_exe_wrapper))
+
+ def _stub_exe_wrapper(self) -> str:
+ return textwrap.dedent('''\
+ #!/usr/bin/env python3
+ import subprocess
+ import sys
+
+ sys.exit(subprocess.run(sys.argv[1:]).returncode)
+ ''')
+
+ def test_needs_exe_wrapper_true(self):
+ testdir = os.path.join(self.unit_test_dir, '72 cross test passed')
+ with tempfile.TemporaryDirectory() as d:
+ p = Path(d) / 'crossfile'
+ with p.open('wt') as f:
+ f.write(self._cross_file_generator(needs_exe_wrapper=True))
+ self.init(testdir, extra_args=['--cross-file=' + str(p)])
+ out = self.run_target('test')
+ self.assertRegex(out, r'Skipped:\s*1\s*\n')
+
+ def test_needs_exe_wrapper_false(self):
+ testdir = os.path.join(self.unit_test_dir, '72 cross test passed')
+ with tempfile.TemporaryDirectory() as d:
+ p = Path(d) / 'crossfile'
+ with p.open('wt') as f:
+ f.write(self._cross_file_generator(needs_exe_wrapper=False))
+ self.init(testdir, extra_args=['--cross-file=' + str(p)])
+ out = self.run_target('test')
+ self.assertNotRegex(out, r'Skipped:\s*1\n')
+
+ def test_needs_exe_wrapper_true_wrapper(self):
+ testdir = os.path.join(self.unit_test_dir, '72 cross test passed')
+ with tempfile.TemporaryDirectory() as d:
+ s = Path(d) / 'wrapper.py'
+ with s.open('wt') as f:
+ f.write(self._stub_exe_wrapper())
+ s.chmod(0o774)
+ p = Path(d) / 'crossfile'
+ with p.open('wt') as f:
+ f.write(self._cross_file_generator(
+ needs_exe_wrapper=True,
+ exe_wrapper=[str(s)]))
+
+ self.init(testdir, extra_args=['--cross-file=' + str(p), '-Dexpect=true'])
+ out = self.run_target('test')
+ self.assertRegex(out, r'Ok:\s*3\s*\n')
+
+ def test_cross_exe_passed_no_wrapper(self):
+ testdir = os.path.join(self.unit_test_dir, '72 cross test passed')
+ with tempfile.TemporaryDirectory() as d:
+ p = Path(d) / 'crossfile'
+ with p.open('wt') as f:
+ f.write(self._cross_file_generator(needs_exe_wrapper=True))
+
+ self.init(testdir, extra_args=['--cross-file=' + str(p)])
+ self.build()
+ out = self.run_target('test')
+ self.assertRegex(out, r'Skipped:\s*1\s*\n')
+
+ # The test uses mocking and thus requires that the current process is the
+ # one to run the Meson steps. If we are using an external test executable
+ # (most commonly in Debian autopkgtests) then the mocking won't work.
+ @unittest.skipIf('MESON_EXE' in os.environ, 'MESON_EXE is defined, can not use mocking.')
+ def test_cross_file_system_paths(self):
+ if is_windows():
+ raise unittest.SkipTest('system crossfile paths not defined for Windows (yet)')
+
+ testdir = os.path.join(self.common_test_dir, '1 trivial')
+ cross_content = self._cross_file_generator()
+ with tempfile.TemporaryDirectory() as d:
+ dir_ = os.path.join(d, 'meson', 'cross')
+ os.makedirs(dir_)
+ with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
+ f.write(cross_content)
+ name = os.path.basename(f.name)
+
+ with mock.patch.dict(os.environ, {'XDG_DATA_HOME': d}):
+ self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
+ self.wipe()
+
+ with mock.patch.dict(os.environ, {'XDG_DATA_DIRS': d}):
+ os.environ.pop('XDG_DATA_HOME', None)
+ self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
+ self.wipe()
+
+ with tempfile.TemporaryDirectory() as d:
+ dir_ = os.path.join(d, '.local', 'share', 'meson', 'cross')
+ os.makedirs(dir_)
+ with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
+ f.write(cross_content)
+ name = os.path.basename(f.name)
+
+ # If XDG_DATA_HOME is set in the environment running the
+ # tests this test will fail, os mock the environment, pop
+ # it, then test
+ with mock.patch.dict(os.environ):
+ os.environ.pop('XDG_DATA_HOME', None)
+ with mock.patch('mesonbuild.coredata.os.path.expanduser', lambda x: x.replace('~', d)):
+ self.init(testdir, extra_args=['--cross-file=' + name], inprocess=True)
+ self.wipe()
+
def test_cross_file_dirs(self):
testcase = os.path.join(self.unit_test_dir, '60 native file override')
self.init(testcase, default_args=False,
diff --git a/test cases/common/36 tryrun/meson.build b/test cases/common/36 tryrun/meson.build
index 261adf2..5580974 100644
--- a/test cases/common/36 tryrun/meson.build
+++ b/test cases/common/36 tryrun/meson.build
@@ -2,7 +2,7 @@ project('tryrun', 'c', 'cpp')
# Complex to exercise all code paths.
if meson.is_cross_build()
- if meson.has_exe_wrapper()
+ if meson.can_run_host_binaries()
compilers = [meson.get_compiler('c', native : false), meson.get_compiler('cpp', native : false)]
else
compilers = [meson.get_compiler('c', native : true), meson.get_compiler('cpp', native : true)]
diff --git a/test cases/common/93 selfbuilt custom/meson.build b/test cases/common/93 selfbuilt custom/meson.build
index 3cc3906..b536352 100644
--- a/test cases/common/93 selfbuilt custom/meson.build
+++ b/test cases/common/93 selfbuilt custom/meson.build
@@ -26,7 +26,7 @@ ctlib = custom_target('ctlib',
build_by_default : true,
)
-if meson.is_cross_build() and meson.has_exe_wrapper()
+if meson.is_cross_build() and meson.can_run_host_binaries()
checkarg_host = executable('checkarg_host', 'checkarg.cpp')
ctlib_host = custom_target(
diff --git a/test cases/failing/34 dependency not-required then required/test.json b/test cases/failing/34 dependency not-required then required/test.json
index bed1a45..3cf35f5 100644
--- a/test cases/failing/34 dependency not-required then required/test.json
+++ b/test cases/failing/34 dependency not-required then required/test.json
@@ -2,7 +2,7 @@
"stdout": [
{
"match": "re",
- "line": "test cases/failing/34 dependency not\\-required then required/meson\\.build:4:0: ERROR: Dependency \"foo\\-bar\\-xyz\\-12\\.3\" not found, tried .*"
+ "line": ".*/meson\\.build:4:0: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foo\\-bar\\-xyz\\-12\\.3\" not found, tried .*)"
}
]
}
diff --git a/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.c b/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.c
new file mode 100644
index 0000000..ee5c5e1
--- /dev/null
+++ b/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.c
@@ -0,0 +1,124 @@
+#include "dep3.h"
+
+struct _MesonDep3
+{
+ GObject parent_instance;
+
+ gchar *msg;
+};
+
+G_DEFINE_TYPE (MesonDep3, meson_dep3, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_MSG,
+ LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+/**
+ * meson_dep3_new:
+ * @msg: The message to set.
+ *
+ * Allocates a new #MesonDep3.
+ *
+ * Returns: (transfer full): a #MesonDep3.
+ */
+MesonDep3 *
+meson_dep3_new (const gchar *msg)
+{
+ g_return_val_if_fail (msg != NULL, NULL);
+
+ return g_object_new (MESON_TYPE_DEP3,
+ "message", msg,
+ NULL);
+}
+
+static void
+meson_dep3_finalize (GObject *object)
+{
+ MesonDep3 *self = (MesonDep3 *)object;
+
+ g_clear_pointer (&self->msg, g_free);
+
+ G_OBJECT_CLASS (meson_dep3_parent_class)->finalize (object);
+}
+
+static void
+meson_dep3_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MesonDep3 *self = MESON_DEP3 (object);
+
+ switch (prop_id)
+ {
+ case PROP_MSG:
+ g_value_set_string (value, self->msg);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+meson_dep3_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MesonDep3 *self = MESON_DEP3 (object);
+
+ switch (prop_id)
+ {
+ case PROP_MSG:
+ self->msg = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+meson_dep3_class_init (MesonDep3Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = meson_dep3_finalize;
+ object_class->get_property = meson_dep3_get_property;
+ object_class->set_property = meson_dep3_set_property;
+
+ gParamSpecs [PROP_MSG] =
+ g_param_spec_string ("message",
+ "Message",
+ "The message to print.",
+ NULL,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
+}
+
+static void
+meson_dep3_init (MesonDep3 *self)
+{
+}
+
+/**
+ * meson_dep3_return_message:
+ * @self: a #MesonDep3.
+ *
+ * Returns the message.
+ *
+ * Returns: (transfer none): a const gchar*
+ */
+const gchar*
+meson_dep3_return_message (MesonDep3 *self)
+{
+ g_return_val_if_fail (MESON_IS_DEP3 (self), NULL);
+
+ return (const gchar*) self->msg;
+}
diff --git a/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h b/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h
new file mode 100644
index 0000000..9883d76
--- /dev/null
+++ b/test cases/frameworks/7 gnome/gir/dep1/dep3/dep3.h
@@ -0,0 +1,21 @@
+#ifndef MESON_DEP3_H
+#define MESON_DEP3_H
+
+#if !defined (MESON_TEST)
+#error "MESON_TEST not defined."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MESON_TYPE_DEP3 (meson_dep3_get_type())
+
+G_DECLARE_FINAL_TYPE (MesonDep3, meson_dep3, MESON, DEP3, GObject)
+
+MesonDep3 *meson_dep3_new (const gchar *msg);
+const gchar *meson_dep3_return_message (MesonDep3 *self);
+
+G_END_DECLS
+
+#endif /* MESON_DEP3_H */
diff --git a/test cases/frameworks/7 gnome/gir/dep1/dep3/meson.build b/test cases/frameworks/7 gnome/gir/dep1/dep3/meson.build
new file mode 100644
index 0000000..1ef7765
--- /dev/null
+++ b/test cases/frameworks/7 gnome/gir/dep1/dep3/meson.build
@@ -0,0 +1,22 @@
+dep3sources = ['dep3.c', 'dep3.h']
+
+dep3lib = shared_library(
+ 'dep3lib',
+ sources : dep3sources,
+ dependencies : gobj,
+ install : true
+)
+
+dep3gir = gnome.generate_gir(
+ dep3lib,
+ sources : dep3sources,
+ nsversion : '1.0',
+ namespace : 'MesonDep3',
+ symbol_prefix : 'meson',
+ identifier_prefix : 'Meson',
+ includes : ['GObject-2.0'],
+ install : true
+)
+
+dep3_dep = declare_dependency(link_with : dep3lib,
+ sources : [dep3gir])
diff --git a/test cases/frameworks/7 gnome/gir/dep1/meson.build b/test cases/frameworks/7 gnome/gir/dep1/meson.build
index baa0b1d..2f03ede 100644
--- a/test cases/frameworks/7 gnome/gir/dep1/meson.build
+++ b/test cases/frameworks/7 gnome/gir/dep1/meson.build
@@ -1,4 +1,5 @@
subdir('dep2')
+subdir('dep3')
dep1sources = ['dep1.c', 'dep1.h']
@@ -20,11 +21,11 @@ dep1gir = gnome.generate_gir(
symbol_prefix : 'meson',
identifier_prefix : 'Meson',
header: 'dep1.h',
- includes : ['GObject-2.0', 'MesonDep2-1.0'],
+ includes : ['GObject-2.0', 'MesonDep2-1.0', dep3gir[0]],
dependencies : [dep2_dep],
install : true
)
dep1_dep = declare_dependency(link_with : dep1lib,
- dependencies : [dep2_dep],
+ dependencies : [dep2_dep, dep3_dep],
sources : [dep1gir])
diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build
index 36bd09c..b1e0fa1 100644
--- a/test cases/frameworks/7 gnome/gir/meson.build
+++ b/test cases/frameworks/7 gnome/gir/meson.build
@@ -45,7 +45,7 @@ gnome.generate_gir(
)
test('gobject introspection/c', girexe)
-gir_paths = ':'.join([girlib.outdir(), dep1lib.outdir(), dep2lib.outdir()])
+gir_paths = ':'.join([girlib.outdir(), dep1lib.outdir(), dep2lib.outdir(), dep3lib.outdir()])
envdata = environment()
envdata.append('GI_TYPELIB_PATH', gir_paths, separator : ':')
envdata.append('LD_LIBRARY_PATH', gir_paths)
diff --git a/test cases/frameworks/7 gnome/test.json b/test cases/frameworks/7 gnome/test.json
index e69c9f0..badf410 100644
--- a/test cases/frameworks/7 gnome/test.json
+++ b/test cases/frameworks/7 gnome/test.json
@@ -13,12 +13,16 @@
{"type": "file", "platform": "cygwin", "file": "usr/lib/libdep1lib.dll.a"},
{"type": "expr", "file": "usr/lib/?libdep2lib.so"},
{"type": "file", "platform": "cygwin", "file": "usr/lib/libdep2lib.dll.a"},
+ {"type": "expr", "file": "usr/lib/?libdep3lib.so"},
+ {"type": "file", "platform": "cygwin", "file": "usr/lib/libdep3lib.dll.a"},
{"type": "file", "file": "usr/lib/girepository-1.0/Meson-1.0.typelib"},
{"type": "file", "file": "usr/lib/girepository-1.0/MesonDep1-1.0.typelib"},
{"type": "file", "file": "usr/lib/girepository-1.0/MesonDep2-1.0.typelib"},
+ {"type": "file", "file": "usr/lib/girepository-1.0/MesonDep3-1.0.typelib"},
{"type": "file", "file": "usr/share/gir-1.0/Meson-1.0.gir"},
{"type": "file", "file": "usr/share/gir-1.0/MesonDep1-1.0.gir"},
{"type": "file", "file": "usr/share/gir-1.0/MesonDep2-1.0.gir"},
+ {"type": "file", "file": "usr/share/gir-1.0/MesonDep3-1.0.gir"},
{"type": "file", "file": "usr/share/glib-2.0/schemas/com.github.meson.gschema.xml"},
{"type": "file", "file": "usr/share/simple-resources.gresource"},
{"type": "file", "file": "usr/include/enums6.h"},
diff --git a/test cases/unit/36 exe_wrapper behaviour/meson.build b/test cases/unit/36 exe_wrapper behaviour/meson.build
index 16a44d5..d0817ba 100644
--- a/test cases/unit/36 exe_wrapper behaviour/meson.build
+++ b/test cases/unit/36 exe_wrapper behaviour/meson.build
@@ -1,7 +1,7 @@
project('exe wrapper behaviour', 'c')
assert(meson.is_cross_build(), 'not setup as cross build')
-assert(meson.has_exe_wrapper(), 'exe wrapper not defined?')
+assert(meson.has_exe_wrapper(), 'exe wrapper not defined?') # intentionally not changed to can_run_host_binaries,
exe = executable('prog', 'prog.c')
diff --git a/test cases/unit/40 external, internal library rpath/built library/meson.build b/test cases/unit/40 external, internal library rpath/built library/meson.build
index f633996..07fe7bb 100644
--- a/test cases/unit/40 external, internal library rpath/built library/meson.build
+++ b/test cases/unit/40 external, internal library rpath/built library/meson.build
@@ -18,4 +18,9 @@ l = shared_library('bar_built', 'bar.c',
if host_machine.system() == 'darwin'
e = executable('prog', 'prog.c', link_with: l, install: true)
test('testprog', e)
+elif host_machine.system() == 'linux'
+ e = executable('prog', 'prog.c', link_with: l, install: true,
+ install_rpath: '$ORIGIN/..' / get_option('libdir'),
+ )
+ test('testprog', e)
endif
diff --git a/test cases/unit/40 external, internal library rpath/external library/meson.build b/test cases/unit/40 external, internal library rpath/external library/meson.build
index 3c311f5..06ffa0f 100644
--- a/test cases/unit/40 external, internal library rpath/external library/meson.build
+++ b/test cases/unit/40 external, internal library rpath/external library/meson.build
@@ -4,16 +4,16 @@ shared_library('foo_in_system', 'foo.c', install : true)
l = shared_library('faa_pkg', 'faa.c', install: true)
if host_machine.system() == 'darwin'
- frameworks = ['-framework', 'CoreFoundation', '-framework', 'CoreMedia']
+ ldflags = ['-framework', 'CoreFoundation', '-framework', 'CoreMedia']
allow_undef_args = ['-Wl,-undefined,dynamic_lookup']
else
- frameworks = []
+ ldflags = ['-Wl,-rpath,${libdir}']
allow_undef_args = []
endif
pkg = import('pkgconfig')
pkg.generate(name: 'faa_pkg',
- libraries: [l] + frameworks,
+ libraries: [l] + ldflags,
description: 'FAA, a pkg-config test library')
# cygwin DLLs can't have undefined symbols
diff --git a/test cases/unit/72 cross test passed/exewrapper.py b/test cases/unit/72 cross test passed/exewrapper.py
new file mode 100755
index 0000000..2c15ed6
--- /dev/null
+++ b/test cases/unit/72 cross test passed/exewrapper.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+# Test that the MESON_EXE_WRAPPER environment variable is set
+
+import argparse
+import os
+import sys
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('binary') # unused, but needed for test behavior
+ parser.add_argument('--expected', action='store_true')
+ args = parser.parse_args()
+
+ defined = 'MESON_EXE_WRAPPER' in os.environ
+
+ if args.expected != defined:
+ print(os.environ, file=sys.stderr)
+ return 1
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/test cases/unit/72 cross test passed/meson.build b/test cases/unit/72 cross test passed/meson.build
new file mode 100644
index 0000000..4deb74b
--- /dev/null
+++ b/test cases/unit/72 cross test passed/meson.build
@@ -0,0 +1,19 @@
+project(
+ 'cross test passed',
+ 'c',
+ version : '>= 0.51'
+)
+
+e = executable('exec', 'src/main.c')
+
+py = import('python').find_installation()
+
+test('root', e)
+test('main', py, args : [meson.current_source_dir() / 'script.py', e])
+
+wrapper_args = []
+if get_option('expect')
+ wrapper_args += '--expected'
+endif
+
+test('exe_wrapper in env', py, args : [meson.current_source_dir() / 'exewrapper.py', e, wrapper_args])
diff --git a/test cases/unit/72 cross test passed/meson_options.txt b/test cases/unit/72 cross test passed/meson_options.txt
new file mode 100644
index 0000000..084c776
--- /dev/null
+++ b/test cases/unit/72 cross test passed/meson_options.txt
@@ -0,0 +1,5 @@
+option(
+ 'expect',
+ type : 'boolean',
+ value : false,
+)
diff --git a/test cases/unit/72 cross test passed/script.py b/test cases/unit/72 cross test passed/script.py
new file mode 100644
index 0000000..257cd30
--- /dev/null
+++ b/test cases/unit/72 cross test passed/script.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python3
+
+import subprocess
+import sys
+
+if __name__ == "__main__":
+ sys.exit(subprocess.run(sys.argv[1:]).returncode)
diff --git a/test cases/unit/72 cross test passed/src/main.c b/test cases/unit/72 cross test passed/src/main.c
new file mode 100644
index 0000000..490b4a6
--- /dev/null
+++ b/test cases/unit/72 cross test passed/src/main.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char const *argv[])
+{
+ return 0;
+}
diff --git a/test cases/unit/72 summary/meson.build b/test cases/unit/73 summary/meson.build
index df4540d..df4540d 100644
--- a/test cases/unit/72 summary/meson.build
+++ b/test cases/unit/73 summary/meson.build
diff --git a/test cases/unit/72 summary/subprojects/sub/meson.build b/test cases/unit/73 summary/subprojects/sub/meson.build
index e7d7833..e7d7833 100644
--- a/test cases/unit/72 summary/subprojects/sub/meson.build
+++ b/test cases/unit/73 summary/subprojects/sub/meson.build
diff --git a/test cases/unit/72 summary/subprojects/sub2/meson.build b/test cases/unit/73 summary/subprojects/sub2/meson.build
index 86b9cfd..86b9cfd 100644
--- a/test cases/unit/72 summary/subprojects/sub2/meson.build
+++ b/test cases/unit/73 summary/subprojects/sub2/meson.build
diff --git a/test cases/unit/73 wrap file url/meson.build b/test cases/unit/74 wrap file url/meson.build
index 3bd3b25..3bd3b25 100644
--- a/test cases/unit/73 wrap file url/meson.build
+++ b/test cases/unit/74 wrap file url/meson.build
diff --git a/test cases/unit/73 wrap file url/subprojects/foo-patch.tar.xz b/test cases/unit/74 wrap file url/subprojects/foo-patch.tar.xz
index fdb026c..fdb026c 100644
--- a/test cases/unit/73 wrap file url/subprojects/foo-patch.tar.xz
+++ b/test cases/unit/74 wrap file url/subprojects/foo-patch.tar.xz
Binary files differ
diff --git a/test cases/unit/73 wrap file url/subprojects/foo.tar.xz b/test cases/unit/74 wrap file url/subprojects/foo.tar.xz
index 2ed6ab4..2ed6ab4 100644
--- a/test cases/unit/73 wrap file url/subprojects/foo.tar.xz
+++ b/test cases/unit/74 wrap file url/subprojects/foo.tar.xz
Binary files differ
diff --git a/test cases/unit/74 dep files/foo.c b/test cases/unit/75 dep files/foo.c
index e69de29..e69de29 100644
--- a/test cases/unit/74 dep files/foo.c
+++ b/test cases/unit/75 dep files/foo.c
diff --git a/test cases/unit/74 dep files/meson.build b/test cases/unit/75 dep files/meson.build
index 4829f56..4829f56 100644
--- a/test cases/unit/74 dep files/meson.build
+++ b/test cases/unit/75 dep files/meson.build
diff --git a/test cases/unit/76 pkgconfig prefixes/client/client.c b/test cases/unit/76 pkgconfig prefixes/client/client.c
new file mode 100644
index 0000000..be9bead
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/client/client.c
@@ -0,0 +1,8 @@
+#include <val2.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ printf("%d\n", val2());
+ return 0;
+}
diff --git a/test cases/unit/76 pkgconfig prefixes/client/meson.build b/test cases/unit/76 pkgconfig prefixes/client/meson.build
new file mode 100644
index 0000000..491937b
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/client/meson.build
@@ -0,0 +1,3 @@
+project('client', 'c')
+val2_dep = dependency('val2')
+executable('client', 'client.c', dependencies : [val2_dep], install: true)
diff --git a/test cases/unit/76 pkgconfig prefixes/val1/meson.build b/test cases/unit/76 pkgconfig prefixes/val1/meson.build
new file mode 100644
index 0000000..cc63e31
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/val1/meson.build
@@ -0,0 +1,5 @@
+project('val1', 'c')
+val1 = shared_library('val1', 'val1.c', install: true)
+install_headers('val1.h')
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(val1, libraries : ['-Wl,-rpath,${libdir}'])
diff --git a/test cases/unit/76 pkgconfig prefixes/val1/val1.c b/test cases/unit/76 pkgconfig prefixes/val1/val1.c
new file mode 100644
index 0000000..591e521
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/val1/val1.c
@@ -0,0 +1,3 @@
+#include "val1.h"
+
+int val1(void) { return 1; }
diff --git a/test cases/unit/76 pkgconfig prefixes/val1/val1.h b/test cases/unit/76 pkgconfig prefixes/val1/val1.h
new file mode 100644
index 0000000..6bd435e
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/val1/val1.h
@@ -0,0 +1 @@
+int val1(void);
diff --git a/test cases/unit/76 pkgconfig prefixes/val2/meson.build b/test cases/unit/76 pkgconfig prefixes/val2/meson.build
new file mode 100644
index 0000000..ce69481
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/val2/meson.build
@@ -0,0 +1,8 @@
+project('val2', 'c')
+val1_dep = dependency('val1')
+val2 = shared_library('val2', 'val2.c',
+ dependencies : [val1_dep],
+ install: true)
+install_headers('val2.h')
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(val2, libraries : ['-Wl,-rpath,${libdir}'])
diff --git a/test cases/unit/76 pkgconfig prefixes/val2/val2.c b/test cases/unit/76 pkgconfig prefixes/val2/val2.c
new file mode 100644
index 0000000..d7d4857
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/val2/val2.c
@@ -0,0 +1,4 @@
+#include "val1.h"
+#include "val2.h"
+
+int val2(void) { return val1() + 2; }
diff --git a/test cases/unit/76 pkgconfig prefixes/val2/val2.h b/test cases/unit/76 pkgconfig prefixes/val2/val2.h
new file mode 100644
index 0000000..995023d
--- /dev/null
+++ b/test cases/unit/76 pkgconfig prefixes/val2/val2.h
@@ -0,0 +1 @@
+int val2(void);
diff --git a/test cases/unit/75 subdir libdir/meson.build b/test cases/unit/76 subdir libdir/meson.build
index 5099c91..5099c91 100644
--- a/test cases/unit/75 subdir libdir/meson.build
+++ b/test cases/unit/76 subdir libdir/meson.build
diff --git a/test cases/unit/75 subdir libdir/subprojects/flub/meson.build b/test cases/unit/76 subdir libdir/subprojects/flub/meson.build
index 7bfd2c5..7bfd2c5 100644
--- a/test cases/unit/75 subdir libdir/subprojects/flub/meson.build
+++ b/test cases/unit/76 subdir libdir/subprojects/flub/meson.build
diff --git a/test cases/unit/77 global-rpath/meson.build b/test cases/unit/77 global-rpath/meson.build
new file mode 100644
index 0000000..c67d9e0
--- /dev/null
+++ b/test cases/unit/77 global-rpath/meson.build
@@ -0,0 +1,3 @@
+project('global-rpath', 'cpp')
+yonder_dep = dependency('yonder')
+executable('rpathified', 'rpathified.cpp', dependencies: [yonder_dep], install: true)
diff --git a/test cases/unit/77 global-rpath/rpathified.cpp b/test cases/unit/77 global-rpath/rpathified.cpp
new file mode 100644
index 0000000..3788906
--- /dev/null
+++ b/test cases/unit/77 global-rpath/rpathified.cpp
@@ -0,0 +1,6 @@
+#include <yonder.h>
+#include <string.h>
+int main(int argc, char **argv)
+{
+ return strcmp(yonder(), "AB54 6BR");
+}
diff --git a/test cases/unit/77 global-rpath/yonder/meson.build b/test cases/unit/77 global-rpath/yonder/meson.build
new file mode 100644
index 0000000..e32f383
--- /dev/null
+++ b/test cases/unit/77 global-rpath/yonder/meson.build
@@ -0,0 +1,5 @@
+project('yonder', 'cpp')
+yonder = shared_library('yonder', 'yonder.cpp', install: true)
+install_headers('yonder.h')
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(yonder)
diff --git a/test cases/unit/77 global-rpath/yonder/yonder.cpp b/test cases/unit/77 global-rpath/yonder/yonder.cpp
new file mode 100644
index 0000000..b182d34
--- /dev/null
+++ b/test cases/unit/77 global-rpath/yonder/yonder.cpp
@@ -0,0 +1,3 @@
+#include "yonder.h"
+
+char *yonder(void) { return "AB54 6BR"; }
diff --git a/test cases/unit/77 global-rpath/yonder/yonder.h b/test cases/unit/77 global-rpath/yonder/yonder.h
new file mode 100644
index 0000000..9d9ad16
--- /dev/null
+++ b/test cases/unit/77 global-rpath/yonder/yonder.h
@@ -0,0 +1 @@
+char *yonder(void);
diff --git a/test cases/warning/1 version for string div/test.json b/test cases/warning/1 version for string div/test.json
index ce1af59..c37931a 100644
--- a/test cases/warning/1 version for string div/test.json
+++ b/test cases/warning/1 version for string div/test.json
@@ -2,7 +2,7 @@
"stdout": [
{
"comment": "literal '/' appears in output, irrespective of os.path.sep, as that's the operator",
- "line": "WARNING: Project targeting '>=0.48.0' but tried to use feature introduced in '0.49.0': / with string arguments"
+ "line": "WARNING: Project targeting '>=0.48.0' but tried to use feature introduced in '0.49.0': / with string arguments."
}
]
}