You don't usually need a full VM, you just need qemu-user-static
and a chroot with the Raspberry Pi OS sysroot.
On Ubuntu, you can get this really easily using some standard development tools like mk-sbuild
.
# Install the tools for the host
sudo apt install sbuild ubuntu-dev-tools
# Get the Raspberry Pi OS public key
wget -qO- https://archive.raspbian.org/raspbian.public.key | gpg --import -
# Use debootstrap to create a RPi OS chroot/sysroot
mk-sbuild --arch=armhf buster --debootstrap-mirror=http://raspbian.raspberrypi.org/raspbian --name=rpizero-buster --debootstrap-keyring "$HOME/.gnupg/pubring.kbx --merged-usr" --skip-proposed --skip-updates --skip-security
# Install packages to the sysroot
sudo sbuild-apt rpizero-buster-armhf apt-get install build-essential
# Access an emulated shell in the chroot
schroot -c rpizero-buster-armhf
# Run GCC (emulated)
(rpizero-buster-armhf):/$ gcc --version
gcc (Raspbian 8.3.0-6+rpi1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
More information here: Ubuntu to Raspberry Pi OS Cross C++ Development: Development setup
The guide then goes into the process of cross-compilation, but you can also just invoke your build tools and compilers in the emulated RPi OS schroot, as shown in the snippet above. However, cross compilation is not that much more work if you've already got a full RPi OS sysroot+package manager anyway, and it will be significantly faster and more convenient than building in an emulator.
Alternatively, you can build a Docker container from the RPi OS image and run that. Basically, use docker import
to create an image from the RPi OS image or sysroot, then make sure you have docker/binfmt
so you can emulate ARM containers, and start a container from the image you imported. The principle is very similar to the chroot described earlier, but you have a nicely packaged Docker image that you could share.
Full instructions: https://raspberrypi.stackexchange.com/a/109524/107831