Skip to content

Commit 2c21f25

Browse files
stefanhaRHstsquad
authored andcommitted
virtio-bindings: use bindgen library from build.rs
Since commit 3e51e2d ("virtio-bindings: regenerate with bindgen 0.70.1") there are compile-time alignment checks in virtio-bindings code. These checks are specific to the architecture where bindgen was run and they can break builds on other architectures. Here is an example i686 build failure after upgrading from virtio-bindings 0.2.2 to 0.2.4: https://koji.fedoraproject.org/koji/taskinfo?taskID=127997322 The bindgen User Guide recommends generating bindings from build.rs because it avoids portability issues and the need to maintain a copy of the bindings for each target: https://rust-lang.github.io/rust-bindgen/library-usage.html Introduce an import-linux-headers.sh script that copies required virtio headers from a Linux headers tree into include/. Do not distribute the full Linux headers tree because it is large and has falls under various software licenses that are not compatible with this crate's license. Generate the actual bindings at compile-time in build.rs and then include!() the output from src/lib.rs. You can verify that the generated bindings from Linux 6.12 have not changed significantly for x86_64 by diffing them against the previous commit. For example: --- orig/virtio_gpu.rs +++ new/virtio_gpu.rs @@ -1,4 +1,4 @@ -/* automatically generated by rust-bindgen 0.70.1 */ +/* automatically generated by rust-bindgen 0.71.1 */ #[repr(C)] #[derive(Default)] @@ -58,7 +58,7 @@ pub const VIRTIO_GPU_MAP_CACHE_WC: u32 = 3; pub type __u8 = ::std::os::raw::c_uchar; pub type __u32 = ::std::os::raw::c_uint; -pub type __u64 = ::std::os::raw::c_ulonglong; +pub type __u64 = ::std::os::raw::c_ulong; pub type __le32 = __u32; pub type __le64 = __u64; pub const virtio_gpu_ctrl_type_VIRTIO_GPU_UNDEFINED: virtio_gpu_ctrl_type = 0 The __u64 change is due to how <linux/types.h> defined __u64. We should avoid using that non-BSD licensed header. The result is equivalent now that the bindings are generated at compile-time. Fixes: #326 Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
1 parent 67d5be7 commit 2c21f25

28 files changed

+2401
-2931
lines changed

virtio-bindings/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
## Changed
44

55
- Regenerate bindings with Linux 6.12.
6+
- Introduced bindgen build dependency and its clang development package
7+
dependency. See bindgen fix below for why this was necessary.
68

79
## Fixed
810

911
- Add license files.
12+
- Use bindgen library from build.rs to fix i686 builds due to x86_64-specific
13+
alignment checks.
1014

1115
# v0.2.4
1216

virtio-bindings/CONTRIBUTING.md

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,47 @@
11
# Contributing to virtio-bindings
22

3-
## Dependencies
3+
## Overview
44

