-
-
Notifications
You must be signed in to change notification settings - Fork 14.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nodejs: fix cross compilation for armv7l #220204
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we truly need to force a 32-bit build system, I think a cleaner way to do it would be to do it in the callPackage
invocation. Then we could just do something like
nodejs = (if stdenv.buildPlatform.isx86_64 && stdenv.is32bit then pkgsi686Linux else pkgs).callPackage …
which is nice because then there's one less package set involved in the actual expression, and it prevents adding 64-bit dependencies as well by mistake.
Either way, this needs a comment explaining what's going on, with a link to documentation or reference to the source code so people can understand what's going on, and where to check to see if it can be removed.
I tweaked it a bit. It is probably reasonable requirement.
I added comment but I am unable to find that this is actually required in the documentation. At the same time build really fails with missing 32bit stubs and thus it for sure tries to use 32bit build somewhere inside. The upstream builds it on Ubuntu and thus they might expect that 32bit libraries are just available while that is not the case with nixpkgs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but I'd really like there to be an upstream issue about this. They shouldn't be passing -m32 to the native compiler just because they're cross compiling for 32 bit.
I only just now saw this, but I do wonder if it may also be fixed by #238377? |
@lilyinstarlight I just tested it, and it doesn't help my issue. The issue here is with cross-compilation from amd64 to 32-bit systems. Node requires bitness to match it seems, and for that reason, we need to build it not in an amd64 environment but instead in an x86 one. I suspect that, especially on new Macs that do not have 32-bit arm support (if I remember correctly) it won't even be possible to cross-compile Node to armv7l. |
I create an issue upstream but I am not expecting much nodejs/node#48612. This is a common issue I saw with other bytecode compilers (for example luajit). |
FWIW I think this is the relevant code that sets -m32 when cross-compiling in your case. host_cxx_is_biarch is defined at https://github.com/nodejs/node/blob/3205b1936a5c3c21b0c8c568a57b0d2bada366b1/tools/v8_gypfiles/toolchain.gypi#L107-L118 That is, it assumes that x86(-64) (and some other systems) have bi-arch capable toolchains (probably for a reason, see below, but maybe not, this is technical decision is really weird). With the following patch, we successfully get a meaningful error (instead of vague compilation failure due to the missing headers) that leads us to https://github.com/nodejs/node/blob/3205b1936a5c3c21b0c8c568a57b0d2bada366b1/deps/v8/include/v8config.h#L863-L892 (or diff --git a/tools/v8_gypfiles/toolchain.gypi b/tools/v8_gypfiles/toolchain.gypi
index 26c6866fa9..658ebd6e86 100644
--- a/tools/v8_gypfiles/toolchain.gypi
+++ b/tools/v8_gypfiles/toolchain.gypi
@@ -109,7 +109,7 @@
host_arch=="s390x" or \
clang==1', {
'variables': {
- 'host_cxx_is_biarch%': 1,
+ 'host_cxx_is_biarch%': 0,
},
}, {
'variables': {
So this seems like an issue with v8 rather than Node.js. At this point I don’t really want to dive deeper into this rabbit hole 🥲 |
@Cynerd Could you rebase and resolve merge conflicts on this? If this is what we have to do, I'm mostly alright with this, but it is rather unfortunate |
Yes, should be targeting staging given the number of rebuilds. |
Rebase and retargeting is done (I am not sure if GitHub sends an email about it). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any changes from the buildroot patch? Can we use fetchpatch2
to fetch the patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No changes in the end. I will switch it to fetchpatch.
@@ -126,7 +127,8 @@ let | |||
|
|||
pos = builtins.unsafeGetAttrPos "version" args; | |||
|
|||
inherit patches; | |||
patches = patches | |||
++ (lib.optional isCrossBitness ./add-qemu-wrapper-support.patch); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m not really a fan of conditional patches. Can we apply the patch unconditionally (and replace MAYBE_WRAPPER
with an empty string if we are not using an emulator)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.. in my eyes, it makes it a bit more complex, but ok. There is also an option to just always use a wrapper because, for the native build, it will work as well.
sed -i "s%@MAYBE_WRAPPER@%'<(PRODUCT_DIR)/v8-qemu-wrapper',%g" node.gyp | ||
sed -i "s%@MAYBE_WRAPPER@%'<(PRODUCT_DIR)/v8-qemu-wrapper',%g" tools/v8_gypfiles/v8.gyp | ||
mkdir -p out/Release | ||
cat > out/Release/v8-qemu-wrapper << "EOF" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I think a symlink should be enough? IIRC emulator contains additional arguments iff canExecute
. Is it the case here?
nixpkgs/lib/systems/default.nix
Lines 285 to 295 in 5d49679
if pkgs.stdenv.hostPlatform.canExecute final | |
then "${pkgs.runtimeShell} -c '\"$@\"' --" | |
else if final.isWindows | |
then "${wine}/bin/wine${optionalString (final.parsed.cpu.bits == 64) "64"}" | |
else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux && final.qemuArch != null | |
then "${qemu-user}/bin/qemu-${final.qemuArch}" | |
else if final.isWasi | |
then "${pkgs.wasmtime}/bin/wasmtime" | |
else if final.isMmix | |
then "${pkgs.mmixware}/bin/mmix" | |
else null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, OK.
nix-repl> (lib.systems.elaborate "x86_64-linux").canExecute (lib.systems.elaborate "i686-linux")
true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah for i686 it needs to be a script.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I’ve opened PR #324071 to make an emulator a simple executable path in native case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With that it should be possible to use only just symlink 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we proceed with this PR and update it just once #324071 is merged. It should be later only a minor change in postPath
. What do you think?
CC_host = "cc"; | ||
CXX_host = "c++"; | ||
CC_host = if isCrossBitness then "${stdenv.cc.targetPrefix}cc" else "cc"; | ||
CXX_host = if isCrossBitness then "${stdenv.cc.targetPrefix}c++" else "c++"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we using $NIX_CC
instead of $NIX_CC_FOR_BUILD
in this case? If we don’t need C compiler for build platform, perhaps it makes sense to omit depsBuildBuild
entirely if isCrossBitness
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it should be possible to just drop depsBuildBuild
in case of isCrossBitness
.
Would it even make sense to always use this magic for cross-compilation and not just when bitness differed? The issue with isCrossBitness
is that as far as I can see, this is only extraction for the Nix-supported platforms, but as you linked, v8 actually supports only limited build platforms not actually matching bitness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it even make sense to always use this magic for cross-compilation and not just when bitness differed?
Yes, sounds reasonable to me. Always using an emulator instead of cross-compiling should make Node.js build faster, see also #321847.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is now converted to build always with the patch and with wrapper.
I tested it on amd64 and cross build from amd64 to armv7.
This needs a rebase. |
The v8 library supports only limited number of build platforms based on the host architecture. The rule there is the bitness (the mixing of 32bit and 64bit architectures seems to be in most cases disallowed). Thus this adds usage of the emulator of the host platform and builds tools for that.
patches = patches ++ [ | ||
(fetchpatch2 { | ||
name = "add-qemu-wrapper-support.patch"; | ||
url = "https://github.com/buildroot/buildroot/raw/ecf060a2ff93626fb5fbe1c52b8d42b6ee0fbb5b/package/nodejs/nodejs-src/0001-add-qemu-wrapper-support.patch"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub repository is a mirror, the official Git repository is at https://gitlab.com/buildroot.org/buildroot.
url = "https://github.com/buildroot/buildroot/raw/ecf060a2ff93626fb5fbe1c52b8d42b6ee0fbb5b/package/nodejs/nodejs-src/0001-add-qemu-wrapper-support.patch"; | |
url = "https://gitlab.com/buildroot.org/buildroot/-/raw/ecf060a2ff93626fb5fbe1c52b8d42b6ee0fbb5b/package/nodejs/nodejs-src/0001-add-qemu-wrapper-support.patch"; |
@@ -180,14 +195,14 @@ let | |||
pushd out/Release/obj.target | |||
find . -path "./torque_*/**/*.o" -or -path "./v8*/**/*.o" | sort -u >files | |||
${if stdenv.buildPlatform.isGnu then '' | |||
ar -cqs $libv8/lib/libv8.a @files | |||
$AR -cqs $libv8/lib/libv8.a @files |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I’m not sure why this line is conditional. I thought Nixpkgs bintools wrapper handled response files, but maybe that’s not the case here for some reason? I’ll have to double-check that.
@Cynerd, I’ve made a few minor adjustments based on this PR and re-implemented buildroot patch in 42fa83e (0001-nodejs-fix-cross-compilation-for-armv7l.patch) so that the emulator trick is upstreamable. What do you think? |
I am ok with that. I tried to compile it and ti seems to work so I would go with your solution. |
Note for reviewers: #327653 contains commits from this PR (with slight modifications, see above) and goes further on top of these changes to use ninja for build. @Cynerd, would it be OK to close this PR (since you’ve approved ninja PR)? |
@tie Yes. This can be closed. |
Description of changes
The cross build for armv7l requires build to be on i686 (32bit in general). This ensures that and thus fixes build for armv7l.
I am not happy with this solution but I am unable to figure out how to fix cross compilation for amv7l in better way than this.
Things done
sandbox = true
set innix.conf
? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)