Skip to content

Commit 6e268bc

Browse files
author
GitHub Actions Bot
committed
[PATCH] rust: add docs
https://lore.kernel.org/qemu-devel/[email protected] --- From: Paolo Bonzini <[email protected]> To: [email protected] Cc: [email protected], [email protected] Subject: [PATCH] rust: add docs Date: Wed, 29 Jan 2025 09:37:15 +0100 Message-ID: <[email protected]> X-Mailer: git-send-email 2.48.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=170.10.133.124; [email protected]; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -32 X-Spam_score: -3.3 X-Spam_bar: --- X-Spam_report: (-3.3 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.3, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, URIBL_SBL_A=0.1 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: [email protected] X-Mailman-Version: 2.1.29 Precedence: list List-Id: <qemu-devel.nongnu.org> List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>, <mailto:[email protected]?subject=unsubscribe> List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel> List-Post: <mailto:[email protected]> List-Help: <mailto:[email protected]?subject=help> List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>, <mailto:[email protected]?subject=subscribe> Errors-To: [email protected] Sender: [email protected] Signed-off-by: Paolo Bonzini <[email protected]> --- docs/devel/index-process.rst | 1 + docs/devel/rust.rst | 423 +++++++++++++++++++++++++++++++++++ 2 files changed, 424 insertions(+) create mode 100644 docs/devel/rust.rst diff --git a/docs/devel/index-process.rst b/docs/devel/index-process.rst index 362f97e..cb7c664 100644 --- a/docs/devel/index-process.rst +++ b/docs/devel/index-process.rst @@ -17,3 +17,4 @@ Notes about how to interact with the community and how and where to submit patch stable-process submitting-a-pull-request secure-coding-practices + rust diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst new file mode 100644 index 00000000000..2fc4e94 --- /dev/null +++ b/docs/devel/rust.rst @@ -0,0 +1,423 @@ +.. |msrv| replace:: 1.63.0 + +Rust in QEMU +============ + +Rust in QEMU is a project to enable using the Rust programming language +to add new functionality to QEMU. + +Right now, the focus is on making it possible to write devices that inherit +from ``SysBusDevice`` in `*safe*`__ Rust. Later, it may become possible +to write other kinds of devices (e.g. PCI devices that can do DMA), +complete boards, or backends (e.g. block device formats). + +__ https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html + +Building the Rust in QEMU code +------------------------------ + +The Rust in QEMU code is included in the emulators via Meson. Meson +invokes rustc directly, building static libraries that are then linked +together with the C code. This is completely automatic when you run +``make`` or ``ninja``. + +However, QEMU's build system also tries to be easy to use for people who +are accustomed to the more "normal" Cargo-based development workflow. +In particular: + +* the set of warnings and lints that are used to build QEMU always + comes from the ``rust/Cargo.toml`` workspace file + +* it is also possible to use ``cargo`` for common Rust-specific coding + tasks, in particular to invoke ``clippy``, ``rustfmt`` and ``rustdoc``. + +To this end, QEMU includes a ``build.rs`` build script that picks up +generated sources from QEMU's build directory and puts it in Cargo's +output directory (typically ``rust/target/``). A vanilla invocation +of Cargo will complain that it cannot find the generated sources, +which can be fixed in different ways: + +* by using special shorthand targets in the QEMU build directory:: + + make clippy + make rustfmt + make rustdoc + +* by invoking ``cargo`` through the Meson `development environment`__ + feature:: + + pyvenv/bin/meson devenv -w ../rust cargo clippy --tests + pyvenv/bin/meson devenv -w ../rust cargo fmt + + If you are going to use ``cargo`` repeatedly, ``pyvenv/bin/meson devenv`` + will enter a shell where commands like ``cargo clippy`` just work. + +__ https://mesonbuild.com/Commands.html#devenv + +* by pointing the ``MESON_BUILD_ROOT`` to the top of your QEMU build + tree. This third method is useful if you are using ``rust-analyzer``; + you can set the environment variable through the + ``rust-analyzer.cargo.extraEnv`` setting. + +As shown above, you can use the ``--tests`` option as usual to operate on test +code. Note however that you cannot *build* or run tests via ``cargo``, because +they need support C code from QEMU that Cargo does not know about. Tests can +be run via ``meson test`` or ``make``:: + + make check-rust + +Building Rust code with ``--enable-modules`` is not supported yet. + +Supported tools +''''''''''''''' + +QEMU supports rustc version 1.63.0 and newer. Notably, the following features +are missing: + +* ``core::ffi`` (1.64.0). Use ``std::os::raw`` and ``std::ffi`` instead. + +* ``cast_mut()``/``cast_const()`` (1.65.0). Use ``as`` instead. + +* "let ... else" (1.65.0). Use ``if let`` instead. This is currently patched + in QEMU's vendored copy of the bilge and ``pinned_init`` crates. + +* Generic Associated Types (1.65.0) + +* ``CStr::from_bytes_with_nul()`` as a ``const`` function (1.72.0). + +* "Return position ``impl Trait`` in Traits" (1.75.0, can be useful with + the pinned-init create). + +* MaybeUninit::zeroed() as a ``const`` function (1.75.0). QEMU uses a + ``Zeroable`` trait, and you can implement it to provide by hand a + ``Zeroable::ZERO`` associated constant. + +* ``c"" literals`` (stable in 1.77.0). QEMU provides a ``c_str!()`` macro + to define ``CStr`` constants easily + +* ``offset_of!`` (stable in 1.77.0). QEMU uses ``offset_of!()`` heavily; it + provides a replacement in the ``qemu_api`` crate, but it does not support + lifetime parameters and therefore `&'a Something` fields in the struct + may have to be replaced by `NonNull<Something>`. *Nested* ``offset_of!`` + was only stabilized in Rust 1.82.0, but it is not used. + +* inline const expression (stable in 1.79.0), currently worked around with + associated constants in the ``FnCall`` trait. + +* associated constants have to be explicitly marked ``'static`` (`changed in + 1.81.0`__) + +* ``&raw`` (stable in 1.82.0). Use ``addr_of!`` and ``addr_of_mut!`` instead, + though hopefully the need for raw pointers will go down over time. + +* ``new_uninit`` (stable in 1.82.0). This is used internally by the ``pinned_init`` + crate, and patched in QEMU's vendored copy of the crate. + +* referencing statics in constants (stable in 1.83.0). For now use a const + function; this is an important limitation for QEMU's migration stream + architecture (VMState). Right now, VMState lacks type safety because + it is hard to place the ``VMStateField`` definitions in traits. + +* associated const equality would be nice to have for some users of + ``callbacks::FnCall``, but is still experimental. ``ASSERT_IS_SOME`` + replaces it. + +__ rust-lang/rust#125258 + +It is expected that QEMU will advance its minimum supported version of +rustc to 1.77.0 as soon; as of January 2025, blockers for that right now +are Debian bookworm and 32-bit MIPS processors. This unfortunately +means that references to statics in constants will remain an issue. + +QEMU also supports version 0.60.x of bindgen, which is missing option +``--generate-cstr``. This option requires version 0.66.x and will +be adopted as soon as supporting these older versions is not necessary +anymore. + +Writing Rust code in QEMU +------------------------- + +Right now QEMU includes three crates: + +* ``qemu_api`` for bindings to C code and useful functionality + +* ``qemu_api_macros`` defines several procedural macros that are useful when + writing C code + +* ``pl011`` (under ``rust/hw/char/pl011``) is the sample device that is being + used to further develop ``qemu_api`` and ``qemu_api_macros``. It is a functional + replacement for the ``hw/char/pl011.c`` file. + +This section explains how to work with them. + +Status +'''''' + +Modules of ``qemu_api`` can be defined as: + +- *complete*: ready for use in new devices; if applicable, the API supports the + full functionality available in C + +- *stable*: ready for production use, the API is safe and should not undergo + major changes + +- *proof of concept*: the API is subject to change but allows working with safe + Rust + +- *initial*: the API is in its initial stages; it requires large amount of + unsafe code; it might have soundness or type-safety issues + +The status of the modules are + +================ ====================== +module status +================ ====================== +``assertions`` stable +``bitops`` complete +``callbacks`` complete +``cell`` stable +``c_str`` complete +``irq`` complete +``module`` complete +``offset_of`` stable +``qdev`` stable +``qom`` stable +``sysbus`` stable +``vmstate`` proof of concept +``zeroable`` stable +================ ====================== + +Common pitfalls +''''''''''''''' + +Rust has very strict rules with respect to how you get an exclusive (``&mut``) +reference; failure to respect those rules is a source of undefined behavior. +In particular, even if a value is loaded from a raw mutable pointer (``*mut``), +it *cannot* be casted to ``&mut`` unless the value was stored to the ``*mut`` +from a mutable reference. Furthermore, it is undefined behavior if any +shared reference was created between the store to the ``*mut`` and the load:: + + let mut p: u32 = 42; + let p_mut = &mut p; // 1 + let p_raw = p_mut as *mut u32; // 2 + + // p_raw keeps the mutable reference "alive" + + let p_shared = &p; // 3 + println!("access from &u32: {}", *p_shared); + + // Bring back the mutable reference, its lifetime overlaps + // with that of a shared reference. + let p_mut = unsafe { &mut *p_raw }; // 4 + println!("access from &mut 32: {}", *p_mut); + + println!("access from &u32: {}", *p_shared); // 5 + +These rules can be tested with `MIRI`__, for example. + +__ https://github.com/rust-lang/miri + +Almost all Rust code in QEMU will involve QOM objects, and pointers to these +objects are *shared*, for example because they are part of the QOM composition +tree. This creates exactly the above scenario: + +1. a QOM object is created + +2. a ``*mut`` is created, for example as the opaque value for a ``MemoryRegion`` + +3. the QOM object is placed in the composition tree + +4. a memory access dereferences the opaque value to a ``&mut`` + +5. but the shared reference is still present in the composition tree + +Because of this, QOM objects should almost always use ``&self`` instead +of ``&mut self``; access to internal fields must use *interior mutability* +to go from a shared reference to a ``&mut``. + +Whenever C code provides you with an opaque ``void *``, avoid converting it +to a Rust mutable reference, and use a shared reference instead. Rust code +will then have to use QEMU's ``BqlRefCell`` and ``BqlCell`` type, which +enforce that locking rules for the "Big QEMU Lock" are respected. These cell +types are also known to the ``vmstate`` crate, which is able to "look inside" +them when building an in-memory representation of a ``struct``s layout. +Note that the same is not true of a ``RefCell`` or ``Mutex``. + +In the future, similar cell types might also be provided for ``AioContext``-based +locking as well. + +Writing bindings to C code +'''''''''''''''''''''''''' + +Here are some things to keep in mind when working on the ``qemu_api`` crate. + +**Look at existing code** + Very often, similar idioms in C code correspond to similar tricks in + Rust bindings. If the C code uses ``offsetof``, look at qdev properties + or ``vmstate``. If the C code has a complex const struct, look at + ``MemoryRegion``. Reuse existing patterns for handling lifetimes; + for example use ``&T`` for QOM objects that do not need a reference + count (including those that can be embedded in other objects) and + ``Owned<T>`` for those that need it. + +**Use the type system** + Bindings often will need access information that is specific to a type + (either a builtin one or a user-defined one) in order to pass it to C + functions. Put them in a trait and access it through generic parameters. + The ``vmstate`` module has examples of how to retrieve type information + for the fields of a Rust ``struct``. + +**Prefer unsafe traits to unsafe functions** + Unsafe traits are much easier to prove correct than unsafe functions. + They are an excellent place to store metadata that can later be accessed + by generic functions. C code usually places metadata in global variables; + in Rust, they can be stored in traits and then turned into ``static`` + variables. Often, unsafe traits can be generated by procedural macros. + +**Document limitations due to old Rust versions** + If you need to settle for an inferior solution because of the currently + supported set of Rust versions, document it in the source and in this + file. This ensures that it can be fixed when the minimum supported + version is bumped. + +**Keep locking in mind**. + When marking a type ``Sync``, be careful of whether it needs the big + QEMU lock. Use ``BqlCell`` and ``BqlRefCell`` for interior data, + or assert ``bql_locked()``. + +**Don't be afraid of complexity, but document and isolate it** + It's okay to be tricky; device code is written more often than bindings + code and it's important that it is idiomatic. However, you should strive + to isolate any tricks in a place (for example a ``struct``, a trait + or a macro) where it can be documented and tested. If needed, include + toy versions of the code in the documentation. + +Writing procedural macros +''''''''''''''''''''''''' + +By conventions, procedural macros are split in two functions, one +returning ``Result<proc_macro2::TokenStream, MacroError>` with the body of +the procedural macro, and the second returning ``proc_macro::TokenStream`` +which is the actual procedural macro. The former's name is the same as +the latter with the ``_or_error`` suffix. The code for the latter is more +or less fixed; it follows the following template, which is fixed apart +from the type after ``as`` in the invocation of ``parse_macro_input!``:: + + #[proc_macro_derive(Object)] + pub fn derive_object(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let expanded = derive_object_or_error(input).unwrap_or_else(Into::into); + + TokenStream::from(expanded) + } + +The ``qemu_api_macros`` crate has utility functions to examine a +``DeriveInput`` and perform common checks (e.g. looking for a struct +with named fields). These functions return ``Result<..., MacroError>`` +and can be used easily in the procedural macro function:: + + fn derive_object_or_error(input: DeriveInput) -> + Result<proc_macro2::TokenStream, MacroError> + { + is_c_repr(&input, "#[derive(Object)]")?; + + let name = &input.ident; + let parent = &get_fields(&input, "#[derive(Object)]")?[0].ident; + ... + } + +Use procedural macros with care. They are mostly useful for two purposes: + +* Performing consistency checks; for example ``#[derive(Object)]`` checks + that the structure has ``#[repr[C])`` and that the type of the first field + is consistent with the ``ObjectType`` declaration. + +* Extracting information from Rust source code into traits, typically based + on types and attributes. For example, ``#[derive(TryInto)]`` builds an + implementation of ``TryFrom``, and it uses the ``#[repr(...)]`` attribute + as the ``TryFrom`` source and error types. + +Procedural macros can be hard to debug and test; if the code generation +exceeds a few lines of code, it may be worthwhile to delegate work to +"regular" declarative (``macro_rules!``) macros and write unit tests for +those instead. + + +Coding style +'''''''''''' + +Code should pass clippy and be formatted with rustfmt. + +Right now, only the nightly version of ``rustfmt`` is supported. This +might change in the future. While CI checks for correct formatting via +``cargo fmt --check``, maintainers can fix this for you when applying patches. + +It is expected that ``qemu_api`` provides full ``rustdoc`` documentation for +bindings that are in their final shape or close. + +Adding dependencies +------------------- + +Generally, the set of dependent crates is kept small. Think twice before +adding a new external crate, especially if it comes with a large set of +dependencies itself. Sometimes QEMU only needs a small subset of the +functionality; see for example QEMU's ``assertions`` or ``c_str`` modules. + +On top of this recommendation, adding external crates to QEMU is a +slightly complicated process, mostly due to the need to teach Meson how +to build them. While Meson has initial support for parsing ``Cargo.lock`` +files, it is still highly experimental and is therefore not used. + +First of all, the crate must be added to the relevant ``Cargo.toml`` files. +External crates must be added as subprojects for Meson to learn how to +build them, as well as to the relevant ``Cargo.toml`` files. Because the +``rust/`` directory forms a Cargo `workspace`__, there is a single +``rust/Cargo.lock`` file for the whole build. + +__ https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace + +Choose a version of the crate that works with QEMU's minimum supported +Rust version (|msrv|). + +Second, a new ``wrap`` file must be added to teach Meson how to download the +crate. The wrap file must be named ``NAME-SEMVER-rs.wrap``, where ``NAME`` +is the name of the crate and ``SEMVER`` is the version up to and including the +first non-zero number. For example, a crate with version ``0.2.3`` will use +``0.2`` for its ``SEMVER``, while a crate with version ``1.0.84`` will use ``1``. + +Third, the Meson rules to build the crate must be added at +``subprojects/NAME-SEMVER-rs/meson.build``. Generally this includes: + +* ``subproject`` and ``dependency`` lines for all dependent crates + +* a ``static_library`` or ``rust.proc_macro`` line to perform the actual build + +* ``declare_dependency`` and a ``meson.override_dependency`` lines to expose + the result to QEMU and to other subprojects + +Remember to add ``native: true`` to ``dependency``, ``static_library`` and +``meson.override_dependency`` for dependencies of procedural macros. +If a crate is needed in both procedural macros and QEMU binaries, everything +apart from ``subproject`` must be duplicated to build both native and +non-native versions of the crate. + +It's important to specify the right compiler options. These include: + +* the language edition (which can be found in the ``Cargo.toml`` file) + +* the ``--cfg`` (which have to be "reverse engineered" from the ``build.rs`` + file of the crate). + +* usually, a ``--cap-lints allow`` argument to hide warnings from rustc + or clippy. + +After every change to the ``meson.build`` file you have to update the patched +version with ``meson subprojects update --reset ``NAME-SEMVER-rs``. This might +be automated in the future. + +Also, after every change to the ``meson.build`` file it is strongly suggested to +do a dummy change to the ``.wrap`` file (for example adding a comment like +``# version 2``), which will help Meson notice that the subproject is out of date. + +As a last step, add the new subproject to ``scripts/archive-source.sh``, +``scripts/make-release`` and ``subprojects/.gitignore``. -- 2.48.1 Signed-off-by: GitHub Actions Bot <[email protected]>
1 parent 5f82722 commit 6e268bc

