From 3934aeae861c489180eb8032497d248460433e23 Mon Sep 17 00:00:00 2001 From: Ihor Dutchak Date: Fri, 6 Nov 2026 01:08:53 +0200 Subject: [PATCH] Fix the libusb virtual-device CI runner Pin the runner to Ubuntu 24.04 so the generic guest kernel has matching modules-extra and headers. Use apt with the primary Ubuntu archive, omit recommended packages, and bound setup, module builds and VM execution. Document the packaged raw_gadget and source-built dummy_hcd setup. Related to libusb/hidapi#799 and libusb/hidapi#728. Assisted-by: Codex:GPT-6 --- .github/workflows/libusb-vhid-test.yml | 40 +++++++++++++------------- src/tests/README.md | 14 ++++----- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/libusb-vhid-test.yml b/.github/workflows/libusb-vhid-test.yml index bfe6d3128..511eca23f 100644 --- a/.github/workflows/libusb-vhid-test.yml +++ b/.github/workflows/libusb-vhid-test.yml @@ -3,13 +3,11 @@ name: Linux libusb Virtual HID Device Test (manual) # Runs the device-I/O test against the HIDAPI *libusb* backend using a real # virtual USB HID device (USB Raw Gadget on top of dummy_hcd). # -# The hosted ubuntu-latest (azure) kernel is built without the USB gadget -# subsystem, so raw_gadget/dummy_hcd can't be loaded (or even built) there. We -# therefore run the test inside a lightweight VM (virtme-ng + QEMU) booting a -# *generic* Ubuntu kernel, whose linux-modules-extra ships dummy_hcd and -# raw_gadget. The VM shares the host filesystem, so it runs the binaries built -# on the host. The same approach works locally and on WSL2 (which also lacks -# those modules in its default kernel). +# Ubuntu 24.04 supplies a generic guest kernel and matching modules-extra +# package containing raw_gadget. Build dummy_hcd against that kernel's headers +# and run the tests in a virtme-ng/QEMU VM. The VM shares the host filesystem +# and uses the host-built binaries; the Azure host kernel need not support USB +# gadgets. # # Runs on demand (workflow_dispatch) or on a PR labelled 'ci-virtual-device'. @@ -21,24 +19,28 @@ on: jobs: libusb-rawgadget: if: github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'ci-virtual-device') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 + timeout-minutes: 25 steps: - uses: actions/checkout@v4 with: path: hidapisrc - name: Install deps + a gadget-capable generic kernel + virtme-ng + timeout-minutes: 10 run: | set -eux - sudo apt-get update - sudo apt-get install -y \ + # Use Ubuntu's primary archive for the guest kernel and VM packages. + printf '%s\n' 'https://archive.ubuntu.com/ubuntu' | sudo tee /etc/apt/apt-mirrors.txt + sudo apt update + sudo apt install -y --no-install-recommends \ build-essential cmake libudev-dev libusb-1.0-0-dev \ qemu-system-x86 virtme-ng linux-image-generic # raw_gadget ships in the generic kernel's modules-extra; install that # plus headers (needed to build dummy_hcd, which Ubuntu doesn't package). KVER=$(ls -1 /lib/modules | grep -- '-generic$' | sort -V | tail -n1) echo "generic kernel: ${KVER}" - sudo apt-get install -y "linux-modules-extra-${KVER}" "linux-headers-${KVER}" + sudo apt install -y --no-install-recommends "linux-modules-extra-${KVER}" "linux-headers-${KVER}" find "/lib/modules/${KVER}" \( -name 'raw_gadget*' -o -name 'dummy_hcd*' \) || true - name: Build dummy_hcd for the generic kernel (Ubuntu ships no package) @@ -47,22 +49,20 @@ jobs: KVER=$(ls -1 /lib/modules | grep -- '-generic$' | sort -V | tail -n1) KMAJ=$(echo "${KVER}" | grep -oE '^[0-9]+\.[0-9]+') mkdir -p dummyhcd - # Ubuntu packages no dummy_hcd; build it from the upstream source that - # matches the generic kernel's major version (xairy's copy tracks newer - # kernels and won't compile against an older one). - curl -fsSL -o dummyhcd/dummy_hcd.c \ + # Use the upstream source matching the guest kernel's major version. + curl -fsSL --connect-timeout 15 --max-time 60 -o dummyhcd/dummy_hcd.c \ "https://raw.githubusercontent.com/torvalds/linux/v${KMAJ}/drivers/usb/gadget/udc/dummy_hcd.c" printf 'obj-m += dummy_hcd.o\n' > dummyhcd/Makefile - make -C "/lib/modules/${KVER}/build" M="${PWD}/dummyhcd" modules + timeout --kill-after=3s 300s make -C "/lib/modules/${KVER}/build" M="${PWD}/dummyhcd" modules sudo install -m 0644 "${PWD}/dummyhcd/dummy_hcd.ko" \ "/lib/modules/${KVER}/kernel/drivers/usb/gadget/udc/" - sudo depmod -a "${KVER}" + sudo timeout --kill-after=3s 60s depmod -a "${KVER}" - name: Build HIDAPI + tests (libusb backend) run: | - cmake -B build -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + timeout --kill-after=3s 60s cmake -B build -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DHIDAPI_WITH_LIBUSB=ON -DHIDAPI_WITH_HIDRAW=OFF -DHIDAPI_WITH_TESTS=ON - cmake --build build + timeout --kill-after=3s 300s cmake --build build - name: Run DeviceIO_libusb inside a VM (generic kernel + raw_gadget) run: | @@ -84,6 +84,6 @@ jobs: # Boot the kernel in a VM and run the guest script via --exec (vng's # native flag; passing a complex command after '--' gets mangled). The # script loads dummy_hcd/raw_gadget and runs the test (see it for why). - vng -v --pwd -r "${KIMG}" --exec "bash hidapisrc/.github/vmrun-libusb.sh" 2>&1 | tee vng.log + timeout --kill-after=3s 300s vng -v --pwd -r "${KIMG}" --exec "bash hidapisrc/.github/vmrun-libusb.sh" 2>&1 | tee vng.log echo "--- VM run result ---" grep -q "VNG_CTEST_EXIT=0" vng.log diff --git a/src/tests/README.md b/src/tests/README.md index 1b6e08e29..c13982806 100644 --- a/src/tests/README.md +++ b/src/tests/README.md @@ -49,13 +49,13 @@ for the per-push CI matrix: is derived from Microsoft's vhidmini2 sample and is licensed separately under the **MS-PL** (not HIDAPI's license); see `windows/driver/README.md` and `windows/driver/LICENSE.txt`. -* **Linux / libusb** — needs the `raw_gadget` and `dummy_hcd` kernel modules, - which the hosted `ubuntu-latest` kernel is built *without* (it has no USB - gadget subsystem). The `libusb-vhid-test` workflow therefore runs the test - inside a lightweight VM (`virtme-ng` + QEMU) booting a *generic* Ubuntu kernel - whose `linux-modules-extra` ships both modules; the VM shares the host - filesystem, so it runs the host-built binaries. The same approach works - locally and on WSL2 (whose default kernel also lacks these modules). +* **Linux / libusb** — needs the `raw_gadget` and `dummy_hcd` kernel modules. + The `libusb-vhid-test` workflow uses an `ubuntu-24.04` runner and boots a + generic guest kernel in a lightweight VM (`virtme-ng` + QEMU). Its + `linux-modules-extra` package supplies `raw_gadget`; the workflow builds + `dummy_hcd` against the matching kernel headers. The VM shares the host + filesystem and runs the host-built binaries. The same approach supports + local hosts and WSL2 without USB gadget kernel support. * **macOS** — creating an `IOHIDUserDevice` is gated by the `com.apple.developer.hid.virtual.device` entitlement *and* an interactive Accessibility (TCC) consent prompt, neither available on a hosted runner, so