aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/modules
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2021-01-06 11:28:50 -0800
committerDylan Baker <dylan@pnwbakers.com>2021-02-06 10:27:04 -0800
commitb28235428df69ba0a90a8f7c0f26db8527ec68a7 (patch)
tree10df8a0b264bf493cbf7de3807e5a56a97d959ab /mesonbuild/modules
parent9d441d26d20a8bd79edd2180160238771fe8c28d (diff)
downloadmeson-b28235428df69ba0a90a8f7c0f26db8527ec68a7.zip
meson-b28235428df69ba0a90a8f7c0f26db8527ec68a7.tar.gz
meson-b28235428df69ba0a90a8f7c0f26db8527ec68a7.tar.bz2
rust: Add a module wrapper for bindgen
This has a couple of advantages over rolling it by hand: 1. it correctly handles include_directories objects, which is always handy 2. it correctly generates a depfile for you, which makes it more reliable 3. it requires less typing
Diffstat (limited to 'mesonbuild/modules')
-rw-r--r--mesonbuild/modules/unstable_rust.py80
1 files changed, 77 insertions, 3 deletions
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