23 files changed

+753
-784
lines changed

.github/workflows/build.yml

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
on: push
2+
3+
concurrency:
4+
group: ${{ github.workflow }}-${{ github.ref }}
5+
cancel-in-progress: true
6+
7+
jobs:
8+
checkapply:
9+
runs-on: ubuntu-24.04
10+
steps:
11+
- uses: actions/checkout@v4
12+
# to debug container live from GitHub
13+
# - uses: mxschmitt/action-tmate@v3
14+
- run: bash -c '[ ! -f shazam.log ] || { cat shazam.log; exit 1; }'
15+
16+
checkpatch-ignore-signoff:
17+
needs: checkapply
18+
runs-on: ubuntu-24.04
19+
steps:
20+
- uses: actions/checkout@v4
21+
- run: git fetch -a origin --unshallow || true
22+
- run: git remote add upstream -f https://gitlab.com/qemu-project/qemu
23+
- run: ./scripts/checkpatch.pl --no-signoff $(git merge-base upstream/master HEAD)..HEAD
24+
25+
checkpatch-with-signoff:
26+
needs: checkapply
27+
runs-on: ubuntu-24.04
28+
steps:
29+
- uses: actions/checkout@v4
30+
- run: git fetch -a origin --unshallow || true
31+
- run: git remote add upstream -f https://gitlab.com/qemu-project/qemu
32+
- run: ./scripts/checkpatch.pl $(git merge-base upstream/master HEAD)..HEAD
33+
34+
# use docker-run to not rebuild images
35+
# images are built daily and pushed on pbolinaro/qemu-ci:*
36+
build-cross:
37+
needs: checkapply
38+
runs-on: ubuntu-24.04
39+
strategy:
40+
fail-fast: false
41+
matrix:
42+
container: [alpine,centos9,debian,debian-all-test-cross,debian-amd64-cross,debian-arm64-cross,debian-armhf-cross,debian-hexagon-cross,debian-i686-cross,debian-legacy-test-cross,debian-loongarch-cross,debian-mips64el-cross,debian-mipsel-cross,debian-ppc64el-cross,debian-riscv64-cross,debian-s390x-cross,debian-tricore-cross,fedora,fedora-rust-nightly,opensuse-leap,ubuntu2204]
43+
steps:
44+
- uses: actions/checkout@v4
45+
- run: pip install meson
46+
- run: make docker-run J=$(nproc) RUNC=podman TEST=test-build IMAGE=docker.io/pbolinaro/qemu-ci:${{matrix.container}}
47+
48+
build:
49+
needs: checkapply
50+
runs-on: ubuntu-24.04
51+
steps:
52+
- uses: actions/checkout@v4
53+
- run: >
54+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
55+
docker.io/pbolinaro/qemu-ci:debian
56+
bash -cx './configure && ninja -C build install'
57+
- run: >
58+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
59+
docker.io/pbolinaro/qemu-ci:debian
60+
./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin
61+
62+
build-cross-mingw64:
63+
needs: checkapply
64+
runs-on: ubuntu-24.04
65+
steps:
66+
- uses: actions/checkout@v4
67+
- run: >
68+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
69+
docker.io/pbolinaro/qemu-ci:fedora-win64-cross
70+
bash -cx './configure $QEMU_CONFIGURE_OPTS && ninja -C build install'
71+
72+
build-windows:
73+
needs: checkapply
74+
runs-on: windows-2025
75+
strategy:
76+
fail-fast: false
77+
matrix:
78+
sys: [UCRT64, CLANG64, MINGW64]
79+
defaults:
80+
run:
81+
shell: msys2 {0}
82+
steps:
83+
- uses: msys2/setup-msys2@v2
84+
with:
85+
update: true
86+
msystem: ${{matrix.sys}}
87+
- run: pacman -S --noconfirm curl git
88+
- uses: actions/checkout@v4
89+
- run: >
90+
pacman -S --noconfirm
91+
base-devel binutils bison diffutils flex git grep make sed
92+
${MINGW_PACKAGE_PREFIX}-toolchain
93+
${MINGW_PACKAGE_PREFIX}-glib2
94+
${MINGW_PACKAGE_PREFIX}-gtk3
95+
${MINGW_PACKAGE_PREFIX}-libnfs
96+
${MINGW_PACKAGE_PREFIX}-libssh
97+
${MINGW_PACKAGE_PREFIX}-ninja
98+
${MINGW_PACKAGE_PREFIX}-pixman
99+
${MINGW_PACKAGE_PREFIX}-pkgconf
100+
${MINGW_PACKAGE_PREFIX}-python
101+
${MINGW_PACKAGE_PREFIX}-SDL2
102+
${MINGW_PACKAGE_PREFIX}-zstd
103+
- run: ./configure && ninja -C build
104+
- run: ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin
105+
106+
build-macos-x86_64:
107+
needs: checkapply
108+
runs-on: macos-13
109+
steps:
110+
- uses: actions/checkout@v4
111+
- run: brew install --quiet $(brew deps --include-build qemu) || true
112+
# on macos, werror is not on by default
113+
- run: ./configure --enable-werror && ninja -C build
114+
- run: ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin
115+
116+
build-macos-aarch64:
117+
needs: checkapply
118+
runs-on: macos-14
119+
steps:
120+
- uses: actions/checkout@v4
121+
- run: brew install --quiet $(brew deps --include-build qemu) || true
122+
# on macos, werror is not on by default
123+
- run: ./configure --enable-werror && ninja -C build
124+
- run: ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin
125+
126+
build-misc:
127+
needs: checkapply
128+
runs-on: ubuntu-24.04
129+
steps:
130+
- uses: actions/checkout@v4
131+
- run: >
132+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
133+
docker.io/pbolinaro/qemu-ci:debian
134+
bash -cx './configure --disable-user --disable-system --enable-docs --enable-tools && ninja -C build install'
135+
136+
build-32bits:
137+
needs: checkapply
138+
runs-on: ubuntu-24.04
139+
steps:
140+
- uses: actions/checkout@v4
141+
- run: >
142+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
143+
docker.io/pbolinaro/qemu-ci:debian-i686-cross
144+
bash -cx './configure $QEMU_CONFIGURE_OPTS && ninja -C build install'
145+
146+
build-big-endian:
147+
needs: checkapply
148+
runs-on: ubuntu-24.04
149+
steps:
150+
- uses: actions/checkout@v4
151+
- run: >
152+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
153+
docker.io/pbolinaro/qemu-ci:debian-s390x-cross
154+
bash -cx './configure $QEMU_CONFIGURE_OPTS && ninja -C build install'
155+
156+
build-debug:
157+
needs: checkapply
158+
runs-on: ubuntu-24.04
159+
steps:
160+
- uses: actions/checkout@v4
161+
- run: >
162+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
163+
docker.io/pbolinaro/qemu-ci:debian
164+
bash -cx './configure --enable-debug --enable-asan --enable-ubsan && ninja -C build install'
165+
- run: >
166+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
167+
docker.io/pbolinaro/qemu-ci:debian
168+
./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin
169+
170+
build-static:
171+
needs: checkapply
172+
runs-on: ubuntu-24.04
173+
steps:
174+
- uses: actions/checkout@v4
175+
- run: >
176+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
177+
docker.io/pbolinaro/qemu-ci:debian
178+
bash -cx './configure --disable-system --disable-tools --disable-guest-agent --disable-docs --static && ninja -C build install'
179+
180+
build-tsan:
181+
needs: checkapply
182+
runs-on: ubuntu-24.04
183+
steps:
184+
- uses: actions/checkout@v4
185+
- run: >
186+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
187+
docker.io/pbolinaro/qemu-ci:debian
188+
bash -cx './configure --enable-tsan && ninja -C build install'
189+
190+
build-clang:
191+
needs: checkapply
192+
runs-on: ubuntu-24.04
193+
steps:
194+
- uses: actions/checkout@v4
195+
- run: >
196+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
197+
docker.io/pbolinaro/qemu-ci:debian
198+
bash -cx './configure --cxx=clang++ --cc=clang --host-cc=clang && ninja -C build install'
199+
200+
build-clang-latest:
201+
needs: checkapply
202+
runs-on: ubuntu-24.04
203+
steps:
204+
- uses: actions/checkout@v4
205+
- run: >
206+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
207+
docker.io/pbolinaro/qemu-ci:debian
208+
bash -cx 'LLVM_VERSION=19 && apt update && apt install -y lsb-release wget software-properties-common gnupg && wget https://apt.llvm.org/llvm.sh && bash llvm.sh ${LLVM_VERSION} && ./configure --cxx=clang++-${LLVM_VERSION} --cc=clang-${LLVM_VERSION} --host-cc=clang-${LLVM_VERSION} && ninja -C build install'
209+
210+
build-rust:
211+
needs: checkapply
212+
runs-on: ubuntu-24.04
213+
steps:
214+
- uses: actions/checkout@v4
215+
- run: >
216+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
217+
docker.io/pbolinaro/qemu-ci:debian
218+
bash -cx './configure --enable-rust && ninja -C build install'
219+
220+
build-disable-tcg:
221+
needs: checkapply
222+
runs-on: ubuntu-24.04
223+
steps:
224+
- uses: actions/checkout@v4
225+
- run: >
226+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
227+
docker.io/pbolinaro/qemu-ci:debian
228+
bash -cx './configure --disable-tcg && ninja -C build install'
229+
230+
build-disable-kvm:
231+
needs: checkapply
232+
runs-on: ubuntu-24.04
233+
steps:
234+
- uses: actions/checkout@v4
235+
- run: >
236+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
237+
docker.io/pbolinaro/qemu-ci:debian
238+
bash -cx './configure --disable-kvm && ninja -C build install'
239+
240+
build-disable-tcg-kvm-for-xen:
241+
needs: checkapply
242+
runs-on: ubuntu-24.04
243+
steps:
244+
- uses: actions/checkout@v4
245+
- run: >
246+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
247+
docker.io/pbolinaro/qemu-ci:debian
248+
bash -cx './configure --disable-tcg --disable-kvm && ninja -C build install'
249+
250+
build-minimal:
251+
needs: checkapply
252+
runs-on: ubuntu-24.04
253+
steps:
254+
- uses: actions/checkout@v4
255+
- run: >
256+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
257+
docker.io/pbolinaro/qemu-ci:debian
258+
bash -cx './configure --without-default-features --without-default-devices --disable-kvm --disable-tcg && ninja -C build install'
259+
260+
check-tcg:
261+
needs: checkapply
262+
runs-on: ubuntu-24.04
263+
steps:
264+
- uses: actions/checkout@v4
265+
- run: >
266+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
267+
docker.io/pbolinaro/qemu-ci:debian-all-test-cross
268+
bash -cx './configure --disable-docs --enable-debug-tcg --enable-debug-graph-lock --enable-debug-mutex --enable-asan --enable-ubsan && ninja -C build'
269+
- run: >
270+
podman run --init --privileged --rm -it -v $(pwd):$(pwd) -w $(pwd)
271+
docker.io/pbolinaro/qemu-ci:debian-all-test-cross
272+
bash -cx "env ASAN_OPTIONS=detect_leaks=0 make -k -j $(nproc) check-tcg"
273+
274+
# run all meson tests, except functional.
275+
# block tests are not ran because they don't support sanitizers:
276+
# https://gitlab.com/qemu-project/qemu/-/blob/master/tests/qemu-iotests/meson.build
277+
check:
278+
needs: checkapply
279+
runs-on: ubuntu-24.04
280+
steps:
281+
- uses: actions/checkout@v4
282+
# we use image with download cache filled. Solves servers flakiness.
283+
- run: >
284+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
285+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
286+
bash -cx './configure --disable-docs --enable-debug-tcg --enable-debug-graph-lock --enable-debug-mutex --enable-asan --enable-ubsan && ninja -C build'
287+
- run: sudo chown $USER:$USER /dev/kvm
288+
- run: >
289+
podman run --init --privileged --rm -i -v /dev/kvm:/dev/kvm -v $(pwd):$(pwd) -w $(pwd)
290+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
291+
bash -cx "env ASAN_OPTIONS=detect_leaks=0 ./build/pyvenv/bin/meson test -C build --setup thorough --no-suite func-quick --no-suite func-thorough -t 5 --print-errorlogs"
292+
293+
check-functional:
294+
needs: checkapply
295+
runs-on: ubuntu-24.04
296+
steps:
297+
# we clean up runner first, to get more disk space
298+
- run: docker system prune -af && sudo rm -rf /opt/*
299+
- uses: actions/checkout@v4
300+
# we use image with download cache filled. Solves servers flakiness.
301+
- run: >
302+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
303+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
304+
bash -cx './configure --disable-docs --enable-debug-tcg --enable-debug-graph-lock --enable-debug-mutex --enable-asan --enable-ubsan && ninja -C build'
305+
- run: sudo chown $USER:$USER /dev/kvm
306+
- run: >
307+
podman run --init --privileged --rm -i -v /dev/kvm:/dev/kvm -v $(pwd):$(pwd) -w $(pwd)
308+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
309+
bash -cx "env ASAN_OPTIONS=detect_leaks=0 ./build/pyvenv/bin/meson test -C build --setup thorough --suite func-quick --suite func-thorough -j $(($(nproc) / 2)) -t 5 --print-errorlogs --wrapper $(pwd)/scripts/run-functional-test.sh --max-lines=0"
310+
# Limit parallelism because it creates timeout.
311+
312+
# iotests do not support sanitizers, so we run them in their own job
313+
check-block:
314+
needs: checkapply
315+
runs-on: ubuntu-24.04
316+
steps:
317+
- uses: actions/checkout@v4
318+
# we use image with download cache filled. Solves servers flakiness.
319+
- run: >
320+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
321+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
322+
bash -cx './configure --disable-docs --enable-debug-tcg --enable-debug-graph-lock --enable-debug-mutex && ninja -C build'
323+
- run: sudo chown $USER:$USER /dev/kvm
324+
- run: >
325+
podman run --init --privileged --rm -i -v /dev/kvm:/dev/kvm -v $(pwd):$(pwd) -w $(pwd)
326+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
327+
bash -cx "./build/pyvenv/bin/meson test -C build --setup thorough --suite block --suite block-slow --suite block-thorough -t 5 --print-errorlogs"
328+
329+
check-avocado:
330+
needs: checkapply
331+
runs-on: ubuntu-24.04
332+
steps:
333+
- uses: actions/checkout@v4
334+
# add more time for all tests
335+
- run: sed -i -e 's/timeout = .*/timeout = 3600/' $(find tests/avocado/ -type f)
336+
# we use image with download cache filled. Solves servers flakiness.
337+
- run: >
338+
podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd)
339+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
340+
bash -cx './configure --disable-docs --enable-debug-tcg --enable-debug-graph-lock --enable-debug-mutex --enable-asan --enable-ubsan && ninja -C build'
341+
- run: sudo chown $USER:$USER /dev/kvm
342+
- run: >
343+
podman run --init --privileged --rm -it -v /dev/kvm:/dev/kvm -v $(pwd):$(pwd) -w $(pwd)
344+
docker.io/pbolinaro/qemu-ci:debian-precache-tests
345+
bash -cx "env ASAN_OPTIONS=detect_leaks=0 make -k check-avocado V=1"

