Re: Cross compiling with interpreter extension library
Hi Keith,
On Tue, Sep 02, 2025 at 01:00:51PM -0700, Keith Packard wrote:
> I'm trying to build 'altos' for arm64 using pbuilder on amd64. I created
> my cross pbuilder environment using:
>
> $ sudo cowbuilder create \
> --basepath /var/cache/pbuilder/base-cross.cow \
> --debootstrap mmdebstrap \
> --debootstrapopts --architectures=amd64,arm64 \
> --debootstrapopts --skip=output/dev \
> --debootstrapopts --variant=buildd \
> --debootstrapopts --include=ca-certificates
I am wondering why you are creating a separate base here. In principle,
pbuilder/cowbuilder should be able to deal with a single base per
release and install a suitable toolchain. There should be no technical
need for a separate base.
There is a possible benefit in having the toolchain pre-installed as it
can save time downloading and unpacking it repeatedly. However, the base
as you are constructing it does not install the cross toolchain. If you
want to do that, you probably also want to add:
--debootstrapopts --include=crossbuild-essential-arm64,libc6-dev:arm64,libstdc++-dev:arm64
Note that once #815172 is resolved, this shall collapse to:
--debootstrapopts --include=build-essential:arm64
> All of my package building is done using this command:
>
> $ GIT_PBUILDER_OPTIONS="--host-arch=arm64 --basepath=/var/cache/pbuilder/base-cross.cow" gbp buildpackage
This is what we figured out in Brest. Did you file a bug with gbp asking
for a better way to forward the host architecture? If not, could you do
so? (Please X-Debbugs-Cc this list)
> The set of packages involved are:
>
> • altos. The test package to cross-build
>
> • cairo-5c. A nickle extension module
>
> • libcairo-5c0. The binary library used by cairo-5c
>
> • libcairo2. The cairo library wrapped by libcairo-5c0
>
> • libcairo2-dev. The developer bits for libcairo2.
>
> • nickle. The nickle interpreter language.
The mentioning of "interpreter" got me looking. I observe that the
nickle package is implicitly Multi-Arch: no. If something Build-Depends
on it, it'll get the host version and as a result will not be able to
run the nickle interpreter during build. I suspect this is not what you
want. Potentially, Multi-Arch: foreign is. But then nickle also contains
headers and might not be suitable for Multi-Arch: foreign after all.
Quite possibly, it may be necessary to split the nickle package into
several binary packages in order to make it usable for cross
compilation. My musings may also be entirely wrong. It's a guess.
> • picolibc-arm-none-eabi. The embedded C library used to create
> firmware images flashed to various devices with ARM Cortex-M socs.
This package has the ABI encoded into the package name. It also got me
looking. It's Arch:all and implicitly M-A:no. Therefore, it'll never
satisfy any cross Build-Depends. Often, the multiarch hinter issues a
hint for such cases, but here it does not. The reason is that it gives
up once it sees maintainer scripts. I checkd the maintainer scripts and
they're fine. This one very likely needs to become Multi-Arch: foreign.
> Version 2.104 of the nickle package builds in this cross-build
> environment. That version also added 'Multi-Arch: allowed' to the binary
> package control fields. Nickle is built with -Wl,-E so that its symbols
> will be visible to any module shared library pulled in at runtime with
> dlopen, but it is installed in /usr/bin.
Aha. My earlier looking at nickle is outdated. What you write makes
sense to me.
> The cairo-5c package contains nickle scripts and docs and depends upon
> the libcairo-5c0 package which contains the shared library binary which
> links to the underlying libraries including libcairo2.
This is Arch:all and implicitly Multi-Arch: no. It'll not be able to
satisfy any cross Build-Depends as is.
> altos uses nickle with the cairo-5c extension to perform some build-time
> graphics operations. Eventually, I think the correct solution will be to
> set the build-time dependencies to 'nickle:native' and 'cairo-5c:native'
> so that we don't run the arm64 version under qemu, but I want to figure
> out how to make the arm64 version work before I do that.
You have wandered into the infamous "Multi-Arch interpreter problem"
now. If your interest is in actually running nickle programs during
build and you expect that nickle does not behave differently (produce
different artifacts) depending on the interpreter architecture, please
go straight for nickle:native, cairo-5c:native and have things work.
If you want to insist on running the host nickle interpreter, you shall
notice that cairo-5c is not satisfiable. Arch:all is implicitly treated
as if it were dpkg's architecture, so it cannot ever pass through the
arm64 architecture constraint to its own dependencies. You may work
around this by changing cairo-5c to Architecture: any.
> picolibc-arm-none-eabi contains static libraries and headers for
> building embedded firmware for ARM microcontrollers, so it is marked
> 'Architecture: all'. I just uploaded version 1.8.10-3 which adds
> 'Multi-Arch: foreign'.
Glad to see we arrived at the same conclusion independently.
> *** QUESTION NUMBER 1 ***
>
> When working on cairo-5c, why did I have to add :native to the
> Build-Depends: value for libcairo2-dev and ttf-bitstream-vera: in order
> to get it to build successfully?
>
> Source: cairo-5c
> Section: libs
> Priority: optional
> Maintainer: Keith Packard <keithp@keithp.com>
> Rules-Requires-Root: no
> Standards-Version: 4.5.0
> Build-Depends: debhelper-compat (= 12), debhelper (>= 12), libcairo2-dev:native, librsvg2-dev,
> nickle:any (>= 2.73), libx11-dev (>= 2:1.4.99.901), libfreetype6-dev,
> ttf-bitstream-vera:native
>
> If I remove the :native annotations from the Build-Depends field, when cross-building, I get this error:
>
> The following packages have unmet dependencies:
> builddeps:/build/cairo-5c_1.22.dsc:arm64 : Depends: libcairo2-dev:arm64 but it is not going to be installed
> Depends: librsvg2-dev:arm64 but it is not going to be installed
> Depends: ttf-bitstream-vera:arm64 but it is not installable
>
ttf-bitstream-vera is #732119. Until that is fixed, you may work around
it by keeping :native, but maybe someone should just NMU it instead.
That bug is actually marked as affecting cairo-5c, so you might have
seen it already. Could you at the very least leave a note in your
Build-Depends that :native on ttf-bitstream-vera is a workaround and
will make your package FTBFS natively once ttf-bitstream-vera is fixed?
That ttf-bitstream-vera bug also meant that cairo-5c completely fell of
my radar.
So I took the cairo-5c package from sid and changed:
* nickle -> nickle:native (as it is not M-A:allowed in the archive)
* ttf-bitstream-vera -> ttf-bitstream-vera:native (workaround #732119)
With these two changes, I can cross build cairo-5c in unstable using
sbuild. I guess that something about your build
environment is at fault here, but it is hard to tell what. Are you sure
that all of your libraries are in version-sync?
Do you actually run nickle during an arch-only build or is it only
needed for building the indep package or for testing? Consider moving it
to Build-Depends-Indep or annotating it <!nocheck> as appropriate.
> *** QUESTION NUMBER 2 ***
>
> When building altos, which depends upon cairo-5c and nickle, why is the
> amd64 version of the libcairo-5c0 package installed rather than the
> arm64 version? When building the package, I get this error:
I cannot reproduce this. As altos Build-Depends: cairo-5c and cairo-5c
is Arch:all M-A:no, it cannot satisfy the dependency. If you were to
annotate it :native, it'd pull a native libcairo-5c0 and that would be
expected.
> nickle led.5c redoff.svg
> Unhandled exception open_error ("libcairo-5c.so.0: cannot open shared object file: No such file or directory", 25, "libcairo-5c.so.0")
> /usr/share/nickle/cairo.5c:39: Foreign::load ("libcairo-5c.so.0");
> /usr/share/nickle/builtin.5c:137: non-existant namespace Cairo
>
> That's because we only have the amd64 version of libcairo-5c0 and not
> the arm64 version:
>
> $ dpkg -l libcairo-5c0
> Desired=Unknown/Install/Remove/Purge/Hold
> | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
> |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
> ||/ Name Version Architecture Description
> +++-==================-============-============-=================================
> ii libcairo-5c0:amd64 1.22 amd64 library for cairo nickle bindings
>
> Installing the arm64 version of the library manually solves the problem.
It is unclear to me how you got into this situation, because cairo-5c
depends on both nickle and libcairo-5c0 without :any. No matter what
architecture or multiarch cairo-5c is, this should result in nickle and
libcairo-5c0 having the same architecture (unless either of them is
M-A:foreign, but neither is). Maybe you can include the apt-cache show
output for all involved packages in your build environment?
> *** QUESTION NUMBER 3 ***
>
> Also when building altos, why did I have to add :native to the
> Build-Depends: value for picolibc-arm-none-eabi? Without that, when
> cross-building, I get this error:
>
> The following packages have unmet dependencies:
> builddeps:/build/altos_1.9.22-2.dsc:arm64 : Depends: picolibc-arm-none-eabi:arm64
>
> picolibc is marked 'Architecture: all', 'Multi-Arch: foreign', so
> why is it looking for an arm64 specific version?
If you are able to resolve picolibc-arm-none-eabi:native, then whatever
satisfies that is not Multi-Arch: foreign. I guess your build
environment did not pick up your correctly patched
picolibc-arm-none-eabi.
I hope that my musings get you quite a bit further. Looking forward to
your next steps.
Helmut
Reply to: