Nodejs doesn't cross-compile to non-executable hostPlatform

Hi there!

I am trying to build an image for a Raspberry Pi Zero (armv6l), for which I need to cross compile nodejs. However, when I attempt to do so, I get

error: builder for '/nix/store/lj5a6bdgs27px64znz7qh1ba842jqanz-nodejs-14.18.2-armv6l-unknown-linux-gnueabihf.drv' failed with exit code 2;
    last 10 log lines:
    >     with Popen(*popenargs, **kwargs) as p:
    >   File "/nix/store/vz8vr9zfabpdg42kbdd90mmvb67mfl9a-python3-3.9.9/lib/python3.9/subprocess.py", line 951, in __init__
    >     self._execute_child(args, executable, preexec_fn, close_fds,
    >   File "/nix/store/vz8vr9zfabpdg42kbdd90mmvb67mfl9a-python3-3.9.9/lib/python3.9/subprocess.py", line 1821, in _execute_child
    >     raise child_exception_type(errno_num, err_msg, err_filename)
    > OSError: [Errno 8] Exec format error: '/build/node-v14.18.2/out/Release/bytecode_builtins_list_generator'
    > make[1]: *** [tools/v8_gypfiles/generate_bytecode_builtins_list.target.mk:13: /build/node-v14.18.2/out/Release/obj/gen/generate-bytecode-output-root/builtins-generated/bytecodes-builtins-list.h] Error 1
    > make[1]: *** Waiting for unfinished jobs....
    > rm 65187b8ab07b214501a28dca107f055b52f95b34.intermediate 1c6ac65e4e7785fe756e577f45a7385d163a3560.intermediate
    > make: *** [Makefile:109: node] Error 2
    For full logs, run 'nix log /nix/store/lj5a6bdgs27px64znz7qh1ba842jqanz-nodejs-14.18.2-armv6l-unknown-linux-gnueabihf.drv'.

That is, the build system is trying to run the Python interpreter for my target system (armv6l), not my build system. Naturally this won’t work. I thought I could solve this by adding an override that sets the right value for the Python3 interpreter, like so:

nixpkgs.overlays = [
  (self: super: lib.optionalAttrs (super.stdenv.hostPlatform != super.stdenv.buildPlatform) {
    nodejs-14_x = super.nodejs-14_x.override { python3 = self.python3; };
  })
];

but with this I run into a different error:

error: builder for '/nix/store/w5mbyalvza6lnhinaggshm5jhbf2mc7n-nodejs-14.18.2-armv6l-unknown-linux-gnueabihf.drv' failed with exit code 2;
    last 10 log lines:
    > ./tools/update-cares.sh: interpreter directive changed from "#!/bin/sh" to "/nix/store/pbfraw351mksnkp2ni9c4rkc9cpp89iv-bash-5.1-p12/bin/sh"
    > ./tools/update-eslint.sh: interpreter directive changed from "#!/bin/sh" to "/nix/store/pbfraw351mksnkp2ni9c4rkc9cpp89iv-bash-5.1-p12/bin/sh"
    > ./tools/update-npm.sh: interpreter directive changed from "#!/bin/sh" to "/nix/store/pbfraw351mksnkp2ni9c4rkc9cpp89iv-bash-5.1-p12/bin/sh"
    > updateAutotoolsGnuConfigScriptsPhase
    > Updating Autotools / GNU config script to a newer upstream version: ./deps/cares/config.sub
    > Updating Autotools / GNU config script to a newer upstream version: ./deps/cares/config.guess
    > configuring
    > fixing libtool script ./deps/cares/ltmain.sh
    > configure flags: --prefix=/nix/store/pdbx0q4mw2fnlm6vi8zvhdqn8clha34f-nodejs-14.18.2-armv6l-unknown-linux-gnueabihf --shared-libuv --shared-libuv-libpath=/nix/store/cyk3lvzymyvxib55kn3by872k6q38phc-libuv-armv6l-unknown-linux-gnueabihf-1.42.0/lib --shared-openssl --shared-openssl-libpath=/nix/store/35fss5dnnr3bsi2afzalb27mcyvb7kyq-openssl-armv6l-unknown-linux-gnueabihf-1.1.1m/lib --shared-zlib --shared-zlib-libpath=/nix/store/1nca1r5x7czqj6nmf9rnkla2ys32qm2c-zlib-1.2.11-armv6l-unknown-linux-gnueabihf/lib --with-intl=system-icu --without-dtrace --cross-compiling --without-intl --without-snapshot --with-arm-fpu=vfp --dest-cpu=arm
    > /nix/store/is0ffn164nqsry9rw87iirqxiz3xqr9d-python3-armv6l-unknown-linux-gnueabihf-3.9.9/bin/python3.9: line 1: syntax error: unexpected word (expecting ")")
    For full logs, run 'nix log /nix/store/w5mbyalvza6lnhinaggshm5jhbf2mc7n-nodejs-14.18.2-armv6l-unknown-linux-gnueabihf.drv'.

This is an error from the shell, most likely due to an invalid shebang. Not sure how I can fix that :stuck_out_tongue:

I also attempted setting the Python interpreter to self.python3.pythonForBuild.interpreter; (which solved a similar but different issue) but then I still get

error: builder for '/nix/store/9k3ni4s2zwz3p4gyl6aahmribkh9h8q0-nodejs-14.18.2-armv6l-unknown-linux-gnueabihf.drv' failed with exit code 126;
    last 1 log lines:
    > /nix/store/17pcj16ms6apv4mhaksgiay152rzmghx-stdenv-linux/setup: line 522: source: /nix/store/vz8vr9zfabpdg42kbdd90mmvb67mfl9a-python3-3.9.9/bin/python3.9: cannot execute binary file
    For full logs, run 'nix log /nix/store/9k3ni4s2zwz3p4gyl6aahmribkh9h8q0-nodejs-14.18.2-armv6l-unknown-linux-gnueabihf.drv'.

so I don’t think this is right.

How can I fix this problem? I’m a bit lost in how to override for cross compilation :smiley:

I think I am running into this Github issue here. That is, it’s not the Python interpreter that’s the problem – it’s the bytecode_builtins_list_generator binary that is executed by a Python script.

Whenever exec format errors like this come up, you need to make sure the executed binaries are taken from the buildPackages.

If they’re in nativeBuildInputs, this gets done automatically but if they’re overridden at callPackage, that can prevent the magic detection from happening. You might need to do things like python = buildPackages.python in such cases.

It’s not the Python interpreter that’s the problem. The nodejs build procedure compiles a binary that is necessary to generate code; that binary is compiled for the target platform rather than the build platform. It looks like buildroot fixes that by compiling nodejs for the build platform first, and then using those binaries when compiling for the target platform: buildroot/nodejs.mk at 5030d7f4ea5004b24025eb93d421ddadb0f8ee06 · buildroot/buildroot · GitHub

You can get binaries for the build platform by using buildPackages. That’s precisely what I meant.

This won’t help you, as you already pointed out that the interpreter is not the problem. Though, I’d like to add as reference for others stumbling across related problems:

  • python.interpreter points to the interpreter for the (target) host and
  • python.pythonForBuild.interpreter points to the interpreter for the … building host