aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Fs-module.md15
-rw-r--r--docs/markdown/snippets/fs_suffix.md4
-rw-r--r--docs/markdown/snippets/swift-module-name.md9
-rw-r--r--docs/markdown/snippets/swift-parse-as-library.md8
-rw-r--r--docs/yaml/functions/configure_file.yaml2
-rw-r--r--docs/yaml/functions/custom_target.yaml2
-rw-r--r--docs/yaml/functions/install_data.yaml3
-rw-r--r--docs/yaml/functions/install_headers.yaml4
-rw-r--r--mesonbuild/backend/ninjabackend.py14
-rw-r--r--mesonbuild/build.py10
-rw-r--r--mesonbuild/compilers/swift.py3
-rw-r--r--mesonbuild/interpreter/kwargs.py1
-rw-r--r--mesonbuild/interpreter/type_checking.py1
-rw-r--r--mesonbuild/mintro.py7
-rw-r--r--mesonbuild/modules/fs.py121
-rw-r--r--test cases/common/220 fs module/meson.build17
-rw-r--r--test cases/swift/14 single-file library/main.swift3
-rw-r--r--test cases/swift/14 single-file library/meson.build4
-rw-r--r--test cases/swift/14 single-file library/singlefile.swift1
-rw-r--r--test cases/swift/15 main in single-file library/main.swift3
-rw-r--r--test cases/swift/15 main in single-file library/meson.build4
-rw-r--r--test cases/swift/15 main in single-file library/module.modulemap3
-rw-r--r--test cases/swift/15 main in single-file library/program.c5
-rw-r--r--test cases/swift/15 main in single-file library/program.h1
-rw-r--r--test cases/swift/16 main in multi-file library/main.swift4
-rw-r--r--test cases/swift/16 main in multi-file library/meson.build4
-rw-r--r--test cases/swift/16 main in multi-file library/module.modulemap3
-rw-r--r--test cases/swift/16 main in multi-file library/more.swift3
-rw-r--r--test cases/swift/16 main in multi-file library/program.c5
-rw-r--r--test cases/swift/16 main in multi-file library/program.h1
-rw-r--r--test cases/swift/8 extra args/lib.swift3
-rw-r--r--test cases/swift/8 extra args/main.swift1
-rw-r--r--test cases/swift/8 extra args/meson.build4
-rw-r--r--test cases/vala/32 valaless vapigen/clib.c5
-rw-r--r--test cases/vala/32 valaless vapigen/clib.h3
-rw-r--r--test cases/vala/32 valaless vapigen/meson.build34
-rw-r--r--test cases/vala/32 valaless vapigen/test_clib.c9
-rw-r--r--unittests/allplatformstests.py20
38 files changed, 273 insertions, 71 deletions
diff --git a/docs/markdown/Fs-module.md b/docs/markdown/Fs-module.md
index 7ba4832..91c706e 100644
--- a/docs/markdown/Fs-module.md
+++ b/docs/markdown/Fs-module.md
@@ -206,13 +206,26 @@ fs.name('foo/bar/baz.dll.a') # baz.dll.a
*since 0.54.0*
Returns the last component of the path, dropping the last part of the
-suffix
+suffix.
```meson
fs.stem('foo/bar/baz.dll') # baz
fs.stem('foo/bar/baz.dll.a') # baz.dll
```
+### suffix
+
+*since 1.9.0*
+
+Returns the last dot-separated portion of the final component of the path
+including the dot, if any.
+
+```meson
+fs.suffix('foo/bar/baz.dll') # .dll
+fs.suffix('foo/bar/baz.dll.a') # .a
+fs.suffix('foo/bar') # (empty)
+```
+
### read
- `read(path, encoding: 'utf-8')` *(since 0.57.0)*:
return a [string](Syntax.md#strings) with the contents of the given `path`.
diff --git a/docs/markdown/snippets/fs_suffix.md b/docs/markdown/snippets/fs_suffix.md
new file mode 100644
index 0000000..7059008
--- /dev/null
+++ b/docs/markdown/snippets/fs_suffix.md
@@ -0,0 +1,4 @@
+## Added suffix function to the FS module
+
+The basename and stem were already available. For completeness, expose also the
+suffix.
diff --git a/docs/markdown/snippets/swift-module-name.md b/docs/markdown/snippets/swift-module-name.md
new file mode 100644
index 0000000..689dd84
--- /dev/null
+++ b/docs/markdown/snippets/swift-module-name.md
@@ -0,0 +1,9 @@
+## Explicitly setting Swift module name is now supported
+
+It is now possible to set the Swift module name for a target via the
+*swift_module_name* target kwarg, overriding the default inferred from the
+target name.
+
+```meson
+lib = library('foo', 'foo.swift', swift_module_name: 'Foo')
+```
diff --git a/docs/markdown/snippets/swift-parse-as-library.md b/docs/markdown/snippets/swift-parse-as-library.md
new file mode 100644
index 0000000..5208899
--- /dev/null
+++ b/docs/markdown/snippets/swift-parse-as-library.md
@@ -0,0 +1,8 @@
+## Top-level statement handling in Swift libraries
+
+The Swift compiler normally treats modules with a single source
+file (and files named main.swift) to run top-level code at program
+start. This emits a main symbol which is usually undesirable in a
+library target. Meson now automatically passes the *-parse-as-library*
+flag to the Swift compiler in case of single-file library targets to
+disable this behavior unless the source file is called main.swift.
diff --git a/docs/yaml/functions/configure_file.yaml b/docs/yaml/functions/configure_file.yaml
index 943ad22..2deeff4 100644
--- a/docs/yaml/functions/configure_file.yaml
+++ b/docs/yaml/functions/configure_file.yaml
@@ -16,6 +16,8 @@ description: |
it takes any source or configured file as the `input:` and assumes
that the `output:` is produced when the specified command is run.
+ You can install the outputted file with the `install_dir:` kwarg, see below.
+
*(since 0.47.0)* When the `copy:` keyword argument is set to `true`,
this function will copy the file provided in `input:` to a file in the
build directory with the name `output:` in the current directory.
diff --git a/docs/yaml/functions/custom_target.yaml b/docs/yaml/functions/custom_target.yaml
index 4920407..094787b 100644
--- a/docs/yaml/functions/custom_target.yaml
+++ b/docs/yaml/functions/custom_target.yaml
@@ -12,6 +12,8 @@ description: |
custom_target('foo', output: 'file.txt', ...)
```
+ You can install the outputted files with the `install_dir:` kwarg, see below.
+
*Since 0.60.0* the name argument is optional and defaults to the basename of the first
output (`file.txt` in the example above).
diff --git a/docs/yaml/functions/install_data.yaml b/docs/yaml/functions/install_data.yaml
index fdedf7e..b9aedca 100644
--- a/docs/yaml/functions/install_data.yaml
+++ b/docs/yaml/functions/install_data.yaml
@@ -2,6 +2,9 @@ name: install_data
returns: void
description: |
Installs files from the source tree that are listed as positional arguments.
+ Please note that this can only install static files from the source tree.
+ Generated files are installed via the `install_dir:` kwarg on the respective
+ generators, such as `custom_target()` or `configure_file().
See [Installing](Installing.md) for more examples.
diff --git a/docs/yaml/functions/install_headers.yaml b/docs/yaml/functions/install_headers.yaml
index da304bc..42f6462 100644
--- a/docs/yaml/functions/install_headers.yaml
+++ b/docs/yaml/functions/install_headers.yaml
@@ -9,6 +9,10 @@ description: |
argument. As an example if this has the value `myproj` then the
headers would be installed to `/{prefix}/include/myproj`.
+ Please note that this can only install static files from the source tree.
+ Generated files are installed via the `install_dir:` kwarg on the respective
+ generators, such as `custom_target()` or `configure_file().
+
example: |
For example, this will install `common.h` and `kola.h` into
`/{prefix}/include`:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index ba75ce7..eebdd05 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -2232,10 +2232,7 @@ class NinjaBackend(backends.Backend):
def swift_module_file_name(self, target):
return os.path.join(self.get_target_private_dir(target),
- self.target_swift_modulename(target) + '.swiftmodule')
-
- def target_swift_modulename(self, target):
- return target.name
+ target.swift_module_name + '.swiftmodule')
def determine_swift_dep_modules(self, target):
result = []
@@ -2262,7 +2259,7 @@ class NinjaBackend(backends.Backend):
return srcs, others
def generate_swift_target(self, target) -> None:
- module_name = self.target_swift_modulename(target)
+ module_name = target.swift_module_name
swiftc = target.compilers['swift']
abssrc = []
relsrc = []
@@ -2288,6 +2285,13 @@ class NinjaBackend(backends.Backend):
compile_args += swiftc.get_cxx_interoperability_args(target.compilers)
compile_args += self.build.get_project_args(swiftc, target.subproject, target.for_machine)
compile_args += self.build.get_global_args(swiftc, target.for_machine)
+ if isinstance(target, (build.StaticLibrary, build.SharedLibrary)):
+ # swiftc treats modules with a single source file, and the main.swift file in multi-source file modules
+ # as top-level code. This is undesirable in library targets since it emits a main function. Add the
+ # -parse-as-library option as necessary to prevent emitting the main function while keeping files explicitly
+ # named main.swift treated as the entrypoint of the module in case this is desired.
+ if len(abssrc) == 1 and os.path.basename(abssrc[0]) != 'main.swift':
+ compile_args += swiftc.get_library_args()
for i in reversed(target.get_include_dirs()):
basedir = i.get_curdir()
for d in i.get_incdirs():
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 72d376d..1745b9e 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -75,6 +75,7 @@ lang_arg_kwargs |= {
vala_kwargs = {'vala_header', 'vala_gir', 'vala_vapi'}
rust_kwargs = {'rust_crate_type', 'rust_dependency_map'}
cs_kwargs = {'resources', 'cs_args'}
+swift_kwargs = {'swift_module_name'}
buildtarget_kwargs = {
'build_by_default',
@@ -110,7 +111,8 @@ known_build_target_kwargs = (
pch_kwargs |
vala_kwargs |
rust_kwargs |
- cs_kwargs)
+ cs_kwargs |
+ swift_kwargs)
known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie', 'vs_module_defs', 'android_exe_type'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi'}
@@ -963,7 +965,7 @@ class BuildTarget(Target):
self.compilers[lang] = compiler
break
else:
- if is_known_suffix(s):
+ if is_known_suffix(s) and not is_header(s):
path = pathlib.Path(str(s)).as_posix()
m = f'No {self.for_machine.get_lower_case_name()} machine compiler for {path!r}'
raise MesonException(m)
@@ -1260,6 +1262,10 @@ class BuildTarget(Target):
raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary with string values.')
self.rust_dependency_map = rust_dependency_map
+ self.swift_module_name = kwargs.get('swift_module_name')
+ if self.swift_module_name == '':
+ self.swift_module_name = self.name
+
def _extract_pic_pie(self, kwargs: T.Dict[str, T.Any], arg: str, option: str) -> bool:
# Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags
all_flags = self.extra_args['c'] + self.extra_args['cpp']
diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py
index 47d254b..3fff7a1 100644
--- a/mesonbuild/compilers/swift.py
+++ b/mesonbuild/compilers/swift.py
@@ -159,6 +159,9 @@ class SwiftCompiler(Compiler):
else:
return ['-cxx-interoperability-mode=off']
+ def get_library_args(self) -> T.List[str]:
+ return ['-parse-as-library']
+
def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str],
build_dir: str) -> T.List[str]:
for idx, i in enumerate(parameter_list):
diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py
index d741aab..62d855d 100644
--- a/mesonbuild/interpreter/kwargs.py
+++ b/mesonbuild/interpreter/kwargs.py
@@ -363,6 +363,7 @@ class _BuildTarget(_BaseBuildTarget):
d_module_versions: T.List[T.Union[str, int]]
d_unittest: bool
rust_dependency_map: T.Dict[str, str]
+ swift_module_name: str
sources: SourcesVarargsType
c_args: T.List[str]
cpp_args: T.List[str]
diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py
index fbe3e3e..a94e26b 100644
--- a/mesonbuild/interpreter/type_checking.py
+++ b/mesonbuild/interpreter/type_checking.py
@@ -633,6 +633,7 @@ _BUILD_TARGET_KWS: T.List[KwargInfo] = [
default={},
since='1.2.0',
),
+ KwargInfo('swift_module_name', str, default='', since='1.9.0'),
KwargInfo('build_rpath', str, default='', since='0.42.0'),
KwargInfo(
'gnu_symbol_visibility',
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 57fa286..e19e528 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -125,14 +125,15 @@ def list_installed(installdata: backends.InstallData) -> T.Dict[str, str]:
res[basename] = os.path.join(installdata.prefix, s.install_path, basename)
return res
-def list_install_plan(installdata: backends.InstallData) -> T.Dict[str, T.Dict[str, T.Dict[str, T.Optional[str]]]]:
- plan: T.Dict[str, T.Dict[str, T.Dict[str, T.Optional[str]]]] = {
+def list_install_plan(installdata: backends.InstallData) -> T.Dict[str, T.Dict[str, T.Dict[str, T.Union[str, T.List[str], None]]]]:
+ plan: T.Dict[str, T.Dict[str, T.Dict[str, T.Union[str, T.List[str], None]]]] = {
'targets': {
Path(installdata.build_dir, target.fname).as_posix(): {
'destination': target.out_name,
'tag': target.tag or None,
'subproject': target.subproject or None,
- 'install_rpath': target.install_rpath or None
+ 'install_rpath': target.install_rpath or None,
+ 'build_rpaths': sorted(x.decode('utf8') for x in target.rpath_dirs_to_remove),
}
for target in installdata.targets
},
diff --git a/mesonbuild/modules/fs.py b/mesonbuild/modules/fs.py
index 1fa368e..57a6b6d 100644
--- a/mesonbuild/modules/fs.py
+++ b/mesonbuild/modules/fs.py
@@ -2,7 +2,9 @@
# Copyright 2019 The Meson development team
from __future__ import annotations
-from pathlib import Path, PurePath, PureWindowsPath
+from ntpath import sep as ntsep
+from pathlib import Path
+from posixpath import sep as posixsep
import hashlib
import os
import typing as T
@@ -12,7 +14,7 @@ from .. import mlog
from ..build import BuildTarget, CustomTarget, CustomTargetIndex, InvalidArguments
from ..interpreter.type_checking import INSTALL_KW, INSTALL_MODE_KW, INSTALL_TAG_KW, NoneType
from ..interpreterbase import FeatureNew, KwargInfo, typed_kwargs, typed_pos_args, noKwargs
-from ..mesonlib import File, MesonException, has_path_sep, path_is_in_root, relpath
+from ..mesonlib import File, MesonException, has_path_sep, is_windows, path_is_in_root, relpath
if T.TYPE_CHECKING:
from . import ModuleState
@@ -42,7 +44,7 @@ class FSModule(ExtensionModule):
INFO = ModuleInfo('fs', '0.53.0')
- def __init__(self, interpreter: 'Interpreter') -> None:
+ def __init__(self, interpreter: Interpreter) -> None:
super().__init__(interpreter)
self.methods.update({
'as_posix': self.as_posix,
@@ -62,29 +64,30 @@ class FSModule(ExtensionModule):
'replace_suffix': self.replace_suffix,
'size': self.size,
'stem': self.stem,
+ 'suffix': self.suffix,
})
- def _absolute_dir(self, state: 'ModuleState', arg: 'FileOrString') -> Path:
+ def _absolute_dir(self, state: ModuleState, arg: FileOrString) -> str:
"""
make an absolute path from a relative path, WITHOUT resolving symlinks
"""
if isinstance(arg, File):
- return Path(arg.absolute_path(state.source_root, state.environment.get_build_dir()))
- return Path(state.source_root) / Path(state.subdir) / Path(arg).expanduser()
+ return arg.absolute_path(state.source_root, state.environment.get_build_dir())
+ return os.path.join(state.source_root, state.subdir, os.path.expanduser(arg))
@staticmethod
- def _obj_to_path(feature_new_prefix: str, obj: T.Union[FileOrString, BuildTargetTypes], state: ModuleState) -> PurePath:
+ def _obj_to_pathstr(feature_new_prefix: str, obj: T.Union[FileOrString, BuildTargetTypes], state: ModuleState) -> str:
if isinstance(obj, str):
- return PurePath(obj)
+ return obj
if isinstance(obj, File):
FeatureNew(f'{feature_new_prefix} with file', '0.59.0').use(state.subproject, location=state.current_node)
- return PurePath(str(obj))
+ return str(obj)
FeatureNew(f'{feature_new_prefix} with build_tgt, custom_tgt, and custom_idx', '1.4.0').use(state.subproject, location=state.current_node)
- return PurePath(state.backend.get_target_filename(obj))
+ return state.backend.get_target_filename(obj)
- def _resolve_dir(self, state: 'ModuleState', arg: 'FileOrString') -> Path:
+ def _resolve_dir(self, state: ModuleState, arg: FileOrString) -> str:
"""
resolves symlinks and makes absolute a directory relative to calling meson.build,
if not already absolute
@@ -92,7 +95,7 @@ class FSModule(ExtensionModule):
path = self._absolute_dir(state, arg)
try:
# accommodate unresolvable paths e.g. symlink loops
- path = path.resolve()
+ path = os.path.realpath(path)
except Exception:
# return the best we could do
pass
@@ -101,123 +104,139 @@ class FSModule(ExtensionModule):
@noKwargs
@FeatureNew('fs.expanduser', '0.54.0')
@typed_pos_args('fs.expanduser', str)
- def expanduser(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> str:
- return str(Path(args[0]).expanduser())
+ def expanduser(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> str:
+ return os.path.expanduser(args[0])
@noKwargs
@FeatureNew('fs.is_absolute', '0.54.0')
@typed_pos_args('fs.is_absolute', (str, File))
- def is_absolute(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> bool:
- if isinstance(args[0], File):
+ def is_absolute(self, state: ModuleState, args: T.Tuple[FileOrString], kwargs: T.Dict[str, T.Any]) -> bool:
+ path = args[0]
+ if isinstance(path, File):
FeatureNew('fs.is_absolute with file', '0.59.0').use(state.subproject, location=state.current_node)
- return PurePath(str(args[0])).is_absolute()
+ path = str(path)
+ if is_windows():
+ # os.path.isabs was broken for Windows before Python 3.13, so we implement it ourselves
+ path = path[:3].replace(posixsep, ntsep)
+ return path.startswith(ntsep * 2) or path.startswith(':' + ntsep, 1)
+ return path.startswith(posixsep)
@noKwargs
@FeatureNew('fs.as_posix', '0.54.0')
@typed_pos_args('fs.as_posix', str)
- def as_posix(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> str:
+ def as_posix(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> str:
r"""
this function assumes you are passing a Windows path, even if on a Unix-like system
and so ALL '\' are turned to '/', even if you meant to escape a character
"""
- return PureWindowsPath(args[0]).as_posix()
+ return args[0].replace(ntsep, posixsep)
@noKwargs
@typed_pos_args('fs.exists', str)
- def exists(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
- return self._resolve_dir(state, args[0]).exists()
+ def exists(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
+ return os.path.exists(self._resolve_dir(state, args[0]))
@noKwargs
@typed_pos_args('fs.is_symlink', (str, File))
- def is_symlink(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> bool:
+ def is_symlink(self, state: ModuleState, args: T.Tuple[FileOrString], kwargs: T.Dict[str, T.Any]) -> bool:
if isinstance(args[0], File):
FeatureNew('fs.is_symlink with file', '0.59.0').use(state.subproject, location=state.current_node)
- return self._absolute_dir(state, args[0]).is_symlink()
+ return os.path.islink(self._absolute_dir(state, args[0]))
@noKwargs
@typed_pos_args('fs.is_file', str)
- def is_file(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
- return self._resolve_dir(state, args[0]).is_file()
+ def is_file(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
+ return os.path.isfile(self._resolve_dir(state, args[0]))
@noKwargs
@typed_pos_args('fs.is_dir', str)
- def is_dir(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
- return self._resolve_dir(state, args[0]).is_dir()
+ def is_dir(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> bool:
+ return os.path.isdir(self._resolve_dir(state, args[0]))
@noKwargs
@typed_pos_args('fs.hash', (str, File), str)
- def hash(self, state: 'ModuleState', args: T.Tuple['FileOrString', str], kwargs: T.Dict[str, T.Any]) -> str:
+ def hash(self, state: ModuleState, args: T.Tuple[FileOrString, str], kwargs: T.Dict[str, T.Any]) -> str:
if isinstance(args[0], File):
FeatureNew('fs.hash with file', '0.59.0').use(state.subproject, location=state.current_node)
file = self._resolve_dir(state, args[0])
- if not file.is_file():
+ if not os.path.isfile(file):
raise MesonException(f'{file} is not a file and therefore cannot be hashed')
try:
h = hashlib.new(args[1])
except ValueError:
raise MesonException('hash algorithm {} is not available'.format(args[1]))
- mlog.debug('computing {} sum of {} size {} bytes'.format(args[1], file, file.stat().st_size))
- h.update(file.read_bytes())
+ mlog.debug('computing {} sum of {} size {} bytes'.format(args[1], file, os.stat(file).st_size))
+ with open(file, mode='rb', buffering=0) as f:
+ h.update(f.read())
return h.hexdigest()
@noKwargs
@typed_pos_args('fs.size', (str, File))
- def size(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: T.Dict[str, T.Any]) -> int:
+ def size(self, state: ModuleState, args: T.Tuple[FileOrString], kwargs: T.Dict[str, T.Any]) -> int:
if isinstance(args[0], File):
FeatureNew('fs.size with file', '0.59.0').use(state.subproject, location=state.current_node)
file = self._resolve_dir(state, args[0])
- if not file.is_file():
+ if not os.path.isfile(file):
raise MesonException(f'{file} is not a file and therefore cannot be sized')
try:
- return file.stat().st_size
+ return os.stat(file).st_size
except ValueError:
raise MesonException('{} size could not be determined'.format(args[0]))
@noKwargs
@typed_pos_args('fs.is_samepath', (str, File), (str, File))
- def is_samepath(self, state: 'ModuleState', args: T.Tuple['FileOrString', 'FileOrString'], kwargs: T.Dict[str, T.Any]) -> bool:
+ def is_samepath(self, state: ModuleState, args: T.Tuple[FileOrString, FileOrString], kwargs: T.Dict[str, T.Any]) -> bool:
if isinstance(args[0], File) or isinstance(args[1], File):
FeatureNew('fs.is_samepath with file', '0.59.0').use(state.subproject, location=state.current_node)
file1 = self._resolve_dir(state, args[0])
file2 = self._resolve_dir(state, args[1])
- if not file1.exists():
+ if not os.path.exists(file1):
return False
- if not file2.exists():
+ if not os.path.exists(file2):
return False
try:
- return file1.samefile(file2)
+ return os.path.samefile(file1, file2)
except OSError:
return False
@noKwargs
@typed_pos_args('fs.replace_suffix', (str, File, CustomTarget, CustomTargetIndex, BuildTarget), str)
- def replace_suffix(self, state: 'ModuleState', args: T.Tuple[T.Union[FileOrString, BuildTargetTypes], str], kwargs: T.Dict[str, T.Any]) -> str:
- path = self._obj_to_path('fs.replace_suffix', args[0], state)
- return str(path.with_suffix(args[1]))
+ def replace_suffix(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes], str], kwargs: T.Dict[str, T.Any]) -> str:
+ if args[1] and not args[1].startswith('.'):
+ raise ValueError(f"Invalid suffix {args[1]!r}")
+ path = self._obj_to_pathstr('fs.replace_suffix', args[0], state)
+ return os.path.splitext(path)[0] + args[1]
@noKwargs
@typed_pos_args('fs.parent', (str, File, CustomTarget, CustomTargetIndex, BuildTarget))
- def parent(self, state: 'ModuleState', args: T.Tuple[T.Union[FileOrString, BuildTargetTypes]], kwargs: T.Dict[str, T.Any]) -> str:
- path = self._obj_to_path('fs.parent', args[0], state)
- return str(path.parent)
+ def parent(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes]], kwargs: T.Dict[str, T.Any]) -> str:
+ path = self._obj_to_pathstr('fs.parent', args[0], state)
+ return os.path.split(path)[0] or '.'
@noKwargs
@typed_pos_args('fs.name', (str, File, CustomTarget, CustomTargetIndex, BuildTarget))
- def name(self, state: 'ModuleState', args: T.Tuple[T.Union[FileOrString, BuildTargetTypes]], kwargs: T.Dict[str, T.Any]) -> str:
- path = self._obj_to_path('fs.name', args[0], state)
- return str(path.name)
+ def name(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes]], kwargs: T.Dict[str, T.Any]) -> str:
+ path = self._obj_to_pathstr('fs.name', args[0], state)
+ return os.path.basename(path)
@noKwargs
@typed_pos_args('fs.stem', (str, File, CustomTarget, CustomTargetIndex, BuildTarget))
@FeatureNew('fs.stem', '0.54.0')
- def stem(self, state: 'ModuleState', args: T.Tuple[T.Union[FileOrString, BuildTargetTypes]], kwargs: T.Dict[str, T.Any]) -> str:
- path = self._obj_to_path('fs.stem', args[0], state)
- return str(path.stem)
+ def stem(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes]], kwargs: T.Dict[str, T.Any]) -> str:
+ path = self._obj_to_pathstr('fs.name', args[0], state)
+ return os.path.splitext(os.path.basename(path))[0]
+
+ @noKwargs
+ @typed_pos_args('fs.suffix', (str, File, CustomTarget, CustomTargetIndex, BuildTarget))
+ @FeatureNew('fs.suffix', '1.9.0')
+ def suffix(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes]], kwargs: T.Dict[str, T.Any]) -> str:
+ path = self._obj_to_pathstr('fs.suffix', args[0], state)
+ return os.path.splitext(path)[1]
@FeatureNew('fs.read', '0.57.0')
@typed_pos_args('fs.read', (str, File))
@typed_kwargs('fs.read', KwargInfo('encoding', str, default='utf-8'))
- def read(self, state: 'ModuleState', args: T.Tuple['FileOrString'], kwargs: 'ReadKwArgs') -> str:
+ def read(self, state: ModuleState, args: T.Tuple[FileOrString], kwargs: ReadKwArgs) -> str:
"""Read a file from the source tree and return its value as a decoded
string.
diff --git a/test cases/common/220 fs module/meson.build b/test cases/common/220 fs module/meson.build
index e5397ee..383b263 100644
--- a/test cases/common/220 fs module/meson.build
+++ b/test cases/common/220 fs module/meson.build
@@ -52,6 +52,7 @@ unixabs = '/foo'
if is_windows
assert(fs.is_absolute(winabs), 'is_absolute windows not detected')
assert(not fs.is_absolute(unixabs), 'is_absolute unix false positive')
+ assert(fs.is_absolute('//foo'), 'is_absolute failed on incomplete UNC path')
else
assert(fs.is_absolute(unixabs), 'is_absolute unix not detected')
assert(not fs.is_absolute(winabs), 'is_absolute windows false positive')
@@ -84,7 +85,7 @@ assert(new == 'foo', 'replace_suffix did not only delete last suffix')
# `/` on windows is interpreted like `.drive` which in general may not be `c:/`
# the files need not exist for fs.replace_suffix()
-original = is_windows ? 'j:/foo/bar.txt' : '/foo/bar.txt'
+original = is_windows ? 'j:\\foo\\bar.txt' : '/foo/bar.txt'
new_check = is_windows ? 'j:\\foo\\bar.ini' : '/foo/bar.ini'
new = fs.replace_suffix(original, '.ini')
@@ -139,11 +140,7 @@ endif
# parts of path
assert(fs.parent('foo/bar') == 'foo', 'failed to get dirname')
-if not is_windows
-assert(fs.parent(f[1]) == 'subdir/..', 'failed to get dirname')
-else
-assert(fs.parent(f[1]) == 'subdir\..', 'failed to get dirname')
-endif
+assert(fs.parent(f[1]) == 'subdir/..', 'failed to get dirname for file')
assert(fs.parent(btgt) == '.', 'failed to get dirname for build target')
assert(fs.parent(ctgt) == '.', 'failed to get dirname for custom target')
assert(fs.parent(ctgt[0]) == '.', 'failed to get dirname for custom target index')
@@ -153,8 +150,10 @@ assert(fs.name(f[1]) == 'meson.build', 'failed to get basename')
assert(fs.name('foo/bar/baz.dll.a') == 'baz.dll.a', 'failed to get basename with compound suffix')
if host_machine.system() in ['cygwin', 'windows']
assert(fs.name(btgt) == 'btgt.exe', 'failed to get basename of build target')
+ assert(fs.suffix(btgt) == '.exe', 'failed to get build target suffix')
else
assert(fs.name(btgt) == 'btgt', 'failed to get basename of build target')
+ assert(fs.suffix(btgt) == '', 'failed to get build target suffix')
endif
assert(fs.name(ctgt) == 'ctgt.txt', 'failed to get basename of custom target')
assert(fs.name(ctgt[0]) == 'ctgt.txt', 'failed to get basename of custom target index')
@@ -163,6 +162,12 @@ assert(fs.stem('foo/bar/baz.dll.a') == 'baz.dll', 'failed to get stem with compo
assert(fs.stem(btgt) == 'btgt', 'failed to get stem of build target')
assert(fs.stem(ctgt) == 'ctgt', 'failed to get stem of custom target')
assert(fs.stem(ctgt[0]) == 'ctgt', 'failed to get stem of custom target index')
+assert(fs.suffix('foo/bar/baz') == '', 'failed to get missing suffix')
+assert(fs.suffix('foo/bar/baz.') == '.', 'failed to get empty suffix')
+assert(fs.suffix('foo/bar/baz.dll') == '.dll', 'failed to get plain suffix')
+assert(fs.suffix('foo/bar/baz.dll.a') == '.a', 'failed to get final suffix')
+assert(fs.suffix(ctgt) == '.txt', 'failed to get suffix of custom target')
+assert(fs.suffix(ctgt[0]) == '.txt', 'failed to get suffix of custom target index')
# relative_to
if build_machine.system() == 'windows'
diff --git a/test cases/swift/14 single-file library/main.swift b/test cases/swift/14 single-file library/main.swift
new file mode 100644
index 0000000..ccc8fb9
--- /dev/null
+++ b/test cases/swift/14 single-file library/main.swift
@@ -0,0 +1,3 @@
+import SingleFile
+
+callMe()
diff --git a/test cases/swift/14 single-file library/meson.build b/test cases/swift/14 single-file library/meson.build
new file mode 100644
index 0000000..8eda1d5
--- /dev/null
+++ b/test cases/swift/14 single-file library/meson.build
@@ -0,0 +1,4 @@
+project('single-file library', 'swift')
+
+lib = static_library('SingleFile', 'singlefile.swift')
+executable('program', 'main.swift', link_with: [lib])
diff --git a/test cases/swift/14 single-file library/singlefile.swift b/test cases/swift/14 single-file library/singlefile.swift
new file mode 100644
index 0000000..617952f
--- /dev/null
+++ b/test cases/swift/14 single-file library/singlefile.swift
@@ -0,0 +1 @@
+public func callMe() {}
diff --git a/test cases/swift/15 main in single-file library/main.swift b/test cases/swift/15 main in single-file library/main.swift
new file mode 100644
index 0000000..0d95abb
--- /dev/null
+++ b/test cases/swift/15 main in single-file library/main.swift
@@ -0,0 +1,3 @@
+import CProgram
+
+precondition(callMe() == 4)
diff --git a/test cases/swift/15 main in single-file library/meson.build b/test cases/swift/15 main in single-file library/meson.build
new file mode 100644
index 0000000..2e1202e
--- /dev/null
+++ b/test cases/swift/15 main in single-file library/meson.build
@@ -0,0 +1,4 @@
+project('main in single-file library', 'swift', 'c')
+
+lib = static_library('Library', 'main.swift', include_directories: ['.'])
+executable('program', 'program.c', link_with: [lib])
diff --git a/test cases/swift/15 main in single-file library/module.modulemap b/test cases/swift/15 main in single-file library/module.modulemap
new file mode 100644
index 0000000..3c1817a
--- /dev/null
+++ b/test cases/swift/15 main in single-file library/module.modulemap
@@ -0,0 +1,3 @@
+module CProgram [extern_c] {
+ header "program.h"
+}
diff --git a/test cases/swift/15 main in single-file library/program.c b/test cases/swift/15 main in single-file library/program.c
new file mode 100644
index 0000000..8959dae
--- /dev/null
+++ b/test cases/swift/15 main in single-file library/program.c
@@ -0,0 +1,5 @@
+#include "program.h"
+
+int callMe() {
+ return 4;
+}
diff --git a/test cases/swift/15 main in single-file library/program.h b/test cases/swift/15 main in single-file library/program.h
new file mode 100644
index 0000000..5058be3
--- /dev/null
+++ b/test cases/swift/15 main in single-file library/program.h
@@ -0,0 +1 @@
+int callMe(void);
diff --git a/test cases/swift/16 main in multi-file library/main.swift b/test cases/swift/16 main in multi-file library/main.swift
new file mode 100644
index 0000000..3682e8d
--- /dev/null
+++ b/test cases/swift/16 main in multi-file library/main.swift
@@ -0,0 +1,4 @@
+import CProgram
+
+precondition(callMe() == 4)
+precondition(callMe2() == 6)
diff --git a/test cases/swift/16 main in multi-file library/meson.build b/test cases/swift/16 main in multi-file library/meson.build
new file mode 100644
index 0000000..4d287f3
--- /dev/null
+++ b/test cases/swift/16 main in multi-file library/meson.build
@@ -0,0 +1,4 @@
+project('main in multi-file library', 'swift', 'c')
+
+lib = static_library('Library', 'main.swift', 'more.swift', include_directories: ['.'])
+executable('program', 'program.c', link_with: [lib])
diff --git a/test cases/swift/16 main in multi-file library/module.modulemap b/test cases/swift/16 main in multi-file library/module.modulemap
new file mode 100644
index 0000000..3c1817a
--- /dev/null
+++ b/test cases/swift/16 main in multi-file library/module.modulemap
@@ -0,0 +1,3 @@
+module CProgram [extern_c] {
+ header "program.h"
+}
diff --git a/test cases/swift/16 main in multi-file library/more.swift b/test cases/swift/16 main in multi-file library/more.swift
new file mode 100644
index 0000000..716500f
--- /dev/null
+++ b/test cases/swift/16 main in multi-file library/more.swift
@@ -0,0 +1,3 @@
+func callMe2() -> Int {
+ 6
+}
diff --git a/test cases/swift/16 main in multi-file library/program.c b/test cases/swift/16 main in multi-file library/program.c
new file mode 100644
index 0000000..8959dae
--- /dev/null
+++ b/test cases/swift/16 main in multi-file library/program.c
@@ -0,0 +1,5 @@
+#include "program.h"
+
+int callMe() {
+ return 4;
+}
diff --git a/test cases/swift/16 main in multi-file library/program.h b/test cases/swift/16 main in multi-file library/program.h
new file mode 100644
index 0000000..5058be3
--- /dev/null
+++ b/test cases/swift/16 main in multi-file library/program.h
@@ -0,0 +1 @@
+int callMe(void);
diff --git a/test cases/swift/8 extra args/lib.swift b/test cases/swift/8 extra args/lib.swift
new file mode 100644
index 0000000..f8167ad
--- /dev/null
+++ b/test cases/swift/8 extra args/lib.swift
@@ -0,0 +1,3 @@
+public func callMe() {
+ print("test")
+}
diff --git a/test cases/swift/8 extra args/main.swift b/test cases/swift/8 extra args/main.swift
deleted file mode 100644
index 1ff8e07..0000000
--- a/test cases/swift/8 extra args/main.swift
+++ /dev/null
@@ -1 +0,0 @@
-print("test")
diff --git a/test cases/swift/8 extra args/meson.build b/test cases/swift/8 extra args/meson.build
index ead2ff5..d243e36 100644
--- a/test cases/swift/8 extra args/meson.build
+++ b/test cases/swift/8 extra args/meson.build
@@ -2,8 +2,8 @@ project('extra args', 'swift')
trace_fname = 'trace.json'
-lib = static_library('main',
- 'main.swift',
+lib = static_library('lib',
+ 'lib.swift',
swift_args: [
'-emit-loaded-module-trace',
'-emit-loaded-module-trace-path', '../' + trace_fname
diff --git a/test cases/vala/32 valaless vapigen/clib.c b/test cases/vala/32 valaless vapigen/clib.c
new file mode 100644
index 0000000..a55ecd4
--- /dev/null
+++ b/test cases/vala/32 valaless vapigen/clib.c
@@ -0,0 +1,5 @@
+#include "clib.h"
+
+int clib_fun(void) {
+ return 42;
+}
diff --git a/test cases/vala/32 valaless vapigen/clib.h b/test cases/vala/32 valaless vapigen/clib.h
new file mode 100644
index 0000000..4d855c9
--- /dev/null
+++ b/test cases/vala/32 valaless vapigen/clib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int clib_fun(void);
diff --git a/test cases/vala/32 valaless vapigen/meson.build b/test cases/vala/32 valaless vapigen/meson.build
new file mode 100644
index 0000000..22a99e5
--- /dev/null
+++ b/test cases/vala/32 valaless vapigen/meson.build
@@ -0,0 +1,34 @@
+project('valaless-vapigen', 'c')
+
+if host_machine.system() == 'cygwin'
+ error('MESON_SKIP_TEST Does not work with the Vala currently packaged in cygwin')
+endif
+
+gnome = import('gnome')
+
+clib_src = [
+ 'clib.c',
+ 'clib.h'
+]
+
+clib_lib = shared_library('clib', clib_src)
+
+clib_gir = gnome.generate_gir(clib_lib,
+ sources: clib_src,
+ namespace: 'Clib',
+ nsversion: '0',
+ header: 'clib.h',
+ symbol_prefix: 'clib'
+)
+
+clib_vapi = gnome.generate_vapi('clib', sources: clib_gir[0])
+
+clib_dep = declare_dependency(
+ include_directories: include_directories('.'),
+ link_with: clib_lib,
+ sources: clib_gir,
+ dependencies: clib_vapi
+)
+
+
+test('clib-test', executable('clib-test', 'test_clib.c', dependencies: clib_dep))
diff --git a/test cases/vala/32 valaless vapigen/test_clib.c b/test cases/vala/32 valaless vapigen/test_clib.c
new file mode 100644
index 0000000..6fd426c
--- /dev/null
+++ b/test cases/vala/32 valaless vapigen/test_clib.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <clib.h>
+
+int main(void) {
+ if (clib_fun () == 42)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index 905ae4d..c006961 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -4812,120 +4812,140 @@ class AllPlatformTests(BasePlatformTests):
expected = {
'targets': {
get_path(f'{self.builddir}/out1-notag.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out1-notag.txt',
'install_rpath': None,
'tag': None,
'subproject': None,
},
get_path(f'{self.builddir}/out2-notag.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out2-notag.txt',
'install_rpath': None,
'tag': None,
'subproject': None,
},
get_path(f'{self.builddir}/libstatic.a'): {
+ 'build_rpaths': [],
'destination': '{libdir_static}/libstatic.a',
'install_rpath': None,
'tag': 'devel',
'subproject': None,
},
get_path(f'{self.builddir}/' + exe_name('app')): {
+ 'build_rpaths': [],
'destination': '{bindir}/' + exe_name('app'),
'install_rpath': None,
'tag': 'runtime',
'subproject': None,
},
get_path(f'{self.builddir}/' + exe_name('app-otherdir')): {
+ 'build_rpaths': [],
'destination': '{prefix}/otherbin/' + exe_name('app-otherdir'),
'install_rpath': None,
'tag': 'runtime',
'subproject': None,
},
get_path(f'{self.builddir}/subdir/' + exe_name('app2')): {
+ 'build_rpaths': [],
'destination': '{bindir}/' + exe_name('app2'),
'install_rpath': None,
'tag': 'runtime',
'subproject': None,
},
get_path(f'{self.builddir}/' + shared_lib_name('shared')): {
+ 'build_rpaths': [],
'destination': '{libdir_shared}/' + shared_lib_name('shared'),
'install_rpath': None,
'tag': 'runtime',
'subproject': None,
},
get_path(f'{self.builddir}/' + shared_lib_name('both')): {
+ 'build_rpaths': [],
'destination': '{libdir_shared}/' + shared_lib_name('both'),
'install_rpath': None,
'tag': 'runtime',
'subproject': None,
},
get_path(f'{self.builddir}/' + static_lib_name('both')): {
+ 'build_rpaths': [],
'destination': '{libdir_static}/' + static_lib_name('both'),
'install_rpath': None,
'tag': 'devel',
'subproject': None,
},
get_path(f'{self.builddir}/' + shared_lib_name('bothcustom')): {
+ 'build_rpaths': [],
'destination': '{libdir_shared}/' + shared_lib_name('bothcustom'),
'install_rpath': None,
'tag': 'custom',
'subproject': None,
},
get_path(f'{self.builddir}/' + static_lib_name('bothcustom')): {
+ 'build_rpaths': [],
'destination': '{libdir_static}/' + static_lib_name('bothcustom'),
'install_rpath': None,
'tag': 'custom',
'subproject': None,
},
get_path(f'{self.builddir}/subdir/' + shared_lib_name('both2')): {
+ 'build_rpaths': [],
'destination': '{libdir_shared}/' + shared_lib_name('both2'),
'install_rpath': None,
'tag': 'runtime',
'subproject': None,
},
get_path(f'{self.builddir}/subdir/' + static_lib_name('both2')): {
+ 'build_rpaths': [],
'destination': '{libdir_static}/' + static_lib_name('both2'),
'install_rpath': None,
'tag': 'devel',
'subproject': None,
},
get_path(f'{self.builddir}/out1-custom.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out1-custom.txt',
'install_rpath': None,
'tag': 'custom',
'subproject': None,
},
get_path(f'{self.builddir}/out2-custom.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out2-custom.txt',
'install_rpath': None,
'tag': 'custom',
'subproject': None,
},
get_path(f'{self.builddir}/out3-custom.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out3-custom.txt',
'install_rpath': None,
'tag': 'custom',
'subproject': None,
},
get_path(f'{self.builddir}/subdir/out1.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out1.txt',
'install_rpath': None,
'tag': None,
'subproject': None,
},
get_path(f'{self.builddir}/subdir/out2.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out2.txt',
'install_rpath': None,
'tag': None,
'subproject': None,
},
get_path(f'{self.builddir}/out-devel.h'): {
+ 'build_rpaths': [],
'destination': '{includedir}/out-devel.h',
'install_rpath': None,
'tag': 'devel',
'subproject': None,
},
get_path(f'{self.builddir}/out3-notag.txt'): {
+ 'build_rpaths': [],
'destination': '{datadir}/out3-notag.txt',
'install_rpath': None,
'tag': None,