aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Builtin-options.md2
-rw-r--r--docs/markdown/FAQ.md34
-rw-r--r--docs/markdown/Reference-manual.md4
-rw-r--r--docs/markdown/snippets/link_language.md10
-rw-r--r--docs/markdown/snippets/linkcustom.md5
-rw-r--r--mesonbuild/backend/backends.py4
-rw-r--r--mesonbuild/backend/vs2010backend.py16
-rw-r--r--mesonbuild/build.py59
-rw-r--r--mesonbuild/compilers/cpp.py1
-rw-r--r--mesonbuild/compilers/fortran.py4
-rw-r--r--mesonbuild/dependencies/base.py5
-rw-r--r--mesonbuild/dependencies/platform.py13
-rw-r--r--mesonbuild/envconfig.py4
-rw-r--r--mesonbuild/environment.py15
-rw-r--r--mesonbuild/interpreter.py1
-rw-r--r--mesonbuild/mesonlib.py10
-rw-r--r--mesonbuild/mtest.py2
-rwxr-xr-xrun_project_tests.py4
-rwxr-xr-xrun_unittests.py32
-rw-r--r--test cases/common/216 link custom/meson.build22
-rw-r--r--test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py90
-rw-r--r--test cases/common/217 link custom_i single from multiple/meson.build37
-rw-r--r--test cases/common/217 link custom_i single from multiple/prog.c5
-rw-r--r--test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py92
-rw-r--r--test cases/common/218 link custom_i multiple from multiple/meson.build37
-rw-r--r--test cases/common/218 link custom_i multiple from multiple/prog.c8
-rw-r--r--test cases/fortran/14 fortran links c/clib.c7
-rw-r--r--test cases/fortran/14 fortran links c/f_call_c.f9010
-rw-r--r--test cases/fortran/14 fortran links c/meson.build13
-rw-r--r--test cases/objc/2 nsstring/meson.build3
-rw-r--r--test cases/unit/4 suite selection/meson.build4
-rw-r--r--test cases/unit/4 suite selection/subprojects/subprjfail/meson.build4
-rw-r--r--test cases/unit/4 suite selection/subprojects/subprjsucc/meson.build4
33 files changed, 501 insertions, 60 deletions
diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md
index 957ce4e..d25d7ab 100644
--- a/docs/markdown/Builtin-options.md
+++ b/docs/markdown/Builtin-options.md
@@ -132,7 +132,7 @@ compiler being used:
| c_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
| cpp_args | | free-form comma-separated list | C++ compile arguments to use |
| cpp_link_args| | free-form comma-separated list | C++ link arguments to use |
-| cpp_std | none | none, c++98, c++03, c++11, c++14, c++17, <br/>c++1z, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z | C++ language standard to use |
+| cpp_std | none | none, c++98, c++03, c++11, c++14, c++17, <br/>c++1z, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z, <br/> vc++14, vc++17, vc++latest | C++ language standard to use |
| cpp_debugstl | false | true, false | C++ STL debug mode |
| cpp_eh | sc | none, a, s, sc | C++ exception handling type |
| cpp_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
diff --git a/docs/markdown/FAQ.md b/docs/markdown/FAQ.md
index ff93216..0208c1a 100644
--- a/docs/markdown/FAQ.md
+++ b/docs/markdown/FAQ.md
@@ -331,3 +331,37 @@ that could fullfill these requirements:
Out of these we have chosen Python because it is the best fit for our
needs.
+
+## I have proprietary compiler toolchain X that does not work with Meson, how can I make it work?
+
+Meson needs to know several details about each compiler in order to
+compile code with it. These include things such as which compiler
+flags to use for each option and how to detect the compiler from its
+output. This information can not be input via a configuration file,
+instead it requires changes to Meson's source code that need to be
+submitted to Meson master repository. In theory you can run your own
+forked version with custom patches, but that's not good use of your
+time. Please submit the code upstream so everyone can use the
+toolchain.
+
+The steps for adding a new compiler for an existing language are
+roughly the following. For simplicity we're going to assume a C
+compiler.
+
+- Create a new class with a proper name in
+ `mesonbuild/compilers/c.py`. Look at the methods that other
+ compilers for the same language have and duplicate what they do.
+
+- If the compiler can only be used for cross compilation, make sure to
+ flag it as such (see existing compiler classes for examples).
+
+- Add detection logic to `mesonbuild/environment.py`, look for a
+ method called `detect_c_compiler`.
+
+- Run the test suite and fix issues until the tests pass.
+
+- Submit a pull request, add the result of the test suite to your MR
+ (linking an existing page is fine).
+
+- If the compiler is freely available, consider adding it to the CI
+ system.
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 056612d..d86d825 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -518,6 +518,8 @@ be passed to [shared and static libraries](#library).
depends on such as a symbol visibility map. The purpose is to
automatically trigger a re-link (but not a re-compile) of the target
when this file changes.
+- `link_language` since 0.51.0 makes the linker for this target
+ be for the specified language. This is helpful for multi-language targets.
- `link_whole` links all contents of the given static libraries
whether they are used by not, equivalent to the
`-Wl,--whole-archive` argument flag of GCC, available since 0.40.0.
@@ -568,7 +570,7 @@ be passed to [shared and static libraries](#library).
the keyword argument for the default behaviour.
- `override_options` takes an array of strings in the same format as
`project`'s `default_options` overriding the values of these options
- for this target only, since 0.40.0
+ for this target only, since 0.40.0.
- `gnu_symbol_visibility` specifies how symbols should be exported, see
e.g [the GCC Wiki](https://gcc.gnu.org/wiki/Visibility) for more
information. This value can either be an empty string or one of
diff --git a/docs/markdown/snippets/link_language.md b/docs/markdown/snippets/link_language.md
new file mode 100644
index 0000000..28ebe8b
--- /dev/null
+++ b/docs/markdown/snippets/link_language.md
@@ -0,0 +1,10 @@
+## New target keyword argument: `link_language`
+There may be situations for which the user wishes to manually specify the linking language.
+For example, a C++ target may link C, Fortran, etc. and perhaps the automatic detection in Meson does not pick the desired compiler.
+The user can manually choose the linker by language per-target like this example of a target where one wishes to link with the Fortran compiler:
+```meson
+executable(..., link_language : 'fortran')
+```
+
+A specific case this option fixes is where for example the main program is Fortran that calls C and/or C++ code.
+The automatic language detection of Meson prioritizes C/C++, and so an compile-time error results like `undefined reference to main`, because the linker is C or C++ instead of Fortran, which is fixed by this per-target override.
diff --git a/docs/markdown/snippets/linkcustom.md b/docs/markdown/snippets/linkcustom.md
index d6ee801..0cf45ad 100644
--- a/docs/markdown/snippets/linkcustom.md
+++ b/docs/markdown/snippets/linkcustom.md
@@ -1,6 +1,6 @@
## Can link against custom targets
-The output of `custom_target` can be used in `link_with` and
+The output of `custom_target` and `custom_target[i]` can be used in `link_with` and
`link_whole` keyword arguments. This is useful for integrating custom
code generator steps, but note that there are many limitations:
@@ -10,7 +10,8 @@ code generator steps, but note that there are many limitations:
- The user is responsible for ensuring that the code produced by
different toolchains are compatible.
- - The custom target can only have one output file.
+ - `custom_target` may only be used when it has a single output file.
+ Use `custom_target[i]` when dealing with multiple output files.
- The output file must have the correct file name extension.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 5ff9b55..d0b4bb5 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -171,6 +171,8 @@ class Backend:
mlog.warning('custom_target {!r} has more than one output! '
'Using the first one.'.format(t.name))
filename = t.get_outputs()[0]
+ elif isinstance(t, build.CustomTargetIndex):
+ filename = t.get_outputs()[0]
else:
assert(isinstance(t, build.BuildTarget))
filename = t.get_filename()
@@ -214,7 +216,7 @@ class Backend:
return os.path.join(self.get_target_dir(target), link_lib)
elif isinstance(target, build.StaticLibrary):
return os.path.join(self.get_target_dir(target), target.get_filename())
- elif isinstance(target, build.CustomTarget):
+ elif isinstance(target, (build.CustomTarget, build.CustomTargetIndex)):
if not target.is_linkable_target():
raise MesonException('Tried to link against custom target "%s", which is not linkable.' % target.name)
return os.path.join(self.get_target_dir(target), target.get_filename())
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 3950a2e..d25798e 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -249,9 +249,15 @@ class Vs2010Backend(backends.Backend):
all_deps[d.get_id()] = d
elif isinstance(target, build.BuildTarget):
for ldep in target.link_targets:
- all_deps[ldep.get_id()] = ldep
+ if isinstance(ldep, build.CustomTargetIndex):
+ all_deps[ldep.get_id()] = ldep.target
+ else:
+ all_deps[ldep.get_id()] = ldep
for ldep in target.link_whole_targets:
- all_deps[ldep.get_id()] = ldep
+ if isinstance(ldep, build.CustomTargetIndex):
+ all_deps[ldep.get_id()] = ldep.target
+ else:
+ all_deps[ldep.get_id()] = ldep
for obj_id, objdep in self.get_obj_target_deps(target.objects):
all_deps[obj_id] = objdep
for gendep in target.get_generated_sources():
@@ -1111,7 +1117,11 @@ class Vs2010Backend(backends.Backend):
# Add more libraries to be linked if needed
for t in target.get_dependencies():
- lobj = self.build.targets[t.get_id()]
+ if isinstance(t, build.CustomTargetIndex):
+ # We don't need the actual project here, just the library name
+ lobj = t
+ else:
+ lobj = self.build.targets[t.get_id()]
linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
if t in target.link_whole_targets:
# /WHOLEARCHIVE:foo must go into AdditionalOptions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 5248d97..603e0d0 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from typing import List
import copy, os, re
from collections import OrderedDict
import itertools, pathlib
@@ -28,7 +29,7 @@ from .mesonlib import (
get_filenames_templates_dict, substitute_values,
for_windows, for_darwin, for_cygwin, for_android, has_path_sep
)
-from .compilers import is_object, clink_langs, sort_clink, lang_suffixes, get_macos_dylib_install_name
+from .compilers import Compiler, is_object, clink_langs, sort_clink, lang_suffixes, get_macos_dylib_install_name
from .interpreterbase import FeatureNew
pch_kwargs = set(['c_pch', 'cpp_pch'])
@@ -88,7 +89,7 @@ known_build_target_kwargs = (
rust_kwargs |
cs_kwargs)
-known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie'}
+known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'link_language', 'pie'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions'}
known_shmod_kwargs = known_build_target_kwargs
known_stlib_kwargs = known_build_target_kwargs | {'pic'}
@@ -425,7 +426,7 @@ a hard error in the future.''' % name)
self.option_overrides = self.parse_overrides(kwargs)
- def parse_overrides(self, kwargs):
+ def parse_overrides(self, kwargs) -> dict:
result = {}
overrides = stringlistify(kwargs.get('override_options', []))
for o in overrides:
@@ -437,7 +438,7 @@ a hard error in the future.''' % name)
result[k] = v
return result
- def is_linkable_target(self):
+ def is_linkable_target(self) -> bool:
return False
class BuildTarget(Target):
@@ -450,10 +451,11 @@ class BuildTarget(Target):
self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '')
self.environment = environment
self.sources = []
- self.compilers = OrderedDict()
+ self.compilers = OrderedDict() # type: OrderedDict[str, Compiler]
self.objects = []
self.external_deps = []
self.include_dirs = []
+ self.link_language = kwargs.get('link_language')
self.link_targets = []
self.link_whole_targets = []
self.link_depends = []
@@ -571,15 +573,18 @@ class BuildTarget(Target):
else:
compilers = self.environment.coredata.compilers
+ # did user override clink_langs for this target?
+ link_langs = [self.link_language] if self.link_language else clink_langs
+
# If this library is linked against another library we need to consider
# the languages of those libraries as well.
if self.link_targets or self.link_whole_targets:
extra = set()
for t in itertools.chain(self.link_targets, self.link_whole_targets):
- if isinstance(t, CustomTarget):
+ if isinstance(t, CustomTarget) or isinstance(t, CustomTargetIndex):
continue # We can't know anything about these.
for name, compiler in t.compilers.items():
- if name in clink_langs:
+ if name in link_langs:
extra.add((name, compiler))
for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])):
self.compilers[name] = compiler
@@ -588,7 +593,7 @@ class BuildTarget(Target):
# No source files or parent targets, target consists of only object
# files of unknown origin. Just add the first clink compiler
# that we have and hope that it can link these objects
- for lang in clink_langs:
+ for lang in link_langs:
if lang in compilers:
self.compilers[lang] = compilers[lang]
break
@@ -1066,7 +1071,7 @@ You probably should put it in link_with instead.''')
def link(self, target):
for t in listify(target, unholder=True):
- if not isinstance(t, Target):
+ if not isinstance(t, (Target, CustomTargetIndex)):
raise InvalidArguments('{!r} is not a target.'.format(t))
if not t.is_linkable_target():
raise InvalidArguments('Link target {!r} is not linkable.'.format(t))
@@ -1074,13 +1079,13 @@ You probably should put it in link_with instead.''')
msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
msg += "Use the 'pic' option to static_library to build with PIC."
raise InvalidArguments(msg)
- if not isinstance(t, CustomTarget) and self.is_cross != t.is_cross:
+ if not isinstance(t, (CustomTarget, CustomTargetIndex)) and self.is_cross != t.is_cross:
raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
self.link_targets.append(t)
def link_whole(self, target):
for t in listify(target, unholder=True):
- if isinstance(t, CustomTarget):
+ if isinstance(t, (CustomTarget, CustomTargetIndex)):
if not t.is_linkable_target():
raise InvalidArguments('Custom target {!r} is not linkable.'.format(t))
if not t.get_filename().endswith('.a'):
@@ -1091,7 +1096,7 @@ You probably should put it in link_with instead.''')
msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
msg += "Use the 'pic' option to static_library to build with PIC."
raise InvalidArguments(msg)
- if not isinstance(t, CustomTarget) and self.is_cross != t.is_cross:
+ if not isinstance(t, (CustomTarget, CustomTargetIndex)) and self.is_cross != t.is_cross:
raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
self.link_whole_targets.append(t)
@@ -1149,7 +1154,7 @@ You probably should put it in link_with instead.''')
def get_aliases(self):
return {}
- def get_langs_used_by_deps(self):
+ def get_langs_used_by_deps(self) -> List[str]:
'''
Sometimes you want to link to a C++ library that exports C API, which
means the linker must link in the C++ stdlib, and we must use a C++
@@ -1159,6 +1164,11 @@ You probably should put it in link_with instead.''')
See: https://github.com/mesonbuild/meson/issues/1653
'''
langs = []
+
+ # User specified link_language of target (for multi-language targets)
+ if self.link_language:
+ return [self.link_language]
+
# Check if any of the external libraries were written in this language
for dep in self.external_deps:
if dep.language is None:
@@ -1168,11 +1178,12 @@ You probably should put it in link_with instead.''')
# Check if any of the internal libraries this target links to were
# written in this language
for link_target in itertools.chain(self.link_targets, self.link_whole_targets):
- if isinstance(link_target, CustomTarget):
+ if isinstance(link_target, (CustomTarget, CustomTargetIndex)):
continue
for language in link_target.compilers:
if language not in langs:
langs.append(language)
+
return langs
def get_clink_dynamic_linker_and_stdlibs(self):
@@ -2259,6 +2270,26 @@ class CustomTargetIndex:
def get_subdir(self):
return self.target.get_subdir()
+ def get_filename(self):
+ return self.output
+
+ def get_id(self):
+ return self.target.get_id()
+
+ def get_all_link_deps(self):
+ return self.target.get_all_link_deps()
+
+ def get_link_deps_mapping(self, prefix, environment):
+ return self.target.get_link_deps_mapping(prefix, environment)
+
+ def get_link_dep_subdirs(self):
+ return self.target.get_link_dep_subdirs()
+
+ def is_linkable_target(self):
+ suf = os.path.splitext(self.output)[-1]
+ if suf == '.a' or suf == '.dll' or suf == '.lib' or suf == '.so':
+ return True
+
class ConfigureFile:
def __init__(self, subdir, sourcename, targetname, configuration_data):
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index 7c2253d..2b2c4a0 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -23,7 +23,6 @@ from .c import CCompiler, VisualStudioCCompiler, ClangClCCompiler, IntelClCCompi
from .compilers import (
gnu_winlibs,
msvc_winlibs,
- CompilerType,
ClangCompiler,
GnuCompiler,
ElbrusCompiler,
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index dd54fd0..86ebe05 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -333,7 +333,6 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler):
def language_stdlib_only_link_flags(self):
return ['-lgfortran', '-lm']
-
class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
GnuFortranCompiler.__init__(self, exelist, version, compiler_type, is_cross, exe_wrapper, defines, **kwargs)
@@ -427,6 +426,9 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler):
FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags)
PGICompiler.__init__(self, compiler_type)
+ def language_stdlib_only_link_flags(self) -> List[str]:
+ return ['-lpgf90rtl', '-lpgf90', '-lpgf90_rpm1', '-lpgf902',
+ '-lpgf90rtl', '-lpgftnrtl', '-lrt']
class FlangFortranCompiler(ClangCompiler, FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index c09f799..9664215 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -14,7 +14,6 @@
# This file contains the detection logic for external dependencies.
# Custom logic for several other packages are in separate files.
-from typing import Dict, Any
import copy
import functools
import os
@@ -26,7 +25,7 @@ import textwrap
import platform
import itertools
import ctypes
-from typing import List, Tuple
+from typing import Any, Dict, List, Tuple
from enum import Enum
from pathlib import Path, PurePath
@@ -2304,7 +2303,7 @@ class ExtraFrameworkDependency(ExternalDependency):
return 'framework'
-def get_dep_identifier(name, kwargs, want_cross):
+def get_dep_identifier(name, kwargs, want_cross: bool) -> Tuple:
identifier = (name, want_cross)
for key, value in kwargs.items():
# 'version' is irrelevant for caching; the caller must check version matches
diff --git a/mesonbuild/dependencies/platform.py b/mesonbuild/dependencies/platform.py
index 9863fb1..e913ed4 100644
--- a/mesonbuild/dependencies/platform.py
+++ b/mesonbuild/dependencies/platform.py
@@ -16,7 +16,7 @@
# platform-specific (generally speaking).
from .base import ExternalDependency, DependencyException
-
+from ..mesonlib import MesonException
class AppleFrameworks(ExternalDependency):
def __init__(self, env, kwargs):
@@ -31,7 +31,16 @@ class AppleFrameworks(ExternalDependency):
raise DependencyException('No C-like compilers are available, cannot find the framework')
self.is_found = True
for f in self.frameworks:
- args = self.clib_compiler.find_framework(f, env, [])
+ try:
+ args = self.clib_compiler.find_framework(f, env, [])
+ except MesonException as e:
+ if 'non-clang' in str(e):
+ self.is_found = False
+ self.link_args = []
+ self.compile_args = []
+ return
+ raise
+
if args is not None:
# No compile args are needed for system frameworks
self.link_args += args
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index f4c371f..977d930 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -255,7 +255,7 @@ class MachineInfo:
def libdir_layout_is_win(self) -> bool:
return self.is_windows() or self.is_cygwin()
-class PerMachineDefaultable(PerMachine[_T]):
+class PerMachineDefaultable(PerMachine[typing.Optional[_T]]):
"""Extends `PerMachine` with the ability to default from `None`s.
"""
def __init__(self) -> None:
@@ -285,7 +285,7 @@ class PerMachineDefaultable(PerMachine[_T]):
if self.host == self.build:
self.host = None
-class MachineInfos(PerMachineDefaultable[typing.Optional[MachineInfo]]):
+class MachineInfos(PerMachineDefaultable[MachineInfo]):
def matches_build_machine(self, machine: MachineChoice) -> bool:
return self.build == self[machine]
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index bf2cce9..462672e 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, platform, re, sys, shlex, shutil, subprocess
+import os, platform, re, sys, shlex, shutil, subprocess, typing
from . import coredata
from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker
@@ -28,6 +28,7 @@ from .envconfig import (
)
from . import compilers
from .compilers import (
+ Compiler,
CompilerType,
is_assembly,
is_header,
@@ -83,6 +84,8 @@ from .compilers import (
build_filename = 'meson.build'
+CompilersDict = typing.Dict[str, Compiler]
+
def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
gcovr_exe = 'gcovr'
try:
@@ -150,7 +153,7 @@ def detect_native_windows_arch():
raise EnvironmentException('Unable to detect native OS architecture')
return arch
-def detect_windows_arch(compilers):
+def detect_windows_arch(compilers: CompilersDict) -> str:
"""
Detecting the 'native' architecture of Windows is not a trivial task. We
cannot trust that the architecture that Python is built for is the 'native'
@@ -190,7 +193,7 @@ def detect_windows_arch(compilers):
return 'x86'
return os_arch
-def any_compiler_has_define(compilers, define):
+def any_compiler_has_define(compilers: CompilersDict, define):
for c in compilers.values():
try:
if c.has_builtin_define(define):
@@ -200,7 +203,7 @@ def any_compiler_has_define(compilers, define):
pass
return False
-def detect_cpu_family(compilers):
+def detect_cpu_family(compilers: CompilersDict) -> str:
"""
Python is inconsistent in its platform module.
It returns different values for the same cpu.
@@ -262,7 +265,7 @@ def detect_cpu_family(compilers):
return trial
-def detect_cpu(compilers):
+def detect_cpu(compilers: CompilersDict):
if mesonlib.is_windows():
trial = detect_windows_arch(compilers)
else:
@@ -295,7 +298,7 @@ def detect_msys2_arch():
return os.environ['MSYSTEM_CARCH']
return None
-def detect_machine_info(compilers = None) -> MachineInfo:
+def detect_machine_info(compilers: typing.Optional[CompilersDict] = None) -> MachineInfo:
"""Detect the machine we're running on
If compilers are not provided, we cannot know as much. None out those
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 9bb4a3c..9d1a27d 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -2996,6 +2996,7 @@ external dependencies (including libraries) must go to "dependencies".''')
self._handle_featurenew_dependencies(name)
kwargs['required'] = required and not has_fallback
dep = dependencies.find_external_dependency(name, self.environment, kwargs)
+
kwargs['required'] = required
# Only store found-deps in the cache
# Never add fallback deps to self.coredata.deps since we
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index d5e60fd..aaaf144 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -323,22 +323,20 @@ class MachineChoice(OrderedEnum):
HOST = 1
TARGET = 2
-_T = typing.TypeVar('_T')
-
class PerMachine(typing.Generic[_T]):
- def __init__(self, build: typing.Optional[_T], host: typing.Optional[_T], target: typing.Optional[_T]):
+ def __init__(self, build: _T, host: _T, target: _T):
self.build = build
self.host = host
self.target = target
- def __getitem__(self, machine: MachineChoice) -> typing.Optional[_T]:
+ def __getitem__(self, machine: MachineChoice) -> _T:
return {
MachineChoice.BUILD: self.build,
MachineChoice.HOST: self.host,
MachineChoice.TARGET: self.target
}[machine]
- def __setitem__(self, machine: MachineChoice, val: typing.Optional[_T]) -> None:
+ def __setitem__(self, machine: MachineChoice, val: _T) -> None:
key = {
MachineChoice.BUILD: 'build',
MachineChoice.HOST: 'host',
@@ -968,7 +966,7 @@ def Popen_safe(args, write=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
return p, o, e
def Popen_safe_legacy(args, write=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs):
- p = subprocess.Popen(args, universal_newlines=False,
+ p = subprocess.Popen(args, universal_newlines=False, close_fds=False,
stdout=stdout, stderr=stderr, **kwargs)
if write is not None:
write = write.encode('utf-8')
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 17af4df..8df8f48 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -873,7 +873,7 @@ Timeout: %4d
return wrap
def get_pretty_suite(self, test):
- if len(self.suites) > 1:
+ 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):
diff --git a/run_project_tests.py b/run_project_tests.py
index 4406e1e..324d824 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -505,6 +505,10 @@ def skippable(suite, test):
if test.endswith('netcdf'):
return True
+ # MSVC doesn't link with GFortran
+ if test.endswith('14 fortran links c'):
+ return True
+
# No frameworks test should be skipped on linux CI, as we expect all
# prerequisites to be installed
if mesonlib.is_linux():
diff --git a/run_unittests.py b/run_unittests.py
index 5c9917a..2683e01 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1813,48 +1813,48 @@ class AllPlatformTests(BasePlatformTests):
self.init(testdir)
self.build()
- self.assertFailedTestCount(3, self.mtest_command)
+ self.assertFailedTestCount(4, self.mtest_command)
self.assertFailedTestCount(0, self.mtest_command + ['--suite', ':success'])
self.assertFailedTestCount(3, self.mtest_command + ['--suite', ':fail'])
- self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', ':success'])
- self.assertFailedTestCount(0, self.mtest_command + ['--no-suite', ':fail'])
+ self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', ':success'])
+ self.assertFailedTestCount(1, self.mtest_command + ['--no-suite', ':fail'])
self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj'])
self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc'])
self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail'])
self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix'])
- self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj'])
- self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc'])
- self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail'])
- self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix'])
+ self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj'])
+ self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjsucc'])
+ self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail'])
+ self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix'])
self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'mainprj:fail'])
self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'mainprj:success'])
- self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'mainprj:fail'])
- self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj:success'])
+ self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'mainprj:fail'])
+ self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'mainprj:success'])
self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail:fail'])
self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjfail:success'])
- self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail:fail'])
- self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail:success'])
+ self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjfail:fail'])
+ self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjfail:success'])
self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:fail'])
self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjsucc:success'])
- self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:fail'])
- self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjsucc:success'])
+ self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjsucc:fail'])
+ self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjsucc:success'])
self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjmix:fail'])
self.assertFailedTestCount(0, self.mtest_command + ['--suite', 'subprjmix:success'])
- self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjmix:fail'])
- self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix:success'])
+ self.assertFailedTestCount(3, self.mtest_command + ['--no-suite', 'subprjmix:fail'])
+ self.assertFailedTestCount(4, self.mtest_command + ['--no-suite', 'subprjmix:success'])
self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix:fail'])
self.assertFailedTestCount(3, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj'])
self.assertFailedTestCount(2, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail'])
self.assertFailedTestCount(1, self.mtest_command + ['--suite', 'subprjfail', '--suite', 'subprjmix', '--suite', 'mainprj', '--no-suite', 'subprjmix:fail', 'mainprj-failing_test'])
- self.assertFailedTestCount(1, self.mtest_command + ['--no-suite', 'subprjfail:fail', '--no-suite', 'subprjmix:fail'])
+ self.assertFailedTestCount(2, self.mtest_command + ['--no-suite', 'subprjfail:fail', '--no-suite', 'subprjmix:fail'])
def test_build_by_default(self):
testdir = os.path.join(self.common_test_dir, '134 build by default')
diff --git a/test cases/common/216 link custom/meson.build b/test cases/common/216 link custom/meson.build
index 5af27cd..c8d3a6d 100644
--- a/test cases/common/216 link custom/meson.build
+++ b/test cases/common/216 link custom/meson.build
@@ -16,6 +16,8 @@ clib = custom_target('linkcustom',
'-o', '@OUTPUT@',
'--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())
+# custom_target tests
+
exe = executable('prog', 'prog.c', link_with: clib)
test('linkcustom', exe)
@@ -33,3 +35,23 @@ d2 = declare_dependency(link_whole: clib)
exe4 = executable('prog4', 'prog.c', dependencies: d2)
test('linkwhole2', exe2)
+
+# custom_target[i] tests
+
+exe_i = executable('prog_i', 'prog.c', link_with: clib[0])
+test('linkcustom', exe_i)
+
+d_i = declare_dependency(link_with: clib[0])
+
+exe2_i = executable('prog2_i', 'prog.c', dependencies: d_i)
+test('linkcustom2_i', exe2_i)
+
+# Link whole tests
+
+exe3_i = executable('prog3_i', 'prog.c', link_whole: clib[0])
+test('linkwhole', exe)
+
+d2_i = declare_dependency(link_whole: clib[0])
+
+exe4_i = executable('prog4_i', 'prog.c', dependencies: d2_i)
+test('linkwhole2_i', exe2_i)
diff --git a/test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py b/test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py
new file mode 100644
index 0000000..42d6631
--- /dev/null
+++ b/test cases/common/217 link custom_i single from multiple/generate_conflicting_stlibs.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+
+import shutil, sys, subprocess, argparse, pathlib
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--private-dir', required=True)
+parser.add_argument('-o', nargs='+', required=True)
+parser.add_argument('cmparr', nargs='+')
+
+contents = ['''
+int flob() {
+ return 0;
+}
+''', '''
+int flob() {
+ return 1;
+}
+''']
+
+def generate_lib_gnulike(outfile, c_file, private_dir, compiler_array):
+ if shutil.which('ar'):
+ static_linker = 'ar'
+ elif shutil.which('llvm-ar'):
+ static_linker = 'llvm-ar'
+ elif shutil.which('gcc-ar'):
+ static_linker = 'gcc-ar'
+ else:
+ sys.exit('Could not detect a static linker.')
+ o_file = c_file.with_suffix('.o')
+ compile_cmd = compiler_array + ['-c', '-g', '-O2', '-o', str(o_file), str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker, 'csr', outfile, str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+
+def generate_lib_msvc(outfile, c_file, private_dir, compiler_array):
+ static_linker = 'lib'
+ o_file = c_file.with_suffix('.obj')
+ compile_cmd = compiler_array + ['/MDd',
+ '/nologo',
+ '/ZI',
+ '/Ob0',
+ '/Od',
+ '/c',
+ '/Fo' + str(o_file),
+ str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker,
+ '/nologo',
+ '/OUT:' + str(outfile),
+ str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+def generate_lib(outfiles, private_dir, compiler_array):
+ private_dir = pathlib.Path(private_dir)
+ if not private_dir.exists():
+ private_dir.mkdir()
+
+ for i, content in enumerate(contents):
+ c_file = private_dir / ('flob_' + str(i + 1) + '.c')
+ c_file.write_text(content)
+ outfile = outfiles[i]
+
+ cl_found = False
+ for cl_arg in compiler_array:
+ if (cl_arg.endswith('cl') or cl_arg.endswith('cl.exe')) and 'clang-cl' not in cl_arg:
+ ret = generate_lib_msvc(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ else:
+ cl_found = True
+ break
+ if not cl_found:
+ ret = generate_lib_gnulike(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ return 0
+
+if __name__ == '__main__':
+ options = parser.parse_args()
+ sys.exit(generate_lib(options.o, options.private_dir, options.cmparr))
diff --git a/test cases/common/217 link custom_i single from multiple/meson.build b/test cases/common/217 link custom_i single from multiple/meson.build
new file mode 100644
index 0000000..eee1fe1
--- /dev/null
+++ b/test cases/common/217 link custom_i single from multiple/meson.build
@@ -0,0 +1,37 @@
+project('linkcustom', 'c')
+
+# This would require passing the static linker to the build script or having
+# it detect it by itself. I'm too lazy to implement it now and it is not
+# really needed for testing that custom targets work. It is the responsibility
+# of the custom target to produce things in the correct format.
+assert(not meson.is_cross_build(),
+ 'MESON_SKIP_TEST cross checking not implemented.')
+
+cc = meson.get_compiler('c')
+genprog = find_program('generate_conflicting_stlibs.py')
+
+clib = custom_target('linkcustom',
+ output: ['libflob_1.a', 'libflob_2.a'],
+ command: [genprog,
+ '-o', '@OUTPUT@',
+ '--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())
+
+clib_2 = clib[1]
+
+exe = executable('prog', 'prog.c', link_with: clib_2)
+test('linkcustom', exe)
+
+d = declare_dependency(link_with: clib_2)
+
+exe2 = executable('prog2', 'prog.c', dependencies: d)
+test('linkcustom2', exe2)
+
+# Link whole tests
+
+exe3 = executable('prog3', 'prog.c', link_whole: clib_2)
+test('linkwhole', exe)
+
+d2 = declare_dependency(link_whole: clib_2)
+
+exe4 = executable('prog4', 'prog.c', dependencies: d2)
+test('linkwhole2', exe2)
diff --git a/test cases/common/217 link custom_i single from multiple/prog.c b/test cases/common/217 link custom_i single from multiple/prog.c
new file mode 100644
index 0000000..8013034
--- /dev/null
+++ b/test cases/common/217 link custom_i single from multiple/prog.c
@@ -0,0 +1,5 @@
+int flob();
+
+int main(int argc, char **argv) {
+ return (flob() == 1 ? 0 : 1);
+}
diff --git a/test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py b/test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py
new file mode 100644
index 0000000..5292006
--- /dev/null
+++ b/test cases/common/218 link custom_i multiple from multiple/generate_stlibs.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+
+import shutil, sys, subprocess, argparse, pathlib
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--private-dir', required=True)
+parser.add_argument('-o', nargs='+', required=True)
+parser.add_argument('cmparr', nargs='+')
+
+contents = ['''#include<stdio.h>
+
+void flob_1() {
+ printf("Now flobbing #1.\\n");
+}
+''', '''#include<stdio.h>
+
+void flob_2() {
+ printf("Now flobbing #2.\\n");
+}
+''']
+
+def generate_lib_gnulike(outfile, c_file, private_dir, compiler_array):
+ if shutil.which('ar'):
+ static_linker = 'ar'
+ elif shutil.which('llvm-ar'):
+ static_linker = 'llvm-ar'
+ elif shutil.which('gcc-ar'):
+ static_linker = 'gcc-ar'
+ else:
+ sys.exit('Could not detect a static linker.')
+ o_file = c_file.with_suffix('.o')
+ compile_cmd = compiler_array + ['-c', '-g', '-O2', '-o', str(o_file), str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker, 'csr', outfile, str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+
+def generate_lib_msvc(outfile, c_file, private_dir, compiler_array):
+ static_linker = 'lib'
+ o_file = c_file.with_suffix('.obj')
+ compile_cmd = compiler_array + ['/MDd',
+ '/nologo',
+ '/ZI',
+ '/Ob0',
+ '/Od',
+ '/c',
+ '/Fo' + str(o_file),
+ str(c_file)]
+ subprocess.check_call(compile_cmd)
+ out_file = pathlib.Path(outfile)
+ if out_file.exists():
+ out_file.unlink()
+ link_cmd = [static_linker,
+ '/nologo',
+ '/OUT:' + str(outfile),
+ str(o_file)]
+ subprocess.check_call(link_cmd)
+ return 0
+
+def generate_lib(outfiles, private_dir, compiler_array):
+ private_dir = pathlib.Path(private_dir)
+ if not private_dir.exists():
+ private_dir.mkdir()
+
+ for i, content in enumerate(contents):
+ c_file = private_dir / ('flob_' + str(i + 1) + '.c')
+ c_file.write_text(content)
+ outfile = outfiles[i]
+
+ cl_found = False
+ for cl_arg in compiler_array:
+ if (cl_arg.endswith('cl') or cl_arg.endswith('cl.exe')) and 'clang-cl' not in cl_arg:
+ ret = generate_lib_msvc(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ else:
+ cl_found = True
+ break
+ if not cl_found:
+ ret = generate_lib_gnulike(outfile, c_file, private_dir, compiler_array)
+ if ret > 0:
+ return ret
+ return 0
+
+if __name__ == '__main__':
+ options = parser.parse_args()
+ sys.exit(generate_lib(options.o, options.private_dir, options.cmparr))
diff --git a/test cases/common/218 link custom_i multiple from multiple/meson.build b/test cases/common/218 link custom_i multiple from multiple/meson.build
new file mode 100644
index 0000000..e5236e5
--- /dev/null
+++ b/test cases/common/218 link custom_i multiple from multiple/meson.build
@@ -0,0 +1,37 @@
+project('linkcustom', 'c')
+
+# This would require passing the static linker to the build script or having
+# it detect it by itself. I'm too lazy to implement it now and it is not
+# really needed for testing that custom targets work. It is the responsibility
+# of the custom target to produce things in the correct format.
+assert(not meson.is_cross_build(),
+ 'MESON_SKIP_TEST cross checking not implemented.')
+
+cc = meson.get_compiler('c')
+genprog = find_program('generate_stlibs.py')
+
+clib = custom_target('linkcustom',
+ output: ['libflob_1.a', 'libflob_2.a'],
+ command: [genprog,
+ '-o', '@OUTPUT@',
+ '--private-dir', '@PRIVATE_DIR@'] + cc.cmd_array())
+
+clibs = [clib[0], clib[1]]
+
+exe = executable('prog', 'prog.c', link_with: clibs)
+test('linkcustom', exe)
+
+d = declare_dependency(link_with: clibs)
+
+exe2 = executable('prog2', 'prog.c', dependencies: d)
+test('linkcustom2', exe2)
+
+# Link whole tests
+
+exe3 = executable('prog3', 'prog.c', link_whole: clibs)
+test('linkwhole', exe)
+
+d2 = declare_dependency(link_whole: clibs)
+
+exe4 = executable('prog4', 'prog.c', dependencies: d2)
+test('linkwhole2', exe2)
diff --git a/test cases/common/218 link custom_i multiple from multiple/prog.c b/test cases/common/218 link custom_i multiple from multiple/prog.c
new file mode 100644
index 0000000..51effe6
--- /dev/null
+++ b/test cases/common/218 link custom_i multiple from multiple/prog.c
@@ -0,0 +1,8 @@
+void flob_1();
+void flob_2();
+
+int main(int argc, char **argv) {
+ flob_1();
+ flob_2();
+ return 0;
+}
diff --git a/test cases/fortran/14 fortran links c/clib.c b/test cases/fortran/14 fortran links c/clib.c
new file mode 100644
index 0000000..81b2e0c
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/clib.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void hello(void){
+
+ printf("hello from C\n");
+
+}
diff --git a/test cases/fortran/14 fortran links c/f_call_c.f90 b/test cases/fortran/14 fortran links c/f_call_c.f90
new file mode 100644
index 0000000..af1e79c
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/f_call_c.f90
@@ -0,0 +1,10 @@
+implicit none
+
+interface
+subroutine hello() bind (c)
+end subroutine hello
+end interface
+
+call hello()
+
+end program
diff --git a/test cases/fortran/14 fortran links c/meson.build b/test cases/fortran/14 fortran links c/meson.build
new file mode 100644
index 0000000..163aec6
--- /dev/null
+++ b/test cases/fortran/14 fortran links c/meson.build
@@ -0,0 +1,13 @@
+project('Fortran calling C', 'fortran', 'c')
+
+ccid = meson.get_compiler('c').get_id()
+if ccid == 'msvc' or ccid == 'clang-cl'
+ error('MESON_SKIP_TEST: MSVC and GCC do not interoperate like this.')
+endif
+
+c_lib = library('clib', 'clib.c')
+
+f_call_c = executable('f_call_c', 'f_call_c.f90',
+ link_with: c_lib,
+ link_language: 'fortran')
+test('Fortran calling C', f_call_c)
diff --git a/test cases/objc/2 nsstring/meson.build b/test cases/objc/2 nsstring/meson.build
index 7f2483f..94d2cf1 100644
--- a/test cases/objc/2 nsstring/meson.build
+++ b/test cases/objc/2 nsstring/meson.build
@@ -15,3 +15,6 @@ else
endif
exe = executable('stringprog', 'stringprog.m', dependencies : dep)
test('stringtest', exe)
+
+# Ensure that a non-required dep that is not found does not cause an error
+dependency('appleframeworks', modules: 'nonexisting', required: false)
diff --git a/test cases/unit/4 suite selection/meson.build b/test cases/unit/4 suite selection/meson.build
index d3d4e1a..ea6db92 100644
--- a/test cases/unit/4 suite selection/meson.build
+++ b/test cases/unit/4 suite selection/meson.build
@@ -11,3 +11,7 @@ test('mainprj-failing_test',
test('mainprj-successful_test',
executable('successful_test', 'successful_test.c'),
suite : 'success')
+
+test('mainprj-successful_test_no_suite',
+ executable('no_suite_test', 'successful_test.c'),
+ suite : [])
diff --git a/test cases/unit/4 suite selection/subprojects/subprjfail/meson.build b/test cases/unit/4 suite selection/subprojects/subprjfail/meson.build
index d95f271..e6270a8 100644
--- a/test cases/unit/4 suite selection/subprojects/subprjfail/meson.build
+++ b/test cases/unit/4 suite selection/subprojects/subprjfail/meson.build
@@ -3,3 +3,7 @@ project('subprjfail', 'c')
test('subprjfail-failing_test',
executable('failing_test', 'failing_test.c'),
suite : 'fail')
+
+test('subprjfail-failing_test_no_suite',
+ executable('failing_test_no_suite', 'failing_test.c'),
+ suite : [])
diff --git a/test cases/unit/4 suite selection/subprojects/subprjsucc/meson.build b/test cases/unit/4 suite selection/subprojects/subprjsucc/meson.build
index 8dafd65..b5ffaa4 100644
--- a/test cases/unit/4 suite selection/subprojects/subprjsucc/meson.build
+++ b/test cases/unit/4 suite selection/subprojects/subprjsucc/meson.build
@@ -3,3 +3,7 @@ project('subprjsucc', 'c')
test('subprjsucc-successful_test',
executable('successful_test', 'successful_test.c'),
suite : 'success')
+
+test('subprjsucc-successful_test_no_suite',
+ executable('successful_test_no_suite', 'successful_test.c'),
+ suite : [])