modules/rust: Add a machine file property for extra clang args with bindgen

It's currently impossible to inject extra clang arguments when using
bindgen, which is problematic when cross compiling since you may need
critical arguments like `--target=...`. Because such arguments must be
passed after the `--` it's impossible to inject them currently without
going to something like a wrapper script.

Fixes: #11805
pull/11902/head
Dylan Baker 1 year ago
parent 43f24060f3
commit c5b16ab8b9
  1. 2
      docs/markdown/Machine-files.md
  2. 9
      docs/markdown/Rust-module.md
  3. 8
      docs/markdown/snippets/rust_extra_clang_bindgen_arguments.md
  4. 6
      mesonbuild/envconfig.py
  5. 5
      mesonbuild/modules/rust.py
  6. 33
      unittests/machinefiletests.py

@ -237,6 +237,8 @@ section.
subprojects. This setting has no effect if the `exe_wrapper` was not specified.
The default value is `true`. (*new in 0.56.0*)
- `java_home` is an absolute path pointing to the root of a Java installation.
- `bindgen_clang_arguments` an array of extra arguments to pass to clang when
calling bindgen
### CMake variables

@ -86,10 +86,17 @@ r1 = rust.bindgen(
)
```
*Since 1.1.0* Meson will synchronize assertions for Rust and C/C++ when the
`b_ndebug` option is set (via `-DNDEBUG` for C/C++, and `-C
debug-assertions=on` for Rust), and will pass `-DNDEBUG` as an extra argument
to clang. This allows for reliable wrapping of `-DNDEBUG` controlled behavior
with `#[cfg(debug_asserions)]` and or `cfg!()`. Before 1.1.0, assertions for Rust
were never turned on by Meson.
*Since 1.2.0* Additional arguments to pass to clang may be specified in a
*machine file in the properties section:
```ini
[properties]
bindgen_clang_arguments = ['--target', 'x86_64-linux-gnu']
```

@ -0,0 +1,8 @@
## A machine file may be used to pass extra arguments to clang in a bindgen call
Because of the way that bindgen proxies arguments to clang the only choice to
add extra arguments currently is to wrap bindgen in a script, since the
arguments must come after a `--`. This is inelegant, and not very portable. Now
a `bindgen_clang_arguments` field may be placed in the machine file for the host
machine, and these arguments will be added to every bindgen call for clang. This
is intended to be useful for things like injecting `--target` arguments.

@ -237,6 +237,12 @@ class Properties:
value = T.cast('T.Optional[str]', self.properties.get('java_home'))
return Path(value) if value else None
def get_bindgen_clang_args(self) -> T.List[str]:
value = mesonlib.listify(self.properties.get('bindgen_clang_arguments', []))
if not all(isinstance(v, str) for v in value):
raise EnvironmentException('bindgen_clang_arguments must be a string or an array of strings')
return T.cast('T.List[str]', value)
def __eq__(self, other: object) -> bool:
if isinstance(other, type(self)):
return self.properties == other.properties

@ -201,7 +201,10 @@ class RustModule(ExtensionModule):
else:
depends.append(d)
clang_args: T.List[str] = []
# Copy to avoid subsequent calls mutating the original
# TODO: if we want this to be per-machine we'll need a native kwarg
clang_args = state.environment.properties.host.get_bindgen_clang_args().copy()
for i in state.process_include_dirs(kwargs['include_directories']):
# bindgen always uses clang, so it's safe to hardcode -I here
clang_args.extend([f'-I{x}' for x in i.to_string_list(

@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import subprocess
import tempfile
import textwrap
@ -67,7 +69,7 @@ class NativeFileTests(BasePlatformTests):
self.current_config = 0
self.current_wrapper = 0
def helper_create_native_file(self, values):
def helper_create_native_file(self, values: T.Dict[str, T.Dict[str, T.Union[str, int, float, bool, T.Sequence[T.Union[str, int, float, bool]]]]]) -> str:
"""Create a config file as a temporary file.
values should be a nested dictionary structure of {section: {key:
@ -81,10 +83,10 @@ class NativeFileTests(BasePlatformTests):
for k, v in entries.items():
if isinstance(v, (bool, int, float)):
f.write(f"{k}={v}\n")
elif isinstance(v, list):
f.write("{}=[{}]\n".format(k, ', '.join([f"'{w}'" for w in v])))
else:
elif isinstance(v, str):
f.write(f"{k}='{v}'\n")
else:
f.write("{}=[{}]\n".format(k, ', '.join([f"'{w}'" for w in v])))
return filename
def helper_create_binary_wrapper(self, binary, dir_=None, extra_args=None, **kwargs):
@ -622,6 +624,29 @@ class NativeFileTests(BasePlatformTests):
else:
self.fail('Did not find bindir in build options?')
@skip_if_not_language('rust')
def test_bindgen_clang_arguments(self) -> None:
if self.backend is not Backend.ninja:
raise SkipTest('Rust is only supported with Ninja')
testcase = os.path.join(self.rust_test_dir, '12 bindgen')
config = self.helper_create_native_file({
'properties': {'bindgen_clang_arguments': 'sentinal'}
})
self.init(testcase, extra_args=['--native-file', config])
targets: T.List[T.Dict[str, T.Any]] = self.introspect('--targets')
for t in targets:
if t['id'].startswith('rustmod-bindgen'):
args: T.List[str] = t['target_sources'][0]['compiler']
self.assertIn('sentinal', args, msg="Did not find machine file value")
cargs_start = args.index('--')
sent_arg = args.index('sentinal')
self.assertLess(cargs_start, sent_arg, msg='sentinal argument does not come after "--"')
break
else:
self.fail('Did not find a bindgen target')
class CrossFileTests(BasePlatformTests):

Loading…
Cancel
Save