Subject: [bug#74343] [PATCH 0/1] Fix cross-compilation for isc-dhcp

From: Christoph Buck <[email-masked]>
Date: Wed, 13 Nov 2024 13:30:09 +0100

Hi!

Cross-compiling isc-dhcp from x64 to arm32 is broken as you can see
below (output shortend to include only the relevant information)

--8<---------------cut here---------------start------------->8---
icepic@G16-Buck ~/guix/src/guix [env]$ ./pre-inst-env guix describe
Git checkout:
  repository: /home/icepic/guix/src/guix/
  branch: master
  commit: b10ce47d8be5b6c15987f4e1d93b3bd71b1eb220
  
./pre-inst-env guix build --target=arm-linux-gnueabihf isc-dhcp -K
[...]
phase `post-configure' succeeded after 0.5 seconds
starting phase `patch-generated-file-shebangs'
patch-shebang: ./bind/bind-9.11.37/contrib/dnsperf-2.1.0.0-1/contrib/queryparse/queryparse: warning: no binary for interpreter `python' found in $PATH
phase `patch-generated-file-shebangs' succeeded after 0.1 seconds
starting phase `update-config-scripts-for-bind'
phase `update-config-scripts-for-bind' succeeded after 0.0 seconds
starting phase `build'
Making all in ./bind
make[1]: Entering directory '/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind'
/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37 already unpacked...
Configuring BIND libraries for DHCP.
Building BIND libraries - this takes some time.
Building isc library in /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/isc
/gnu/store/ylgkrq9j1gyfig2y66srmgsbyh9w20d9-binutils-2.41/bin/ar: `u' modifier ignored since `D' is the default (see `U')
/gnu/store/ylgkrq9j1gyfig2y66srmgsbyh9w20d9-binutils-2.41/bin/ar: `u' modifier ignored since `D' is the default (see `U')
Building dns library in /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns
make[3]: *** [Makefile:601: include/dns/enumtype.h] Error 1
make[2]: *** [Makefile:595: include] Error 2
Building isccfg library in /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/isccfg
In file included from /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/isccfg/include/isccfg/aclconf.h:24,
                 from aclconf.c:24:
/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/types.h:230:10: fatal error: dns/enumtype.h: No such file or directory
  230 | #include <dns/enumtype.h>       /* Provides dns_rdatatype_t. */
      |          ^~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [Makefile:239: aclconf.o] Error 1
Building irs library in /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/irs
In file included from /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/tsig.h:28,
                 from /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/client.h:45,
                 from context.c:28:
/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/types.h:230:10: fatal error: dns/enumtype.h: No such file or directory
  230 | #include <dns/enumtype.h>       /* Provides dns_rdatatype_t. */
      |          ^~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [Makefile:237: context.o] Error 1
Installing BIND libraries to /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind.
mkdir /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/include
mkdir /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/include/isc
mkdir /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/include/pk11
mkdir /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/include/pkcs11
mkdir /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/lib
make[3]: *** [Makefile:601: include/dns/enumtype.h] Error 1
make[2]: *** [Makefile:595: include] Error 2
In file included from /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/isccfg/include/isccfg/aclconf.h:24,
                 from aclconf.c:24:
/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/types.h:230:10: fatal error: dns/enumtype.h: No such file or directory
  230 | #include <dns/enumtype.h>       /* Provides dns_rdatatype_t. */
      |          ^~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [Makefile:239: aclconf.o] Error 1
In file included from /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/tsig.h:28,
                 from /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/client.h:45,
                 from context.c:28:
/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/include/dns/types.h:230:10: fatal error: dns/enumtype.h: No such file or directory
  230 | #include <dns/enumtype.h>       /* Provides dns_rdatatype_t. */
      |          ^~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [Makefile:237: context.o] Error 1
make[1]: *** [Makefile:77: bind2] Error 2
make[1]: Leaving directory '/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1/bind'
make: *** [Makefile:463: all-recursive] Error 1
error: in phase 'build': uncaught exception:
%exception #<&invoke-error program: "make" arguments: () exit-status: 2 term-signal: #f stop-signal: #f>
phase `build' failed after 14.3 seconds
command "make" failed with status 2
build process 18 exited with status 256
note: keeping build directory `/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0'
builder for `/gnu/store/havk5qmkfa6vz9f7vw794vp3n49fx21a-isc-dhcp-4.4.3-P1.drv' failed with exit code 1
--8<---------------cut here---------------end--------------->8---

>From what i understand the following goes wrong. During compilation of
the `isc-dhcp` package, the package `bind` is also build. `isc-dhcp`
includes the bind source tree but guix replaces it with a more recent
version. During the build process of `bind`, which is triggered from
`isc-dhcp` an executable named `gen` (see `lib/dns`) is compiled and
executed to generate the `dns/enumtype.h` header. Execution on `gen`
during cross-compilation however fails, because `gen` was cross-compiled
and not build for the host system where it is executed.

--8<---------------cut here---------------start------------->8---
icepic@G16-Buck:~$ file /tmp/guix-build-isc-dhcp-4.4.3-P1.drv-1/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/gen
/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-1/dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/gen: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /gnu/store/yxbip29ib6rf69pfpqsxpi8wvslm1gng-glibc-cross-arm-linux-gnueabihf-2.39/lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, with debug_info, not stripped
icepic@G16-Buck:~$
--8<---------------cut here---------------end--------------->8---

According to the documentation setting the `BUILD_CC` variable to the
native compiler should prevent this error, and indeed guilx sets this
variable in the build process. But this variable is ignored by the
`configure` script of bind.

--8<---------------cut here---------------start------------->8---
icepic@G16-Buck:/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-1$ source environment-variables
icepic@G16-Buck:/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1$ printenv | grep BUILD_CC
BUILD_CC=gcc
icepic@G16-Buck:/tmp/guix-build-isc-dhcp-4.4.3-P1.drv-0/dhcp-4.4.3-P1$ cat dhcp-4.4.3-P1/bind/bind-9.11.37/lib/dns/Makefile | grep BUILD_CC
BUILD_CC = arm-linux-gnueabihf-gcc
        ${BUILD_CC} ${BUILD_CFLAGS} -I${top_srcdir}/lib/isc/include \
--8<---------------cut here---------------end--------------->8---

Configure of bind is called with the following paramters:

--8<---------------cut here---------------start------------->8---
 $ ./configure CONFIG_SHELL=/gnu/store/3jhfhxdf6v5ms10x5zmnl166dh3yhbr1-bash-minimal-5.1.16/bin/sh SHELL=/gnu/store/3jhfhxdf6v5ms10x5zmnl166dh3yhbr1-bash-minimal-5.1.16/bin/sh --without-openssl --without-libxml2 --without-libjson --without-gssapi --disable-threads --without-lmdb --includedir=/gnu/store/qfndmj9gi31qbzl7f9b00pcylnah4pf2-isc-dhcp-4.4.3-P1/include --libdir=/gnu/store/qfndmj9gi31qbzl7f9b00pcylnah4pf2-isc-dhcp-4.4.3-P1/lib --without-python --disable-kqueue --disable-epoll --disable-devpoll --host=arm-linux-gnueabihf CC_FOR_BUILD=gcc CONFIG_SHELL=/gnu/store/3jhfhxdf6v5ms10x5zmnl166dh3yhbr1-bash-minimal-5.1.16/bin/bash SHELL=/gnu/store/3jhfhxdf6v5ms10x5zmnl166dh3yhbr1-bash-minimal-5.1.16/bin/bash --with-randomdev=/dev/random --enable-full-report
--8<---------------cut here---------------end--------------->8---

If you look closely, you can see that parameter `--host` is set to
`arm-linux-gnueabihf` but `--build` is missing.

A quick look in the configure script of bind reveals, that `BUILD_CC` is
only propagated from the env, if we are in a cross-compiling context :

--8<---------------cut here---------------start------------->8---
if test "yes" = "$cross_compiling"; then if test -z "$BUILD_CC"; then
	as_fn_error $? "BUILD_CC not set" "$LINENO" 5 fi
	BUILD_CFLAGS="$BUILD_CFLAGS" BUILD_CPPFLAGS="$BUILD_CPPFLAGS"
	BUILD_LDFLAGS="$BUILD_LDFLAGS" BUILD_LIBS="$BUILD_LIBS" else
	BUILD_CC="$CC" BUILD_CFLAGS="$CFLAGS" BUILD_CPPFLAGS="$CPPFLAGS
	$GEN_NEED_OPTARG" BUILD_LDFLAGS="$LDFLAGS" BUILD_LIBS="$LIBS" fi
--8<---------------cut here---------------end--------------->8---

And finally if we are in a cross compiled context is checked by

--8<---------------cut here---------------start------------->8---
# FIXME: To remove some day.
if test "x$host_alias" != x; then
  if test "x$build_alias" = x; then
    cross_compiling=maybe
  elif test "x$build_alias" != "x$host_alias"; then
    cross_compiling=yes
  fi
fi
--8<---------------cut here---------------end--------------->8---

in the configure script of `bind`. Since we don't have explicitly set
the `--build` parameter of the configure script, i suspect this test
fails and the `BUILD_CC` variable from the environment is not picked up.

One can test this quickly, by extending the the `--build` parameter in
the package description in admin.scm, namely

--8<---------------cut here---------------start------------->8---
(lambda _
  (substitute* "configure"
    (("--host=\\$host")
     "--host=$host_alias --build=$build_alias"))
  ;; BIND needs a native compiler because the DHCP
  ;; build system uses the built 'gen' executable.
  (setenv "BUILD_CC" "gcc")
  ;; powerpc-linux needs to be told to use -latomic.
  ,@(if (target-ppc32?)
      `((setenv "LIBS" "-latomic"))
      '()))))
--8<---------------cut here---------------end--------------->8---

And indeed, building this package description seems to fix the problem.

One thing however is suspicious. Why did cross compilation for aarch64
work? I didn't figure this out.

However, the following patch should fix this issue for arm32 and aarch64
crossbuild still works.

Christoph Buck (1):
  gnu: isc-dhcp: Fix cross compilation for arm32

 gnu/packages/admin.scm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

base-commit: 1f057603ef59c7b9c32f610a897321fd75dc4dad
-- 
2.46.0