aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2021-02-07 16:57:39 +0000
committerGitHub <noreply@github.com>2021-02-07 16:57:39 +0000
commita855bcab1ccaff68155374c53896c1a780337f40 (patch)
tree9f5da58d50d50e74bd0c3741420f72918f161863 /mesonbuild
parent3f8585676ba6d2c1bcd5d80a44275fdfa695f8c2 (diff)
parent9cebd29da973553c6e657f7b318ab1d6afbc76e6 (diff)
downloadmeson-a855bcab1ccaff68155374c53896c1a780337f40.zip
meson-a855bcab1ccaff68155374c53896c1a780337f40.tar.gz
meson-a855bcab1ccaff68155374c53896c1a780337f40.tar.bz2
Merge pull request #8162 from dcbaker/wip/2021-01/rust-module-bindgen
Add a wrapper to the rust module for bindgen
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/ninjabackend.py19
-rw-r--r--mesonbuild/build.py12
-rw-r--r--mesonbuild/interpreter.py6
-rw-r--r--mesonbuild/mesonlib/universal.py4
-rw-r--r--mesonbuild/modules/unstable_rust.py80
5 files changed, 103 insertions, 18 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 3eca3c0..b93ac39 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1597,14 +1597,19 @@ int dummy;
args += target.get_extra_args('rust')
args += rustc.get_output_args(os.path.join(target.subdir, target.get_filename()))
args += self.environment.coredata.get_external_args(target.for_machine, rustc.language)
- linkdirs = OrderedDict()
+ linkdirs = mesonlib.OrderedSet()
for d in target.link_targets:
- linkdirs[d.subdir] = True
- # specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust
- # dependency, so that collisions with libraries in rustc's
- # sysroot don't cause ambiguity
- args += ['--extern', '{}={}'.format(d.name, os.path.join(d.subdir, d.filename))]
- for d in linkdirs.keys():
+ linkdirs.add(d.subdir)
+ if d.uses_rust():
+ # specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust
+ # dependency, so that collisions with libraries in rustc's
+ # sysroot don't cause ambiguity
+ args += ['--extern', '{}={}'.format(d.name, os.path.join(d.subdir, d.filename))]
+ else:
+ # Rust uses -l for non rust dependencies, but we still need to add (shared|static)=foo
+ _type = 'static' if d.typename == 'static library' else 'shared'
+ args += ['-l', f'{_type}={d.name}']
+ for d in linkdirs:
if d == '':
d = '.'
args += ['-L', d]
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 160ee9a..9a4f8b1 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -322,6 +322,13 @@ class IncludeDirs:
def get_extra_build_dirs(self):
return self.extra_build_dirs
+ def to_string_list(self, sourcedir: str) -> T.List[str]:
+ """Convert IncludeDirs object to a list of strings."""
+ strlist: T.List[str] = []
+ for idir in self.incdirs:
+ strlist.append(os.path.join(sourcedir, self.curdir, idir))
+ return strlist
+
class ExtractedObjects:
'''
Holds a list of sources for which the objects must be extracted
@@ -2189,7 +2196,8 @@ class CustomTarget(Target, CommandBase):
'env',
])
- def __init__(self, name, subdir, subproject, kwargs, absolute_paths=False, backend=None):
+ def __init__(self, name: str, subdir: str, subproject: str, kwargs: T.Dict[str, T.Any],
+ absolute_paths: bool = False, backend: T.Optional[str] = None):
self.typename = 'custom'
# TODO expose keyword arg to make MachineChoice.HOST configurable
super().__init__(name, subdir, subproject, False, MachineChoice.HOST)
@@ -2204,7 +2212,7 @@ class CustomTarget(Target, CommandBase):
for k in kwargs:
if k not in CustomTarget.known_kwargs:
unknowns.append(k)
- if len(unknowns) > 0:
+ if unknowns:
mlog.warning('Unknown keyword arguments in target {}: {}'.format(self.name, ', '.join(unknowns)))
def get_default_install_dir(self, environment):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 176c1da..f670aec 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -918,7 +918,7 @@ class CustomTargetIndexHolder(TargetHolder):
return self.interpreter.backend.get_target_filename_abs(self.held_object)
class CustomTargetHolder(TargetHolder):
- def __init__(self, target, interp):
+ def __init__(self, target: 'build.CustomTarget', interp: 'Interpreter'):
super().__init__(target, interp)
self.methods.update({'full_path': self.full_path_method,
'to_list': self.to_list_method,
@@ -1132,9 +1132,7 @@ class CompilerHolder(InterpreterObject):
for i in incdirs:
if not isinstance(i, IncludeDirsHolder):
raise InterpreterException('Include directories argument must be an include_directories object.')
- for idir in i.held_object.get_incdirs():
- idir = os.path.join(self.environment.get_source_dir(),
- i.held_object.get_curdir(), idir)
+ for idir in i.held_object.to_string_list(self.environment.get_source_dir()):
args += self.compiler.get_include_args(idir, False)
if not nobuiltins:
opts = self.environment.coredata.options
diff --git a/mesonbuild/mesonlib/universal.py b/mesonbuild/mesonlib/universal.py
index 4b913a8..7deb24a 100644
--- a/mesonbuild/mesonlib/universal.py
+++ b/mesonbuild/mesonlib/universal.py
@@ -1262,10 +1262,10 @@ def typeslistify(item: 'T.Union[_T, T.Sequence[_T]]',
if isinstance(item, types):
item = T.cast(T.List[_T], [item])
if not isinstance(item, list):
- raise MesonException('Item must be a list or one of {!r}'.format(types))
+ raise MesonException('Item must be a list or one of {!r}, not {!r}'.format(types, type(item)))
for i in item:
if i is not None and not isinstance(i, types):
- raise MesonException('List item must be one of {!r}'.format(types))
+ raise MesonException('List item must be one of {!r}, not {!r}'.format(types, type(i)))
return item
diff --git a/mesonbuild/modules/unstable_rust.py b/mesonbuild/modules/unstable_rust.py
index e74c181..c4d7d41 100644
--- a/mesonbuild/modules/unstable_rust.py
+++ b/mesonbuild/modules/unstable_rust.py
@@ -12,18 +12,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import typing as T
from . import ExtensionModule, ModuleReturnValue
from .. import mlog
-from ..build import BuildTarget, Executable, InvalidArguments
+from ..build import BuildTarget, CustomTargetIndex, Executable, GeneratedList, InvalidArguments, IncludeDirs, CustomTarget
from ..dependencies import Dependency, ExternalLibrary
-from ..interpreter import ExecutableHolder, BuildTargetHolder, permitted_kwargs
+from ..interpreter import ExecutableHolder, BuildTargetHolder, CustomTargetHolder, permitted_kwargs, noPosargs
from ..interpreterbase import InterpreterException, permittedKwargs, FeatureNew, typed_pos_args
-from ..mesonlib import stringlistify, unholder, listify
+from ..mesonlib import stringlistify, unholder, listify, typeslistify, File
if T.TYPE_CHECKING:
from ..interpreter import ModuleState, Interpreter
+ from ..dependencies import ExternalProgram
class RustModule(ExtensionModule):
@@ -33,6 +35,7 @@ class RustModule(ExtensionModule):
@FeatureNew('rust module', '0.57.0')
def __init__(self, interpreter: 'Interpreter') -> None:
super().__init__(interpreter)
+ self._bindgen_bin: T.Optional['ExternalProgram'] = None
@permittedKwargs(permitted_kwargs['test'] | {'dependencies'} ^ {'protocol'})
@typed_pos_args('rust.test', str, BuildTargetHolder)
@@ -127,6 +130,77 @@ class RustModule(ExtensionModule):
return ModuleReturnValue([], [e, test])
+ @noPosargs
+ @permittedKwargs({'input', 'output', 'include_directories', 'c_args', 'args'})
+ def bindgen(self, state: 'ModuleState', args: T.List, kwargs: T.Dict[str, T.Any]) -> ModuleReturnValue:
+ """Wrapper around bindgen to simplify it's use.
+
+ The main thing this simplifies is the use of `include_directory`
+ objects, instead of having to pass a plethora of `-I` arguments.
+ """
+ header: T.Union[File, CustomTarget, GeneratedList, CustomTargetIndex]
+ _deps: T.Sequence[T.Union[File, CustomTarget, GeneratedList, CustomTargetIndex]]
+ try:
+ header, *_deps = unholder(self.interpreter.source_strings_to_files(listify(kwargs['input'])))
+ except KeyError:
+ raise InvalidArguments('rustmod.bindgen() `input` argument must have at least one element.')
+
+ try:
+ output: str = kwargs['output']
+ except KeyError:
+ raise InvalidArguments('rustmod.bindgen() `output` must be provided')
+ if not isinstance(output, str):
+ raise InvalidArguments('rustmod.bindgen() `output` argument must be a string.')
+
+ include_dirs: T.List[IncludeDirs] = typeslistify(unholder(listify(kwargs.get('include_directories', []))), IncludeDirs)
+ c_args: T.List[str] = stringlistify(listify(kwargs.get('c_args', [])))
+ bind_args: T.List[str] = stringlistify(listify(kwargs.get('args', [])))
+
+ # Split File and Target dependencies to add pass to CustomTarget
+ depends: T.List[BuildTarget] = []
+ depend_files: T.List[File] = []
+ for d in _deps:
+ if isinstance(d, File):
+ depend_files.append(d)
+ else:
+ depends.append(d)
+
+ inc_strs: T.List[str] = []
+ for i in include_dirs:
+ # bindgen always uses clang, so it's safe to hardcode -I here
+ inc_strs.extend([f'-I{x}' for x in i.to_string_list(state.environment.get_source_dir())])
+
+ if self._bindgen_bin is None:
+ # there's some bugs in the interpreter typeing.
+ self._bindgen_bin = T.cast('ExternalProgram', self.interpreter.find_program_impl(['bindgen']).held_object)
+
+ name: str
+ if isinstance(header, File):
+ name = header.fname
+ else:
+ name = header.get_outputs()[0]
+
+ target = CustomTarget(
+ f'rustmod-bindgen-{name}'.replace('/', '_'),
+ state.subdir,
+ state.subproject,
+ {
+ 'input': header,
+ 'output': output,
+ 'command': self._bindgen_bin.get_command() + [
+ '@INPUT@', '--output',
+ os.path.join(state.environment.build_dir, '@OUTPUT@')] +
+ bind_args + ['--'] + c_args + inc_strs +
+ ['-MD', '-MQ', '@INPUT@', '-MF', '@DEPFILE@'],
+ 'depfile': '@PLAINNAME@.d',
+ 'depends': depends,
+ 'depend_files': depend_files,
+ },
+ backend=state.backend,
+ )
+
+ return ModuleReturnValue([target], [CustomTargetHolder(target, self.interpreter)])
+
def initialize(*args: T.List, **kwargs: T.Dict) -> RustModule:
return RustModule(*args, **kwargs) # type: ignore