Hi Simon and Niels,

(fixed Cc address for architecture-properties maintainers)

On Thu, Aug 01, 2024 at 05:26:04PM +0100, Simon McVittie wrote:
> On Thu, 01 Aug 2024 at 12:58:54 +0200, Helmut Grohne wrote:
> > I anticipate that more than gobject-introspection will need the
> > cross-exe-wrapper.
> 
> Yes, probably: Meson's "exe_wrapper" interface (which is where I got the
> idea from) is a generic thing that any cross-file describing a foreign
> architecture might have, and any upstream project that finds a need to
> do so can make use of it.
> 
> > Therefore, I'd prefer to decouple it.
> 
> I agree - I definitely wouldn't want gobject-introspection to be the
> place where this is maintained as a generic interface, because that's
> tied to a particular upstream project that is not really anything to do
> with how Debian supports cross architectures.
> 
> > Any ideas for a
> > good place for it? I am wondering whether architecture-properties would
> > be willing to carry this.
> 
> I think it should be in a native, "Debian-infrastructure-ish" source
> package: perhaps architecture-properties, build-essential or dpkg-cross
> (if dpkg-cross wasn't orphaned), or somewhere similar to those, or its
> own separate source package.

I talked to Niels off list and he was vaguely positive about riding on
architecture-properties. He had some concerns about the bus factor that
this work might impose on architecture-properties. Guillem also
indicated that he wants to give feedback though not right now.

To me this is sufficient to prototype an implementation. I'm attaching a
patch for architecture-properties that hopefully gets most of the
details right (thanks to Simon's design feedback). If you prefer
reviewing it on salsa, go
https://salsa.debian.org/debian/architecture-properties/-/merge_requests/1

I request that we give people at least one week to reply before
uploading this. I appreciate feedback from Niels as to how acceptable he
finds this contribution. I also appreciate feedback from Simon as to how
well this solves the gobject-introspection use case. Other reviews are
welcome as well.

Writing tests is a bit non-trivial. Whilst Ubuntu has pioneered an
autopkgtest extension for cross architecture testing, this does not seem
to be available in Debian. Testing the native case is rather boring in
my view. As for manual testing, I verified that :amd64 (natively), :i386
(without installing qemu), and :armhf (qemu) work as expected on amd64.

In the event that dpkg gains the Provides suggested by Simon, we can
delete both native-architecture and native-architecture-is.

Helmut
diff --minimal -Nru architecture-properties-0.1.1/Makefile 
architecture-properties-0.1.1+nmu1/Makefile
--- architecture-properties-0.1.1/Makefile      1970-01-01 01:00:00.000000000 
+0100
+++ architecture-properties-0.1.1+nmu1/Makefile 2024-08-02 00:21:54.000000000 
+0200
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+WRAPPER=$(DEB_HOST_GNU_TYPE)-cross-exe-wrapper
+all:$(WRAPPER) cross-exe-wrapper.1 cross-exe-test
+$(WRAPPER):cross-exe-wrapper.in
+       sed \
+               -e 's/#DEB_HOST_ARCH#/$(DEB_HOST_ARCH)/g' \
+               -e 's/#DEB_HOST_MULTIARCH#/$(DEB_HOST_MULTIARCH)/g' \
+               $< > $@
+       chmod +x $@
+cross-exe-wrapper.1:cross-exe-wrapper.in
+       pod2man --name cross-exe-wrapper $< > $@
+cross-exe-test:cross-exe-test.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $<
+clean:
+       $(RM) -- *-cross-exe-wrapper cross-exe-wrapper.1 cross-exe-test
diff --minimal -Nru architecture-properties-0.1.1/cross-exe-test.c 
architecture-properties-0.1.1+nmu1/cross-exe-test.c
--- architecture-properties-0.1.1/cross-exe-test.c      1970-01-01 
01:00:00.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/cross-exe-test.c 2024-08-02 
00:21:54.000000000 +0200
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void die(const char *message) __attribute__((noreturn))
+{
+       fprintf(stderr, "error: %s\n", message);
+       exit(2);
+}
+
+int main(void)
+{
+       char buff[1024];
+       char cmd[1024];
+       FILE *prog;
+       char *s;
+
+       /* Guess whether we are run in emulation by resolving /proc/self/exe
+        * and matching its basename against our expected program name. We need
+        * to fork another non-emulated process to avoid getting our readlink
+        * syscall emulated too well and assume that coreutils' readlink is not
+        * emulated.
+        */
+       snprintf(cmd, sizeof(cmd), "readlink -n /proc/%d/exe", getpid());
+       prog = popen(cmd, "r");
+       if (!prog)
+               die("failed to spawn readlink");
+       if (!fgets(buff, sizeof(buff), prog))
+               die("failed to read output of readlink");
+       if (pclose(prog))
+               die("readlink failed");
+       s = strrchr(buff, '/');
+       if (s)
+               ++s;
+       else
+               s = buff;
+       return !!strcmp(s, "cross-exe-test");
+}
diff --minimal -Nru architecture-properties-0.1.1/cross-exe-wrapper.in 
architecture-properties-0.1.1+nmu1/cross-exe-wrapper.in
--- architecture-properties-0.1.1/cross-exe-wrapper.in  1970-01-01 
01:00:00.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/cross-exe-wrapper.in     2024-08-02 
00:21:54.000000000 +0200
@@ -0,0 +1,60 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+: <<'POD2MAN'
+=head1 NAME
+
+<gnu-triplet>-cross-exe-wrapper - Run an executable using CPU emulation if 
needed
+
+=head1 SYNOPSIS
+
+<I<gnu-triplet>>B<-cross-exe-wrapper> <I<executable>> [I<options>]
+
+=head1 DESCRIPTION
+
+<I<gnu-triplet>>B<-cross-exe-wrapper> can be used to wrap a program compiled 
the architecture designated by its prefix in GNU triplet form.
+If the CPU happens to be able to run the program directly, it is run without 
emulation.
+The personality(2) of the execution environment is adjusted if necessary.
+The first argument must be a full path to the target executable.
+All further arguments are forwarded to the target executable.
+
+=head1 SEE ALSO
+
+L<qemu-user(1)>, L<qemu-user-static(1)>, L<personality(2)>
+
+=cut
+POD2MAN
+
+if test "$(dpkg --print-architecture)" = #DEB_HOST_ARCH#; then
+       exec "$@"
+fi
+
+cross_exe_test_output=$(/usr/lib/#DEB_HOST_MULTIARCH#/cross-exe-wrapper/cross-exe-test
 2>&1)
+cross_exe_test_result=$?
+if test "$cross_exe_test_result" = 0; then
+       case #DEB_HOST_ARCH# in
+               amd64|x32)
+                       exec setarch linux64 -- "$@"
+               ;;
+               armel|armhf|i386|mipsel|powerpc|sparc)
+                       exec setarch linux32 -- "$@"
+               ;;
+       esac
+       exec "$@"
+fi
+
+if test "$cross_exe_test_result" = 2; then
+       echo "$cross_exe_test_output" >&2
+       exit 126
+fi
+
+if command -v qemu-#DEB_HOST_ARCH# >/dev/null; then
+       exec qemu-#DEB_HOST_ARCH# -- "$@"
+fi
+
+if command -v qemu-#DEB_HOST_ARCH#-static >/dev/null; then
+       exec qemu-#DEB_HOST_ARCH#-static -- "$@"
+fi
+
+echo "$0: failed to locate emulator for #DEB_HOST_ARCH#" >&2
+exit 126
diff --minimal -Nru architecture-properties-0.1.1/debian/changelog 
architecture-properties-0.1.1+nmu1/debian/changelog
--- architecture-properties-0.1.1/debian/changelog      2022-12-19 
21:52:18.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/debian/changelog 2024-08-02 
00:21:54.000000000 +0200
@@ -1,3 +1,10 @@
+architecture-properties (0.1.1+nmu1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * Add cross-exe-wrapper package and supporting packages.
+
+ -- Helmut Grohne <hel...@subdivi.de>  Fri, 02 Aug 2024 00:21:54 +0200
+
 architecture-properties (0.1.1) unstable; urgency=medium
 
   * Upload to unstable.
diff --minimal -Nru architecture-properties-0.1.1/debian/control 
architecture-properties-0.1.1+nmu1/debian/control
--- architecture-properties-0.1.1/debian/control        2022-12-14 
14:57:33.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/debian/control   2024-08-02 
00:21:54.000000000 +0200
@@ -3,7 +3,7 @@
 Priority: optional
 Maintainer: Architecture Properties Maintainers 
<achitecture-propert...@packages.debian.org>
 Uploaders: Niels Thykier <ni...@thykier.net>,
-Build-Depends: debhelper-compat (= 13)
+Build-Depends: debhelper-compat (= 13), perl:any
 Rules-Requires-Root: no
 Standards-Version: 4.6.1
 Vcs-Git: https://salsa.debian.org/debian/architecture-properties.git
@@ -26,3 +26,51 @@
  in build-dependencies to simplify management of architecture
  support.
 
+Package: native-architecture
+Architecture: all
+Multi-Arch: no
+# Due to being M-A:no, this package can only ever satisfy native architecture
+# dependencies and that quite precisely is its purpose. Its Multi-Arch value
+# must not change even if the hinter says so.
+Description: Declarative native architecture constraint
+ This is a meta package that can only satisfy a dependency for the
+ native architecture. The native architecture is defined as the
+ architecture of the dpkg package by the Multi-Arch specification. By
+ depending on native-architecture, a client package can prevent its
+ installation for a non-native architecture.
+
+Package: native-architecture-is
+Architecture: any
+Multi-Arch: foreign
+Depends: native-architecture
+Provides: native-architecture-is-${DEB-HOST-ARCH}
+# Due to the dependency on native-architecture, this package can only ever be
+# installed for the native architecture. The native instance of this package
+# can always be installed. A dependency on native-architecture-is is thus
+# always satisfiable and thereby meaningless. The benefit of this package
+# arises from its Provides where the architecture constraint is lifted into the
+# package name.
+Description: Declarative native architecture assertions
+ This is a meta package that can be used to assert that a particular
+ architecture is native. The native architecture is defined as the
+ architecture of the dpkg package by the Multi-Arch specification. By
+ depending on e.g. native-architecture-is-amd64, a client package can
+ prevent its installation unless the native architecture is amd64.
+
+Package: cross-exe-wrapper
+Architecture: any
+Multi-Arch: same
+Depends:
+ ${shlibs:Depends},
+ native-architecture | native-architecture-is-amd64 [i386] | 
native-architecture-is-x32 [i386] | native-architecture-is-armhf [armel] | 
native-architecture-is-mips64el [mipsel] | native-architecture-is-ppc64 
[powerpc] | native-architecture-is-sparc64 [sparc] | qemu-user | 
qemu-user-static,
+# The dependency ensures that either the architecture we use for installing is
+# the native architecture or the native architecture is sibling architecture of
+# the package architecture that is known to reliably run its code or a qemu is
+# installed. For instance, native-architecture-is-arm64 [armhf] is missing as
+# some recent arm64 CPUs no longer run 32bit code. The alternatives also ensure
+# that e.g. no qemu is required for installing cross-exe-wrapper:i386 on amd64
+# as we can reliably run i386 executables there without emulation.
+Description: Wrapper for executing binaries from other architectures
+ Provide a tool ${DEB_HOST_GNU_TYPE}-cross-exe-wrapper that can be
+ used to run ${DEB_HOST_ARCH} ELF executables on the current CPU
+ employing emulation technology if required.
diff --minimal -Nru architecture-properties-0.1.1/debian/copyright 
architecture-properties-0.1.1+nmu1/debian/copyright
--- architecture-properties-0.1.1/debian/copyright      2022-12-14 
13:01:30.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/debian/copyright 2024-08-02 
00:21:54.000000000 +0200
@@ -1,7 +1,9 @@
 Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 
 Files: *
-Copyright: 2022 Niels Thykier <ni...@thykier.net>
+Copyright:
+ 2022 Niels Thykier <ni...@thykier.net>
+ 2024 Helmut Grohne <hel...@subdivi.de>
 License: GPL-2+
  The full text of the GPL version 2 is distributed in
  /usr/share/common-licenses/GPL-2 on Debian systems.
diff --minimal -Nru 
architecture-properties-0.1.1/debian/cross-exe-wrapper.install 
architecture-properties-0.1.1+nmu1/debian/cross-exe-wrapper.install
--- architecture-properties-0.1.1/debian/cross-exe-wrapper.install      
1970-01-01 01:00:00.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/debian/cross-exe-wrapper.install 
2024-08-02 00:21:54.000000000 +0200
@@ -0,0 +1,2 @@
+${DEB_HOST_GNU_TYPE}-cross-exe-wrapper usr/bin
+cross-exe-test usr/lib/${DEB_HOST_MULTIARCH}/cross-exe-wrapper/
diff --minimal -Nru 
architecture-properties-0.1.1/debian/cross-exe-wrapper.links 
architecture-properties-0.1.1+nmu1/debian/cross-exe-wrapper.links
--- architecture-properties-0.1.1/debian/cross-exe-wrapper.links        
1970-01-01 01:00:00.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/debian/cross-exe-wrapper.links   
2024-08-02 00:21:54.000000000 +0200
@@ -0,0 +1 @@
+usr/share/man/man1/cross-exe-wrapper.1.gz 
usr/share/man/man1/${DEB_HOST_GNU_TYPE}-cross-exe-wrapper.1.gz
diff --minimal -Nru 
architecture-properties-0.1.1/debian/cross-exe-wrapper.manpages 
architecture-properties-0.1.1+nmu1/debian/cross-exe-wrapper.manpages
--- architecture-properties-0.1.1/debian/cross-exe-wrapper.manpages     
1970-01-01 01:00:00.000000000 +0100
+++ architecture-properties-0.1.1+nmu1/debian/cross-exe-wrapper.manpages        
2024-08-02 00:21:54.000000000 +0200
@@ -0,0 +1 @@
+cross-exe-wrapper.1
diff --minimal -Nru architecture-properties-0.1.1/debian/rules 
architecture-properties-0.1.1+nmu1/debian/rules
--- architecture-properties-0.1.1/debian/rules  2022-12-14 13:03:02.000000000 
+0100
+++ architecture-properties-0.1.1+nmu1/debian/rules     2024-08-02 
00:21:54.000000000 +0200
@@ -1,9 +1,11 @@
 #!/usr/bin/make -f
 
+include /usr/share/dpkg/architecture.mk
+
 %:
        dh $@
 
 execute_before_dh_gencontrol:
        echo "DEB-HOST-ARCH-BITS=$(DEB_HOST_ARCH_BITS)" >> 
debian/architecture-properties.substvars
        echo "DEB-HOST-ARCH-ENDIAN=$(DEB_HOST_ARCH_ENDIAN)" >> 
debian/architecture-properties.substvars
-
+       echo "DEB-HOST-ARCH=$(DEB_HOST_ARCH)" >> 
debian/native-architecture-is.substvars

Reply via email to