aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Reference-manual.md35
-rw-r--r--docs/markdown/snippets/dependency_version.md14
-rw-r--r--docs/markdown/snippets/native_args.md34
-rwxr-xr-xghwt.py5
-rwxr-xr-xmanual tests/4 standalone binaries/build_windows_package.py2
-rw-r--r--mesonbuild/backend/backends.py14
-rw-r--r--mesonbuild/backend/ninjabackend.py22
-rw-r--r--mesonbuild/backend/vs2010backend.py4
-rw-r--r--mesonbuild/build.py25
-rw-r--r--mesonbuild/compilers/c.py116
-rw-r--r--mesonbuild/compilers/compilers.py51
-rw-r--r--mesonbuild/compilers/d.py2
-rw-r--r--mesonbuild/compilers/fortran.py14
-rw-r--r--mesonbuild/coredata.py8
-rw-r--r--mesonbuild/dependencies/base.py155
-rw-r--r--mesonbuild/dependencies/boost.py2
-rw-r--r--mesonbuild/dependencies/dev.py2
-rw-r--r--mesonbuild/dependencies/misc.py21
-rw-r--r--mesonbuild/dependencies/platform.py6
-rw-r--r--mesonbuild/dependencies/ui.py8
-rw-r--r--mesonbuild/environment.py6
-rw-r--r--mesonbuild/interpreter.py153
-rw-r--r--mesonbuild/mconf.py5
-rw-r--r--mesonbuild/mesonmain.py12
-rw-r--r--mesonbuild/minstall.py14
-rw-r--r--mesonbuild/mintro.py3
-rw-r--r--mesonbuild/mlog.py3
-rw-r--r--mesonbuild/modules/windows.py27
-rw-r--r--mesonbuild/wrap/__init__.py9
-rw-r--r--mesonbuild/wrap/wrap.py7
-rw-r--r--mesonbuild/wrap/wraptool.py4
-rwxr-xr-xrun_tests.py36
-rwxr-xr-xrun_unittests.py102
-rw-r--r--test cases/common/190 openmp/meson.build3
-rw-r--r--test cases/common/206 subproject with features/meson.build17
-rw-r--r--test cases/common/206 subproject with features/meson_options.txt3
-rw-r--r--test cases/common/206 subproject with features/nothing.c4
-rw-r--r--test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build3
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build3
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c5
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h6
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build3
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/lib/meson.build2
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/lib/sub.c5
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/lib/sub.h6
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/meson.build3
-rw-r--r--test cases/common/21 global arg/meson.build11
-rw-r--r--test cases/common/21 global arg/prog.c36
-rw-r--r--test cases/failing/81 framework dependency with version/meson.build4
-rw-r--r--test cases/failing/82 gl dependency with version/meson.build9
-rw-r--r--test cases/failing/83 threads dependency with version/meson.build3
-rw-r--r--test cases/failing/84 gtest dependency with version/meson.build3
-rw-r--r--test cases/frameworks/1 boost/meson.build3
-rw-r--r--test cases/frameworks/15 llvm/meson.build3
-rw-r--r--test cases/frameworks/16 sdl2/meson.build4
-rw-r--r--test cases/frameworks/17 mpi/meson.build3
-rw-r--r--test cases/frameworks/18 vulkan/meson.build3
-rw-r--r--test cases/frameworks/19 pcap/meson.build4
-rw-r--r--test cases/frameworks/20 cups/meson.build4
-rw-r--r--test cases/frameworks/21 libwmf/meson.build4
-rw-r--r--test cases/frameworks/4 qt/meson.build4
-rw-r--r--test cases/frameworks/9 wxwidgets/meson.build4
-rw-r--r--test cases/python3/2 extmodule/meson.build4
-rw-r--r--test cases/unit/39 external, internal library rpath/built library/meson.build13
-rw-r--r--test cases/unit/39 external, internal library rpath/external library/bar.c6
-rw-r--r--test cases/unit/39 external, internal library rpath/external library/meson.build17
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build5
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c6
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc11
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c3
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc11
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build5
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c6
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc11
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c3
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc11
-rw-r--r--test cases/windows/15 resource scripts with duplicate filenames/meson.build2
77 files changed, 868 insertions, 332 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 3ae740d..6d2b2da 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -13,13 +13,22 @@ afterwards](#returned-objects).
void add_global_arguments(arg1, arg2, ...)
```
-Adds the positional arguments to the compiler command line for the
-language specified in `language` keyword argument. If a list of
-languages is given, the arguments are added to each of the
-corresponding compiler command lines. Note that there is no way to
-remove an argument set in this way. If you have an argument that is
-only used in a subset of targets, you have to specify it in per-target
-flags.
+Adds the positional arguments to the compiler command line. This
+function has two keyword arguments:
+
+- `language` specifies the language(s) that the arguments should be
+applied to. If a list of languages is given, the arguments are added
+to each of the corresponding compiler command lines. Note that there
+is no way to remove an argument set in this way. If you have an
+argument that is only used in a subset of targets, you have to specify
+it in per-target flags.
+
+- `native` is a boolean specifying whether the arguments should be
+ applied to the native or cross compilation. If `true` the arguments
+ will only be used for native compilations. If `false` the arguments
+ will only be used in cross compilations. If omitted, the flags are
+ added to native compilations if compiling natively and cross
+ compilations (only) when cross compiling. Available since 0.48.0
The arguments are used in all compiler invocations with the exception
of compile tests, because you might need to run a compile test with
@@ -60,8 +69,9 @@ endif
Takes one keyword argument, `required`. It defaults to `true`, which
means that if any of the languages specified is not found, Meson will
halt. Returns true if all languages specified were found and false
-otherwise. Since *0.47.0* the value of a [`feature`](Build-options.md#features)
-option can also be passed to the `required` keyword argument.
+otherwise. Since *0.47.0* the value of a
+[`feature`](Build-options.md#features) option can also be passed to
+the `required` keyword argument.
### add_project_arguments()
@@ -370,11 +380,12 @@ otherwise. This function supports the following keyword arguments:
- `static` tells the dependency provider to try to get static
libraries instead of dynamic ones (note that this is not supported
by all dependency backends)
-- `version`, specifies the required version, a string containing a
+- `version` specifies the required version, a string containing a
comparison operator followed by the version string, examples include
`>1.0.0`, `<=2.3.5` or `3.1.4` for exact matching. (*Added 0.37.0*)
You can also specify multiple restrictions by passing a list to this
keyword argument, such as: `['>=3.14.0', '<=4.1.0']`.
+ These requirements are never met if the version is unknown.
- other
[library-specific](Dependencies.md#dependencies-with-custom-lookup-functionality)
keywords may also be accepted (e.g. `modules` specifies submodules to use for
@@ -1976,7 +1987,9 @@ an external dependency with the following methods:
with `declare_dependency()` and `pkgconfig` for system dependencies
obtained with Pkg-config.
- - `version()` is the version number as a string, for example `1.2.8`
+ - `version()` is the version number as a string, for example `1.2.8`.
+ `unknown` if the dependency provider doesn't support determining the
+ version.
- `partial_dependency(compile_args : false, link_args : false, links
: false, includes : false, source : false)` (*added 0.46.0*) returns
diff --git a/docs/markdown/snippets/dependency_version.md b/docs/markdown/snippets/dependency_version.md
new file mode 100644
index 0000000..4bbf346
--- /dev/null
+++ b/docs/markdown/snippets/dependency_version.md
@@ -0,0 +1,14 @@
+## `dependency(version:)` now applies to all dependency types
+
+Previously, version constraints were only enforced for dependencies found using
+the pkg-config dependency provider. These constraints now apply to dependencies
+found using any dependency provider.
+
+Some combinations of dependency, host and method do not currently support
+discovery of the version. In these cases, the dependency will not be found if a
+version constraint is applied, otherwise the `version()` method for the
+dependency object will return `'unknown'`.
+
+(If discovering the version in one of these combinations is important to you,
+and a method exists to determine the version in that case, please file an issue
+with as much information as possible.)
diff --git a/docs/markdown/snippets/native_args.md b/docs/markdown/snippets/native_args.md
new file mode 100644
index 0000000..54c6de2
--- /dev/null
+++ b/docs/markdown/snippets/native_args.md
@@ -0,0 +1,34 @@
+## Projects args can be set separately for cross and native builds (potentially breaking change)
+
+It has been a longstanding bug (or let's call it a "delayed bug fix")
+that if yo do this:
+
+```meson
+add_project_arguments('-DFOO', language : 'c')
+```
+
+Then the flag is used both in native and cross compilations. This is
+very confusing and almost never what you want. To fix this a new
+keyword `native` has been added to all functions that add arguments,
+namely `add_global_arguments`, `add_global_link_arguments`,
+`add_project_arguments` and `add_project_link_arguments` that behaves
+like the following:
+
+```
+## Added to native builds when compiling natively and to cross
+## compilations when doing cross compiles.
+add_project_arguments(...)
+
+## Added only to native compilations, not used in cross compilations.
+add_project_arguments(..., native : true)
+
+## Added only to cross compilations, not used in native compilations.
+add_project_arguments(..., native : false)
+```
+
+Also remember that cross compilation is a property of each
+target. There can be target that are compiled with the native compiler
+and some which are compiled with the cross compiler.
+
+Unfortunately this change is backwards incompatible and may cause some
+projects to fail building. However this should be very rare in practice.
diff --git a/ghwt.py b/ghwt.py
index 32db4be..cc79ce7 100755
--- a/ghwt.py
+++ b/ghwt.py
@@ -22,10 +22,11 @@
import urllib.request, json, sys, os, shutil, subprocess
import configparser, hashlib
+req_timeout = 600.0
private_repos = {'meson', 'wrapweb', 'meson-ci'}
def gh_get(url):
- r = urllib.request.urlopen(url)
+ r = urllib.request.urlopen(url, timeout=req_timeout)
jd = json.loads(r.read().decode('utf-8'))
return jd
@@ -45,7 +46,7 @@ def unpack(sproj, branch, outdir):
config = configparser.ConfigParser()
config.read(usfile)
us_url = config['wrap-file']['source_url']
- us = urllib.request.urlopen(us_url).read()
+ us = urllib.request.urlopen(us_url, timeout=req_timeout).read()
h = hashlib.sha256()
h.update(us)
dig = h.hexdigest()
diff --git a/manual tests/4 standalone binaries/build_windows_package.py b/manual tests/4 standalone binaries/build_windows_package.py
index b30ec4d..0932eac 100755
--- a/manual tests/4 standalone binaries/build_windows_package.py
+++ b/manual tests/4 standalone binaries/build_windows_package.py
@@ -11,7 +11,7 @@ shutil.rmtree('build', ignore_errors=True)
os.mkdir('build')
if not os.path.exists(sdl_filename):
- response = urllib.request.urlopen(sdl_url)
+ response = urllib.request.urlopen(sdl_url, timeout=600.0)
data = response.read()
open(sdl_filename, 'wb').write(data)
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 7ed97b2..bdc3fad 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -355,9 +355,9 @@ class Backend:
return l, stdlib_args
@staticmethod
- def _libdir_is_system(libdir, compilers):
+ def _libdir_is_system(libdir, compilers, env):
for cc in compilers.values():
- if libdir in cc.get_library_dirs():
+ if libdir in cc.get_library_dirs(env):
return True
return False
@@ -372,7 +372,7 @@ class Backend:
# The only link argument is an absolute path to a library file.
libpath = la[0]
libdir = os.path.dirname(libpath)
- if exclude_system and self._libdir_is_system(libdir, target.compilers):
+ if exclude_system and self._libdir_is_system(libdir, target.compilers, self.environment):
# No point in adding system paths.
continue
# Windows doesn't support rpaths, but we use this function to
@@ -535,10 +535,10 @@ class Backend:
commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target))
commands += compiler.get_debug_args(self.get_option_for_target('debug', target))
# Add compile args added using add_project_arguments()
- commands += self.build.get_project_args(compiler, target.subproject)
+ commands += self.build.get_project_args(compiler, target.subproject, target.is_cross)
# Add compile args added using add_global_arguments()
# These override per-project arguments
- commands += self.build.get_global_args(compiler)
+ commands += self.build.get_global_args(compiler, target.is_cross)
if not target.is_cross:
# Compile args added from the env: CFLAGS/CXXFLAGS, etc. We want these
# to override all the defaults, but not the per-target compile args.
@@ -612,8 +612,8 @@ class Backend:
# Get program and library dirs from all target compilers
if isinstance(target, build.BuildTarget):
for cc in target.compilers.values():
- paths.update(cc.get_program_dirs())
- paths.update(cc.get_library_dirs())
+ paths.update(cc.get_program_dirs(self.environment))
+ paths.update(cc.get_library_dirs(self.environment))
return list(paths)
def determine_windows_extra_paths(self, target, extra_bdeps, is_cross=False):
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 6b2b130..acbeed3 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -855,8 +855,8 @@ int dummy;
for dep in target.get_external_deps():
commands.extend_direct(dep.get_link_args())
- commands += self.build.get_project_args(compiler, target.subproject)
- commands += self.build.get_global_args(compiler)
+ commands += self.build.get_project_args(compiler, target.subproject, target.is_cross)
+ commands += self.build.get_global_args(compiler, target.is_cross)
elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs)
elem.add_dep(deps)
@@ -869,8 +869,8 @@ int dummy;
deps = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets]
args = []
args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target))
- args += self.build.get_global_args(compiler)
- args += self.build.get_project_args(compiler, target.subproject)
+ args += self.build.get_global_args(compiler, target.is_cross)
+ args += self.build.get_project_args(compiler, target.subproject, target.is_cross)
args += target.get_java_args()
args += compiler.get_output_args(self.get_target_private_dir(target))
args += target.get_classpath_args()
@@ -1247,8 +1247,8 @@ int dummy;
compile_args += swiftc.get_optimization_args(self.get_option_for_target('optimization', target))
compile_args += swiftc.get_debug_args(self.get_option_for_target('debug', target))
compile_args += swiftc.get_module_args(module_name)
- compile_args += self.build.get_project_args(swiftc, target.subproject)
- compile_args += self.build.get_global_args(swiftc)
+ compile_args += self.build.get_project_args(swiftc, target.subproject, target.is_cross)
+ compile_args += self.build.get_global_args(swiftc, target.is_cross)
for i in reversed(target.get_include_dirs()):
basedir = i.get_curdir()
for d in i.get_incdirs():
@@ -1260,8 +1260,8 @@ int dummy;
sargs = swiftc.get_include_args(srctreedir)
compile_args += sargs
link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)))
- link_args += self.build.get_project_link_args(swiftc, target.subproject)
- link_args += self.build.get_global_link_args(swiftc)
+ link_args += self.build.get_project_link_args(swiftc, target.subproject, target.is_cross)
+ link_args += self.build.get_global_link_args(swiftc, target.is_cross)
rundir = self.get_target_private_dir(target)
out_module_name = self.swift_module_file_name(target)
in_module_files = self.determine_swift_dep_modules(target)
@@ -2333,7 +2333,7 @@ rule FORTRAN_DEP_HACK%s
guessed_dependencies = []
# TODO The get_library_naming requirement currently excludes link targets that use d or fortran as their main linker
if hasattr(linker, 'get_library_naming'):
- search_dirs = list(search_dirs) + linker.get_library_dirs()
+ search_dirs = list(search_dirs) + linker.get_library_dirs(self.environment)
static_patterns = linker.get_library_naming(self.environment, 'static', strict=True)
shared_patterns = linker.get_library_naming(self.environment, 'shared', strict=True)
for libname in libs:
@@ -2395,10 +2395,10 @@ rule FORTRAN_DEP_HACK%s
if not isinstance(target, build.StaticLibrary):
# Add link args added using add_project_link_arguments()
- commands += self.build.get_project_link_args(linker, target.subproject)
+ commands += self.build.get_project_link_args(linker, target.subproject, target.is_cross)
# Add link args added using add_global_link_arguments()
# These override per-project link arguments
- commands += self.build.get_global_link_args(linker)
+ commands += self.build.get_global_link_args(linker, target.is_cross)
if not target.is_cross:
# Link args added from the env: LDFLAGS. We want these to
# override all the defaults but not the per-target link args.
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 4c799d0..2e86ca9 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -998,10 +998,10 @@ class Vs2010Backend(backends.Backend):
options = self.environment.coredata.base_options
extra_link_args += compiler.get_std_shared_module_link_args(options)
# Add link args added using add_project_link_arguments()
- extra_link_args += self.build.get_project_link_args(compiler, target.subproject)
+ extra_link_args += self.build.get_project_link_args(compiler, target.subproject, target.is_cross)
# Add link args added using add_global_link_arguments()
# These override per-project link arguments
- extra_link_args += self.build.get_global_link_args(compiler)
+ extra_link_args += self.build.get_global_link_args(compiler, target.is_cross)
if not target.is_cross:
# Link args added from the env: LDFLAGS. We want these to
# override all the defaults but not the per-target link args.
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 96c64b8..b34ae2f 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -108,6 +108,10 @@ class Build:
self.projects_args = {}
self.global_link_args = {}
self.projects_link_args = {}
+ self.cross_global_args = {}
+ self.cross_projects_args = {}
+ self.cross_global_link_args = {}
+ self.cross_projects_link_args = {}
self.tests = []
self.benchmarks = []
self.headers = []
@@ -168,20 +172,25 @@ class Build:
def get_install_subdirs(self):
return self.install_dirs
- def get_global_args(self, compiler):
- return self.global_args.get(compiler.get_language(), [])
+ def get_global_args(self, compiler, for_cross):
+ d = self.cross_global_args if for_cross else self.global_args
+ return d.get(compiler.get_language(), [])
- def get_project_args(self, compiler, project):
- args = self.projects_args.get(project)
+ def get_project_args(self, compiler, project, for_cross):
+ d = self.cross_projects_args if for_cross else self.projects_args
+ args = d.get(project)
if not args:
return []
return args.get(compiler.get_language(), [])
- def get_global_link_args(self, compiler):
- return self.global_link_args.get(compiler.get_language(), [])
+ def get_global_link_args(self, compiler, for_cross):
+ d = self.cross_global_link_args if for_cross else self.global_link_args
+ return d.get(compiler.get_language(), [])
- def get_project_link_args(self, compiler, project):
- link_args = self.projects_link_args.get(project)
+ def get_project_link_args(self, compiler, project, for_cross):
+ d = self.cross_projects_link_args if for_cross else self.projects_link_args
+
+ link_args = d.get(project)
if not link_args:
return []
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index c7092b8..436f699 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -16,6 +16,8 @@ import re
import glob
import os.path
import subprocess
+import functools
+import itertools
from pathlib import Path
from .. import mlog
@@ -49,6 +51,7 @@ gnu_compiler_internal_libs = ('m', 'c', 'pthread', 'dl', 'rt')
class CCompiler(Compiler):
+ # TODO: Replace this manual cache with functools.lru_cache
library_dirs_cache = {}
program_dirs_cache = {}
find_library_cache = {}
@@ -144,6 +147,30 @@ class CCompiler(Compiler):
'''
return self.get_no_optimization_args()
+ def get_allow_undefined_link_args(self):
+ '''
+ Get args for allowing undefined symbols when linking to a shared library
+ '''
+ if self.id == 'clang':
+ if self.clang_type == compilers.CLANG_OSX:
+ # Apple ld
+ return ['-Wl,-undefined,dynamic_lookup']
+ else:
+ # GNU ld and LLVM lld
+ return ['-Wl,--allow-shlib-undefined']
+ elif self.id == 'gcc':
+ if self.gcc_type == compilers.GCC_OSX:
+ # Apple ld
+ return ['-Wl,-undefined,dynamic_lookup']
+ else:
+ # GNU ld and LLVM lld
+ return ['-Wl,--allow-shlib-undefined']
+ elif self.id == 'msvc':
+ # link.exe
+ return ['/FORCE:UNRESOLVED']
+ # FIXME: implement other linkers
+ return []
+
def get_output_args(self, target):
return ['-o', target]
@@ -172,42 +199,47 @@ class CCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return ['-shared']
- def get_library_dirs_real(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ @functools.lru_cache()
+ def _get_search_dirs(self, env):
+ extra_args = ['--print-search-dirs']
+ stdo = None
+ with self._build_wrapper('', env, extra_args, None, 'compile', True) as p:
+ stdo = p.stdo
+ return stdo
+
+ @staticmethod
+ def _split_fetch_real_dirs(pathstr, sep=':'):
paths = []
- for line in stdo.split('\n'):
- if line.startswith('libraries:'):
- libstr = line.split('=', 1)[1]
- paths = [os.path.realpath(p) for p in libstr.split(':') if os.path.exists(os.path.realpath(p))]
+ for p in pathstr.split(sep):
+ p = Path(p)
+ if p.exists():
+ paths.append(p.resolve().as_posix())
return paths
- def get_library_dirs(self):
- key = tuple(self.exelist)
+ def get_compiler_dirs(self, env, name):
+ '''
+ Get dirs from the compiler, either `libraries:` or `programs:`
+ '''
+ stdo = self._get_search_dirs(env)
+ for line in stdo.split('\n'):
+ if line.startswith(name + ':'):
+ return CCompiler._split_fetch_real_dirs(line.split('=', 1)[1])
+ return []
+
+ def get_library_dirs(self, env):
+ key = (tuple(self.exelist), env)
if key not in self.library_dirs_cache:
- self.library_dirs_cache[key] = self.get_library_dirs_real()
+ self.library_dirs_cache[key] = self.get_compiler_dirs(env, 'libraries')
return self.library_dirs_cache[key][:]
- def get_program_dirs_real(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
- paths = []
- for line in stdo.split('\n'):
- if line.startswith('programs:'):
- libstr = line.split('=', 1)[1]
- paths = [os.path.realpath(p) for p in libstr.split(':')]
- return paths
-
- def get_program_dirs(self):
+ def get_program_dirs(self, env):
'''
Programs used by the compiler. Also where toolchain DLLs such as
libstdc++-6.dll are found with MinGW.
'''
- key = tuple(self.exelist)
+ key = (tuple(self.exelist), env)
if key not in self.program_dirs_cache:
- self.program_dirs_cache[key] = self.get_program_dirs_real()
+ self.program_dirs_cache[key] = self.get_compiler_dirs(env, 'programs')
return self.program_dirs_cache[key][:]
def get_pic_args(self):
@@ -908,7 +940,8 @@ class CCompiler(Compiler):
# Only try to find std libs if no extra dirs specified.
if not extra_dirs or libname in self.internal_libs:
args = ['-l' + libname]
- if self.links(code, env, extra_args=args):
+ largs = self.linker_to_compiler_args(self.get_allow_undefined_link_args())
+ if self.links(code, env, extra_args=(args + largs)):
return args
# Don't do a manual search for internal libs
if libname in self.internal_libs:
@@ -916,35 +949,19 @@ class CCompiler(Compiler):
# Not found or we want to use a specific libtype? Try to find the
# library file itself.
patterns = self.get_library_naming(env, libtype)
- for d in extra_dirs:
+ # Search in the specified dirs, and then in the system libraries
+ for d in itertools.chain(extra_dirs, self.get_library_dirs(env)):
for p in patterns:
trial = self._get_trials_from_pattern(p, d, libname)
if not trial:
continue
+ # We just check whether the library exists. We can't do a link
+ # check because the library might have unresolved symbols that
+ # require other libraries.
trial = self._get_file_from_list(trial)
if not trial:
continue
return [trial]
- # Search in the system libraries too
- for d in self.get_library_dirs():
- for p in patterns:
- trial = self._get_trials_from_pattern(p, d, libname)
- if not trial:
- continue
- trial = self._get_file_from_list(trial)
- if not trial:
- continue
- # When searching the system paths used by the compiler, we
- # need to check linking with link-whole, as static libs
- # (.a) need to be checked to ensure they are the right
- # architecture, e.g. 32bit or 64-bit.
- # Just a normal test link won't work as the .a file doesn't
- # seem to be checked by linker if there are no unresolved
- # symbols from the main C file.
- extra_link_args = self.get_link_whole_for([trial])
- extra_link_args = self.linker_to_compiler_args(extra_link_args)
- if self.links(code, env, extra_args=extra_link_args):
- return [trial]
return None
def find_library_impl(self, libname, env, extra_dirs, code, libtype):
@@ -1230,7 +1247,10 @@ class VisualStudioCCompiler(CCompiler):
return ['/MDd']
def get_buildtype_args(self, buildtype):
- return compilers.msvc_buildtype_args[buildtype]
+ args = compilers.msvc_buildtype_args[buildtype]
+ if version_compare(self.version, '<18.0'):
+ args = [arg for arg in args if arg != '/Gw']
+ return args
def get_buildtype_linker_args(self, buildtype):
return compilers.msvc_buildtype_linker_args[buildtype]
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 47c222d..352c49e 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -145,8 +145,8 @@ arm_buildtype_args = {'plain': [],
msvc_buildtype_args = {'plain': [],
'debug': ["/ZI", "/Ob0", "/Od", "/RTC1"],
'debugoptimized': ["/Zi", "/Ob1"],
- 'release': ["/Ob2"],
- 'minsize': ["/Zi", "/Ob1"],
+ 'release': ["/Ob2", "/Gw"],
+ 'minsize': ["/Zi", "/Gw"],
}
apple_buildtype_linker_args = {'plain': [],
@@ -267,7 +267,7 @@ msvc_optimization_args = {'0': [],
'1': ['/O1'],
'2': ['/O2'],
'3': ['/O3'],
- 's': ['/Os'],
+ 's': ['/O1'], # Implies /Os.
}
clike_debug_args = {False: [],
@@ -611,27 +611,32 @@ class CompilerArgs(list):
return True
return False
- def to_native(self):
+ def to_native(self, copy=False):
# Check if we need to add --start/end-group for circular dependencies
# between static libraries, and for recursively searching for symbols
# needed by static libraries that are provided by object files or
# shared libraries.
+ if copy:
+ new = self.copy()
+ else:
+ new = self
if get_compiler_uses_gnuld(self.compiler):
global soregex
group_start = -1
- for each in self:
+ group_end = -1
+ for i, each in enumerate(new):
if not each.startswith('-l') and not each.endswith('.a') and \
not soregex.match(each):
continue
- i = self.index(each)
+ group_end = i
if group_start < 0:
# First occurrence of a library
group_start = i
if group_start >= 0:
# Last occurrence of a library
- self.insert(i + 1, '-Wl,--end-group')
- self.insert(group_start, '-Wl,--start-group')
- return self.compiler.unix_args_to_native(self)
+ new.insert(group_end + 1, '-Wl,--end-group')
+ new.insert(group_start, '-Wl,--start-group')
+ return self.compiler.unix_args_to_native(new)
def append_direct(self, arg):
'''
@@ -867,11 +872,11 @@ class Compiler:
self.language + '_args': coredata.UserArrayOption(
self.language + '_args',
description + ' compiler',
- compile_args, shlex_split=True, user_input=True),
+ compile_args, shlex_split=True, user_input=True, allow_dups=True),
self.language + '_link_args': coredata.UserArrayOption(
self.language + '_link_args',
description + ' linker',
- link_args, shlex_split=True, user_input=True),
+ link_args, shlex_split=True, user_input=True, allow_dups=True),
})
return opts
@@ -917,7 +922,7 @@ class Compiler:
def find_library(self, *args, **kwargs):
raise EnvironmentException('Language {} does not support library finding.'.format(self.get_display_language()))
- def get_library_dirs(self):
+ def get_library_dirs(self, *args, **kwargs):
return []
def has_multi_arguments(self, args, env):
@@ -1004,7 +1009,9 @@ class Compiler:
mlog.debug('Working directory: ', tmpdirname)
mlog.debug('Command line: ', ' '.join(commands), '\n')
mlog.debug('Code:\n', code)
- p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname)
+ os_env = os.environ.copy()
+ os_env['LC_ALL'] = 'C'
+ p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname, env=os_env)
mlog.debug('Compiler stdout:\n', p.stdo)
mlog.debug('Compiler stderr:\n', p.stde)
p.commands = commands
@@ -1362,10 +1369,12 @@ class ElbrusCompiler(GnuCompiler):
'b_ndebug', 'b_staticpic',
'b_lundef', 'b_asneeded']
- def get_library_dirs(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ # FIXME: use _build_wrapper to call this so that linker flags from the env
+ # get applied
+ def get_library_dirs(self, env):
+ os_env = os.environ.copy()
+ os_env['LC_ALL'] = 'C'
+ stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=os_env)[1]
paths = []
for line in stdo.split('\n'):
if line.startswith('libraries:'):
@@ -1375,10 +1384,10 @@ class ElbrusCompiler(GnuCompiler):
break
return paths
- def get_program_dirs(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ def get_program_dirs(self, env):
+ os_env = os.environ.copy()
+ os_env['LC_ALL'] = 'C'
+ stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=os_env)[1]
paths = []
for line in stdo.split('\n'):
if line.startswith('programs:'):
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 7d682ec..a03af3e 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -269,7 +269,7 @@ class DCompiler(Compiler):
continue
dcargs.append('-L' + la.strip())
continue
- elif arg.startswith('-install-name'):
+ elif arg.startswith('-install_name'):
dcargs.append('-L' + arg)
continue
elif arg.startswith('-link-defaultlib') or arg.startswith('-linker'):
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index 5648a6f..1ee1fcb 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -144,6 +144,9 @@ end program prog
def get_compiler_check_args(self):
return CCompiler.get_compiler_check_args(self)
+ def get_allow_undefined_link_args(self):
+ return CCompiler.get_allow_undefined_link_args(self)
+
def get_output_args(self, target):
return CCompiler.get_output_args(self, target)
@@ -177,11 +180,14 @@ end program prog
def get_std_shared_lib_link_args(self):
return CCompiler.get_std_shared_lib_link_args(self)
- def get_library_dirs_real(self):
- return CCompiler.get_library_dirs_real(self)
+ def _get_search_dirs(self, *args, **kwargs):
+ return CCompiler._get_search_dirs(self, *args, **kwargs)
+
+ def get_compiler_dirs(self, *args, **kwargs):
+ return CCompiler.get_compiler_dirs(self, *args, **kwargs)
- def get_library_dirs(self):
- return CCompiler.get_library_dirs(self)
+ def get_library_dirs(self, *args, **kwargs):
+ return CCompiler.get_library_dirs(self, *args, **kwargs)
def get_pic_args(self):
return CCompiler.get_pic_args(self)
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 7520e06..4b32c19 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -19,6 +19,7 @@ from pathlib import PurePath
from collections import OrderedDict
from .mesonlib import MesonException
from .mesonlib import default_libdir, default_libexecdir, default_prefix
+from .wrap import WrapMode
import ast
import argparse
@@ -138,9 +139,10 @@ class UserComboOption(UserOption):
return value
class UserArrayOption(UserOption):
- def __init__(self, name, description, value, shlex_split=False, user_input=False, **kwargs):
+ def __init__(self, name, description, value, shlex_split=False, user_input=False, allow_dups=False, **kwargs):
super().__init__(name, description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None))
self.shlex_split = shlex_split
+ self.allow_dups = allow_dups
self.value = self.validate_value(value, user_input=user_input)
def validate_value(self, value, user_input=True):
@@ -166,7 +168,7 @@ class UserArrayOption(UserOption):
else:
raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
- if len(set(newvalue)) != len(newvalue):
+ if not self.allow_dups and len(set(newvalue)) != len(newvalue):
msg = 'Duplicated values in array option "%s" is deprecated. ' \
'This will become a hard error in the future.' % (self.name)
mlog.deprecation(msg)
@@ -221,7 +223,7 @@ class CoreData:
self.base_options = {}
self.external_preprocess_args = {} # CPPFLAGS only
self.cross_file = self.__load_cross_file(options.cross_file)
- self.wrap_mode = options.wrap_mode
+ self.wrap_mode = options.wrap_mode if options.wrap_mode is not None else WrapMode.default
self.compilers = OrderedDict()
self.cross_compilers = OrderedDict()
self.deps = OrderedDict()
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 20ba06c..04c4701 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -98,7 +98,7 @@ class Dependency:
def __init__(self, type_name, kwargs):
self.name = "null"
- self.version = 'none'
+ self.version = None
self.language = None # None means C-like
self.is_found = False
self.type_name = type_name
@@ -138,7 +138,10 @@ class Dependency:
return self.name
def get_version(self):
- return self.version
+ if self.version:
+ return self.version
+ else:
+ return 'unknown'
def get_exe_args(self, compiler):
return []
@@ -218,6 +221,8 @@ class ExternalDependency(Dependency):
self.is_found = False
self.language = language
self.version_reqs = kwargs.get('version', None)
+ if isinstance(self.version_reqs, str):
+ self.version_reqs = [self.version_reqs]
self.required = kwargs.get('required', True)
self.silent = kwargs.get('silent', False)
self.static = kwargs.get('static', False)
@@ -275,6 +280,41 @@ class ExternalDependency(Dependency):
def log_tried(self):
return ''
+ # Check if dependency version meets the requirements
+ def _check_version(self):
+ if not self.is_found:
+ return
+
+ if self.version_reqs:
+ # an unknown version can never satisfy any requirement
+ if not self.version:
+ found_msg = ['Dependency', mlog.bold(self.name), 'found:']
+ found_msg += [mlog.red('NO'), 'unknown version, but need:',
+ self.version_reqs]
+ mlog.log(*found_msg)
+
+ if self.required:
+ m = 'Unknown version of dependency {!r}, but need {!r}.'
+ raise DependencyException(m.format(self.name, self.version_reqs))
+
+ else:
+ (self.is_found, not_found, found) = \
+ version_compare_many(self.version, self.version_reqs)
+ if not self.is_found:
+ found_msg = ['Dependency', mlog.bold(self.name), 'found:']
+ found_msg += [mlog.red('NO'),
+ 'found {!r} but need:'.format(self.version),
+ ', '.join(["'{}'".format(e) for e in not_found])]
+ if found:
+ found_msg += ['; matched:',
+ ', '.join(["'{}'".format(e) for e in found])]
+ mlog.log(*found_msg)
+
+ if self.required:
+ m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
+ raise DependencyException(m.format(self.name, not_found, self.version))
+ return
+
class NotFoundDependency(Dependency):
def __init__(self, environment):
@@ -375,7 +415,7 @@ class ConfigToolDependency(ExternalDependency):
# don't fail with --version, in that case just assume that there is
# only one version and return it.
if not out:
- return (tool, 'none')
+ return (tool, None)
if versions:
is_found = version_compare_many(out, versions)[0]
# This allows returning a found version without a config tool,
@@ -480,20 +520,6 @@ class PkgConfigDependency(ExternalDependency):
ret, self.version = self._call_pkgbin(['--modversion', name])
if ret != 0:
return
- if self.version_reqs is None:
- self.is_found = True
- else:
- if not isinstance(self.version_reqs, (str, list)):
- raise DependencyException('Version argument must be string or list.')
- if isinstance(self.version_reqs, str):
- self.version_reqs = [self.version_reqs]
- (self.is_found, not_found, found) = \
- version_compare_many(self.version, self.version_reqs)
- if not self.is_found:
- if self.required:
- m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
- raise DependencyException(m.format(name, not_found, self.version))
- return
try:
# Fetch cargs to be used while using this dependency
@@ -509,6 +535,8 @@ class PkgConfigDependency(ExternalDependency):
self.is_found = False
self.reason = e
+ self.is_found = True
+
def __repr__(self):
s = '<{0} {1}: {2} {3}>'
return s.format(self.__class__.__name__, self.name, self.is_found,
@@ -576,29 +604,59 @@ class PkgConfigDependency(ExternalDependency):
self.compile_args = self._convert_mingw_paths(shlex.split(out))
def _search_libs(self, out, out_raw):
- link_args = []
- raw_link_args = []
+ '''
+ @out: PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs
+ @out_raw: pkg-config --libs
+
+ We always look for the file ourselves instead of depending on the
+ compiler to find it with -lfoo or foo.lib (if possible) because:
+ 1. We want to be able to select static or shared
+ 2. We need the full path of the library to calculate RPATH values
+ 3. De-dup of libraries is easier when we have absolute paths
+
+ Libraries that are provided by the toolchain or are not found by
+ find_library() will be added with -L -l pairs.
+ '''
# Library paths should be safe to de-dup
- libpaths = OrderedSet()
- raw_libpaths = OrderedSet()
+ #
+ # First, figure out what library paths to use. Originally, we were
+ # doing this as part of the loop, but due to differences in the order
+ # of -L values between pkg-config and pkgconf, we need to do that as
+ # a separate step. See:
+ # https://github.com/mesonbuild/meson/issues/3951
+ # https://github.com/mesonbuild/meson/issues/4023
+ #
+ # Separate system and prefix paths, and ensure that prefix paths are
+ # always searched first.
+ prefix_libpaths = OrderedSet()
+ # We also store this raw_link_args on the object later
+ raw_link_args = self._convert_mingw_paths(shlex.split(out_raw))
+ for arg in raw_link_args:
+ if arg.startswith('-L') and not arg.startswith(('-L-l', '-L-L')):
+ prefix_libpaths.add(arg[2:])
+ system_libpaths = OrderedSet()
+ full_args = self._convert_mingw_paths(shlex.split(out))
+ for arg in full_args:
+ if arg.startswith(('-L-l', '-L-L')):
+ # These are D language arguments, not library paths
+ continue
+ if arg.startswith('-L') and arg[2:] not in prefix_libpaths:
+ system_libpaths.add(arg[2:])
+ # Use this re-ordered path list for library resolution
+ libpaths = list(prefix_libpaths) + list(system_libpaths)
# Track -lfoo libraries to avoid duplicate work
libs_found = OrderedSet()
# Track not-found libraries to know whether to add library paths
libs_notfound = []
libtype = 'static' if self.static else 'default'
- # We always look for the file ourselves instead of depending on the
- # compiler to find it with -lfoo or foo.lib (if possible) because:
- # 1. We want to be able to select static or shared
- # 2. We need the full path of the library to calculate RPATH values
- #
- # Libraries that are provided by the toolchain or are not found by
- # find_library() will be added with -L -l pairs.
- for lib in self._convert_mingw_paths(shlex.split(out)):
+ # Generate link arguments for this library
+ link_args = []
+ for lib in full_args:
if lib.startswith(('-L-l', '-L-L')):
# These are D language arguments, add them as-is
pass
elif lib.startswith('-L'):
- libpaths.add(lib[2:])
+ # We already handled library paths above
continue
elif lib.startswith('-l'):
# Don't resolve the same -lfoo argument again
@@ -606,7 +664,7 @@ class PkgConfigDependency(ExternalDependency):
continue
if self.clib_compiler:
args = self.clib_compiler.find_library(lib[2:], self.env,
- list(reversed(libpaths)), libtype)
+ libpaths, libtype)
# If the project only uses a non-clib language such as D, Rust,
# C#, Python, etc, all we can do is limp along by adding the
# arguments as-is and then adding the libpaths at the end.
@@ -650,16 +708,11 @@ class PkgConfigDependency(ExternalDependency):
if lib in link_args:
continue
link_args.append(lib)
- # Also store the raw link arguments, and store raw_libpaths
- for lib in self._convert_mingw_paths(shlex.split(out_raw)):
- if lib.startswith('-L') and not lib.startswith(('-L-l', '-L-L')):
- raw_libpaths.add(lib[2:])
- raw_link_args.append(lib)
# Add all -Lbar args if we have -lfoo args in link_args
if libs_notfound:
# Order of -L flags doesn't matter with ld, but it might with other
# linkers such as MSVC, so prepend them.
- link_args = ['-L' + lp for lp in raw_libpaths] + link_args
+ link_args = ['-L' + lp for lp in prefix_libpaths] + link_args
return link_args, raw_link_args
def _set_libs(self):
@@ -837,22 +890,6 @@ class DubDependency(ExternalDependency):
self.pkg = package
break
- # Check if package version meets the requirements
- if self.version_reqs is None:
- self.is_found = True
- else:
- if not isinstance(self.version_reqs, (str, list)):
- raise DependencyException('Version argument must be string or list.')
- if isinstance(self.version_reqs, str):
- self.version_reqs = [self.version_reqs]
- (self.is_found, not_found, found) = \
- version_compare_many(self.version, self.version_reqs)
- if not self.is_found:
- if self.required:
- m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
- raise DependencyException(m.format(name, not_found, self.version))
- return
-
if self.pkg['targetFileName'].endswith('.a'):
self.static = True
@@ -872,9 +909,7 @@ class DubDependency(ExternalDependency):
for file in res:
self.link_args.append(file)
- if not found:
- self.is_found = False
- return
+ self.is_found = found
def get_compiler(self):
return self.compiler
@@ -1216,9 +1251,6 @@ class ExtraFrameworkDependency(ExternalDependency):
self.is_found = True
return
- def get_version(self):
- return 'unknown'
-
def log_info(self):
return os.path.join(self.path, self.name)
@@ -1266,6 +1298,8 @@ def find_external_dependency(name, env, kwargs):
lname = name.lower()
if lname not in _packages_accept_language and 'language' in kwargs:
raise DependencyException('%s dependency does not accept "language" keyword argument' % (name, ))
+ if not isinstance(kwargs.get('version', ''), (str, list)):
+ raise DependencyException('Keyword "Version" must be string or list.')
# display the dependency name with correct casing
display_name = display_name_map.get(lname, lname)
@@ -1288,6 +1322,7 @@ def find_external_dependency(name, env, kwargs):
# try this dependency method
try:
d = c()
+ d._check_version()
pkgdep.append(d)
except Exception as e:
mlog.debug(str(e))
@@ -1308,7 +1343,7 @@ def find_external_dependency(name, env, kwargs):
if info:
info = ', ' + info
- mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.green('YES'), d.version + info)
+ mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.green('YES'), (d.version if d.version else '') + info)
return d
diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py
index 17f9240..b06f62d 100644
--- a/mesonbuild/dependencies/boost.py
+++ b/mesonbuild/dependencies/boost.py
@@ -443,7 +443,7 @@ class BoostDependency(ExternalDependency):
if self.libdir:
libdirs = [self.libdir]
elif self.boost_root is None:
- libdirs = mesonlib.get_library_dirs()
+ libdirs = mesonlib.get_library_dirs(self.env)
else:
libdirs = [os.path.join(self.boost_root, 'lib')]
for libdir in libdirs:
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index 0cd3c2b..0876391 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -35,7 +35,6 @@ class GTestDependency(ExternalDependency):
self.detect()
def detect(self):
- self.version = '1.something_maybe'
gtest_detect = self.clib_compiler.find_library("gtest", self.env, [])
gtest_main_detect = self.clib_compiler.find_library("gtest_main", self.env, [])
if gtest_detect and (not self.main or gtest_main_detect):
@@ -85,7 +84,6 @@ class GTestDependency(ExternalDependency):
class GMockDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('gmock', environment, 'cpp', kwargs)
- self.version = '1.something_maybe'
# GMock may be a library or just source.
# Work with both.
gmock_detect = self.clib_compiler.find_library("gmock", self.env, [])
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 78ce51b..014be84 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -180,7 +180,7 @@ class MPIDependency(ExternalDependency):
if version:
version = version.group(0)
else:
- version = 'none'
+ version = None
return version, cargs, libs
@@ -197,7 +197,7 @@ class MPIDependency(ExternalDependency):
return
args = shlex.split(o)
- version = 'none'
+ version = None
return version, args, args
@@ -222,11 +222,11 @@ class MPIDependency(ExternalDependency):
else:
return
if self.language == 'fortran':
- return ('none',
+ return (None,
['-I' + incdir, '-I' + os.path.join(incdir, post)],
[os.path.join(libdir, 'msmpi.lib'), os.path.join(libdir, 'msmpifec.lib')])
else:
- return ('none',
+ return (None,
['-I' + incdir, '-I' + os.path.join(incdir, post)],
[os.path.join(libdir, 'msmpi.lib')])
@@ -267,17 +267,13 @@ class OpenMPDependency(ExternalDependency):
class ThreadDependency(ExternalDependency):
def __init__(self, environment, kwargs):
- super().__init__('threads', environment, None, {})
+ super().__init__('threads', environment, None, kwargs)
self.name = 'threads'
self.is_found = True
- mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
def need_threads(self):
return True
- def get_version(self):
- return 'unknown'
-
class Python3Dependency(ExternalDependency):
def __init__(self, environment, kwargs):
@@ -447,8 +443,11 @@ class PcapDependency(ExternalDependency):
@staticmethod
def get_pcap_lib_version(ctdep):
- return ctdep.clib_compiler.get_return_value('pcap_lib_version', 'string',
- '#include <pcap.h>', ctdep.env, [], [ctdep])
+ v = ctdep.clib_compiler.get_return_value('pcap_lib_version', 'string',
+ '#include <pcap.h>', ctdep.env, [], [ctdep])
+ v = re.sub(r'libpcap version ', '', v)
+ v = re.sub(r' -- Apple version.*$', '', v)
+ return v
class CupsDependency(ExternalDependency):
diff --git a/mesonbuild/dependencies/platform.py b/mesonbuild/dependencies/platform.py
index 5f89ccb..0c05156 100644
--- a/mesonbuild/dependencies/platform.py
+++ b/mesonbuild/dependencies/platform.py
@@ -33,8 +33,4 @@ class AppleFrameworks(ExternalDependency):
for f in self.frameworks:
self.link_args += ['-framework', f]
- def found(self):
- return mesonlib.is_osx()
-
- def get_version(self):
- return 'unknown'
+ self.is_found = mesonlib.is_osx()
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index c877f51..f19a76d 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -44,14 +44,12 @@ class GLDependency(ExternalDependency):
# FIXME: Use AppleFrameworks dependency
self.link_args = ['-framework', 'OpenGL']
# FIXME: Detect version using self.clib_compiler
- self.version = '1'
return
if mesonlib.is_windows():
self.is_found = True
# FIXME: Use self.clib_compiler.find_library()
self.link_args = ['-lopengl32']
# FIXME: Detect version using self.clib_compiler
- self.version = '1'
return
@classmethod
@@ -63,7 +61,7 @@ class GLDependency(ExternalDependency):
candidates.append(functools.partial(PkgConfigDependency, 'gl', environment, kwargs))
if DependencyMethods.SYSTEM in methods:
- candidates.append(functools.partial(GLDependency), environment, kwargs)
+ candidates.append(functools.partial(GLDependency, environment, kwargs))
return candidates
@@ -224,7 +222,7 @@ class QtBaseDependency(ExternalDependency):
self.compile_args = []
self.link_args = []
self.from_text = mlog.format_list(methods)
- self.version = 'none'
+ self.version = None
def compilers_detect(self):
"Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"
@@ -557,7 +555,6 @@ class VulkanDependency(ExternalDependency):
# TODO: find a way to retrieve the version from the sdk?
# Usually it is a part of the path to it (but does not have to be)
- self.version = '1'
return
else:
# simply try to guess it, usually works on linux
@@ -565,7 +562,6 @@ class VulkanDependency(ExternalDependency):
if libs is not None and self.clib_compiler.has_header('vulkan/vulkan.h', '', environment):
self.type_name = 'system'
self.is_found = True
- self.version = 1 # TODO
for lib in libs:
self.link_args.append(lib)
return
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 9777540..38f66e9 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -814,6 +814,12 @@ This is probably wrong, it should always point to the native compiler.''' % evar
# up to date language version at time (2016).
if 'DC' in os.environ:
exelist = shlex.split(os.environ['DC'])
+ for dc in exelist[:]:
+ if os.path.basename(dc).startswith(('ldmd', 'gdmd')):
+ mlog.log('Meson doesn\'t support', mlog.bold(dc), 'as it\'s only a DMD frontend for another compiler, skipping.')
+ exelist.remove(dc)
+ if not exelist:
+ raise EnvironmentException('Couldn\'t find any compatible D compiler in the DC environment variable. Please provide a valid value for DC or unset it so that Meson resolve the compiler by itself.')
elif self.is_cross_build() and want_cross:
exelist = mesonlib.stringlistify(self.cross_info.config['binaries']['d'])
is_cross = True
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index c0f3745..e001232 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -383,6 +383,9 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
'partial_dependency': self.partial_dependency_method,
})
+ def found(self):
+ return self.found_method([], {})
+
@noPosargs
@permittedKwargs({})
def type_name_method(self, args, kwargs):
@@ -916,16 +919,30 @@ class Test(InterpreterObject):
class SubprojectHolder(InterpreterObject, ObjectHolder):
- def __init__(self, subinterpreter):
+ def __init__(self, subinterpreter, subproject_dir, name):
InterpreterObject.__init__(self)
ObjectHolder.__init__(self, subinterpreter)
+ self.name = name
+ self.subproject_dir = subproject_dir
self.methods.update({'get_variable': self.get_variable_method,
+ 'found': self.found_method,
})
+ @noPosargs
+ @permittedKwargs({})
+ def found_method(self, args, kwargs):
+ return self.found()
+
+ def found(self):
+ return self.held_object is not None
+
@permittedKwargs({})
def get_variable_method(self, args, kwargs):
if len(args) != 1:
raise InterpreterException('Get_variable takes one argument.')
+ if not self.found():
+ raise InterpreterException('Subproject "%s/%s" disabled can\'t get_variable on it.' % (
+ self.subproject_dir, self.name))
varname = args[0]
if not isinstance(varname, str):
raise InterpreterException('Get_variable takes a string argument.')
@@ -1808,11 +1825,11 @@ known_build_target_kwargs = (
{'target_type'}
)
-permitted_kwargs = {'add_global_arguments': {'language'},
- 'add_global_link_arguments': {'language'},
- 'add_project_link_arguments': {'language'},
+permitted_kwargs = {'add_global_arguments': {'language', 'native'},
+ 'add_global_link_arguments': {'language', 'native'},
'add_languages': {'required'},
- 'add_project_arguments': {'language'},
+ 'add_project_link_arguments': {'language', 'native'},
+ 'add_project_arguments': {'language', 'native'},
'add_test_setup': {'exe_wrapper', 'gdb', 'timeout_multiplier', 'env'},
'benchmark': {'args', 'env', 'should_fail', 'timeout', 'workdir', 'suite'},
'build_target': known_build_target_kwargs,
@@ -1838,7 +1855,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'both_libraries': known_library_kwargs,
'library': known_library_kwargs,
'subdir': {'if_found'},
- 'subproject': {'version', 'default_options'},
+ 'subproject': {'version', 'default_options', 'required'},
'test': {'args', 'depends', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite'},
'vcs_tag': {'input', 'output', 'fallback', 'command', 'replace_string'},
}
@@ -2219,7 +2236,16 @@ external dependencies (including libraries) must go to "dependencies".''')
dirname = args[0]
return self.do_subproject(dirname, kwargs)
+ def disabled_subproject(self, dirname):
+ self.subprojects[dirname] = SubprojectHolder(None, self.subproject_dir, dirname)
+ return self.subprojects[dirname]
+
def do_subproject(self, dirname, kwargs):
+ disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
+ if disabled:
+ mlog.log('\nSubproject', mlog.bold(dirname), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
+ return self.disabled_subproject(dirname)
+
default_options = mesonlib.stringlistify(kwargs.get('default_options', []))
default_options = coredata.create_options_dict(default_options)
if dirname == '':
@@ -2237,7 +2263,13 @@ external dependencies (including libraries) must go to "dependencies".''')
incpath = ' => '.join(fullstack)
raise InvalidCode('Recursive include of subprojects: %s.' % incpath)
if dirname in self.subprojects:
- return self.subprojects[dirname]
+ subproject = self.subprojects[dirname]
+
+ if required and not subproject.found():
+ raise InterpreterException('Subproject "%s/%s" required but not found.' % (
+ self.subproject_dir, dirname))
+
+ return subproject
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
r = wrap.Resolver(subproject_dir_abs, self.coredata.wrap_mode)
try:
@@ -2249,22 +2281,35 @@ external dependencies (including libraries) must go to "dependencies".''')
# promotion...
self.print_nested_info(dirname)
- msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}'
- raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e))
+ if required:
+ msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}'
+ raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e))
+
+ mlog.log('\nSubproject ', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)\n')
+ return self.disabled_subproject(dirname)
+
subdir = os.path.join(self.subproject_dir, resolved)
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
self.global_args_frozen = True
mlog.log()
with mlog.nested():
- mlog.log('\nExecuting subproject', mlog.bold(dirname), '\n')
- subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
- self.modules, default_options)
- subi.subprojects = self.subprojects
-
- subi.subproject_stack = self.subproject_stack + [dirname]
- current_active = self.active_projectname
- subi.run()
- mlog.log('\nSubproject', mlog.bold(dirname), 'finished.')
+ try:
+ mlog.log('\nExecuting subproject', mlog.bold(dirname), '\n')
+ subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
+ self.modules, default_options)
+ subi.subprojects = self.subprojects
+
+ subi.subproject_stack = self.subproject_stack + [dirname]
+ current_active = self.active_projectname
+ subi.run()
+ mlog.log('\nSubproject', mlog.bold(dirname), 'finished.')
+ except Exception as e:
+ if not required:
+ mlog.log(e)
+ mlog.log('\nSubproject', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)')
+ return self.disabled_subproject(dirname)
+ else:
+ raise e
if 'version' in kwargs:
pv = subi.project_version
@@ -2274,26 +2319,24 @@ external dependencies (including libraries) must go to "dependencies".''')
self.active_projectname = current_active
self.build.subprojects[dirname] = subi.project_version
self.subprojects.update(subi.subprojects)
- self.subprojects[dirname] = SubprojectHolder(subi)
+ self.subprojects[dirname] = SubprojectHolder(subi, self.subproject_dir, dirname)
self.build_def_files += subi.build_def_files
return self.subprojects[dirname]
def get_option_internal(self, optname):
+ # Some base options are not defined in some environments, return the
+ # default value from compilers.base_options in that case.
+ for d in [self.coredata.base_options, compilers.base_options,
+ self.coredata.builtins, self.coredata.compiler_options]:
+ try:
+ return d[optname]
+ except KeyError:
+ pass
+
raw_optname = optname
- try:
- return self.coredata.base_options[optname]
- except KeyError:
- pass
- try:
- return self.coredata.builtins[optname]
- except KeyError:
- pass
- try:
- return self.coredata.compiler_options[optname]
- except KeyError:
- pass
- if not coredata.is_builtin_option(optname) and self.is_subproject():
+ if self.is_subproject():
optname = self.subproject + ':' + optname
+
try:
opt = self.coredata.user_options[optname]
if opt.yielding and ':' in optname and raw_optname in self.coredata.user_options:
@@ -2313,11 +2356,7 @@ external dependencies (including libraries) must go to "dependencies".''')
return opt
except KeyError:
pass
- # Some base options are not defined in some environments, return the default value.
- try:
- return compilers.base_options[optname]
- except KeyError:
- pass
+
raise InterpreterException('Tried to access unknown option "%s".' % optname)
@stringArgs
@@ -2805,6 +2844,13 @@ external dependencies (including libraries) must go to "dependencies".''')
def get_subproject_dep(self, name, dirname, varname, required):
try:
+ subproject = self.subprojects[dirname]
+ if not subproject.found():
+ if not required:
+ return DependencyHolder(NotFoundDependency(self.environment), self.subproject)
+
+ raise DependencyException('Subproject %s was not found.' % (name))
+
dep = self.subprojects[dirname].get_variable_method([varname], {})
except InvalidArguments as e:
if required:
@@ -2826,9 +2872,12 @@ external dependencies (including libraries) must go to "dependencies".''')
dep = self.get_subproject_dep(name, dirname, varname, required)
if not dep:
return False
+ if not dep.found():
+ return dep
+
found = dep.version_method([], {})
# Don't do a version check if the dependency is not found and not required
- if found == 'none' and not required:
+ if not dep.found_method([], {}) and not required:
subproj_path = os.path.join(self.subproject_dir, dirname)
mlog.log('Dependency', mlog.bold(name), 'from subproject',
mlog.bold(subproj_path), 'found:', mlog.red('NO'), '(cached)')
@@ -3653,25 +3702,45 @@ different subdirectory.
timeout_multiplier=timeout_multiplier,
env=env)
+ def get_argdict_on_crossness(self, native_dict, cross_dict, kwargs):
+ for_native = kwargs.get('native', not self.environment.is_cross_build())
+ if not isinstance(for_native, bool):
+ raise InterpreterException('Keyword native must be a boolean.')
+ if for_native:
+ return native_dict
+ else:
+ return cross_dict
+
@permittedKwargs(permitted_kwargs['add_global_arguments'])
@stringArgs
def func_add_global_arguments(self, node, args, kwargs):
- self.add_global_arguments(node, self.build.global_args, args, kwargs)
+ argdict = self.get_argdict_on_crossness(self.build.global_args,
+ self.build.cross_global_args,
+ kwargs)
+ self.add_global_arguments(node, argdict, args, kwargs)
@permittedKwargs(permitted_kwargs['add_global_link_arguments'])
@stringArgs
def func_add_global_link_arguments(self, node, args, kwargs):
- self.add_global_arguments(node, self.build.global_link_args, args, kwargs)
+ argdict = self.get_argdict_on_crossness(self.build.global_link_args,
+ self.build.cross_global_link_args,
+ kwargs)
+ self.add_global_arguments(node, argdict, args, kwargs)
@permittedKwargs(permitted_kwargs['add_project_arguments'])
@stringArgs
def func_add_project_arguments(self, node, args, kwargs):
- self.add_project_arguments(node, self.build.projects_args, args, kwargs)
+ argdict = self.get_argdict_on_crossness(self.build.projects_args,
+ self.build.cross_projects_args,
+ kwargs)
+ self.add_project_arguments(node, argdict, args, kwargs)
@permittedKwargs(permitted_kwargs['add_project_link_arguments'])
@stringArgs
def func_add_project_link_arguments(self, node, args, kwargs):
- self.add_project_arguments(node, self.build.projects_link_args, args, kwargs)
+ argdict = self.get_argdict_on_crossness(self.build.projects_link_args,
+ self.build.cross_projects_link_args, kwargs)
+ self.add_project_arguments(node, argdict, args, kwargs)
def add_global_arguments(self, node, argsdict, args, kwargs):
if self.is_subproject():
diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py
index 513c238..2fd69b0 100644
--- a/mesonbuild/mconf.py
+++ b/mesonbuild/mconf.py
@@ -13,7 +13,6 @@
# limitations under the License.
import os
-import sys
import argparse
from . import (coredata, mesonlib, build)
@@ -172,7 +171,3 @@ def run(args):
print('Meson configurator encountered an error:')
raise e
return 0
-
-
-if __name__ == '__main__':
- sys.exit(run(sys.argv[1:]))
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 68a2ddb..e8b7b30 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -36,7 +36,7 @@ def create_parser():
p.add_argument('-v', '--version', action='version',
version=coredata.version)
# See the mesonlib.WrapMode enum for documentation
- p.add_argument('--wrap-mode', default=WrapMode.default,
+ p.add_argument('--wrap-mode', default=None,
type=wrapmodetype, choices=WrapMode,
help='Special wrap mode to use')
p.add_argument('--profile-self', action='store_true', dest='profile',
@@ -71,18 +71,18 @@ class MesonApp:
if not os.path.exists(ndir2):
os.makedirs(ndir2)
if not stat.S_ISDIR(os.stat(ndir1).st_mode):
- raise RuntimeError('%s is not a directory' % dir1)
+ raise MesonException('%s is not a directory' % dir1)
if not stat.S_ISDIR(os.stat(ndir2).st_mode):
- raise RuntimeError('%s is not a directory' % dir2)
+ raise MesonException('%s is not a directory' % dir2)
if os.path.samefile(dir1, dir2):
- raise RuntimeError('Source and build directories must not be the same. Create a pristine build directory.')
+ raise MesonException('Source and build directories must not be the same. Create a pristine build directory.')
if self.has_build_file(ndir1):
if self.has_build_file(ndir2):
- raise RuntimeError('Both directories contain a build file %s.' % environment.build_filename)
+ raise MesonException('Both directories contain a build file %s.' % environment.build_filename)
return ndir1, ndir2
if self.has_build_file(ndir2):
return ndir2, ndir1
- raise RuntimeError('Neither directory contains a build file %s.' % environment.build_filename)
+ raise MesonException('Neither directory contains a build file %s.' % environment.build_filename)
def validate_dirs(self, dir1, dir2, handshake):
(src_dir, build_dir) = self.validate_core_dirs(dir1, dir2)
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
index 748f06b..1d72179 100644
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -27,6 +27,10 @@ except ImportError:
# This is only used for pkexec which is not, so this is fine.
main_file = None
+symlink_warning = '''Warning: trying to copy a symlink that points to a file. This will copy the file,
+but this will be changed in a future version of Meson to copy the symlink as is. Please update your
+build definitions so that it will not break when the change happens.'''
+
selinux_updates = []
def buildparser():
@@ -242,7 +246,15 @@ class Installer:
os.remove(to_file)
print('Installing %s to %s' % (from_file, outdir))
if os.path.islink(from_file):
- shutil.copy(from_file, outdir, follow_symlinks=False)
+ if not os.path.exists(from_file):
+ # Dangling symlink. Replicate as is.
+ shutil.copy(from_file, outdir, follow_symlinks=False)
+ else:
+ # Remove this entire branch when changing the behaviour to duplicate
+ # symlinks rather than copying what they point to.
+ print(symlink_warning)
+ shutil.copyfile(from_file, to_file)
+ shutil.copystat(from_file, to_file)
else:
shutil.copyfile(from_file, to_file)
shutil.copystat(from_file, to_file)
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 94bc00b..188459a 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -249,6 +249,3 @@ def run(args):
print('No command specified')
return 1
return 0
-
-if __name__ == '__main__':
- sys.exit(run(sys.argv[1:]))
diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py
index 1654824..b8d3ccc 100644
--- a/mesonbuild/mlog.py
+++ b/mesonbuild/mlog.py
@@ -59,9 +59,12 @@ def set_timestamp_start(start):
def shutdown():
global log_file
if log_file is not None:
+ path = log_file.name
exception_around_goer = log_file
log_file = None
exception_around_goer.close()
+ return path
+ return None
class AnsiDecorator:
plain_code = "\033[0m"
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index 19f3e2b..87209d6 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -88,35 +88,38 @@ class WindowsModule(ExtensionModule):
if hasattr(src, 'held_object'):
src = src.held_object
- res_kwargs = {
- 'output': '@BASENAME@.' + suffix,
- 'input': [src],
- 'command': [rescomp] + res_args,
- 'depend_files': wrc_depend_files,
- 'depends': wrc_depends,
- }
-
if isinstance(src, str):
- name = 'file {!r}'.format(os.path.join(state.subdir, src))
+ name_format = 'file {!r}'
+ name = os.path.join(state.subdir, src)
elif isinstance(src, mesonlib.File):
- name = 'file {!r}'.format(src.relative_name())
+ name_format = 'file {!r}'
+ name = src.relative_name()
elif isinstance(src, build.CustomTarget):
if len(src.get_outputs()) > 1:
raise MesonException('windows.compile_resources does not accept custom targets with more than 1 output.')
- name = 'target {!r}'.format(src.get_id())
+ name_format = 'target {!r}'
+ name = src.get_id()
else:
raise MesonException('Unexpected source type {!r}. windows.compile_resources accepts only strings, files, custom targets, and lists thereof.'.format(src))
# Path separators are not allowed in target names
name = name.replace('/', '_').replace('\\', '_')
+ res_kwargs = {
+ 'output': name + '_@BASENAME@.' + suffix,
+ 'input': [src],
+ 'command': [rescomp] + res_args,
+ 'depend_files': wrc_depend_files,
+ 'depends': wrc_depends,
+ }
+
# instruct binutils windres to generate a preprocessor depfile
if comp.id != 'msvc':
res_kwargs['depfile'] = res_kwargs['output'] + '.d'
res_kwargs['command'] += ['--preprocessor-arg=-MD', '--preprocessor-arg=-MQ@OUTPUT@', '--preprocessor-arg=-MF@DEPFILE@']
- res_targets.append(build.CustomTarget('Windows resource for ' + name, state.subdir, state.subproject, res_kwargs))
+ res_targets.append(build.CustomTarget('Windows resource for ' + name_format.format(name), state.subdir, state.subproject, res_kwargs))
add_target(args)
diff --git a/mesonbuild/wrap/__init__.py b/mesonbuild/wrap/__init__.py
index 6e2bc83..b792dfa 100644
--- a/mesonbuild/wrap/__init__.py
+++ b/mesonbuild/wrap/__init__.py
@@ -33,4 +33,11 @@ from enum import Enum
# Note that these options do not affect subprojects that
# are git submodules since those are only usable in git
# repositories, and you almost always want to download them.
-WrapMode = Enum('WrapMode', 'default nofallback nodownload forcefallback')
+class WrapMode(Enum):
+ default = 1
+ nofallback = 2
+ nodownload = 3
+ forcefallback = 4
+
+ def __str__(self):
+ return self.name
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index a3f8ab1..412097c 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -29,6 +29,7 @@ except ImportError:
has_ssl = False
API_ROOT = 'http://wrapdb.mesonbuild.com/v1/'
+req_timeout = 600.0
ssl_warning_printed = False
def build_ssl_context():
@@ -51,7 +52,7 @@ def open_wrapdburl(urlstring):
global ssl_warning_printed
if has_ssl:
try:
- return urllib.request.urlopen(urlstring)# , context=build_ssl_context())
+ return urllib.request.urlopen(urlstring, timeout=req_timeout)# , context=build_ssl_context())
except urllib.error.URLError:
if not ssl_warning_printed:
print('SSL connection failed. Falling back to unencrypted connections.')
@@ -64,7 +65,7 @@ def open_wrapdburl(urlstring):
# certificate is not known.
if urlstring.startswith('https'):
urlstring = 'http' + urlstring[5:]
- return urllib.request.urlopen(urlstring)
+ return urllib.request.urlopen(urlstring, timeout=req_timeout)
class PackageDefinition:
@@ -270,7 +271,7 @@ class Resolver:
if url.startswith('https://wrapdb.mesonbuild.com'):
resp = open_wrapdburl(url)
else:
- resp = urllib.request.urlopen(url)
+ resp = urllib.request.urlopen(url, timeout=req_timeout)
with contextlib.closing(resp) as resp:
try:
dlsize = int(resp.info()['Content-Length'])
diff --git a/mesonbuild/wrap/wraptool.py b/mesonbuild/wrap/wraptool.py
index 570e691..364452d 100644
--- a/mesonbuild/wrap/wraptool.py
+++ b/mesonbuild/wrap/wraptool.py
@@ -213,6 +213,4 @@ def run(args):
add_arguments(parser)
options = parser.parse_args(args)
options.wrap_func(options)
-
-if __name__ == '__main__':
- sys.exit(run(sys.argv[1:]))
+ return 0
diff --git a/run_tests.py b/run_tests.py
index 6e441d3..a5fd7a5 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -31,7 +31,32 @@ from mesonbuild import mesonlib
from mesonbuild import mesonmain
from mesonbuild import mtest
from mesonbuild import mlog
-from mesonbuild.environment import detect_ninja
+from mesonbuild.environment import Environment, detect_ninja
+
+
+# Fake classes and objects for mocking
+class FakeBuild:
+ def __init__(self, env):
+ self.environment = env
+
+class FakeCompilerOptions:
+ def __init__(self):
+ self.value = []
+
+def get_fake_options(prefix):
+ import argparse
+ opts = argparse.Namespace()
+ opts.cross_file = None
+ opts.wrap_mode = None
+ opts.prefix = prefix
+ opts.cmd_line_options = {}
+ return opts
+
+def get_fake_env(sdir, bdir, prefix):
+ env = Environment(sdir, bdir, get_fake_options(prefix))
+ env.coredata.compiler_options['c_args'] = FakeCompilerOptions()
+ return env
+
Backend = Enum('Backend', 'ninja vs xcode')
@@ -148,15 +173,6 @@ def ensure_backend_detects_changes(backend):
if backend is Backend.ninja:
time.sleep(1)
-def get_fake_options(prefix):
- import argparse
- opts = argparse.Namespace()
- opts.cross_file = None
- opts.wrap_mode = None
- opts.prefix = prefix
- opts.cmd_line_options = {}
- return opts
-
def run_mtest_inprocess(commandlist):
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
diff --git a/run_unittests.py b/run_unittests.py
index 2e29af7..ebead66 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -41,24 +41,16 @@ from mesonbuild.mesonlib import (
windows_proof_rmtree, python_command, version_compare,
grab_leading_numbers, BuildDirLock
)
-from mesonbuild.environment import Environment, detect_ninja
+from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException
from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
import mesonbuild.modules.pkgconfig
-from run_tests import exe_suffix, get_fake_options, get_meson_script
+from run_tests import exe_suffix, get_fake_env, get_meson_script
from run_tests import get_builddir_target_args, get_backend_commands, Backend
from run_tests import ensure_backend_detects_changes, run_configure_inprocess
from run_tests import run_mtest_inprocess
-
-# Fake classes for mocking
-class FakeBuild:
- def __init__(self, env):
- self.environment = env
-
-class FakeCompilerOptions:
- def __init__(self):
- self.value = []
+from run_tests import FakeBuild, FakeCompilerOptions
def get_dynamic_section_entry(fname, entry):
if is_cygwin() or is_osx():
@@ -176,19 +168,19 @@ class InternalTests(unittest.TestCase):
def test_compiler_args_class(self):
cargsfunc = mesonbuild.compilers.CompilerArgs
- c = mesonbuild.compilers.CCompiler([], 'fake', False)
+ cc = mesonbuild.compilers.CCompiler([], 'fake', False)
# Test that bad initialization fails
self.assertRaises(TypeError, cargsfunc, [])
self.assertRaises(TypeError, cargsfunc, [], [])
- self.assertRaises(TypeError, cargsfunc, c, [], [])
+ self.assertRaises(TypeError, cargsfunc, cc, [], [])
# Test that empty initialization works
- a = cargsfunc(c)
+ a = cargsfunc(cc)
self.assertEqual(a, [])
# Test that list initialization works
- a = cargsfunc(['-I.', '-I..'], c)
+ a = cargsfunc(['-I.', '-I..'], cc)
self.assertEqual(a, ['-I.', '-I..'])
# Test that there is no de-dup on initialization
- self.assertEqual(cargsfunc(['-I.', '-I.'], c), ['-I.', '-I.'])
+ self.assertEqual(cargsfunc(['-I.', '-I.'], cc), ['-I.', '-I.'])
## Test that appending works
a.append('-I..')
@@ -234,7 +226,7 @@ class InternalTests(unittest.TestCase):
self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall'])
## Test that adding libraries works
- l = cargsfunc(c, ['-Lfoodir', '-lfoo'])
+ l = cargsfunc(cc, ['-Lfoodir', '-lfoo'])
self.assertEqual(l, ['-Lfoodir', '-lfoo'])
# Adding a library and a libpath appends both correctly
l += ['-Lbardir', '-lbar']
@@ -244,7 +236,7 @@ class InternalTests(unittest.TestCase):
self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar'])
## Test that 'direct' append and extend works
- l = cargsfunc(c, ['-Lfoodir', '-lfoo'])
+ l = cargsfunc(cc, ['-Lfoodir', '-lfoo'])
self.assertEqual(l, ['-Lfoodir', '-lfoo'])
# Direct-adding a library and a libpath appends both correctly
l.extend_direct(['-Lbardir', '-lbar'])
@@ -259,6 +251,29 @@ class InternalTests(unittest.TestCase):
l.append_direct('/libbaz.a')
self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a'])
+ def test_compiler_args_class_gnuld(self):
+ cargsfunc = mesonbuild.compilers.CompilerArgs
+ ## Test --start/end-group
+ gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', 0, False)
+ ## Test that 'direct' append and extend works
+ l = cargsfunc(gcc, ['-Lfoodir', '-lfoo'])
+ self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group'])
+ # Direct-adding a library and a libpath appends both correctly
+ l.extend_direct(['-Lbardir', '-lbar'])
+ self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-Wl,--end-group'])
+ # Direct-adding the same library again still adds it
+ l.append_direct('-lbar')
+ self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '-Wl,--end-group'])
+ # Direct-adding with absolute path deduplicates
+ l.append_direct('/libbaz.a')
+ self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group'])
+ # Adding libbaz again does nothing
+ l.append_direct('/libbaz.a')
+ self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group'])
+ # Adding a non-library argument doesn't include it in the group
+ l += ['-Lfoo', '-Wl,--export-dynamic']
+ self.assertEqual(l.to_native(copy=True), ['-Lfoo', '-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--end-group', '-Wl,--export-dynamic'])
+
def test_string_templates_substitution(self):
dictfunc = mesonbuild.mesonlib.get_filenames_templates_dict
substfunc = mesonbuild.mesonlib.substitute_values
@@ -563,7 +578,7 @@ class InternalTests(unittest.TestCase):
'windows-mingw': {'shared': ['lib{}.dll.a', 'lib{}.lib', 'lib{}.dll',
'{}.dll.a', '{}.lib', '{}.dll'],
'static': msvc_static}}
- env = Environment('', '', get_fake_options(''))
+ env = get_fake_env('', '', '')
cc = env.detect_c_compiler(False)
if is_osx():
self._test_all_naming(cc, env, patterns, 'darwin')
@@ -606,7 +621,7 @@ class InternalTests(unittest.TestCase):
'''
with tempfile.TemporaryDirectory() as tmpdir:
pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True)
- env = Environment('', '', get_fake_options(''))
+ env = get_fake_env('', '', '')
compiler = env.detect_c_compiler(False)
env.coredata.compilers = {'c': compiler}
env.coredata.compiler_options['c_link_args'] = FakeCompilerOptions()
@@ -630,7 +645,7 @@ class InternalTests(unittest.TestCase):
if '--libs' not in args:
return 0, ''
if args[0] == 'foo':
- return 0, '-L{} -lfoo -L{} -lbar'.format(p1.as_posix(), p2.as_posix())
+ return 0, '-L{} -lfoo -L{} -lbar'.format(p2.as_posix(), p1.as_posix())
if args[0] == 'bar':
return 0, '-L{} -lbar'.format(p2.as_posix())
if args[0] == 'internal':
@@ -672,6 +687,8 @@ class DataTests(unittest.TestCase):
self.assertTrue(snippet_dir.is_dir())
for f in snippet_dir.glob('*'):
self.assertTrue(f.is_file())
+ if f.parts[-1].endswith('~'):
+ continue
if f.suffix == '.md':
with f.open() as snippet:
for line in snippet:
@@ -692,7 +709,7 @@ class DataTests(unittest.TestCase):
with open('docs/markdown/Builtin-options.md') as f:
md = f.read()
self.assertIsNotNone(md)
- env = Environment('', '', get_fake_options(''))
+ env = get_fake_env('', '', '')
# FIXME: Support other compilers
cc = env.detect_c_compiler(False)
cpp = env.detect_cpp_compiler(False)
@@ -738,7 +755,7 @@ class DataTests(unittest.TestCase):
Ensure that syntax highlighting files were updated for new functions in
the global namespace in build files.
'''
- env = Environment('', '', get_fake_options(''))
+ env = get_fake_env('', '', '')
interp = Interpreter(FakeBuild(env), mock=True)
with open('data/syntax-highlighting/vim/syntax/meson.vim') as f:
res = re.search(r'syn keyword mesonBuiltin(\s+\\\s\w+)+', f.read(), re.MULTILINE)
@@ -1172,7 +1189,7 @@ class AllPlatformTests(BasePlatformTests):
https://github.com/mesonbuild/meson/issues/1355
'''
testdir = os.path.join(self.common_test_dir, '3 static')
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(False)
static_linker = env.detect_static_linker(cc)
if is_windows():
@@ -1459,7 +1476,7 @@ class AllPlatformTests(BasePlatformTests):
if not is_windows():
langs += [('objc', 'OBJC'), ('objcpp', 'OBJCXX')]
testdir = os.path.join(self.unit_test_dir, '5 compiler detection')
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
for lang, evar in langs:
# Detect with evar and do sanity checks on that
if evar in os.environ:
@@ -1561,7 +1578,7 @@ class AllPlatformTests(BasePlatformTests):
def test_always_prefer_c_compiler_for_asm(self):
testdir = os.path.join(self.common_test_dir, '138 c cpp and asm')
# Skip if building with MSVC
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
if env.detect_c_compiler(False).get_id() == 'msvc':
raise unittest.SkipTest('MSVC can\'t compile assembly')
self.init(testdir)
@@ -1819,7 +1836,7 @@ int main(int argc, char **argv) {
self.assertPathExists(os.path.join(testdir, i))
def detect_prebuild_env(self):
- env = Environment('', self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env('', self.builddir, self.prefix)
cc = env.detect_c_compiler(False)
stlinker = env.detect_static_linker(cc)
if mesonbuild.mesonlib.is_windows():
@@ -1985,7 +2002,7 @@ int main(int argc, char **argv) {
'--libdir=' + libdir])
# Find foo dependency
os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
kwargs = {'required': True, 'silent': True}
foo_dep = PkgConfigDependency('libfoo', env, kwargs)
# Ensure link_args are properly quoted
@@ -2292,7 +2309,7 @@ recommended as it is not supported on some platforms''')
testdirbase = os.path.join(self.unit_test_dir, '29 guessed linker dependencies')
testdirlib = os.path.join(testdirbase, 'lib')
extra_args = None
- env = Environment(testdirlib, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdirlib, self.builddir, self.prefix)
if env.detect_c_compiler(False).get_id() != 'msvc':
# static libraries are not linkable with -l with msvc because meson installs them
# as .a files which unix_args_to_native will not know as it expects libraries to use
@@ -2746,7 +2763,7 @@ class FailureTests(BasePlatformTests):
'''
Test that when we can't detect objc or objcpp, we fail gracefully.
'''
- env = Environment('', self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env('', self.builddir, self.prefix)
try:
env.detect_objc_compiler(False)
env.detect_objcpp_compiler(False)
@@ -2831,6 +2848,16 @@ class FailureTests(BasePlatformTests):
msg = '.*WARNING:.*feature.*build_always_stale.*custom_target.*'
self.assertMesonDoesNotOutput(vcs_tag, msg, meson_version='>=0.43')
+ def test_missing_subproject_not_required_and_required(self):
+ self.assertMesonRaises("sub1 = subproject('not-found-subproject', required: false)\n" +
+ "sub2 = subproject('not-found-subproject', required: true)",
+ """.*Subproject "subprojects/not-found-subproject" required but not found.*""")
+
+ def test_get_variable_on_not_found_project(self):
+ self.assertMesonRaises("sub1 = subproject('not-found-subproject', required: false)\n" +
+ "sub1.get_variable('naaa')",
+ """Subproject "subprojects/not-found-subproject" disabled can't get_variable on it.""")
+
class WindowsTests(BasePlatformTests):
'''
@@ -2883,7 +2910,7 @@ class WindowsTests(BasePlatformTests):
ExternalLibraryHolder from build files.
'''
testdir = os.path.join(self.platform_test_dir, '1 basic')
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(False)
if cc.id != 'msvc':
raise unittest.SkipTest('Not using MSVC')
@@ -2896,7 +2923,7 @@ class WindowsTests(BasePlatformTests):
testdir = os.path.join(self.platform_test_dir, '5 resources')
# resource compiler depfile generation is not yet implemented for msvc
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
depfile_works = env.detect_c_compiler(False).get_id() != 'msvc'
self.init(testdir)
@@ -2985,7 +3012,7 @@ class LinuxlikeTests(BasePlatformTests):
'''
testdir = os.path.join(self.common_test_dir, '48 pkgconfig-gen')
self.init(testdir)
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
kwargs = {'required': True, 'silent': True}
os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
foo_dep = PkgConfigDependency('libfoo', env, kwargs)
@@ -3241,7 +3268,7 @@ class LinuxlikeTests(BasePlatformTests):
an ordinary test because it requires passing options to meson.
'''
testdir = os.path.join(self.common_test_dir, '1 trivial')
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(False)
self._test_stds_impl(testdir, cc, 'c')
@@ -3251,7 +3278,7 @@ class LinuxlikeTests(BasePlatformTests):
be an ordinary test because it requires passing options to meson.
'''
testdir = os.path.join(self.common_test_dir, '2 cpp')
- env = Environment(testdir, self.builddir, get_fake_options(self.prefix))
+ env = get_fake_env(testdir, self.builddir, self.prefix)
cpp = env.detect_cpp_compiler(False)
self._test_stds_impl(testdir, cpp, 'cpp')
@@ -3796,8 +3823,6 @@ endian = 'little'
The system library is found with cc.find_library() and pkg-config deps.
'''
- if not is_osx():
- raise unittest.SkipTest('workflow currently only works on macOS')
oldprefix = self.prefix
# Install external library so we can find it
testdir = os.path.join(self.unit_test_dir, '39 external, internal library rpath', 'external library')
@@ -3820,6 +3845,9 @@ endian = 'little'
self.build()
# test uninstalled
self.run_tests()
+ if not is_osx():
+ # Rest of the workflow only works on macOS
+ return
# test running after installation
self.install(use_destdir=False)
prog = os.path.join(self.installdir, 'bin', 'prog')
diff --git a/test cases/common/190 openmp/meson.build b/test cases/common/190 openmp/meson.build
index a05ca59..eb270ab 100644
--- a/test cases/common/190 openmp/meson.build
+++ b/test cases/common/190 openmp/meson.build
@@ -38,3 +38,6 @@ if add_languages('fortran', required : false)
test('OpenMP Fortran', execpp, env : env)
endif
+
+# Check we can apply a version constraint
+dependency('openmp', version: '>=@0@'.format(openmp.version()))
diff --git a/test cases/common/206 subproject with features/meson.build b/test cases/common/206 subproject with features/meson.build
new file mode 100644
index 0000000..5bdfefb
--- /dev/null
+++ b/test cases/common/206 subproject with features/meson.build
@@ -0,0 +1,17 @@
+project('proj', 'c')
+
+auto_subproj = subproject('sub', required: get_option('use-subproject'))
+assert(auto_subproj.found(), 'Subproject should always be buildable and thus found')
+
+auto_dep = dependency('', fallback: ['sub', 'libSub'], required: true)
+assert(auto_dep.found() == true, 'Subproject is required and foundable, dependency should be found.')
+
+disabled_subproj = subproject('disabled_sub', required: get_option('disabled-subproject'))
+assert(disabled_subproj.found() == false, 'Disabled subproject should be NOT found')
+
+disabled_dep = dependency('', fallback: ['disabled_sub', 'libSub'], required: false)
+assert(disabled_dep.found() == false, 'Subprojetc was disabled, it should never be built.')
+nothing = executable('nothing', 'nothing.c', dependencies: [disabled_dep])
+
+subproj_with_missing_dep = subproject('auto_sub_with_missing_dep', required: get_option('auto-sub-with-missing-dep'))
+assert(subproj_with_missing_dep.found() == false, 'Subproject with required=auto and missing dependency should be NOT found')
diff --git a/test cases/common/206 subproject with features/meson_options.txt b/test cases/common/206 subproject with features/meson_options.txt
new file mode 100644
index 0000000..a46e5fb
--- /dev/null
+++ b/test cases/common/206 subproject with features/meson_options.txt
@@ -0,0 +1,3 @@
+option('use-subproject', type : 'feature', value : 'auto')
+option('disabled-subproject', type : 'feature', value : 'disabled')
+option('auto-sub-with-missing-dep', type : 'feature', value : 'auto')
diff --git a/test cases/common/206 subproject with features/nothing.c b/test cases/common/206 subproject with features/nothing.c
new file mode 100644
index 0000000..77750c2
--- /dev/null
+++ b/test cases/common/206 subproject with features/nothing.c
@@ -0,0 +1,4 @@
+int main(int argc, char const *argv[])
+{
+ return 0;
+} \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build b/test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build
new file mode 100644
index 0000000..fa6b011
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build
@@ -0,0 +1,3 @@
+project('sub', 'c')
+
+dependency('no_way_this_exists', required: true) \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build
new file mode 100644
index 0000000..933001a
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build
@@ -0,0 +1,3 @@
+lib = static_library('sub', 'sub.c')
+
+libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c
new file mode 100644
index 0000000..068a5b8
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c
@@ -0,0 +1,5 @@
+#include "sub.h"
+
+int sub() {
+ return 0;
+}
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h
new file mode 100644
index 0000000..f1ab0e1
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h
@@ -0,0 +1,6 @@
+#ifndef SUB_H
+#define SUB_H
+
+int sub();
+
+#endif
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build b/test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build
new file mode 100644
index 0000000..65fef03
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build
@@ -0,0 +1,3 @@
+project('disabled_sub', 'c')
+
+subdir('lib') \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/sub/lib/meson.build b/test cases/common/206 subproject with features/subprojects/sub/lib/meson.build
new file mode 100644
index 0000000..731d22b
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/lib/meson.build
@@ -0,0 +1,2 @@
+lib = static_library('sub', 'sub.c')
+libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
diff --git a/test cases/common/206 subproject with features/subprojects/sub/lib/sub.c b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.c
new file mode 100644
index 0000000..ed78306
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.c
@@ -0,0 +1,5 @@
+#include "sub.h"
+
+int sub() {
+ return 0;
+}
diff --git a/test cases/common/206 subproject with features/subprojects/sub/lib/sub.h b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.h
new file mode 100644
index 0000000..f1ab0e1
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.h
@@ -0,0 +1,6 @@
+#ifndef SUB_H
+#define SUB_H
+
+int sub();
+
+#endif
diff --git a/test cases/common/206 subproject with features/subprojects/sub/meson.build b/test cases/common/206 subproject with features/subprojects/sub/meson.build
new file mode 100644
index 0000000..31882ac
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/meson.build
@@ -0,0 +1,3 @@
+project('sub', 'c')
+
+subdir('lib') \ No newline at end of file
diff --git a/test cases/common/21 global arg/meson.build b/test cases/common/21 global arg/meson.build
index d7fd428..699dae6 100644
--- a/test cases/common/21 global arg/meson.build
+++ b/test cases/common/21 global arg/meson.build
@@ -3,9 +3,18 @@ project('global arg test', 'cpp', 'c')
add_global_arguments('-DMYTHING', language : 'c')
add_global_arguments('-DMYCPPTHING', language : 'cpp')
+add_global_arguments('-DGLOBAL_NATIVE', language : 'c', native : true)
+add_global_arguments('-DGLOBAL_CROSS', language : 'c', native : false)
+
+if meson.is_cross_build()
+ c_args = ['-DARG_CROSS']
+else
+ c_args = ['-DARG_NATIVE']
+endif
+
add_global_arguments('-DMYCANDCPPTHING', language: ['c', 'cpp'])
-exe1 = executable('prog', 'prog.c')
+exe1 = executable('prog', 'prog.c', c_args : c_args)
exe2 = executable('prog2', 'prog.cc')
test('prog1', exe1)
diff --git a/test cases/common/21 global arg/prog.c b/test cases/common/21 global arg/prog.c
index ace5a0a..fb014c7 100644
--- a/test cases/common/21 global arg/prog.c
+++ b/test cases/common/21 global arg/prog.c
@@ -10,6 +10,42 @@
#error "Global argument not set"
#endif
+#ifdef GLOBAL_NATIVE
+ #ifndef ARG_NATIVE
+ #error "Global is native but arg_native is not set."
+ #endif
+
+ #ifdef GLOBAL_CROSS
+ #error "Both global native and global cross set."
+ #endif
+#else
+ #ifndef GLOBAL_CROSS
+ #error "Neither global_cross nor glogal_native is set."
+ #endif
+
+ #ifndef ARG_CROSS
+ #error "Global is cross but arg_cross is not set."
+ #endif
+
+ #ifdef ARG_NATIVE
+ #error "Global is cross but arg_native is set."
+ #endif
+#endif
+
+#ifdef GLOBAL_CROSS
+ #ifndef ARG_CROSS
+ #error "Global is cross but arg_cross is not set."
+ #endif
+#else
+ #ifdef ARG_CROSS
+ #error "Global is cross but arg_native is set."
+ #endif
+
+ #ifdef ARG_CROSS
+ #error "Global is native but arg cross is set."
+ #endif
+#endif
+
int main(int argc, char **argv) {
return 0;
}
diff --git a/test cases/failing/81 framework dependency with version/meson.build b/test cases/failing/81 framework dependency with version/meson.build
new file mode 100644
index 0000000..714ad3b
--- /dev/null
+++ b/test cases/failing/81 framework dependency with version/meson.build
@@ -0,0 +1,4 @@
+project('framework dependency with version')
+# do individual frameworks have a meaningful version to test? And multiple frameworks might be listed...
+# otherwise we're not on OSX and this will definitely fail
+dep = dependency('appleframeworks', modules: 'foundation', version: '>0')
diff --git a/test cases/failing/82 gl dependency with version/meson.build b/test cases/failing/82 gl dependency with version/meson.build
new file mode 100644
index 0000000..3014d43
--- /dev/null
+++ b/test cases/failing/82 gl dependency with version/meson.build
@@ -0,0 +1,9 @@
+project('gl dependency with version', 'c')
+
+host_system = host_machine.system()
+if host_system != 'windows' and host_system != 'darwin'
+ error('Test only fails on Windows and OSX')
+endif
+
+# gl dependency found via system method doesn't have a meaningful version to check
+dep = dependency('gl', method: 'system', version: '>0')
diff --git a/test cases/failing/83 threads dependency with version/meson.build b/test cases/failing/83 threads dependency with version/meson.build
new file mode 100644
index 0000000..6023fae
--- /dev/null
+++ b/test cases/failing/83 threads dependency with version/meson.build
@@ -0,0 +1,3 @@
+project('threads dependency with version', 'c')
+# threads dependency doesn't have a meaningful version to check
+dep = dependency('threads', version: '>0')
diff --git a/test cases/failing/84 gtest dependency with version/meson.build b/test cases/failing/84 gtest dependency with version/meson.build
new file mode 100644
index 0000000..5115f27
--- /dev/null
+++ b/test cases/failing/84 gtest dependency with version/meson.build
@@ -0,0 +1,3 @@
+project('gtest dependency with version', ['c', 'cpp'])
+# discovering gtest version is not yet implemented
+dep = dependency('gtest', version: '>0')
diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build
index 9399598..d1e1da4 100644
--- a/test cases/frameworks/1 boost/meson.build
+++ b/test cases/frameworks/1 boost/meson.build
@@ -33,3 +33,6 @@ test('Boost nomod', nomodexe)
test('Boost extralib test', extralibexe)
subdir('partial_dep')
+
+# check we can apply a version constraint
+dependency('boost', version: '>=@0@'.format(dep.version()))
diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build
index b5505eb..e05fddd 100644
--- a/test cases/frameworks/15 llvm/meson.build
+++ b/test cases/frameworks/15 llvm/meson.build
@@ -41,3 +41,6 @@ foreach static : [true, false]
)
endif
endforeach
+
+# Check we can apply a version constraint
+dependency('llvm', version: '>=@0@'.format(d.version()))
diff --git a/test cases/frameworks/16 sdl2/meson.build b/test cases/frameworks/16 sdl2/meson.build
index 1bbf09f..fd90e36 100644
--- a/test cases/frameworks/16 sdl2/meson.build
+++ b/test cases/frameworks/16 sdl2/meson.build
@@ -15,3 +15,7 @@ configdep = dependency('sdl2', method : 'sdlconfig')
# And the modern method name
configdep = dependency('sdl2', method : 'config-tool')
+
+# Check we can apply a version constraint
+dependency('sdl2', version: '>=@0@'.format(sdl2_dep.version()), method: 'pkg-config')
+dependency('sdl2', version: '>=@0@'.format(sdl2_dep.version()), method: 'config-tool')
diff --git a/test cases/frameworks/17 mpi/meson.build b/test cases/frameworks/17 mpi/meson.build
index f3eacac..1085d40 100644
--- a/test cases/frameworks/17 mpi/meson.build
+++ b/test cases/frameworks/17 mpi/meson.build
@@ -42,3 +42,6 @@ if uburesult.returncode() != 0 and add_languages('fortran', required : false)
test('MPI Fortran', exef)
endif
+
+# Check we can apply a version constraint
+dependency('mpi', version: '>=@0@'.format(mpic.version()))
diff --git a/test cases/frameworks/18 vulkan/meson.build b/test cases/frameworks/18 vulkan/meson.build
index e98854e..5cfe89f 100644
--- a/test cases/frameworks/18 vulkan/meson.build
+++ b/test cases/frameworks/18 vulkan/meson.build
@@ -8,3 +8,6 @@ endif
e = executable('vulkanprog', 'vulkanprog.c', dependencies : vulkan_dep)
test('vulkantest', e)
+
+# Check we can apply a version constraint
+dependency('vulkan', version: '>=@0@'.format(vulkan_dep.version()))
diff --git a/test cases/frameworks/19 pcap/meson.build b/test cases/frameworks/19 pcap/meson.build
index eb6fc2c..051e49e 100644
--- a/test cases/frameworks/19 pcap/meson.build
+++ b/test cases/frameworks/19 pcap/meson.build
@@ -16,3 +16,7 @@ test('pcaptest', e)
# Ensure discovery via the configuration tools work also
pcap_dep = dependency('pcap', version : '>=1.0', method : 'pcap-config')
pcap_dep = dependency('pcap', version : '>=1.0', method : 'config-tool')
+
+# Check we can apply a version constraint
+dependency('pcap', version: '>=@0@'.format(pcap_dep.version()), method: 'pkg-config', required: false)
+dependency('pcap', version: '>=@0@'.format(pcap_dep.version()), method: 'config-tool')
diff --git a/test cases/frameworks/20 cups/meson.build b/test cases/frameworks/20 cups/meson.build
index 9040de6..d50c4a8 100644
--- a/test cases/frameworks/20 cups/meson.build
+++ b/test cases/frameworks/20 cups/meson.build
@@ -14,3 +14,7 @@ test('cupstest', e)
# options
dep = dependency('cups', version : '>=1.4', method : 'cups-config')
dep = dependency('cups', version : '>=1.4', method : 'config-tool')
+
+# check we can apply a version constraint
+dependency('cups', version: '>=@0@'.format(dep.version()), method: 'pkg-config', required: false)
+dependency('cups', version: '>=@0@'.format(dep.version()), method: 'config-tool')
diff --git a/test cases/frameworks/21 libwmf/meson.build b/test cases/frameworks/21 libwmf/meson.build
index 1fdce2e..ab0ebf6 100644
--- a/test cases/frameworks/21 libwmf/meson.build
+++ b/test cases/frameworks/21 libwmf/meson.build
@@ -17,3 +17,7 @@ test('libwmftest', e)
dependency('libwmf', method : 'config-tool')
dependency('libwmf', method : 'libwmf-config')
+
+# Check we can apply a version constraint
+dependency('libwmf', version: '>=@0@'.format(libwmf_dep.version()), method: 'pkg-config', required: false)
+dependency('libwmf', version: '>=@0@'.format(libwmf_dep.version()), method: 'config-tool')
diff --git a/test cases/frameworks/4 qt/meson.build b/test cases/frameworks/4 qt/meson.build
index 16fe564..1d7ff4e 100644
--- a/test cases/frameworks/4 qt/meson.build
+++ b/test cases/frameworks/4 qt/meson.build
@@ -103,5 +103,9 @@ foreach qt : ['qt4', 'qt5']
if qt == 'qt5'
subdir('subfolder')
endif
+
+ # Check we can apply a version constraint
+ dependency(qt, modules: qt_modules, version: '>=@0@'.format(qtdep.version()), method : get_option('method'))
+
endif
endforeach
diff --git a/test cases/frameworks/9 wxwidgets/meson.build b/test cases/frameworks/9 wxwidgets/meson.build
index d815a2d..0c7ecaa 100644
--- a/test cases/frameworks/9 wxwidgets/meson.build
+++ b/test cases/frameworks/9 wxwidgets/meson.build
@@ -12,4 +12,8 @@ if wxd.found()
wx_stc = dependency('wxwidgets', version : '>=3.0.0', modules : ['std', 'stc'])
stc_exe = executable('wxstc', 'wxstc.cpp', dependencies : wx_stc)
test('wxstctest', stc_exe)
+
+ # Check we can apply a version constraint
+ dependency('wxwidgets', version: '>=@0@'.format(wxd.version()))
+
endif
diff --git a/test cases/python3/2 extmodule/meson.build b/test cases/python3/2 extmodule/meson.build
index 0ecc813..4916a69 100644
--- a/test cases/python3/2 extmodule/meson.build
+++ b/test cases/python3/2 extmodule/meson.build
@@ -14,6 +14,10 @@ if py3_dep.found()
py3,
args : files('blaster.py'),
env : ['PYTHONPATH=' + pypathdir])
+
+ # Check we can apply a version constraint
+ dependency('python3', version: '>=@0@'.format(py3_dep.version()))
+
else
error('MESON_SKIP_TEST: Python3 libraries not found, skipping test.')
endif
diff --git a/test cases/unit/39 external, internal library rpath/built library/meson.build b/test cases/unit/39 external, internal library rpath/built library/meson.build
index 2b422f4..f633996 100644
--- a/test cases/unit/39 external, internal library rpath/built library/meson.build
+++ b/test cases/unit/39 external, internal library rpath/built library/meson.build
@@ -1,12 +1,21 @@
project('built library', 'c')
cc = meson.get_compiler('c')
+
+if host_machine.system() != 'cygwin'
+ # bar_in_system has undefined symbols, but still must be found
+ bar_system_dep = cc.find_library('bar_in_system')
+endif
+
foo_system_dep = cc.find_library('foo_in_system')
+
faa_pkg_dep = dependency('faa_pkg')
l = shared_library('bar_built', 'bar.c',
install: true,
dependencies : [foo_system_dep, faa_pkg_dep])
-e = executable('prog', 'prog.c', link_with: l, install: true)
-test('testprog', e)
+if host_machine.system() == 'darwin'
+ e = executable('prog', 'prog.c', link_with: l, install: true)
+ test('testprog', e)
+endif
diff --git a/test cases/unit/39 external, internal library rpath/external library/bar.c b/test cases/unit/39 external, internal library rpath/external library/bar.c
new file mode 100644
index 0000000..c6f42d6
--- /dev/null
+++ b/test cases/unit/39 external, internal library rpath/external library/bar.c
@@ -0,0 +1,6 @@
+int some_undefined_func (void);
+
+int bar_system_value (void)
+{
+ return some_undefined_func ();
+}
diff --git a/test cases/unit/39 external, internal library rpath/external library/meson.build b/test cases/unit/39 external, internal library rpath/external library/meson.build
index 6dcc97e..3c311f5 100644
--- a/test cases/unit/39 external, internal library rpath/external library/meson.build
+++ b/test cases/unit/39 external, internal library rpath/external library/meson.build
@@ -1,9 +1,22 @@
-project('system library', 'c')
+project('system library', 'c', default_options : ['b_lundef=false'])
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']
+ allow_undef_args = ['-Wl,-undefined,dynamic_lookup']
+else
+ frameworks = []
+ allow_undef_args = []
+endif
+
pkg = import('pkgconfig')
pkg.generate(name: 'faa_pkg',
- libraries: [l, '-framework', 'CoreFoundation', '-framework', 'CoreMedia'],
+ libraries: [l] + frameworks,
description: 'FAA, a pkg-config test library')
+
+# cygwin DLLs can't have undefined symbols
+if host_machine.system() != 'cygwin'
+ shared_library('bar_in_system', 'bar.c', install : true, link_args : allow_undef_args)
+endif
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build b/test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build
new file mode 100644
index 0000000..1b97435
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build
@@ -0,0 +1,5 @@
+dll_res = win.compile_resources('src_dll/version.rc')
+shared_library('lib3', 'src_dll/main.c', dll_res)
+
+exe_res = win.compile_resources('src_exe/version.rc')
+executable('exe3', 'src_exe/main.c', exe_res)
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c
new file mode 100644
index 0000000..673b5e4
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c
@@ -0,0 +1,6 @@
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return TRUE;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc
new file mode 100644
index 0000000..abdbaaa
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c
new file mode 100644
index 0000000..11b7fad
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c
@@ -0,0 +1,3 @@
+int main(int argc, char **argv) {
+ return 0;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc
new file mode 100644
index 0000000..abdbaaa
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build b/test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build
new file mode 100644
index 0000000..2ae3a71
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build
@@ -0,0 +1,5 @@
+dll_res = win.compile_resources(files('src_dll/version.rc'))
+shared_library('lib4', 'src_dll/main.c', dll_res)
+
+exe_res = win.compile_resources(files('src_exe/version.rc'))
+executable('exe4', 'src_exe/main.c', exe_res)
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c
new file mode 100644
index 0000000..673b5e4
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c
@@ -0,0 +1,6 @@
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return TRUE;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc
new file mode 100644
index 0000000..abdbaaa
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c
new file mode 100644
index 0000000..11b7fad
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c
@@ -0,0 +1,3 @@
+int main(int argc, char **argv) {
+ return 0;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc
new file mode 100644
index 0000000..abdbaaa
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/meson.build b/test cases/windows/15 resource scripts with duplicate filenames/meson.build
index 4073a8e..9fa3525 100644
--- a/test cases/windows/15 resource scripts with duplicate filenames/meson.build
+++ b/test cases/windows/15 resource scripts with duplicate filenames/meson.build
@@ -5,6 +5,8 @@ win = import('windows')
subdir('a')
subdir('b')
subdir('c')
+subdir('exe3')
+subdir('exe4')
main = win.compile_resources('rsrc.rc')