What is the current state of cross-compiling snaps for Core24? Specifically, is it possible to build snaps for ARM64 on an AMD64 machine?
On Core20, I was able to use the --target-arch and --enable-experimental-target-arch flags to achieve this. Outside of Snapcraft, I can cross-compile most software using CMake and appropriate toolchains. I cannot use Launchpad build farms, as the software is proprietary, and I don’t currently have access to a decent ARM64 build server.
For Core24, is there a way to emulate ARM64 for snap builds, or is building directly on an ARM64 machine still required?
We’ve recently improved cross-compiling for core24. See this how-to for more information. It’s currently only available on the latest/edge channel, but will be included in the Snapcraft 8.8 release later this month.
We do not use autotools, but I get the gist of it.
In principle, this means that I should be able to cross compile our software by normal means, then use dump plugin to dump the resulting ARM64 executables into a snap. Then I can use stage-dependencies to source ARM64 run-time dependencies from ubuntu-ports as long as I remember to suffix the packages with :$CRAFT_ARCH_BUILD_FOR (except for those dependencies with architecture all).
I tried it out, but I have some trouble pulling dependencies outside of ubuntu and ubuntu-ports. Consider this minimal example - I create part foo with dependency libc6 and ros-jazzy-ros-base, the latter of which is available in the ROS2 repo. The following snapcraft.yaml builds fine on Ubuntu 24.04.2 LTS (AMD64) with snapcraft 8.7.4.post91:
Stage package not found in part 'foo': ros-jazzy-ros-base:arm64.
I think it is odd that libc6:arm64 is successfully marked and installed while ros-jazzy-ros-base:arm64 is not. I wanted to file a bug, but I am not sure if this is intentional or I am missing something.
Thanks for trying it out! This smells like a bug to me.
I suspect it’s related to craft-parts passing the host architecture when downloading the package here. It appears this causes craft-parts to see if the package is available for the host arch and then download it for the foreign arch. In your scenario, it fails because ros-jazzy-ros-base isn’t available for AMD64. (edit: I don’t think this is the root cause anymore)
Since you’re trying to pull ros-jazzy-ros-base, you could give a shot at using the ros-jazzy-ros-base snaps as they are released for arm as well . Those snaps exists to support content-sharing (see this doc page and build/stage-snaps as well).
Note that I haven’t tried such setup (cross-compilation w/ build/stage-snaps) myself, it likely won’t work out of the box.
Note also that any ROS 2 dependencies that aren’t part of ros-jazzy-ros-base, or your source, would have to be pulled by apt and may thus result in the same error.
The ros-jazzy-ros-base snap seems promising but you are right in assuming we have ROS dependencies outside of base, which would cause us to run into the same issues.
For now, we are just building the main bulk of software with our cross-compilation toolchain, transferring to an arm64 machine, then building the rest from there (including downloading stage dependencies).
Importantly, you shouldn’t need to stage libc6 in your snap (as that should be provided by the core24 ARM64 base snap).
To debug this further you can try snapcraft --debug to dump yourself into the build environment and try and see if you can find the package on your own. One thing that sometimes happens is if you specify foo:$CRAFT_ARCH_BUILD_FOR but the package is actually available for all architectures (instead of each architecture individually), you’ll get a failure in finding the package. For instance, snaps using the linux-firmware package will have to be specified differently if they use base: core22 or base: core24 (see here, switching between the jammy package and the noble package).
ETA: I see now the conversation did indeed reach the point of distinguishing between all and $arch; if snapcraft recursively checks dependencies and blindly suffixes :arm64 to every dependency package, you’ll always hit this problem. Especially with python packages.
@dilyn You’re right about not needing libc6, but I just used it for demonstrative purposes.
Since my original post, I tried staging the ubuntu-ports package python3-apt:arm64 which depends on python-apt-common:all. This is similar to the situation with ros-jazzy-ros-base:arm64 depending on some Architecture: all packages. However snapcraft stages python3-apt:arm64 fine, leading me to think it is a problem wit the ROS repository.
I noticed that the python packages in the ROS repo do not have the Multi-Arch field while the packages in ubuntu-ports do. Perhaps the issue lies here? I am not exactly sure how this package property works.