5-
### Bindgen
6-
The bindings are currently generated using
7-
[bindgen](https://rust-lang.github.io/rust-bindgen/) version 0.70.1:
8-
```bash
9-
cargo install bindgen-cli --vers 0.70.1
10-
```
5+
virtio-bindings is periodically updated with imported virtio headers from the
6+
Linux kernel. The Linux header files have kernel header dependencies that are
7+
removed during import so that bindgen can process them in isolation without a
8+
full set of kernel headers. This is also necessary because the licenses of
9+
individual kernel header files varies and we only want to distribute
10+
BSD-licensed virtio headers.
1111

12-
### Linux Kernel
12+
## Importing kernel headers
1313
Generating bindings depends on the Linux kernel, so you need to have the
1414
repository on your machine:
1515

1616
```bash
1717
git clone https://github.com/torvalds/linux.git
1818
```
1919

20-
## Example for updating to a new kernel version
20+
Install the headers so they can be used for import:
21+
```bash
22+
cd linux
23+
git checkout <linux-version>
24+
make headers_install INSTALL_HDR_PATH=headers-<linux-version>
25+
```
2126

22-
For this example we assume that you have both linux and virtio-bindings
23-
repositories in your root.
27+
Import kernel headers into `include/`:
28+
```bash
29+
cd ~/vm-virtio/virtio-bindings
30+
./import-linux-headers.sh path/to/headers-<linux-version>
31+
```
2432

33+
Test that the build still works:
2534
```bash
26-
# linux is the repository that you cloned at the previous step.
27-
cd linux
28-
# Step 1: Checkout the version you want to generate the bindings for.
29-
git checkout v5.0
30-
31-
# Step 2: Generate the bindings from the kernel headers. We need to generate a
32-
# file for each one of the virtio headers. For the moment, we are only picking
33-
# headers that we are interested in. Feel free to add additional header files if
34-
# you need them for your project.
35-
make headers_install INSTALL_HDR_PATH=v5_0_headers
36-
cd v5_0_headers
37-
for i in \
38-
virtio_blk \
39-
virtio_config \
40-
virtio_gpu \
41-
virtio_ids \
42-
virtio_input \
43-
virtio_mmio \
44-
virtio_net \
45-
virtio_ring \
46-
virtio_scsi \
47-
; do \
48-
bindgen include/linux/$i.h -o $i.rs \
49-
--allowlist-file include/linux/$i.h \
50-
--with-derive-default \
51-
--with-derive-partialeq \
52-
-- -Iinclude
53-
done
54-
cd ~
55-
56-
# Step 6: Copy the generated files to the new version module.
57-
cp linux/v5_0_headers/*.rs vm-virtio/virtio-bindings/src
58-
mv vm-virtio/virtio-bindings/src/virtio_net.rs vm-virtio/virtio-bindings/src/virtio_net/generated.rs
35+
cargo build
5936
```
37+
38+
## Adding bindings for new header files
39+
New kernel headers can be added as follows:
40+
1. Add the new file to import-linux-headers.sh so it is imported from the Linux
41+
kernel header directory into include/.
42+
2. Add the new file to build.rs so bindgen generates bindings.
43+
3. Add the new module to src/lib.rs so the generated bindings are exposed in
44+
the crate.
45+
4. Check if `cargo build` still succeeds. If the header has new kernel header
46+
dependencies then you need to add them (if they are BSD licensed) or stub
47+
them out (if they are not BSD licensed).

virtio-bindings/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ license = "BSD-3-Clause OR Apache-2.0"
1515
virtio-v4_14_0 = []
1616
virtio-v5_0_0 = []
1717

18+
[build-dependencies]
19+
bindgen = "0.71.0"
20+
1821
[dependencies]

virtio-bindings/build.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright Red Hat, Inc.
2+
// SPDX-License-Identifier: (BSD-3-Clause OR Apache-2.0)
3+
4+
use std::env;
5+
use std::path::PathBuf;
6+
7+
fn generate_bindings(header: &str) {
8+
let bindings = bindgen::Builder::default()
9+
.header(format!("include/linux/{header}.h"))
10+
.allowlist_file(format!("include/linux/{header}.h"))
11+
.derive_default(true)
12+
.derive_partialeq(true)
13+
.clang_arg("-Iinclude")
14+
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
15+
.generate()
16+
.unwrap_or_else(|_| panic!("Unable to generate bindings for {header}"));
17+
18+
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
19+
bindings
20+
.write_to_file(out_path.join(format!("{header}.rs")))
21+
.unwrap_or_else(|_| panic!("Couldn't write bindings for {header}"));
22+
}
23+
24+
fn main() {
25+
// If you change this list, remember to update src/lib.rs
26+
for header in [
27+
"virtio_blk",
28+
"virtio_config",
29+
"virtio_gpu",
30+
"virtio_ids",
31+
"virtio_input",
32+
"virtio_mmio",
33+
"virtio_net",
34+
"virtio_ring",
35+
"virtio_scsi",
36+
] {
37+
generate_bindings(header);
38+
}
39+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: (BSD-3-Clause OR Apache-2.0)
3+
# Copyright Red Hat, Inc.
4+
#
5+
# ./import-linux-headers.sh path/to/kernel/headers
6+
#
7+
# Import header files from a Linux kernel header tree. Be sure to run `cargo
8+
# build` to test that bindgen succeeds before committing the updated headers.
9+
10+
src=$1
11+
dst=include/linux
12+
13+
import_header() {
14+
# Use our local header files rather than system headers
15+
sed -e 's%#include <\([^>]*\)>%#include "\1"%' "$1" >"$2"
16+
}
17+
18+
mkdir -p "$dst"
19+
20+
# If you change this list, remember to update build.rs
21+
for header in \
22+
virtio_blk \
23+
virtio_config \
24+
virtio_gpu \
25+
virtio_ids \
26+
virtio_input \
27+
virtio_mmio \
28+
virtio_net \
29+
virtio_ring \
30+
virtio_scsi \
31+
virtio_types; do
32+
import_header "$src/include/linux/$header.h" "$dst/$header.h"
33+
done
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/* SPDX-License-Identifier: (BSD-3-Clause OR Apache-2.0) */
2+
3+
#pragma once
4+
5+
#define ETH_ALEN 6 /* needed by virtio_net */

virtio-bindings/include/linux/types.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* SPDX-License-Identifier: (BSD-3-Clause OR Apache-2.0) */
2+
3+
#pragma once
4+
5+
/* Built-ins avoid the need for <stdint.h> */
6+
typedef __UINT8_TYPE__ __u8;
7+
typedef __UINT16_TYPE__ __u16;
8+
typedef __UINT32_TYPE__ __u32;
9+
typedef __UINT64_TYPE__ __u64;
10+
11+
typedef __u16 __le16;
12+
typedef __u32 __le32;
13+
typedef __u64 __le64;
14+
15+
#define __bitwise /* ignore */

0 commit comments

Comments
 (0)