.github/workflows/containers.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
on:
2+
schedule:
3+
- cron: '0 6 * * *'
4+
workflow_dispatch:
5+
6+
permissions: write-all
7+
8+
jobs:
9+
build_container:
10+
runs-on: ubuntu-24.04
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
# cd tests/docker/dockerfiles/
15+
# ls *docker | sed -e 's/.docker//' | tr '\n' ','
16+
# remove: debian-bootstrap,debian-toolchain
17+
container: [alpine,centos9,debian-all-test-cross,debian-amd64-cross,debian-arm64-cross,debian-armhf-cross,debian,debian-hexagon-cross,debian-i686-cross,debian-legacy-test-cross,debian-loongarch-cross,debian-mips64el-cross,debian-mipsel-cross,debian-ppc64el-cross,debian-riscv64-cross,debian-s390x-cross,debian-tricore-cross,debian-xtensa-cross,fedora,fedora-rust-nightly,fedora-win64-cross,opensuse-leap,python,ubuntu2204]
18+
steps:
19+
- uses: actions/checkout@v4
20+
- run: make docker-image-${{matrix.container}} RUNC=podman V=1
21+
- run: podman tag qemu/${{matrix.container}} docker.io/pbolinaro/qemu-ci:${{matrix.container}}
22+
- run: podman login -u pbolinaro -p ${{secrets.DOCKERHUB_PASSWORD}}
23+
- run: podman push docker.io/pbolinaro/qemu-ci:${{matrix.container}}
24+
25+
build_container_debian-precache-tests:
26+
runs-on: ubuntu-24.04
27+
steps:
28+
# we clean up runner first, to get more disk space
29+
- run: docker system prune -af && sudo rm -rf /opt/*
30+
- uses: actions/checkout@v4
31+
- run: make docker-image-debian RUNC=podman V=1
32+
# fill download cache for functional and check-avocado
33+
# running check-avocado without any qemu binary will only download data
34+
# in /root/avocado
35+
- run: >
36+
podman run -it -v $(pwd):$(pwd) -w $(pwd) qemu/debian
37+
./precache_tests.sh
38+
# commit result as a new image. Cache will be in /root/.cache and /root/avocado
39+
- run: podman commit "$(podman ps -aq)" docker.io/pbolinaro/qemu-ci:debian-precache-tests
40+
- run: podman login -u pbolinaro -p ${{secrets.DOCKERHUB_PASSWORD}}
41+
- run: podman push docker.io/pbolinaro/qemu-ci:debian-precache-tests

0 commit comments

Comments
 (0)