aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Commands.md29
-rw-r--r--docs/markdown/Dependencies.md6
-rw-r--r--docs/markdown/snippets/dataonly-pkgconfig-default-install-path.md4
-rw-r--r--docs/markdown/snippets/env2mfile.md40
-rw-r--r--docs/markdown/snippets/openssl_dependency.md11
-rw-r--r--docs/markdown/snippets/rust_proc_macro_crates.md16
-rw-r--r--docs/markdown/snippets/strip.md5
-rw-r--r--docs/yaml/functions/_build_target_base.yaml20
-rw-r--r--man/meson.12
-rw-r--r--mesonbuild/ast/interpreter.py14
-rw-r--r--mesonbuild/backend/backends.py10
-rw-r--r--mesonbuild/build.py8
-rw-r--r--mesonbuild/compilers/cpp.py2
-rw-r--r--mesonbuild/compilers/detect.py2
-rw-r--r--mesonbuild/coredata.py6
-rw-r--r--mesonbuild/dependencies/detect.py12
-rw-r--r--mesonbuild/dependencies/pkgconfig.py4
-rw-r--r--mesonbuild/dependencies/qt.py4
-rw-r--r--mesonbuild/envconfig.py2
-rw-r--r--mesonbuild/environment.py4
-rw-r--r--mesonbuild/interpreter/interpreter.py16
-rw-r--r--mesonbuild/interpreter/interpreterobjects.py2
-rw-r--r--mesonbuild/interpreter/mesonmain.py2
-rw-r--r--mesonbuild/interpreter/primitives/array.py3
-rw-r--r--mesonbuild/interpreter/primitives/dict.py3
-rw-r--r--mesonbuild/interpreter/primitives/integer.py5
-rw-r--r--mesonbuild/interpreter/primitives/string.py5
-rw-r--r--mesonbuild/interpreter/type_checking.py3
-rw-r--r--mesonbuild/interpreterbase/baseobjects.py14
-rw-r--r--mesonbuild/interpreterbase/decorators.py48
-rw-r--r--mesonbuild/interpreterbase/disabler.py7
-rw-r--r--mesonbuild/interpreterbase/interpreterbase.py5
-rw-r--r--mesonbuild/linkers/detect.py8
-rw-r--r--mesonbuild/linkers/linkers.py2
-rw-r--r--mesonbuild/mesonlib/universal.py4
-rw-r--r--mesonbuild/mesonmain.py4
-rw-r--r--mesonbuild/minstall.py23
-rw-r--r--mesonbuild/mlog.py2
-rw-r--r--mesonbuild/modules/gnome.py10
-rw-r--r--mesonbuild/modules/java.py13
-rw-r--r--mesonbuild/modules/pkgconfig.py1
-rw-r--r--mesonbuild/modules/python.py68
-rw-r--r--mesonbuild/modules/qt.py2
-rwxr-xr-xmesonbuild/scripts/env2mfile.py368
-rw-r--r--mesonbuild/wrap/wraptool.py2
-rw-r--r--test cases/common/44 pkgconfig-gen/test.json4
-rw-r--r--test cases/common/66 vcstag/meson.build6
-rw-r--r--test cases/failing/54 wrong shared crate type/test.json2
-rw-r--r--test cases/java/9 jni/meson.build15
-rw-r--r--test cases/java/9 jni/src/com/mesonbuild/Configured.java.in5
-rw-r--r--test cases/java/9 jni/src/com/mesonbuild/JniTest.java2
-rw-r--r--test cases/java/9 jni/src/com/mesonbuild/meson.build10
-rw-r--r--test cases/java/9 jni/src/meson.build18
-rw-r--r--test cases/osx/7 bitcode/meson.build3
-rw-r--r--test cases/rust/18 proc-macro/meson.build19
-rw-r--r--test cases/rust/18 proc-macro/proc.rs7
-rw-r--r--test cases/rust/18 proc-macro/use.rs8
-rw-r--r--test cases/unit/104 strip/lib.c1
-rw-r--r--test cases/unit/104 strip/meson.build3
-rwxr-xr-xtools/regenerate_docs.py19
-rw-r--r--unittests/allplatformstests.py16
-rw-r--r--unittests/linuxliketests.py20
62 files changed, 802 insertions, 177 deletions
diff --git a/docs/markdown/Commands.md b/docs/markdown/Commands.md
index 3542aa4..f905d2c 100644
--- a/docs/markdown/Commands.md
+++ b/docs/markdown/Commands.md
@@ -150,6 +150,35 @@ Create a project in `sourcedir`:
meson init -C sourcedir
```
+### env2mfile
+
+*This command is experimental and subject to change.*
+
+*{Since 0.62.0}*
+
+{{ env2mfile_usage.inc }}
+
+Create native and cross files from the current environment, typically
+by sniffing environment variables like `CC` and `CFLAGS`.
+
+{{ env2mfile_arguments.inc }}
+
+#### Examples:
+
+Autodetect the current cross build environment:
+
+```
+meson env2mfile --cross -o current_cross.txt --cpu=arm7a --cpu-family=arm --system=linux
+```
+
+Generate a cross build using Debian system information:
+
+```
+meson env2mfile --cross --debarch=armhf -o deb_arm_cross.txt
+```
+
+
+
### introspect
{{ introspect_usage.inc }}
diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md
index 8165955..15da929 100644
--- a/docs/markdown/Dependencies.md
+++ b/docs/markdown/Dependencies.md
@@ -625,6 +625,12 @@ for OpenMP support.
The `language` keyword may used.
+## OpenSSL
+
+*(added 0.62.0)*
+
+`method` may be `auto`, `pkg-config`, `system` or `cmake`.
+
## pcap
*(added 0.42.0)*
diff --git a/docs/markdown/snippets/dataonly-pkgconfig-default-install-path.md b/docs/markdown/snippets/dataonly-pkgconfig-default-install-path.md
new file mode 100644
index 0000000..d968158
--- /dev/null
+++ b/docs/markdown/snippets/dataonly-pkgconfig-default-install-path.md
@@ -0,0 +1,4 @@
+## `dataonly` Pkgconfig Default Install Path
+
+The default install path for `dataonly` pkgconfig files has changed from
+`${libdir}/pkgconfig` to `${datadir}/pkgconfig`.
diff --git a/docs/markdown/snippets/env2mfile.md b/docs/markdown/snippets/env2mfile.md
new file mode 100644
index 0000000..a575618
--- /dev/null
+++ b/docs/markdown/snippets/env2mfile.md
@@ -0,0 +1,40 @@
+## Experimental command to convert environments to cross files
+
+Meson has a new command `env2mfile` that can be used to convert
+"environment variable based" cross and native compilation environments
+to Meson machine files. This is especially convenient for e.g. distro
+packagers so they can easily generate unambiguous configuration files
+for packge building.
+
+As an example here's how you would generate a cross file that takes
+its settings from the `CC`, `CXX`, `CFLAGS` etc environment variables.
+
+ meson env2mfile --cross --system=baremetal --cpu=armv7 --cpu-family=arm -o armcross.txt
+
+The command also has support for generating Debian build files using
+system introspection:
+
+ meson env2mfile --cross --debarch armhf -o debarmhf_cross.txt
+
+Note how you don't need to specify any system details, the command
+gets them transparently via `dpkg-architecture`.
+
+Creating a native file is done in the same way:
+
+ meson env2mfile --native -o current_system.txt
+
+This system will detect if the `_FOR_BUILD` environment variables are
+enabled and then uses them as needed.
+
+With this you should be able to convert any envvar-based cross build
+setup to cross and native files and then use those. This means, among
+other things, that you can then run your compilations from any shell,
+not just the special one that has all the environment variables set.
+
+As this functionality is still a bit in flux, the specific behaviour
+and command line arguments to use are subject to change. Because of
+this the main documentation has not yet been updated.
+
+Please try this for your use cases and report to us if it is working.
+Patches to make the autodetection work on other distros and platforms
+are also welcome.
diff --git a/docs/markdown/snippets/openssl_dependency.md b/docs/markdown/snippets/openssl_dependency.md
new file mode 100644
index 0000000..f6f9b63
--- /dev/null
+++ b/docs/markdown/snippets/openssl_dependency.md
@@ -0,0 +1,11 @@
+## New custom dependency for OpenSSL
+
+Detecting an OpenSSL installation in a cross-platform manner can be
+complicated. Officially, pkg-config is supported by upstream. Unofficially,
+cmake includes a FindOpenSSL using a different name and which requires
+specifying modules.
+
+Meson will now allow the pkg-config name to work in all cases using the following lookup order:
+- prefer pkg-config if at all possible
+- attempt to probe the system for the standard library naming, and retrieve the version from the headers
+- if all else fails, check if cmake can find it
diff --git a/docs/markdown/snippets/rust_proc_macro_crates.md b/docs/markdown/snippets/rust_proc_macro_crates.md
new file mode 100644
index 0000000..780a5b3
--- /dev/null
+++ b/docs/markdown/snippets/rust_proc_macro_crates.md
@@ -0,0 +1,16 @@
+## Rust proc-macro crates
+
+Rust has these handy things called proc-macro crates, which are a bit like a
+compiler plugin. We can now support them, simply build a [[shared_library]] with
+the `rust_crate_type` set to `proc-macro`.
+
+```meson
+proc = shared_library(
+ 'proc',
+ 'proc.rs',
+ rust_crate_type : 'proc-macro',
+ install : false,
+)
+
+user = executable('user, 'user.rs', link_with : proc)
+```
diff --git a/docs/markdown/snippets/strip.md b/docs/markdown/snippets/strip.md
new file mode 100644
index 0000000..e971df6
--- /dev/null
+++ b/docs/markdown/snippets/strip.md
@@ -0,0 +1,5 @@
+## `meson install --strip`
+
+It is now possible to strip targets using `meson install --strip` even if
+`-Dstrip=true` option was not set during configuration. This allows doing
+stripped and not stripped installations without reconfiguring the build.
diff --git a/docs/yaml/functions/_build_target_base.yaml b/docs/yaml/functions/_build_target_base.yaml
index 4db37f4..87966f6 100644
--- a/docs/yaml/functions/_build_target_base.yaml
+++ b/docs/yaml/functions/_build_target_base.yaml
@@ -276,3 +276,23 @@ kwargs:
version specification such as `windows,6.0`. See [MSDN
documentation](https://docs.microsoft.com/en-us/cpp/build/reference/subsystem-specify-subsystem)
for the full list.
+
+ rust_crate_type:
+ type: str
+ since: 0.41.0
+ description: |
+ Set the specific type of rust crate to compile (when compiling rust).
+
+ If the target is an [[executable]] this defaults to "bin", the only
+ allowed value.
+
+ If it is a [[static_library]] it defaults to "lib", and may be "lib",
+ "staticlib", or "rlib". If "lib" then Rustc will pick a default, "staticlib"
+ means a C ABI library, "rlib" means a Rust ABI.
+
+ If it is a [[shared_library]] it defaults to "lib", and may be "lib",
+ "dylib", "cdylib", or "proc-macro". If "lib" then Rustc will pick a
+ default, "cdylib" means a C ABI library, "dylib" means a Rust ABI, and
+ "proc-macro" is a special rust proceedural macro crate.
+
+ "proc-macro" is new in 0.62.0.
diff --git a/man/meson.1 b/man/meson.1
index 0443d6e..8a7999e 100644
--- a/man/meson.1
+++ b/man/meson.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "January 2022" "meson 0.61.0" "User Commands"
+.TH MESON "1" "March 2022" "meson 0.62.0" "User Commands"
.SH NAME
meson - a high productivity build system
.SH DESCRIPTION
diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py
index e5ff266..e3d3e93 100644
--- a/mesonbuild/ast/interpreter.py
+++ b/mesonbuild/ast/interpreter.py
@@ -31,7 +31,6 @@ from ..interpreterbase import (
)
from ..interpreter import (
- Interpreter,
StringHolder,
BooleanHolder,
IntegerHolder,
@@ -64,6 +63,9 @@ from ..mparser import (
import os, sys
import typing as T
+if T.TYPE_CHECKING:
+ from ..interpreter import Interpreter
+
class DontCareObject(MesonInterpreterObject):
pass
@@ -379,15 +381,15 @@ class AstInterpreter(InterpreterBase):
mkwargs = {} # type: T.Dict[str, TYPE_nvar]
try:
if isinstance(src, str):
- result = StringHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
+ result = StringHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, bool):
- result = BooleanHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
+ result = BooleanHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, int):
- result = IntegerHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
+ result = IntegerHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, list):
- result = ArrayHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
+ result = ArrayHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, dict):
- result = DictHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
+ result = DictHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
except mesonlib.MesonException:
return None
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index b98eb08..6a78ed0 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -144,6 +144,7 @@ class TargetInstallData:
subproject: str
optional: bool = False
tag: T.Optional[str] = None
+ can_strip: bool = False
def __post_init__(self, outdir_name: str) -> None:
self.out_name = os.path.join(outdir_name, os.path.basename(self.fname))
@@ -328,7 +329,7 @@ class Backend:
# cast, we know what's in coredata anyway.
# TODO: if it's possible to annotate get_option or validate_option_value
# in the future we might be able to remove the cast here
- return T.cast(T.Union[str, int, bool, 'WrapMode'], v)
+ return T.cast('T.Union[str, int, bool, WrapMode]', v)
def get_source_dir_include_args(self, target: build.BuildTarget, compiler: 'Compiler', *, absolute_path: bool = False) -> T.List[str]:
curdir = target.get_subdir()
@@ -937,7 +938,7 @@ class Backend:
commands += compiler.get_no_warn_args()
else:
# warning_level is a string, but mypy can't determine that
- commands += compiler.get_warn_args(T.cast(str, self.get_option_for_target(OptionKey('warning_level'), target)))
+ commands += compiler.get_warn_args(T.cast('str', self.get_option_for_target(OptionKey('warning_level'), target)))
# Add -Werror if werror=true is set in the build options set on the
# command-line or default_options inside project(). This only sets the
# action to be done for warnings if/when they are emitted, so it's ok
@@ -1573,7 +1574,8 @@ class Backend:
#
# TODO: Create GNUStrip/AppleStrip/etc. hierarchy for more
# fine-grained stripping of static archives.
- should_strip = not isinstance(t, build.StaticLibrary) and self.get_option_for_target(OptionKey('strip'), t)
+ can_strip = not isinstance(t, build.StaticLibrary)
+ should_strip = can_strip and self.get_option_for_target(OptionKey('strip'), t)
assert isinstance(should_strip, bool), 'for mypy'
# Install primary build output (library/executable/jar, etc)
# Done separately because of strip/aliases/rpath
@@ -1584,7 +1586,7 @@ class Backend:
install_dir_name,
should_strip, mappings, t.rpath_dirs_to_remove,
t.install_rpath, install_mode, t.subproject,
- tag=tag)
+ tag=tag, can_strip=can_strip)
d.targets.append(i)
for alias, to, tag in t.get_aliases():
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index f2de50c..fbc1618 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -712,7 +712,7 @@ class Target(HoldableObject):
# In this case we have an already parsed and ready to go dictionary
# provided by typed_kwargs
if isinstance(opts, dict):
- return T.cast(T.Dict[OptionKey, str], opts)
+ return T.cast('T.Dict[OptionKey, str]', opts)
result: T.Dict[OptionKey, str] = {}
overrides = stringlistify(opts)
@@ -2069,8 +2069,8 @@ class SharedLibrary(BuildTarget):
mlog.debug('Defaulting Rust dynamic library target crate type to "dylib"')
self.rust_crate_type = 'dylib'
# Don't let configuration proceed with a non-dynamic crate type
- elif self.rust_crate_type not in ['dylib', 'cdylib']:
- raise InvalidArguments(f'Crate type "{self.rust_crate_type}" invalid for dynamic libraries; must be "dylib" or "cdylib"')
+ elif self.rust_crate_type not in ['dylib', 'cdylib', 'proc-macro']:
+ raise InvalidArguments(f'Crate type "{self.rust_crate_type}" invalid for dynamic libraries; must be "dylib", "cdylib", or "proc-macro"')
if not hasattr(self, 'prefix'):
self.prefix = None
if not hasattr(self, 'suffix'):
@@ -2302,6 +2302,8 @@ class SharedLibrary(BuildTarget):
self.rust_crate_type = rust_crate_type
else:
raise InvalidArguments(f'Invalid rust_crate_type "{rust_crate_type}": must be a string.')
+ if rust_crate_type == 'proc-macro':
+ FeatureNew.single_use('Rust crate type "proc-macro"', '0.62.0', self.subproject)
def get_import_filename(self) -> T.Optional[str]:
"""
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index a26f731..8baa727 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -622,7 +622,7 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase):
def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
# need a typeddict for this
key = OptionKey('winlibs', machine=self.for_machine, lang=self.language)
- return T.cast(T.List[str], options[key].value[:])
+ return T.cast('T.List[str]', options[key].value[:])
def _get_options_impl(self, opts: 'KeyedOptionDictType', cpp_stds: T.List[str]) -> 'KeyedOptionDictType':
key = OptionKey('std', machine=self.for_machine, lang=self.language)
diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py
index 6a595e1..c48b62c 100644
--- a/mesonbuild/compilers/detect.py
+++ b/mesonbuild/compilers/detect.py
@@ -1055,7 +1055,7 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
else:
linker = type(cc.linker)(compiler, for_machine, cc.LINKER_PREFIX,
always_args=always_args, version=cc.linker.version,
- **extra_args) # type: ignore
+ **extra_args)
elif 'link' in override[0]:
linker = guess_win_linker(env,
override, cls, for_machine, use_linker_prefix=False)
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index f4365e1..04264e5 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -35,6 +35,7 @@ import typing as T
if T.TYPE_CHECKING:
from . import dependencies
from .compilers.compilers import Compiler, CompileResult
+ from .dependencies.detect import TV_DepID
from .environment import Environment
from .mesonlib import OptionOverrideProxy, FileOrString
from .cmake.traceparser import CMakeCacheEntry
@@ -50,7 +51,7 @@ if T.TYPE_CHECKING:
#
# Pip requires that RCs are named like this: '0.1.0.rc1'
# But the corresponding Git tag needs to be '0.1.0rc1'
-version = '0.61.99'
+version = '0.62.0.rc1'
backendlist = ['ninja', 'vs', 'vs2010', 'vs2012', 'vs2013', 'vs2015', 'vs2017', 'vs2019', 'vs2022', 'xcode']
@@ -282,9 +283,6 @@ class UserFeatureOption(UserComboOption):
def is_auto(self) -> bool:
return self.value == 'auto'
-if T.TYPE_CHECKING:
- from .dependencies.detect import TV_DepID
-
class DependencyCacheType(enum.Enum):
diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py
index f54d101..a721cba 100644
--- a/mesonbuild/dependencies/detect.py
+++ b/mesonbuild/dependencies/detect.py
@@ -27,6 +27,9 @@ if T.TYPE_CHECKING:
from ..environment import Environment
from .factory import DependencyFactory, WrappedFactoryFunc, DependencyGenerator
+ TV_DepIDEntry = T.Union[str, bool, int, T.Tuple[str, ...]]
+ TV_DepID = T.Tuple[T.Tuple[str, TV_DepIDEntry], ...]
+
# These must be defined in this file to avoid cyclical references.
packages: T.Dict[
str,
@@ -34,11 +37,6 @@ packages: T.Dict[
] = {}
_packages_accept_language: T.Set[str] = set()
-if T.TYPE_CHECKING:
- TV_DepIDEntry = T.Union[str, bool, int, T.Tuple[str, ...]]
- TV_DepID = T.Tuple[T.Tuple[str, TV_DepIDEntry], ...]
-
-
def get_dep_identifier(name: str, kwargs: T.Dict[str, T.Any]) -> 'TV_DepID':
identifier: 'TV_DepID' = (('name', name), )
from ..interpreter import permitted_dependency_kwargs
@@ -178,13 +176,13 @@ def _build_external_dependency_list(name: str, env: 'Environment', for_machine:
# class method, if one exists, otherwise the list just consists of the
# constructor
if isinstance(packages[lname], type):
- entry1 = T.cast(T.Type[ExternalDependency], packages[lname]) # mypy doesn't understand isinstance(..., type)
+ entry1 = T.cast('T.Type[ExternalDependency]', packages[lname]) # mypy doesn't understand isinstance(..., type)
if issubclass(entry1, ExternalDependency):
# TODO: somehow make mypy understand that entry1(env, kwargs) is OK...
func: T.Callable[[], 'ExternalDependency'] = lambda: entry1(env, kwargs) # type: ignore
dep = [func]
else:
- entry2 = T.cast(T.Union['DependencyFactory', 'WrappedFactoryFunc'], packages[lname])
+ entry2 = T.cast('T.Union[DependencyFactory, WrappedFactoryFunc]', packages[lname])
dep = entry2(env, for_machine, kwargs)
return dep
diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py
index 73f2e60..55a364c 100644
--- a/mesonbuild/dependencies/pkgconfig.py
+++ b/mesonbuild/dependencies/pkgconfig.py
@@ -11,9 +11,10 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
from .base import ExternalDependency, DependencyException, sort_libpaths, DependencyTypeName
-from ..mesonlib import MachineChoice, OptionKey, OrderedSet, PerMachine, Popen_safe
+from ..mesonlib import OptionKey, OrderedSet, PerMachine, Popen_safe
from ..programs import find_external_program, ExternalProgram
from .. import mlog
from pathlib import PurePath
@@ -24,6 +25,7 @@ import typing as T
if T.TYPE_CHECKING:
from ..environment import Environment
+ from ..mesonlib import MachineChoice
from .._typing import ImmutableListProtocol
class PkgConfigDependency(ExternalDependency):
diff --git a/mesonbuild/dependencies/qt.py b/mesonbuild/dependencies/qt.py
index a004688..f645f0e 100644
--- a/mesonbuild/dependencies/qt.py
+++ b/mesonbuild/dependencies/qt.py
@@ -127,13 +127,13 @@ class _QtBase:
else:
self.qtpkgname = self.qtname
- self.private_headers = T.cast(bool, kwargs.get('private_headers', False))
+ self.private_headers = T.cast('bool', kwargs.get('private_headers', False))
self.requested_modules = mesonlib.stringlistify(mesonlib.extract_as_list(kwargs, 'modules'))
if not self.requested_modules:
raise DependencyException('No ' + self.qtname + ' modules specified.')
- self.qtmain = T.cast(bool, kwargs.get('main', False))
+ self.qtmain = T.cast('bool', kwargs.get('main', False))
if not isinstance(self.qtmain, bool):
raise DependencyException('"main" argument must be a boolean')
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index 94127dc..0723675 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -216,7 +216,7 @@ class Properties:
return res
def get_java_home(self) -> T.Optional[Path]:
- value = T.cast(T.Optional[str], self.properties.get('java_home'))
+ value = T.cast('T.Optional[str]', self.properties.get('java_home'))
return Path(value) if value else None
def __eq__(self, other: object) -> bool:
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index b2ddb44..5e8575a 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -47,6 +47,7 @@ from functools import lru_cache
from mesonbuild import envconfig
if T.TYPE_CHECKING:
+ import argparse
from configparser import ConfigParser
from .wrap.wrap import Resolver
@@ -55,9 +56,6 @@ build_filename = 'meson.build'
CompilersDict = T.Dict[str, Compiler]
-if T.TYPE_CHECKING:
- import argparse
-
def _get_env_var(for_machine: MachineChoice, is_cross: bool, var_name: str) -> T.Optional[str]:
"""
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index bc011b7..27f4c69 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -33,10 +33,9 @@ from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCod
from ..interpreterbase import Disabler, disablerIfNotFound
from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs
from ..interpreterbase import ObjectHolder
-from ..interpreterbase.baseobjects import InterpreterObject, TYPE_var, TYPE_kwargs
from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule
from ..cmake import CMakeInterpreter
-from ..backend.backends import Backend, ExecutableSerialisation
+from ..backend.backends import ExecutableSerialisation
from . import interpreterobjects as OBJ
from . import compiler as compilerOBJ
@@ -96,6 +95,8 @@ if T.TYPE_CHECKING:
from typing_extensions import Literal
from . import kwargs
+ from ..backend.backends import Backend
+ from ..interpreterbase.baseobjects import InterpreterObject, TYPE_var, TYPE_kwargs
from ..programs import OverrideProgram
# Input source types passed to Targets
@@ -798,8 +799,6 @@ external dependencies (including libraries) must go to "dependencies".''')
def func_option(self, nodes, args, kwargs):
raise InterpreterException('Tried to call option() in build description file. All options must be in the option file.')
- @FeatureNewKwargs('subproject', '0.38.0', ['default_options'])
- @permittedKwargs({'version', 'default_options', 'required'})
@typed_pos_args('subproject', str)
@typed_kwargs(
'subproject',
@@ -1731,7 +1730,9 @@ external dependencies (including libraries) must go to "dependencies".''')
vcs_cmd = kwargs['command']
source_dir = os.path.normpath(os.path.join(self.environment.get_source_dir(), self.subdir))
if vcs_cmd:
- vcs_cmd[0] = self.find_program_impl(vcs_cmd[0])
+ maincmd = self.find_program_impl(vcs_cmd[0], required=False)
+ if maincmd.found():
+ vcs_cmd[0] = maincmd
else:
vcs = mesonlib.detect_vcs(source_dir)
if vcs:
@@ -1987,7 +1988,10 @@ external dependencies (including libraries) must go to "dependencies".''')
location=node)
name = name.replace(':', '_')
exe = args[1]
- if isinstance(exe, mesonlib.File):
+ if isinstance(exe, ExternalProgram):
+ if not exe.found():
+ raise InvalidArguments('Tried to use not-found external program as test exe')
+ elif isinstance(exe, mesonlib.File):
exe = self.find_program_impl([exe])
env = self.unpack_env_kwarg(kwargs)
diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py
index d3bab08..bf668f3 100644
--- a/mesonbuild/interpreter/interpreterobjects.py
+++ b/mesonbuild/interpreter/interpreterobjects.py
@@ -88,7 +88,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
super().__init__(option, interpreter)
if option and option.is_auto():
# TODO: we need to case here because options is not a TypedDict
- self.held_object = T.cast(coredata.UserFeatureOption, self.env.coredata.options[OptionKey('auto_features')])
+ self.held_object = T.cast('coredata.UserFeatureOption', self.env.coredata.options[OptionKey('auto_features')])
self.held_object.name = option.name
self.methods.update({'enabled': self.enabled_method,
'disabled': self.disabled_method,
diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py
index 4533c4a..01d0029 100644
--- a/mesonbuild/interpreter/mesonmain.py
+++ b/mesonbuild/interpreter/mesonmain.py
@@ -372,7 +372,7 @@ class MesonMain(MesonInterpreterObject):
static: T.Optional[bool], permissive: bool = False) -> None:
# We need the cast here as get_dep_identifier works on such a dict,
# which FuncOverrideDependency is, but mypy can't fgure that out
- nkwargs = T.cast(T.Dict[str, T.Any], kwargs.copy())
+ nkwargs = T.cast('T.Dict[str, T.Any]', kwargs.copy())
if static is None:
del nkwargs['static']
else:
diff --git a/mesonbuild/interpreter/primitives/array.py b/mesonbuild/interpreter/primitives/array.py
index e48e1c2..eeea112 100644
--- a/mesonbuild/interpreter/primitives/array.py
+++ b/mesonbuild/interpreter/primitives/array.py
@@ -1,5 +1,6 @@
# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
+from __future__ import annotations
import typing as T
@@ -15,7 +16,6 @@ from ...interpreterbase import (
FeatureNew,
TYPE_var,
- TYPE_kwargs,
InvalidArguments,
)
@@ -24,6 +24,7 @@ from ...mparser import PlusAssignmentNode
if T.TYPE_CHECKING:
# Object holders need the actual interpreter
from ...interpreter import Interpreter
+ from ...interpreterbase import TYPE_kwargs
class ArrayHolder(ObjectHolder[T.List[TYPE_var]], IterableObject):
def __init__(self, obj: T.List[TYPE_var], interpreter: 'Interpreter') -> None:
diff --git a/mesonbuild/interpreter/primitives/dict.py b/mesonbuild/interpreter/primitives/dict.py
index 24f4d21..ac7c99b 100644
--- a/mesonbuild/interpreter/primitives/dict.py
+++ b/mesonbuild/interpreter/primitives/dict.py
@@ -1,5 +1,6 @@
# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
+from __future__ import annotations
import typing as T
@@ -14,7 +15,6 @@ from ...interpreterbase import (
typed_pos_args,
TYPE_var,
- TYPE_kwargs,
InvalidArguments,
)
@@ -22,6 +22,7 @@ from ...interpreterbase import (
if T.TYPE_CHECKING:
# Object holders need the actual interpreter
from ...interpreter import Interpreter
+ from ...interpreterbase import TYPE_kwargs
class DictHolder(ObjectHolder[T.Dict[str, TYPE_var]], IterableObject):
def __init__(self, obj: T.Dict[str, TYPE_var], interpreter: 'Interpreter') -> None:
diff --git a/mesonbuild/interpreter/primitives/integer.py b/mesonbuild/interpreter/primitives/integer.py
index 6563ee9..f433f57 100644
--- a/mesonbuild/interpreter/primitives/integer.py
+++ b/mesonbuild/interpreter/primitives/integer.py
@@ -1,5 +1,6 @@
# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
+from __future__ import annotations
from ...interpreterbase import (
ObjectHolder,
@@ -8,9 +9,6 @@ from ...interpreterbase import (
noKwargs,
noPosargs,
- TYPE_var,
- TYPE_kwargs,
-
InvalidArguments
)
@@ -19,6 +17,7 @@ import typing as T
if T.TYPE_CHECKING:
# Object holders need the actual interpreter
from ...interpreter import Interpreter
+ from ...interpreterbase import TYPE_var, TYPE_kwargs
class IntegerHolder(ObjectHolder[int]):
def __init__(self, obj: int, interpreter: 'Interpreter') -> None:
diff --git a/mesonbuild/interpreter/primitives/string.py b/mesonbuild/interpreter/primitives/string.py
index 9cd51b4..9129303 100644
--- a/mesonbuild/interpreter/primitives/string.py
+++ b/mesonbuild/interpreter/primitives/string.py
@@ -1,5 +1,6 @@
# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
+from __future__ import annotations
import re
import os
@@ -17,9 +18,6 @@ from ...interpreterbase import (
noPosargs,
typed_pos_args,
- TYPE_var,
- TYPE_kwargs,
-
InvalidArguments,
)
@@ -27,6 +25,7 @@ from ...interpreterbase import (
if T.TYPE_CHECKING:
# Object holders need the actual interpreter
from ...interpreter import Interpreter
+ from ...interpreterbase import TYPE_var, TYPE_kwargs
class StringHolder(ObjectHolder[str]):
def __init__(self, obj: str, interpreter: 'Interpreter') -> None:
diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py
index cce0024..37ab192 100644
--- a/mesonbuild/interpreter/type_checking.py
+++ b/mesonbuild/interpreter/type_checking.py
@@ -11,7 +11,6 @@ from .. import compilers
from ..build import (EnvironmentVariables, EnvInitValueType, CustomTarget, BuildTarget,
CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs)
from ..coredata import UserFeatureOption
-from ..interpreterbase import TYPE_var
from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo
from ..mesonlib import File, FileMode, MachineChoice, listify, has_path_sep, OptionKey
from ..programs import ExternalProgram
@@ -22,6 +21,8 @@ NoneType: T.Type[None] = type(None)
if T.TYPE_CHECKING:
from typing_extensions import Literal
+ from ..interpreterbase import TYPE_var
+
def in_set_validator(choices: T.Set[str]) -> T.Callable[[str], T.Optional[str]]:
"""Check that the choice given was one of the given set."""
diff --git a/mesonbuild/interpreterbase/baseobjects.py b/mesonbuild/interpreterbase/baseobjects.py
index 7186001..2e675e2 100644
--- a/mesonbuild/interpreterbase/baseobjects.py
+++ b/mesonbuild/interpreterbase/baseobjects.py
@@ -23,9 +23,16 @@ import typing as T
from abc import ABCMeta
if T.TYPE_CHECKING:
+ from typing_extensions import Protocol
+
# Object holders need the actual interpreter
from ..interpreter import Interpreter
+ __T = T.TypeVar('__T', bound=TYPE_var, contravariant=True)
+
+ class OperatorCall(Protocol[__T]):
+ def __call__(self, other: __T) -> TYPE_var: ...
+
TV_fw_var = T.Union[str, int, bool, list, dict, 'InterpreterObject']
TV_fw_args = T.List[T.Union[mparser.BaseNode, TV_fw_var]]
TV_fw_kwargs = T.Dict[str, T.Union[mparser.BaseNode, TV_fw_var]]
@@ -41,13 +48,6 @@ TYPE_key_resolver = T.Callable[[mparser.BaseNode], str]
SubProject = T.NewType('SubProject', str)
-if T.TYPE_CHECKING:
- from typing_extensions import Protocol
- __T = T.TypeVar('__T', bound=TYPE_var, contravariant=True)
-
- class OperatorCall(Protocol[__T]):
- def __call__(self, other: __T) -> TYPE_var: ...
-
class InterpreterObject:
def __init__(self, *, subproject: T.Optional['SubProject'] = None) -> None:
self.methods: T.Dict[
diff --git a/mesonbuild/interpreterbase/decorators.py b/mesonbuild/interpreterbase/decorators.py
index 7c04483..e678fd9 100644
--- a/mesonbuild/interpreterbase/decorators.py
+++ b/mesonbuild/interpreterbase/decorators.py
@@ -11,12 +11,11 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
from .. import mesonlib, mlog
-from .baseobjects import TV_func, TYPE_var, TYPE_kwargs
from .disabler import Disabler
from .exceptions import InterpreterException, InvalidArguments
-from .operator import MesonOperator
from ._unholder import _unholder
from dataclasses import dataclass
@@ -25,9 +24,21 @@ import abc
import itertools
import copy
import typing as T
+
if T.TYPE_CHECKING:
+ from typing_extensions import Protocol
+
from .. import mparser
+ from .baseobjects import InterpreterObject, TV_func, TYPE_var, TYPE_kwargs
from .interpreterbase import SubProject
+ from .operator import MesonOperator
+
+ _TV_IntegerObject = T.TypeVar('_TV_IntegerObject', bound=InterpreterObject, contravariant=True)
+ _TV_ARG1 = T.TypeVar('_TV_ARG1', bound=TYPE_var, contravariant=True)
+
+ class FN_Operator(Protocol[_TV_IntegerObject, _TV_ARG1]):
+ def __call__(s, self: _TV_IntegerObject, other: _TV_ARG1) -> TYPE_var: ...
+ _TV_FN_Operator = T.TypeVar('_TV_FN_Operator', bound=FN_Operator)
def get_callee_args(wrapped_args: T.Sequence[T.Any]) -> T.Tuple['mparser.BaseNode', T.List['TYPE_var'], 'TYPE_kwargs', 'SubProject']:
# First argument could be InterpreterBase, InterpreterObject or ModuleObject.
@@ -51,7 +62,7 @@ def noPosargs(f: TV_func) -> TV_func:
if args:
raise InvalidArguments('Function does not take positional arguments.')
return f(*wrapped_args, **wrapped_kwargs)
- return T.cast(TV_func, wrapped)
+ return T.cast('TV_func', wrapped)
def noKwargs(f: TV_func) -> TV_func:
@wraps(f)
@@ -60,7 +71,7 @@ def noKwargs(f: TV_func) -> TV_func:
if kwargs:
raise InvalidArguments('Function does not take keyword arguments.')
return f(*wrapped_args, **wrapped_kwargs)
- return T.cast(TV_func, wrapped)
+ return T.cast('TV_func', wrapped)
def stringArgs(f: TV_func) -> TV_func:
@wraps(f)
@@ -73,7 +84,7 @@ def stringArgs(f: TV_func) -> TV_func:
mlog.debug('Element not a string:', str(args))
raise InvalidArguments('Arguments must be strings.')
return f(*wrapped_args, **wrapped_kwargs)
- return T.cast(TV_func, wrapped)
+ return T.cast('TV_func', wrapped)
def noArgsFlattening(f: TV_func) -> TV_func:
setattr(f, 'no-args-flattening', True) # noqa: B010
@@ -88,7 +99,7 @@ def unholder_return(f: TV_func) -> T.Callable[..., TYPE_var]:
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
res = f(*wrapped_args, **wrapped_kwargs)
return _unholder(res)
- return T.cast(T.Callable[..., TYPE_var], wrapped)
+ return T.cast('T.Callable[..., TYPE_var]', wrapped)
def disablerIfNotFound(f: TV_func) -> TV_func:
@wraps(f)
@@ -99,7 +110,7 @@ def disablerIfNotFound(f: TV_func) -> TV_func:
if disabler and not ret.found():
return Disabler()
return ret
- return T.cast(TV_func, wrapped)
+ return T.cast('TV_func', wrapped)
@dataclass(repr=False, eq=False)
class permittedKwargs:
@@ -114,18 +125,7 @@ class permittedKwargs:
ustr = ', '.join([f'"{u}"' for u in sorted(unknowns)])
raise InvalidArguments(f'Got unknown keyword arguments {ustr}')
return f(*wrapped_args, **wrapped_kwargs)
- return T.cast(TV_func, wrapped)
-
-if T.TYPE_CHECKING:
- from .baseobjects import InterpreterObject
- from typing_extensions import Protocol
-
- _TV_IntegerObject = T.TypeVar('_TV_IntegerObject', bound=InterpreterObject, contravariant=True)
- _TV_ARG1 = T.TypeVar('_TV_ARG1', bound=TYPE_var, contravariant=True)
-
- class FN_Operator(Protocol[_TV_IntegerObject, _TV_ARG1]):
- def __call__(s, self: _TV_IntegerObject, other: _TV_ARG1) -> TYPE_var: ...
- _TV_FN_Operator = T.TypeVar('_TV_FN_Operator', bound=FN_Operator)
+ return T.cast('TV_func', wrapped)
def typed_operator(operator: MesonOperator,
types: T.Union[T.Type, T.Tuple[T.Type, ...]]) -> T.Callable[['_TV_FN_Operator'], '_TV_FN_Operator']:
@@ -276,7 +276,7 @@ def typed_pos_args(name: str, *types: T.Union[T.Type, T.Tuple[T.Type, ...]],
nargs[i] = tuple(args)
return f(*nargs, **wrapped_kwargs)
- return T.cast(TV_func, wrapper)
+ return T.cast('TV_func', wrapper)
return inner
@@ -521,7 +521,7 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
node, _, _kwargs, subproject = get_callee_args(wrapped_args)
# Cast here, as the convertor function may place something other than a TYPE_var in the kwargs
- kwargs = T.cast(T.Dict[str, object], _kwargs)
+ kwargs = T.cast('T.Dict[str, object]', _kwargs)
all_names = {t.name for t in types}
unknowns = set(kwargs).difference(all_names)
@@ -572,7 +572,7 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
kwargs[info.name] = info.convertor(kwargs[info.name])
return f(*wrapped_args, **wrapped_kwargs)
- return T.cast(TV_func, wrapper)
+ return T.cast('TV_func', wrapper)
return inner
@@ -664,7 +664,7 @@ class FeatureCheckBase(metaclass=abc.ABCMeta):
raise AssertionError(f'{wrapped_args!r}')
self.use(subproject, node)
return f(*wrapped_args, **wrapped_kwargs)
- return T.cast(TV_func, wrapped)
+ return T.cast('TV_func', wrapped)
@classmethod
def single_use(cls, feature_name: str, version: str, subproject: 'SubProject',
@@ -766,7 +766,7 @@ class FeatureCheckKwargsBase(metaclass=abc.ABCMeta):
self.feature_check_class.single_use(
name, self.feature_version, subproject, self.extra_message, node)
return f(*wrapped_args, **wrapped_kwargs)
- return T.cast(TV_func, wrapped)
+ return T.cast('TV_func', wrapped)
class FeatureNewKwargs(FeatureCheckKwargsBase):
feature_check_class = FeatureNew
diff --git a/mesonbuild/interpreterbase/disabler.py b/mesonbuild/interpreterbase/disabler.py
index 63b914e..182bb62 100644
--- a/mesonbuild/interpreterbase/disabler.py
+++ b/mesonbuild/interpreterbase/disabler.py
@@ -11,10 +11,15 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
-from .baseobjects import MesonInterpreterObject, TYPE_var, TYPE_kwargs
import typing as T
+from .baseobjects import MesonInterpreterObject
+
+if T.TYPE_CHECKING:
+ from .baseobjects import TYPE_var, TYPE_kwargs
+
class Disabler(MesonInterpreterObject):
def method_call(self, method_name: str, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> TYPE_var:
if method_name == 'found':
diff --git a/mesonbuild/interpreterbase/interpreterbase.py b/mesonbuild/interpreterbase/interpreterbase.py
index 28211b0..85aabd1 100644
--- a/mesonbuild/interpreterbase/interpreterbase.py
+++ b/mesonbuild/interpreterbase/interpreterbase.py
@@ -14,6 +14,7 @@
# This class contains the basic functionality needed to run any interpreter
# or an interpreter-based tool.
+from __future__ import annotations
from .. import mparser, mesonlib
from .. import environment
@@ -26,10 +27,7 @@ from .baseobjects import (
ObjectHolder,
IterableObject,
- SubProject,
-
TYPE_var,
- TYPE_kwargs,
HoldableTypes,
)
@@ -54,6 +52,7 @@ import typing as T
import textwrap
if T.TYPE_CHECKING:
+ from .baseobjects import SubProject, TYPE_kwargs
from ..interpreter import Interpreter
HolderMapType = T.Dict[
diff --git a/mesonbuild/linkers/detect.py b/mesonbuild/linkers/detect.py
index 0bfd708..80e0948 100644
--- a/mesonbuild/linkers/detect.py
+++ b/mesonbuild/linkers/detect.py
@@ -12,14 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import annotations
+
from ..mesonlib import (
- EnvironmentException, MachineChoice, OptionKey,
+ EnvironmentException, OptionKey,
Popen_safe, search_version
)
from .linkers import (
- DynamicLinker,
AppleDynamicLinker,
- GnuDynamicLinker,
GnuGoldDynamicLinker,
GnuBFDDynamicLinker,
LLVMDynamicLinker,
@@ -36,8 +36,10 @@ import shlex
import typing as T
if T.TYPE_CHECKING:
+ from .linkers import DynamicLinker, GnuDynamicLinker
from ..environment import Environment
from ..compilers import Compiler
+ from ..mesonlib import MachineChoice
defaults: T.Dict[str, T.List[str]] = {}
defaults['static_linker'] = ['ar', 'gar']
diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py
index 9cc217a..88b66be 100644
--- a/mesonbuild/linkers/linkers.py
+++ b/mesonbuild/linkers/linkers.py
@@ -1182,7 +1182,7 @@ class VisualStudioLikeLinkerMixin:
def get_always_args(self) -> T.List[str]:
parent = super().get_always_args() # type: ignore
- return self._apply_prefix('/nologo') + T.cast(T.List[str], parent)
+ return self._apply_prefix('/nologo') + T.cast('T.List[str]', parent)
def get_search_args(self, dirname: str) -> T.List[str]:
return self._apply_prefix('/LIBPATH:' + dirname)
diff --git a/mesonbuild/mesonlib/universal.py b/mesonbuild/mesonlib/universal.py
index 99bcd32..d4f51c1 100644
--- a/mesonbuild/mesonlib/universal.py
+++ b/mesonbuild/mesonlib/universal.py
@@ -900,7 +900,7 @@ def version_compare_condition_with_min(condition: str, minimum: str) -> bool:
if re.match(r'^\d+.\d+$', condition):
condition += '.0'
- return T.cast(bool, cmpop(Version(minimum), Version(condition)))
+ return T.cast('bool', cmpop(Version(minimum), Version(condition)))
def search_version(text: str) -> str:
# Usually of the type 4.1.4 but compiler output may contain
@@ -1346,7 +1346,7 @@ def typeslistify(item: 'T.Union[_T, T.Sequence[_T]]',
list of items all of which are of type @types
'''
if isinstance(item, types):
- item = T.cast(T.List[_T], [item])
+ item = T.cast('T.List[_T]', [item])
if not isinstance(item, list):
raise MesonException('Item must be a list or one of {!r}, not {!r}'.format(types, type(item)))
for i in item:
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 93cb8b0..89816ec 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -30,7 +30,7 @@ from . import mconf, mdist, minit, minstall, mintro, msetup, mtest, rewriter, ms
from .mesonlib import MesonException, MesonBugException
from .environment import detect_msys2_arch
from .wrap import wraptool
-
+from .scripts import env2mfile
# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
@@ -70,6 +70,8 @@ class CommandLineParser:
help_msg='Build the project')
self.add_command('devenv', mdevenv.add_arguments, mdevenv.run,
help_msg='Run commands in developer environment')
+ self.add_command('env2mfile', env2mfile.add_arguments, env2mfile.run,
+ help_msg='Convert current environment to a cross or native file')
# Hidden commands
self.add_command('runpython', self.add_runpython_arguments, self.run_runpython_command,
diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py
index b51d4f0..f33ad0a 100644
--- a/mesonbuild/minstall.py
+++ b/mesonbuild/minstall.py
@@ -61,6 +61,7 @@ if T.TYPE_CHECKING:
dry_run: bool
skip_subprojects: str
tags: str
+ strip: bool
symlink_warning = '''Warning: trying to copy a symlink that points to a file. This will copy the file,
@@ -88,6 +89,8 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
help='Do not install files from given subprojects. (Since 0.58.0)')
parser.add_argument('--tags', default=None,
help='Install only targets having one of the given tags. (Since 0.60.0)')
+ parser.add_argument('--strip', action='store_true',
+ help='Strip targets even if strip option was not set during configure. (Since 0.62.0)')
class DirMaker:
def __init__(self, lf: T.TextIO, makedirs: T.Callable[..., None]):
@@ -564,6 +567,15 @@ class Installer:
else:
raise
+ def do_strip(self, strip_bin: T.List[str], fname: str, outname: str) -> None:
+ self.log(f'Stripping target {fname!r}.')
+ returncode, stdo, stde = self.Popen_safe(strip_bin + [outname])
+ if returncode != 0:
+ print('Could not strip file.\n')
+ print(f'Stdout:\n{stdo}\n')
+ print(f'Stderr:\n{stde}\n')
+ sys.exit(1)
+
def install_subdirs(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None:
for i in d.install_subdirs:
if not self.should_install(i):
@@ -676,7 +688,7 @@ class Installer:
outdir = get_destdir_path(destdir, fullprefix, t.outdir)
outname = os.path.join(outdir, os.path.basename(fname))
final_path = os.path.join(d.prefix, t.outdir, os.path.basename(fname))
- should_strip = t.strip
+ should_strip = t.strip or (t.can_strip and self.options.strip)
install_rpath = t.install_rpath
install_name_mappings = t.install_name_mappings
install_mode = t.install_mode
@@ -689,13 +701,7 @@ class Installer:
if fname.endswith('.jar'):
self.log('Not stripping jar target: {}'.format(os.path.basename(fname)))
continue
- self.log('Stripping target {!r} using {}.'.format(fname, d.strip_bin[0]))
- returncode, stdo, stde = self.Popen_safe(d.strip_bin + [outname])
- if returncode != 0:
- print('Could not strip file.\n')
- print(f'Stdout:\n{stdo}\n')
- print(f'Stderr:\n{stde}\n')
- sys.exit(1)
+ self.do_strip(d.strip_bin, fname, outname)
if fname.endswith('.js'):
# Emscripten outputs js files and optionally a wasm file.
# If one was generated, install it as well.
@@ -721,7 +727,6 @@ class Installer:
else:
raise
-
def rebuild_all(wd: str) -> bool:
if not (Path(wd) / 'build.ninja').is_file():
print('Only ninja backend is supported to rebuild the project before installation.')
diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py
index bdc9da5..d3ef68d 100644
--- a/mesonbuild/mlog.py
+++ b/mesonbuild/mlog.py
@@ -320,7 +320,7 @@ def _log_error(severity: str, *rargs: TV_Loggable,
location_str = get_error_location_string(location_file, location.lineno)
# Unions are frankly awful, and we have to T.cast here to get mypy
# to understand that the list concatenation is safe
- location_list = T.cast(TV_LoggableList, [location_str])
+ location_list = T.cast('TV_LoggableList', [location_str])
args = location_list + args
log(*args, once=once, **kwargs)
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index d1729ef..f908a83 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -1168,7 +1168,7 @@ class GnomeModule(ExtensionModule):
scan_target = self._make_gir_target(
state, girfile, scan_command, generated_files, depends,
# We have to cast here because mypy can't figure this out
- T.cast(T.Dict[str, T.Any], kwargs))
+ T.cast('T.Dict[str, T.Any]', kwargs))
typelib_output = f'{ns}-{nsversion}.typelib'
typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
@@ -1177,7 +1177,7 @@ class GnomeModule(ExtensionModule):
for incdir in typelib_includes:
typelib_cmd += ["--includedir=" + incdir]
- typelib_target = self._make_typelib_target(state, typelib_output, typelib_cmd, generated_files, T.cast(T.Dict[str, T.Any], kwargs))
+ typelib_target = self._make_typelib_target(state, typelib_output, typelib_cmd, generated_files, T.cast('T.Dict[str, T.Any]', kwargs))
self._devenv_prepend('GI_TYPELIB_PATH', os.path.join(state.environment.get_build_dir(), state.subdir))
@@ -1417,8 +1417,10 @@ class GnomeModule(ExtensionModule):
t_args.append(f'--{program_name}={path}')
if namespace:
t_args.append('--namespace=' + namespace)
- if state.environment.need_exe_wrapper() and not isinstance(state.environment.get_exe_wrapper(), EmptyExternalProgram):
- t_args.append('--run=' + ' '.join(state.environment.get_exe_wrapper().get_command()))
+ # if not need_exe_wrapper, we get an EmptyExternalProgram. If none provided, we get NoneType
+ exe_wrapper = state.environment.get_exe_wrapper()
+ if not isinstance(exe_wrapper, (NoneType, EmptyExternalProgram)):
+ t_args.append('--run=' + ' '.join(exe_wrapper.get_command()))
t_args.append(f'--htmlargs={"@@".join(kwargs["html_args"])}')
t_args.append(f'--scanargs={"@@".join(kwargs["scan_args"])}')
t_args.append(f'--scanobjsargs={"@@".join(kwargs["scanobjs_args"])}')
diff --git a/mesonbuild/modules/java.py b/mesonbuild/modules/java.py
index 6884a22..ddb14c8 100644
--- a/mesonbuild/modules/java.py
+++ b/mesonbuild/modules/java.py
@@ -16,7 +16,7 @@ import os
import pathlib
import typing as T
from mesonbuild import mesonlib
-from mesonbuild.build import CustomTarget
+from mesonbuild.build import CustomTarget, CustomTargetIndex, GeneratedList, Target
from mesonbuild.compilers import detect_compiler_for, Compiler
from mesonbuild.interpreter import Interpreter
from mesonbuild.interpreterbase.decorators import ContainerTypeInfo, FeatureDeprecated, FeatureNew, KwargInfo, typed_pos_args, typed_kwargs
@@ -80,14 +80,15 @@ class JavaModule(NewExtensionModule):
return ModuleReturnValue(target, [target])
@FeatureNew('java.generate_native_headers', '0.62.0')
- @typed_pos_args('java.generate_native_headers', (str, mesonlib.File), min_varargs=1)
+ @typed_pos_args('java.generate_native_headers',
+ varargs=(str, mesonlib.File, Target, CustomTargetIndex, GeneratedList))
@typed_kwargs('java.generate_native_headers',
- KwargInfo('classes', (ContainerTypeInfo(list, str)), default=[], listify=True,
+ KwargInfo('classes', ContainerTypeInfo(list, str), default=[], listify=True,
required=True),
KwargInfo('package', str, default=None))
- def generate_native_headers(self, state: ModuleState, args: T.List[mesonlib.FileOrString],
+ def generate_native_headers(self, state: ModuleState, args: T.Tuple[T.List[mesonlib.FileOrString]],
kwargs: T.Dict[str, T.Optional[str]]) -> ModuleReturnValue:
- classes = T.cast(T.List[str], kwargs.get('classes'))
+ classes = T.cast('T.List[str]', kwargs.get('classes'))
package = kwargs.get('package')
headers: T.List[str] = []
@@ -112,7 +113,7 @@ class JavaModule(NewExtensionModule):
prefix = classes[0] if not package else package
target = CustomTarget(f'{prefix}-native-headers', state.subdir, state.subproject, command,
- sources=list(args), outputs=headers, backend=state.backend)
+ sources=args[0], outputs=headers, backend=state.backend)
# It is only known that 1.8.0 won't pre-create the directory. 11 and 16
# do not exhibit this behavior.
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index f67e6eb..0eac360 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -524,6 +524,7 @@ class PkgConfigModule(ExtensionModule):
blocked_vars = ['libraries', 'libraries_private', 'require_private', 'extra_cflags', 'subdirs']
if any(k in kwargs for k in blocked_vars):
raise mesonlib.MesonException(f'Cannot combine dataonly with any of {blocked_vars}')
+ default_install_dir = os.path.join(state.environment.get_datadir(), 'pkgconfig')
subdirs = mesonlib.stringlistify(kwargs.get('subdirs', default_subdirs))
version = kwargs.get('version', default_version)
diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py
index f149ca1..3eac33f 100644
--- a/mesonbuild/modules/python.py
+++ b/mesonbuild/modules/python.py
@@ -38,28 +38,52 @@ from ..mesonlib import MachineChoice
from ..programs import ExternalProgram, NonExistingExternalProgram
if T.TYPE_CHECKING:
+ from typing_extensions import TypedDict
+
from . import ModuleState
from ..build import SharedModule, Data
from ..dependencies import ExternalDependency, Dependency
from ..dependencies.factory import DependencyGenerator
from ..environment import Environment
from ..interpreter import Interpreter
+ from ..interpreter.kwargs import ExtractRequired
from ..interpreterbase.interpreterbase import TYPE_var, TYPE_kwargs
from ..backends import InstallData
- from typing_extensions import TypedDict
+ class PythonIntrospectionDict(TypedDict):
+ install_paths: T.Dict[str, str]
+ is_pypy: bool
+ is_venv: bool
+ link_libpython: bool
+ sysconfig_paths: T.Dict[str, str]
+ paths: T.Dict[str, str]
+ platform: str
+ suffix: str
+ variables: T.Dict[str, str]
+ version: str
-mod_kwargs = {'subdir'}
-mod_kwargs.update(known_shmod_kwargs)
-mod_kwargs -= {'name_prefix', 'name_suffix'}
+ class PyInstallKw(TypedDict):
+
+ pure: bool
+ subdir: str
+ install_tag: T.Optional[str]
+ class FindInstallationKw(ExtractRequired):
+
+ disabler: bool
+ modules: T.List[str]
-if T.TYPE_CHECKING:
_Base = ExternalDependency
else:
_Base = object
+
+mod_kwargs = {'subdir'}
+mod_kwargs.update(known_shmod_kwargs)
+mod_kwargs -= {'name_prefix', 'name_suffix'}
+
+
class _PythonDependencyBase(_Base):
def __init__(self, python_holder: 'PythonInstallation', embed: bool):
@@ -134,7 +158,7 @@ class PythonSystemDependency(SystemDependency, _PythonDependencyBase):
if largs is not None:
self.link_args = largs
- self.is_found = largs is not None or self.link_libpython
+ self.is_found = largs is not None or not self.link_libpython
inc_paths = mesonlib.OrderedSet([
self.variables.get('INCLUDEPY'),
@@ -350,20 +374,6 @@ print(json.dumps({
}))
'''
-if T.TYPE_CHECKING:
- class PythonIntrospectionDict(TypedDict):
-
- install_paths: T.Dict[str, str]
- is_pypy: bool
- is_venv: bool
- link_libpython: bool
- sysconfig_paths: T.Dict[str, str]
- paths: T.Dict[str, str]
- platform: str
- suffix: str
- variables: T.Dict[str, str]
- version: str
-
class PythonExternalProgram(ExternalProgram):
def __init__(self, name: str, command: T.Optional[T.List[str]] = None,
@@ -404,7 +414,6 @@ class PythonExternalProgram(ExternalProgram):
if subdir_parts[-len(install_subdir_parts):] == install_subdir_parts:
pypath = os.path.join(basedir, *subdir_parts[:-len(install_subdir_parts)])
self.devenv_pythonpath.add(pypath)
- print('done', pypath)
def _check_version(self, version: str) -> bool:
if self.name == 'python2':
@@ -474,14 +483,6 @@ class PythonExternalProgram(ExternalProgram):
_PURE_KW = KwargInfo('pure', bool, default=True)
_SUBDIR_KW = KwargInfo('subdir', str, default='')
-if T.TYPE_CHECKING:
-
- class PyInstallKw(TypedDict):
-
- pure: bool
- subdir: str
- install_tag: T.Optional[str]
-
class PythonInstallation(ExternalProgramHolder):
def __init__(self, python: 'PythonExternalProgram', interpreter: 'Interpreter'):
@@ -649,15 +650,6 @@ class PythonInstallation(ExternalProgramHolder):
return super().path_method(args, kwargs)
-if T.TYPE_CHECKING:
- from ..interpreter.kwargs import ExtractRequired
-
- class FindInstallationKw(ExtractRequired):
-
- disabler: bool
- modules: T.List[str]
-
-
class PythonModule(ExtensionModule):
@FeatureNew('Python Module', '0.46.0')
diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py
index 37072b4..bf6d30c 100644
--- a/mesonbuild/modules/qt.py
+++ b/mesonbuild/modules/qt.py
@@ -486,7 +486,7 @@ class QtBaseModule(ExtensionModule):
if _sources:
FeatureDeprecated.single_use('qt.preprocess positional sources', '0.59', state.subproject, location=state.current_node)
# List is invariant, os we have to cast...
- sources = T.cast(T.List[T.Union[str, File, build.GeneratedList, build.CustomTarget]],
+ sources = T.cast('T.List[T.Union[str, File, build.GeneratedList, build.CustomTarget]]',
_sources + kwargs['sources'])
for s in sources:
if not isinstance(s, (str, File)):
diff --git a/mesonbuild/scripts/env2mfile.py b/mesonbuild/scripts/env2mfile.py
new file mode 100755
index 0000000..9441402
--- /dev/null
+++ b/mesonbuild/scripts/env2mfile.py
@@ -0,0 +1,368 @@
+# Copyright 2022 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys, os, subprocess, shutil
+import shlex
+
+import argparse
+from typing import TextIO, Dict, List, Union, Tuple, Any, Optional
+
+from .. import mlog
+
+UNIXY_ENVVARS_COMPILER = {'c': 'CC',
+ 'cpp': 'CXX',
+ 'objc': 'OBJCC',
+ 'objcpp': 'OBJCXX',
+ 'fortran': 'FC',
+ 'rust': 'RUSTC',
+ 'vala': 'VALAC',
+ 'cs': 'CSC',
+ }
+
+UNIXY_ENVVARS_TOOLS = {'ar': 'AR',
+ 'strip': 'STRIP',
+ 'windres': 'WINDRES',
+ 'pkgconfig': 'PKG_CONFIG',
+ 'vapigen': 'VAPIGEN',
+ 'cmake': 'CMAKE',
+ 'qmake': 'QMAKE',
+ }
+
+UNIXY_ENVVARS_FLAGS = {'c': 'CFLAGS',
+ 'cpp': 'CXXFLAGS',
+ 'objc': 'OBJCFLAGS',
+ 'objcpp': 'OBJCXXFLAGS',
+ 'fortran': 'FFLAGS',
+ 'rust': 'RUSTFLAGS',
+ 'vala': 'VALAFLAGS',
+ 'cs': 'CSFLAGS', # This one might not be standard.
+ }
+
+TYPICAL_UNIXY_COMPILER_NAMES = {'c': ['cc', 'gcc', 'clang'],
+ 'cpp': ['c++', 'g++', 'clang++'],
+ 'objc': ['objc', 'clang'],
+ 'objcpp': ['objcpp', 'clang++'],
+ 'fortran': ['gfortran'],
+ }
+
+LANGS_USING_CPPFLAGS = {'c', 'cpp', 'objc', 'objcxx'}
+
+def has_for_build() -> bool:
+ for cenv in UNIXY_ENVVARS_COMPILER.values():
+ if os.environ.get(cenv + '_FOR_BUILD'):
+ return True
+ return False
+
+def add_arguments(parser: 'argparse.ArgumentParser') -> None:
+ parser.add_argument('--debarch', default=None,
+ help='The dpkg architecture to generate.')
+ parser.add_argument('--gccsuffix', default="",
+ help='A particular gcc version suffix if necessary.')
+ parser.add_argument('-o', required=True, dest='outfile',
+ help='The output file.')
+ parser.add_argument('--cross', default=False, action='store_true',
+ help='Generate a cross compilation file.')
+ parser.add_argument('--native', default=False, action='store_true',
+ help='Generate a native compilation file.')
+ parser.add_argument('--system', default=None,
+ help='Define system for cross compilation.')
+ parser.add_argument('--cpu', default=None,
+ help='Define cpu for cross compilation.')
+ parser.add_argument('--cpu-family', default=None,
+ help='Define cpu family for cross compilation.')
+ parser.add_argument('--endian', default='little', choices=['big', 'little'],
+ help='Define endianness for cross compilation.')
+
+class MachineInfo:
+ def __init__(self) -> None:
+ self.compilers: Dict[str, List[str]] = {}
+ self.binaries: Dict[str, List[str]] = {}
+ self.properties: Dict[str, Union[str, List[str]]] = {}
+ self.compile_args: Dict[str, List[str]] = {}
+ self.link_args: Dict[str, List[str]] = {}
+
+ self.system: Optional[str] = None
+ self.cpu: Optional[str] = None
+ self.cpu_family: Optional[str] = None
+ self.endian: Optional[str] = None
+
+#parser = argparse.ArgumentParser(description='''Generate cross compilation definition file for the Meson build system.
+#
+#If you do not specify the --arch argument, Meson assumes that running
+#plain 'dpkg-architecture' will return correct information for the
+#host system.
+#
+#This script must be run in an environment where CPPFLAGS et al are set to the
+#same values used in the actual compilation.
+#'''
+#)
+
+def locate_path(program: str) -> List[str]:
+ if os.path.isabs(program):
+ return [program]
+ for d in os.get_exec_path():
+ f = os.path.join(d, program)
+ if os.access(f, os.X_OK):
+ return [f]
+ raise ValueError("%s not found on $PATH" % program)
+
+def write_args_line(ofile: TextIO, name: str, args: List[str]) -> None:
+ if len(args) == 0:
+ return
+ ostr = name + ' = ['
+ ostr += ', '.join("'" + i + "'" for i in args)
+ ostr += ']\n'
+ ofile.write(ostr)
+
+def get_args_from_envvars(infos: MachineInfo) -> None:
+ cppflags = shlex.split(os.environ.get('CPPFLAGS', ''))
+ cflags = shlex.split(os.environ.get('CFLAGS', ''))
+ cxxflags = shlex.split(os.environ.get('CXXFLAGS', ''))
+ objcflags = shlex.split(os.environ.get('OBJCFLAGS', ''))
+ objcxxflags = shlex.split(os.environ.get('OBJCXXFLAGS', ''))
+ ldflags = shlex.split(os.environ.get('LDFLAGS', ''))
+
+ c_args = cppflags + cflags
+ cpp_args = cppflags + cxxflags
+ c_link_args = cflags + ldflags
+ cpp_link_args = cxxflags + ldflags
+
+ objc_args = cppflags + objcflags
+ objcpp_args = cppflags + objcxxflags
+ objc_link_args = objcflags + ldflags
+ objcpp_link_args = objcxxflags + ldflags
+
+ if c_args:
+ infos.compile_args['c'] = c_args
+ if c_link_args:
+ infos.link_args['c'] = c_link_args
+ if cpp_args:
+ infos.compile_args['cpp'] = cpp_args
+ if cpp_link_args:
+ infos.link_args['cpp'] = cpp_link_args
+ if objc_args:
+ infos.compile_args['objc'] = objc_args
+ if objc_link_args:
+ infos.link_args['objc'] = objc_link_args
+ if objcpp_args:
+ infos.compile_args['objcpp'] = objcpp_args
+ if objcpp_link_args:
+ infos.link_args['objcpp'] = objcpp_link_args
+
+cpu_family_map = dict(mips64el="mips64",
+ i686='x86')
+cpu_map = dict(armhf="arm7hlf",
+ mips64el="mips64",)
+
+def deb_compiler_lookup(infos: MachineInfo, compilerstems: List[Tuple[str, str]], host_arch: str, gccsuffix: str) -> None:
+ for langname, stem in compilerstems:
+ compilername = f'{host_arch}-{stem}{gccsuffix}'
+ try:
+ p = locate_path(compilername)
+ infos.compilers[langname] = p
+ except ValueError:
+ pass
+
+def detect_cross_debianlike(options: Any) -> MachineInfo:
+ if options.debarch is None:
+ cmd = ['dpkg-architecture']
+ else:
+ cmd = ['dpkg-architecture', '-a' + options.debarch]
+ output = subprocess.check_output(cmd, universal_newlines=True,
+ stderr=subprocess.DEVNULL)
+ data = {}
+ for line in output.split('\n'):
+ line = line.strip()
+ if line == '':
+ continue
+ k, v = line.split('=', 1)
+ data[k] = v
+ host_arch = data['DEB_HOST_GNU_TYPE']
+ host_os = data['DEB_HOST_ARCH_OS']
+ host_cpu_family = cpu_family_map.get(data['DEB_HOST_GNU_CPU'],
+ data['DEB_HOST_GNU_CPU'])
+ host_cpu = cpu_map.get(data['DEB_HOST_ARCH'],
+ data['DEB_HOST_ARCH'])
+ host_endian = data['DEB_HOST_ARCH_ENDIAN']
+
+ compilerstems = [('c', 'gcc'),
+ ('cpp', 'h++'),
+ ('objc', 'gobjc'),
+ ('objcpp', 'gobjc++')]
+ infos = MachineInfo()
+ deb_compiler_lookup(infos, compilerstems, host_arch, options.gccsuffix)
+ if len(infos.compilers) == 0:
+ print('Warning: no compilers were detected.')
+ infos.binaries['ar'] = locate_path("%s-ar" % host_arch)
+ infos.binaries['strip'] = locate_path("%s-strip" % host_arch)
+ infos.binaries['objcopy'] = locate_path("%s-objcopy" % host_arch)
+ infos.binaries['ld'] = locate_path("%s-ld" % host_arch)
+ try:
+ infos.binaries['pkgconfig'] = locate_path("%s-pkg-config" % host_arch)
+ except ValueError:
+ pass # pkg-config is optional
+ try:
+ infos.binaries['cups-config'] = locate_path("cups-config")
+ except ValueError:
+ pass
+ infos.system = host_os
+ infos.cpu_family = host_cpu_family
+ infos.cpu = host_cpu
+ infos.endian = host_endian
+
+ get_args_from_envvars(infos)
+ return infos
+
+def write_machine_file(infos: MachineInfo, ofilename: str, write_system_info: bool) -> None:
+ tmpfilename = ofilename + '~'
+ with open(tmpfilename, 'w') as ofile:
+ ofile.write('[binaries]\n')
+ ofile.write('# Compilers\n')
+ for langname in sorted(infos.compilers.keys()):
+ compiler = infos.compilers[langname]
+ write_args_line(ofile, langname, compiler)
+ ofile.write('\n')
+
+ ofile.write('# Other binaries\n')
+ for exename in sorted(infos.binaries.keys()):
+ exe = infos.binaries[exename]
+ write_args_line(ofile, exename, exe)
+ ofile.write('\n')
+
+ ofile.write('[properties]\n')
+ all_langs = list(set(infos.compile_args.keys()).union(set(infos.link_args.keys())))
+ all_langs.sort()
+ for lang in all_langs:
+ if lang in infos.compile_args:
+ write_args_line(ofile, lang + '_args', infos.compile_args[lang])
+ if lang in infos.link_args:
+ write_args_line(ofile, lang + '_link_args', infos.link_args[lang])
+ ofile.write('\n')
+
+ if write_system_info:
+ ofile.write('[host_machine]\n')
+ ofile.write(f"cpu = '{infos.cpu}'\n")
+ ofile.write(f"cpu_family = '{infos.cpu_family}'\n")
+ ofile.write(f"endian = '{infos.endian}'\n")
+ ofile.write(f"system = '{infos.system}'\n")
+ os.replace(tmpfilename, ofilename)
+
+def detect_language_args_from_envvars(langname: str, envvar_suffix: str ='') -> Tuple[List[str], List[str]]:
+ ldflags = tuple(shlex.split(os.environ.get('LDFLAGS' + envvar_suffix, '')))
+ compile_args = shlex.split(os.environ.get(UNIXY_ENVVARS_FLAGS[langname] + envvar_suffix, ''))
+ if langname in LANGS_USING_CPPFLAGS:
+ cppflags = tuple(shlex.split(os.environ.get('CPPFLAGS' + envvar_suffix, '')))
+ lang_compile_args = list(cppflags) + compile_args
+ else:
+ lang_compile_args = compile_args
+ lang_link_args = list(ldflags) + compile_args
+ return (lang_compile_args, lang_link_args)
+
+def detect_compilers_from_envvars(envvar_suffix:str ='') -> MachineInfo:
+ infos = MachineInfo()
+ for langname, envvarname in UNIXY_ENVVARS_COMPILER.items():
+ compilerstr = os.environ.get(envvarname + envvar_suffix)
+ if not compilerstr:
+ continue
+ compiler = shlex.split(compilerstr)
+ infos.compilers[langname] = compiler
+ lang_compile_args, lang_link_args = detect_language_args_from_envvars(langname, envvar_suffix)
+ if lang_compile_args:
+ infos.compile_args[langname] = lang_compile_args
+ if lang_link_args:
+ infos.link_args[langname] = lang_link_args
+ return infos
+
+def detect_binaries_from_envvars(infos: MachineInfo, envvar_suffix:str ='') -> None:
+ for binname, envvar_base in UNIXY_ENVVARS_TOOLS.items():
+ envvar = envvar_base + envvar_suffix
+ binstr = os.environ.get(envvar)
+ if binstr:
+ infos.binaries[binname] = shlex.split(binstr)
+
+def detect_cross_system(infos: MachineInfo, options: Any) -> None:
+ for optname in ('system', 'cpu', 'cpu_family', 'endian'):
+ v = getattr(options, optname)
+ if not v:
+ mlog.error(f'Cross property "{optname}" missing, set it with --{optname.replace("_", "-")}.')
+ sys.exit(1)
+ setattr(infos, optname, v)
+
+def detect_cross_env(options: Any) -> MachineInfo:
+ if options.debarch:
+ print('Detecting cross environment via dpkg-reconfigure.')
+ infos = detect_cross_debianlike(options)
+ else:
+ print('Detecting cross environment via environment variables.')
+ infos = detect_compilers_from_envvars()
+ detect_cross_system(infos, options)
+ return infos
+
+def add_compiler_if_missing(infos: MachineInfo, langname: str, exe_names: List[str]) -> None:
+ if langname in infos.compilers:
+ return
+ for exe_name in exe_names:
+ lookup = shutil.which(exe_name)
+ if not lookup:
+ continue
+ compflags, linkflags = detect_language_args_from_envvars(langname)
+ infos.compilers[langname] = [lookup]
+ if compflags:
+ infos.compile_args[langname] = compflags
+ if linkflags:
+ infos.link_args[langname] = linkflags
+ return
+
+def detect_missing_native_compilers(infos: MachineInfo) -> None:
+ # Any per-platform special detection should go here.
+ for langname, exes in TYPICAL_UNIXY_COMPILER_NAMES.items():
+ add_compiler_if_missing(infos, langname, exes)
+
+def detect_missing_native_binaries(infos: MachineInfo) -> None:
+ # Any per-platform special detection should go here.
+ for toolname in sorted(UNIXY_ENVVARS_TOOLS.keys()):
+ if toolname in infos.binaries:
+ continue
+ exe = shutil.which(toolname)
+ if exe:
+ infos.binaries[toolname] = [exe]
+
+def detect_native_env(options: Any) -> MachineInfo:
+ use_for_build = has_for_build()
+ if use_for_build:
+ mlog.log('Using FOR_BUILD envvars for detection')
+ esuffix = '_FOR_BUILD'
+ else:
+ mlog.log('Using regular envvars for detection.')
+ esuffix = ''
+ infos = detect_compilers_from_envvars(esuffix)
+ detect_missing_native_compilers(infos)
+ detect_binaries_from_envvars(infos, esuffix)
+ detect_missing_native_binaries(infos)
+ return infos
+
+def run(options: Any) -> None:
+ if options.cross and options.native:
+ sys.exit('You can only specify either --cross or --native, not both.')
+ if not options.cross and not options.native:
+ sys.exit('You must specify --cross or --native.')
+ mlog.notice('This functionality is experimental and subject to change.')
+ detect_cross = options.cross
+ if detect_cross:
+ infos = detect_cross_env(options)
+ write_system_info = True
+ else:
+ infos = detect_native_env(options)
+ write_system_info = False
+ write_machine_file(infos, options.outfile, write_system_info)
diff --git a/mesonbuild/wrap/wraptool.py b/mesonbuild/wrap/wraptool.py
index 664bfec..ca14315 100644
--- a/mesonbuild/wrap/wraptool.py
+++ b/mesonbuild/wrap/wraptool.py
@@ -60,7 +60,7 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None:
def get_releases() -> T.Dict[str, T.Any]:
url = urlopen('https://wrapdb.mesonbuild.com/v2/releases.json')
- return T.cast(T.Dict[str, T.Any], json.loads(url.read().decode()))
+ return T.cast('T.Dict[str, T.Any]', json.loads(url.read().decode()))
def list_projects(options: 'argparse.Namespace') -> None:
releases = get_releases()
diff --git a/test cases/common/44 pkgconfig-gen/test.json b/test cases/common/44 pkgconfig-gen/test.json
index 118fecd..4630a02 100644
--- a/test cases/common/44 pkgconfig-gen/test.json
+++ b/test cases/common/44 pkgconfig-gen/test.json
@@ -6,7 +6,6 @@
{"type": "file", "file": "usr/lib/pkgconfig/libanswer.pc"},
{"type": "file", "file": "usr/lib/pkgconfig/libfoo.pc"},
{"type": "file", "file": "usr/lib/pkgconfig/libhello.pc"},
- {"type": "file", "file": "usr/lib/pkgconfig/libhello_nolib.pc"},
{"type": "file", "file": "usr/lib/pkgconfig/libvartest.pc"},
{"type": "file", "file": "usr/lib/pkgconfig/libvartest2.pc"},
{"type": "file", "file": "usr/lib/pkgconfig/simple2.pc"},
@@ -14,7 +13,8 @@
{"type": "file", "file": "usr/lib/pkgconfig/simple5.pc"},
{"type": "file", "file": "usr/lib/pkgconfig/simple6.pc"},
{"type": "file", "file": "usr/lib/pkgconfig/ct.pc"},
- {"type": "file", "file": "usr/lib/pkgconfig/ct0.pc"}
+ {"type": "file", "file": "usr/lib/pkgconfig/ct0.pc"},
+ {"type": "file", "file": "usr/share/pkgconfig/libhello_nolib.pc"}
],
"stdout": [
{
diff --git a/test cases/common/66 vcstag/meson.build b/test cases/common/66 vcstag/meson.build
index 256d2e9..520f72a 100644
--- a/test cases/common/66 vcstag/meson.build
+++ b/test cases/common/66 vcstag/meson.build
@@ -9,9 +9,15 @@ output : 'vcstag-custom.c',
command : ['git', 'show-ref', '-s', 'refs/heads/master'],
fallback : '1.0.0')
+version_src_notfound_fallback = vcs_tag(input : 'vcstag.c.in',
+output : 'vcstag-notfound-fallback.c',
+command : ['git-but-not-found-sorry', 'show-ref', '-s', 'refs/heads/master'],
+fallback : '1.0.0')
+
version_src_fallback = vcs_tag(input : 'vcstag.c.in',
output : 'vcstag-fallback.c')
executable('tagprog', 'tagprog.c', version_src)
executable('tagprog-custom', 'tagprog.c', version_src_custom)
executable('tagprog-fallback', 'tagprog.c', version_src_fallback)
+executable('tagprog-notfound-fallback', 'tagprog.c', version_src_notfound_fallback)
diff --git a/test cases/failing/54 wrong shared crate type/test.json b/test cases/failing/54 wrong shared crate type/test.json
index 5cced6f..a5b7961 100644
--- a/test cases/failing/54 wrong shared crate type/test.json
+++ b/test cases/failing/54 wrong shared crate type/test.json
@@ -1,7 +1,7 @@
{
"stdout": [
{
- "line": "test cases/failing/54 wrong shared crate type/meson.build:7:0: ERROR: Crate type \"staticlib\" invalid for dynamic libraries; must be \"dylib\" or \"cdylib\""
+ "line": "test cases/failing/54 wrong shared crate type/meson.build:7:0: ERROR: Crate type \"staticlib\" invalid for dynamic libraries; must be \"dylib\", \"cdylib\", or \"proc-macro\""
}
]
}
diff --git a/test cases/java/9 jni/meson.build b/test cases/java/9 jni/meson.build
index 1239e19..90a8485 100644
--- a/test cases/java/9 jni/meson.build
+++ b/test cases/java/9 jni/meson.build
@@ -16,6 +16,17 @@ java = find_program('java')
jni_dep = dependency('jni', version : '>=1.8', modules: ['jvm', 'awt'])
# generate native headers
-subdir('src/com/mesonbuild')
-subdir('lib')
subdir('src')
+subdir('lib')
+
+test(
+ 'jnitest',
+ java,
+ args: [
+ '-Djava.library.path=@0@'.format(fs.parent(jnijava.full_path())),
+ '-jar',
+ jnijar,
+ ],
+ protocol : 'exitcode',
+ depends : [jnijava],
+)
diff --git a/test cases/java/9 jni/src/com/mesonbuild/Configured.java.in b/test cases/java/9 jni/src/com/mesonbuild/Configured.java.in
new file mode 100644
index 0000000..fac6e05
--- /dev/null
+++ b/test cases/java/9 jni/src/com/mesonbuild/Configured.java.in
@@ -0,0 +1,5 @@
+package com.mesonbuild;
+
+public final class Configured {
+ public static final int FINGERPRINT = @fingerprint@;
+}
diff --git a/test cases/java/9 jni/src/com/mesonbuild/JniTest.java b/test cases/java/9 jni/src/com/mesonbuild/JniTest.java
index f80b326..4bfffe9 100644
--- a/test cases/java/9 jni/src/com/mesonbuild/JniTest.java
+++ b/test cases/java/9 jni/src/com/mesonbuild/JniTest.java
@@ -4,7 +4,7 @@ public final class JniTest {
private static native int jni_test();
public static void main(String[] args) {
- if (jni_test() != 0xdeadbeef) {
+ if (jni_test() != Configured.FINGERPRINT) {
throw new RuntimeException("jdk_test() did not return 0");
}
}
diff --git a/test cases/java/9 jni/src/com/mesonbuild/meson.build b/test cases/java/9 jni/src/com/mesonbuild/meson.build
index 3ee2083..2d88c5e 100644
--- a/test cases/java/9 jni/src/com/mesonbuild/meson.build
+++ b/test cases/java/9 jni/src/com/mesonbuild/meson.build
@@ -1,3 +1,11 @@
+configured = configure_file(
+ input: files('Configured.java.in'),
+ output: 'Configured.java',
+ configuration: configuration_data({'fingerprint': '0xdeadbeef'})
+)
+
+sources += configured
+
native_headers = javamod.generate_native_headers(
- 'JniTest.java', package: 'com.mesonbuild', classes: ['JdkTest'])
+ sources, package: 'com.mesonbuild', classes: ['JniTest'])
native_header_includes = include_directories('.')
diff --git a/test cases/java/9 jni/src/meson.build b/test cases/java/9 jni/src/meson.build
index 07a0664..af443b5 100644
--- a/test cases/java/9 jni/src/meson.build
+++ b/test cases/java/9 jni/src/meson.build
@@ -1,17 +1,9 @@
+sources = [files('com/mesonbuild/JniTest.java')]
+
+subdir('com/mesonbuild')
+
jnijar = jar(
'jnijar',
- 'com' / 'mesonbuild' / 'JniTest.java',
+ sources,
main_class : 'com.mesonbuild.JniTest',
)
-
-test(
- 'jnitest',
- java,
- args: [
- '-Djava.library.path=@0@'.format(fs.parent(jnijava.full_path())),
- '-jar',
- jnijar,
- ],
- protocol : 'exitcode',
- depends : [jnijava],
-)
diff --git a/test cases/osx/7 bitcode/meson.build b/test cases/osx/7 bitcode/meson.build
index f94bf9d..50ce3f2 100644
--- a/test cases/osx/7 bitcode/meson.build
+++ b/test cases/osx/7 bitcode/meson.build
@@ -1,4 +1,5 @@
-project('bitcode test', 'c', 'objc', 'objcpp')
+project('bitcode test', 'c', 'objc', 'objcpp',
+ default_options : ['b_bitcode=true'])
both_libraries('alib', 'libfoo.m')
shared_module('amodule', 'libfoo.m')
diff --git a/test cases/rust/18 proc-macro/meson.build b/test cases/rust/18 proc-macro/meson.build
new file mode 100644
index 0000000..01c4cbe
--- /dev/null
+++ b/test cases/rust/18 proc-macro/meson.build
@@ -0,0 +1,19 @@
+project('rust proc-macro', 'rust')
+
+if build_machine.system() != 'linux'
+ error('MESON_SKIP_TEST, this test only works on Linux. Patches welcome.')
+endif
+
+pm = shared_library(
+ 'proc_macro_examples',
+ 'proc.rs',
+ rust_crate_type : 'proc-macro',
+)
+
+main = executable(
+ 'main',
+ 'use.rs',
+ link_with : pm
+)
+
+test('main_test', main)
diff --git a/test cases/rust/18 proc-macro/proc.rs b/test cases/rust/18 proc-macro/proc.rs
new file mode 100644
index 0000000..53935e4
--- /dev/null
+++ b/test cases/rust/18 proc-macro/proc.rs
@@ -0,0 +1,7 @@
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn make_answer(_item: TokenStream) -> TokenStream {
+ "fn answer() -> u32 { 42 }".parse().unwrap()
+}
diff --git a/test cases/rust/18 proc-macro/use.rs b/test cases/rust/18 proc-macro/use.rs
new file mode 100644
index 0000000..0b6342b
--- /dev/null
+++ b/test cases/rust/18 proc-macro/use.rs
@@ -0,0 +1,8 @@
+extern crate proc_macro_examples;
+use proc_macro_examples::make_answer;
+
+make_answer!();
+
+fn main() {
+ assert_eq!(42, answer());
+}
diff --git a/test cases/unit/104 strip/lib.c b/test cases/unit/104 strip/lib.c
new file mode 100644
index 0000000..3940fde
--- /dev/null
+++ b/test cases/unit/104 strip/lib.c
@@ -0,0 +1 @@
+void func(void){}
diff --git a/test cases/unit/104 strip/meson.build b/test cases/unit/104 strip/meson.build
new file mode 100644
index 0000000..dff61ab
--- /dev/null
+++ b/test cases/unit/104 strip/meson.build
@@ -0,0 +1,3 @@
+project('strip', 'c')
+
+shared_library('a', 'lib.c', install: true)
diff --git a/tools/regenerate_docs.py b/tools/regenerate_docs.py
index 887db9c..25e6b53 100755
--- a/tools/regenerate_docs.py
+++ b/tools/regenerate_docs.py
@@ -37,6 +37,23 @@ def _get_meson_output(root_dir: Path, args: T.List) -> str:
env['COLUMNS'] = '80'
return subprocess.run([str(sys.executable), str(root_dir/'meson.py')] + args, check=True, capture_output=True, text=True, env=env).stdout.strip()
+def get_commands(help_output: str) -> T.Set[str]:
+ # Python's argument parser might put the command list to its own line. Or it might not.
+ assert(help_output.startswith('usage: '))
+ lines = help_output.split('\n')
+ line1 = lines[0]
+ line2 = lines[1]
+ if '{' in line1:
+ cmndline = line1
+ else:
+ assert('{' in line2)
+ cmndline = line2
+ cmndstr = cmndline.split('{')[1]
+ assert('}' in cmndstr)
+ help_commands = set(cmndstr.split('}')[0].split(','))
+ assert(len(help_commands) > 0)
+ return {c.strip() for c in help_commands}
+
def get_commands_data(root_dir: Path) -> T.Dict[str, T.Any]:
usage_start_pattern = re.compile(r'^usage: ', re.MULTILINE)
positional_start_pattern = re.compile(r'^positional arguments:[\t ]*[\r\n]+', re.MULTILINE)
@@ -96,7 +113,7 @@ def get_commands_data(root_dir: Path) -> T.Dict[str, T.Any]:
return out
output = _get_meson_output(root_dir, ['--help'])
- commands = {c.strip() for c in re.findall(r'usage:(?:.+)?{((?:[a-z]+,*)+?)}', output, re.MULTILINE|re.DOTALL)[0].split(',')}
+ commands = get_commands(output)
commands.remove('help')
cmd_data = dict()
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index b424b15..5a533a9 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -3376,9 +3376,21 @@ class AllPlatformTests(BasePlatformTests):
## Validate commands
md_commands = {k for k,v in md_command_sections.items()}
-
help_output = self._run(self.meson_command + ['--help'])
- help_commands = {c.strip() for c in re.findall(r'usage:(?:.+)?{((?:[a-z]+,*)+?)}', help_output, re.MULTILINE|re.DOTALL)[0].split(',')}
+ # Python's argument parser might put the command list to its own line. Or it might not.
+ self.assertTrue(help_output.startswith('usage: '))
+ lines = help_output.split('\n')
+ line1 = lines[0]
+ line2 = lines[1]
+ if '{' in line1:
+ cmndline = line1
+ else:
+ self.assertIn('{', line2)
+ cmndline = line2
+ cmndstr = cmndline.split('{')[1]
+ self.assertIn('}', cmndstr)
+ help_commands = set(cmndstr.split('}')[0].split(','))
+ self.assertTrue(len(help_commands) > 0, 'Must detect some command names.')
self.assertEqual(md_commands | {'help'}, help_commands, f'Doc file: `{doc_path}`')
diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py
index f3dc7b3..79db0b8 100644
--- a/unittests/linuxliketests.py
+++ b/unittests/linuxliketests.py
@@ -1760,3 +1760,23 @@ class LinuxlikeTests(BasePlatformTests):
# If so, we can test that cmake works with "gcc -m32"
self.do_one_test_with_nativefile('../cmake/1 basic', "['gcc', '-m32']")
+
+ @skipUnless(is_linux(), 'Test only applicable to Linux')
+ def test_install_strip(self):
+ testdir = os.path.join(self.unit_test_dir, '104 strip')
+ self.init(testdir)
+ self.build()
+
+ destdir = self.installdir + self.prefix
+ lib = os.path.join(destdir, self.libdir, 'liba.so')
+ install_cmd = self.meson_command + ['install', '--destdir', self.installdir]
+
+ # Check we have debug symbols by default
+ self._run(install_cmd, workdir=self.builddir)
+ stdout = self._run(['file', '-b', lib])
+ self.assertIn('not stripped', stdout)
+
+ # Check debug symbols got removed with --strip
+ self._run(install_cmd + ['--strip'], workdir=self.builddir)
+ stdout = self._run(['file', '-b', lib])
+ self.assertNotIn('not stripped', stdout)