[PATCH 09/13] qemu: split into verify, setup and a build chain
Daniel Gomez <[email protected]> Fri, 12 Jun 2026 14:36:47 +0200
| Newsgroups | dev.linux.lists.kdevops |
|---|---|
| Message-ID | <[email protected]> |
From: Daniel Gomez <[email protected]> Building QEMU was one privileged, expensive step wired into a bare make through LOCALHOST_SETUP_WORK and DEFAULT_DEPS. Split it into a controller setup step and a chain of build targets, none on the default make path. make qemu-controller-setup installs the build and runtime dependencies so the controller can fetch, build and run QEMU. It is the privileged preparation, may escalate, and is the only qemu step that installs system packages; it is registered with the controller-setup umbrella. The build is a chain of independent targets, each depending on the previous: qemu-verify, qemu-fetch, qemu-configure, qemu-build and qemu-install, with make qemu running the whole chain. It starts with verify because you cannot fetch without git: verify is read-only and sudoless and checks the build toolchain (git, meson, ninja, cc), failing with a diagnostic that points at make qemu-controller-setup when a tool is missing. Because qemu-fetch depends on qemu-verify and so on, any target pulls in the steps before it, so make qemu-build verifies, fetches and configures first. The install escalates only for the libvirt /usr/local prefix; the qemu-destdir prefix used by other backends needs no root. A top-level make controller-setup aggregates the migrated CONTROLLER_SETUP_WORK and the grandfathered LOCALHOST_SETUP_WORK so all controller setup can be driven from one umbrella. Only qemu is migrated here to avoid regressing the contributors still on the default path. Generated-by: Claude AI Signed-off-by: Daniel Gomez <[email protected]> --- Makefile | 5 +++ docs/qemu.md | 16 ++++--- playbooks/roles/qemu/README.md | 6 --- playbooks/roles/qemu/defaults/main.yml | 2 - playbooks/roles/qemu/tasks/main.yml | 80 +++++++++++++--------------------- scripts/qemu.Makefile | 48 +++++++++++++------- 6 files changed, 79 insertions(+), 78 deletions(-) diff --git a/Makefile b/Makefile index 0d6f7c4f..d43d9611 100644 --- a/Makefile +++ b/Makefile @@ -138,6 +138,8 @@ endif # CONFIG_NEEDS_LOCAL_DEVELOPMENT_PATH # make with no arguments. LOCALHOST_SETUP_WORK := +CONTROLLER_SETUP_WORK := + ANSIBLE_EXTRA_ARGS += $(LOCAL_DEVELOPMENT_ARGS) # We may not need the extra_args.yaml file all the time. If this file is empty @@ -285,6 +287,9 @@ $(KDEVOPS_NODES): .config $(ANSIBLE_CFG_FILE) $(KDEVOPS_NODES_TEMPLATE) $(KDEVOP DEFAULT_DEPS += $(LOCALHOST_SETUP_WORK) +PHONY += controller-setup +controller-setup: $(CONTROLLER_SETUP_WORK) + include scripts/tests.Makefile include scripts/linux-ab-testing.Makefile include scripts/ci.Makefile diff --git a/docs/qemu.md b/docs/qemu.md index ce4899ce..396c589c 100644 --- a/docs/qemu.md +++ b/docs/qemu.md @@ -67,10 +67,14 @@ it for the systemd unit `ExecStart`. ## Make targets -QEMU is built as part of the localhost setup performed during `make` and -`make bringup`. The build can also be driven explicitly: - -- `make qemu` — fetch, build, and install QEMU on localhost -- `make qemu-configure` — run QEMU's configure step +QEMU builds only when you run its targets, never during `make` or +`make bringup`. The build targets form a chain; each pulls in the ones +before it, and `make qemu` runs the whole chain: + +- `make qemu-controller-setup` — install the build and runtime dependencies (may sudo) +- `make qemu-verify` — verify the build toolchain is present (read-only) +- `make qemu-fetch` — fetch the QEMU git tree +- `make qemu-configure` — configure the QEMU build - `make qemu-build` — build QEMU -- `make qemu-install` — install the built QEMU on localhost +- `make qemu-install` — install QEMU on localhost +- `make qemu` — verify, fetch, configure, build, and install QEMU diff --git a/playbooks/roles/qemu/README.md b/playbooks/roles/qemu/README.md index f439bdca..56f646b9 100644 --- a/playbooks/roles/qemu/README.md +++ b/playbooks/roles/qemu/README.md @@ -14,12 +14,6 @@ Run a supported OS/distribution: * Red Hat / Fedora * Debian / Ubuntu -Role Variables --------------- - - * qemu_force_install_if_present: set to False by default, set this to True to - force building even if you have /usr/local/bin/qemu-system-x86_64 - Dependencies ------------ diff --git a/playbooks/roles/qemu/defaults/main.yml b/playbooks/roles/qemu/defaults/main.yml index 31671d78..5fe2f375 100644 --- a/playbooks/roles/qemu/defaults/main.yml +++ b/playbooks/roles/qemu/defaults/main.yml @@ -4,8 +4,6 @@ qemu_install_dir: "{{ qemu_install_dir | default('/usr/local') }}" qemu_install_needs_sudo: false -# Forces to build and install even if the binary is already present -qemu_force_install_if_present: false qemu_bin_path: "{{ qemu_bin_path | default(qemu_install_dir + '/bin/qemu-system-x86_64') }}" qemu_data: "{{ qemu_git_data_path | default(kdevops_controller_data_path + '/qemu') }}" qemu_git: "{{ qemu_git | default('https://github.com/qemu/qemu.git') }}" diff --git a/playbooks/roles/qemu/tasks/main.yml b/playbooks/roles/qemu/tasks/main.yml index 015c4d15..8298adcf 100644 --- a/playbooks/roles/qemu/tasks/main.yml +++ b/playbooks/roles/qemu/tasks/main.yml @@ -11,39 +11,40 @@ skip: true tags: vars -- name: Verify local build QEMU installation - ansible.builtin.stat: - path: "{{ qemu_bin_path }}" - register: qemu_present +- name: Check the QEMU build toolchain is present + ansible.builtin.shell: | + missing= + for tool in git meson ninja cc; do + command -v "$tool" >/dev/null 2>&1 || missing="$missing $tool" + done + [ -z "$missing" ] || { echo "$missing"; exit 1; } + register: qemu_toolchain changed_when: false - failed_when: qemu_present.stat.exists and not qemu_present.stat.executable - tags: ["qemu", "verify"] + failed_when: false + tags: ["qemu_verify"] -- name: Install build-deps for QEMU as per each Linux distribution - ansible.builtin.include_tasks: install-deps/main.yml +- name: Fail when the QEMU build toolchain is missing + ansible.builtin.fail: + msg: | + Missing QEMU build tools:{{ qemu_toolchain.stdout }}. + Run make qemu-controller-setup to install the build and runtime + dependencies, then retry. when: - - qemu_force_install_if_present|bool or not qemu_present.stat.exists + - qemu_toolchain.rc != 0 + tags: ["qemu_verify"] -- name: Assume we won't build QEMU first - ansible.builtin.set_fact: - qemu_build_now: false - tags: vars - -- name: Annotate when we are building QEMU - ansible.builtin.set_fact: - qemu_build_now: true +- name: Install build and runtime deps for QEMU per Linux distribution + ansible.builtin.include_tasks: install-deps/main.yml when: - - qemu_force_install_if_present|bool or not qemu_present.stat.exists - tags: vars + - "'qemu_controller_setup' in ansible_run_tags" + tags: ["qemu_controller_setup"] - name: Ensure the controller data path exists ansible.builtin.file: path: "{{ kdevops_controller_data_path }}" state: directory mode: "0755" - tags: ["qemu", "build-deps"] - when: - - qemu_build_now|bool + tags: ["qemu_fetch"] - name: Fetch the QEMU git tree environment: @@ -52,34 +53,21 @@ repo: "{{ qemu_git }}" dest: "{{ qemu_data }}" version: "{{ qemu_version }}" - when: - - qemu_build_now|bool - -- name: Nuke old build directory - ansible.builtin.file: - path: "{{ qemu_build_dir }}" - state: absent - tags: ["qemu", "build-deps"] - when: - - qemu_build_now|bool + tags: ["qemu_fetch"] - name: Create the out-of-tree build directory ansible.builtin.file: path: "{{ qemu_build_dir }}" state: directory mode: "0755" - tags: ["qemu", "build-deps"] - when: - - qemu_build_now|bool + tags: ["qemu_configure"] - name: Pre-fetch QEMU subprojects so configure can disable downloads ansible.builtin.command: "meson subprojects download" changed_when: true - tags: ["qemu", "configure"] + tags: ["qemu_configure"] args: chdir: "{{ qemu_data }}" - when: - - qemu_build_now|bool - name: Run configure for QEMU ansible.builtin.command: >- @@ -88,27 +76,21 @@ --prefix={{ qemu_install_dir }} --disable-download changed_when: true - tags: ["qemu", "configure"] + tags: ["qemu_configure"] args: chdir: "{{ qemu_build_dir }}" - when: - - qemu_build_now|bool - name: Get the number of build jobs ansible.builtin.command: "{{ num_jobs }}" changed_when: false - tags: ["qemu", "configure", "build"] + tags: ["qemu_build"] register: qemu_nproc - when: - - qemu_build_now|bool - name: Build QEMU community.general.make: chdir: "{{ qemu_build_dir }}" jobs: "{{ qemu_nproc.stdout }}" - tags: ["qemu", "build"] - when: - - qemu_build_now|bool + tags: ["qemu_build"] - name: Install QEMU become: "{{ qemu_install_needs_sudo | bool }}" @@ -117,6 +99,6 @@ changed_when: true args: chdir: "{{ qemu_build_dir }}" - tags: ["qemu", "install"] when: - - qemu_build_now|bool + - "'qemu_install' in ansible_run_tags" + tags: ["qemu_install"] diff --git a/scripts/qemu.Makefile b/scripts/qemu.Makefile index 8d7c446e..a7bdfb72 100644 --- a/scripts/qemu.Makefile +++ b/scripts/qemu.Makefile @@ -1,38 +1,56 @@ # SPDX-License-Identifier: copyleft-next-0.3.1 -qemu: $(KDEVOPS_EXTRA_VARS) +qemu-controller-setup: $(KDEVOPS_EXTRA_VARS) $(Q)ansible-playbook \ $(KDEVOPS_PLAYBOOKS_DIR)/qemu.yml \ - --extra-vars=@./extra_vars.yaml -PHONY += qemu + --extra-vars=@./extra_vars.yaml --tags vars,qemu_controller_setup +PHONY += qemu-controller-setup -qemu-install: $(KDEVOPS_EXTRA_VARS) +qemu-verify: $(KDEVOPS_EXTRA_VARS) $(Q)ansible-playbook \ $(KDEVOPS_PLAYBOOKS_DIR)/qemu.yml \ - --extra-vars=@./extra_vars.yaml --tags vars,install -PHONY += qemu-install + --extra-vars=@./extra_vars.yaml --tags vars,qemu_verify +PHONY += qemu-verify + +qemu-fetch: qemu-verify + $(Q)ansible-playbook \ + $(KDEVOPS_PLAYBOOKS_DIR)/qemu.yml \ + --extra-vars=@./extra_vars.yaml --tags vars,qemu_fetch +PHONY += qemu-fetch -qemu-configure: $(KDEVOPS_EXTRA_VARS) +qemu-configure: qemu-fetch $(Q)ansible-playbook \ $(KDEVOPS_PLAYBOOKS_DIR)/qemu.yml \ - --extra-vars=@./extra_vars.yaml --tags vars,configure + --extra-vars=@./extra_vars.yaml --tags vars,qemu_configure PHONY += qemu-configure -qemu-build: $(KDEVOPS_EXTRA_VARS) +qemu-build: qemu-configure $(Q)ansible-playbook \ $(KDEVOPS_PLAYBOOKS_DIR)/qemu.yml \ - --extra-vars=@./extra_vars.yaml --tags vars,build + --extra-vars=@./extra_vars.yaml --tags vars,qemu_build PHONY += qemu-build +qemu-install: qemu-build + $(Q)ansible-playbook \ + $(KDEVOPS_PLAYBOOKS_DIR)/qemu.yml \ + --extra-vars=@./extra_vars.yaml --tags vars,qemu_install +PHONY += qemu-install + +qemu: qemu-install +PHONY += qemu qemu-help-menu: @echo "qemu options:" - @echo "qemu - Git fetches QEMU, builds and install it on localhost" - @echo "qemu-configure - Configure QEMU build" - @echo "qemu-build - Build QEMU" - @echo "qemu-install - Do the install of the QEMU build on localhost" + @echo "qemu-controller-setup - Install QEMU build and runtime deps (controller setup, may sudo)" + @echo "qemu - Verify, fetch, configure, build and install QEMU" + @echo "qemu-verify - Verify the build toolchain is present (read-only)" + @echo "qemu-fetch - Fetch the QEMU git tree (after verify)" + @echo "qemu-configure - Configure the QEMU build (after fetch)" + @echo "qemu-build - Build QEMU (after configure)" + @echo "qemu-install - Install QEMU (after build)" + @echo "controller-setup - Runs qemu-controller-setup as part of opt-in controller setup" @echo "" HELP_TARGETS += qemu-help-menu -LOCALHOST_SETUP_WORK += qemu +CONTROLLER_SETUP_WORK += qemu-controller-setup -- 2.54.0