-
-
Notifications
You must be signed in to change notification settings - Fork 15k
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
Make cross-compiling with the crossSystem argument work #18386
Make cross-compiling with the crossSystem argument work #18386
Conversation
No more mutual importing between top-level/default.nix and top-level/stdenv.nix. Instead of having stdenv.nix import default.nix, we will have default.nix construct the allPackages function and pass it as an argument to stdenv.nix. No more use of misleading names "self" and "super" in stdenv.nix. Those names have a specific meaning given to them by lib.extend, which did not apply. Incorporate all topLevelArguments into allPackages. Previously, allPackages used default values for bootStdenv, noSysDirs, crossSystem, and platform, ignoring the values passed by the user to default.nix. That behavior seemed surprising and likely to cause bugs, so I changed it. In stdenv.nix, use better indentation to make it clear that there are four basic ways to choose a stdenv.
native derivations (e.g. gcc) to change when crossSystem is specified. A common sense principle of the crossSystem argument is that its value should not affect the native derivations. Instead of using that hack, we use a smarter stdenvOverrides system that allows us to just change the nativeDrvs while leaving the crossDrvs alone. NOTE: Someone should do the same thing for the Darwin stdenv if they want to cross-compile things on Darwin.
gcc5: - Make it so crossSystem and libcCross do not affect the native compiler. - NOTE: We should do this for the other gcc versions too. gccCrossStageStatic, gccCrossStageFinal: - Use the real stdenv instead of using bootstrap tools. Bootstrap tools are a threat to the purity of the Nix system, so we should only use them to build the stdenv and nothing else. Also, this seemed to fix a configure error I was getting with cross glibc for the Raspberry Pi. - Explicitly disable langObjC and langObjCpp. glibcCross: - Use the real stdenv instead of using bootstrap tools. libcCross1: - Move the logic for picking this so it is closer to libcCrossChooser. libiconv: - Choose the nativeDrv and crossDrv independently so that the crossSystem does not affect the nativeDrv. At this point, cross-compiling seems to work fine. I tested it by applying nix-build to this expression: rec { myNixpkgsFunc = import ./nixpkgs; myNixpkgs = myNixpkgsFunc {}; baseNixpkgsFunc = import ((import <nixpkgs> { }).fetchFromGitHub { owner = "NixOS"; repo = "nixpkgs"; rev = "d4eac0278ca188aa236b6a7f0fbb15f8ee4273d0"; sha256 = "0mpx6bjvix7dfmgn6a2chmmicamz9v941fki0lgzfk2gw90fqg6w"; }); baseNixpkgs = baseNixpkgsFunc {}; myTestsPass = (import ./nixpkgs/test/cross_system.nix).testsPass; gcc6Same = myNixpkgs.gcc6 == baseNixpkgs.gcc6; gcc5Same = myNixpkgs.gcc5 == baseNixpkgs.gcc5; gcc49Same = myNixpkgs.gcc49 == baseNixpkgs.gcc49; gcc48Same = myNixpkgs.gcc48 == baseNixpkgs.gcc48; gcc45Same = myNixpkgs.gcc45 == baseNixpkgs.gcc45; gccSame = gcc6Same && gcc5Same && gcc49Same && gcc45Same; testsPass = myTestsPass && gccSame; derivations = rec { recurseForDerivations = assert testsPass; true; rpiCrossSystem = { config = "armv6l-unknown-linux-gnueabi"; bigEndian = false; arch = "arm"; float = "hard"; fpu = "vfp"; withTLS = true; libc = "glibc"; platform = myNixpkgs.platforms.raspberrypi; openssl.system = "linux-generic32"; gcc = { arch = "armv6"; fpu = "vfp"; float = "softfp"; abi = "aapcs-linux"; }; }; rpiPkgs = myNixpkgsFunc { crossSystem = rpiCrossSystem; }; rpiHello = rpiPkgs.hello.crossDrv; }; }
argument does not affect native derivations.
@DavidEGrayson, thanks for your PR! By analyzing the annotation information on this pull request, we identified @nbp, @shlevy and @errge to be potential reviewers |
I'll also ping @viric because it sounds like he was doing cross-compiling. |
Also @dezgeg, @Ericson2314, @rasendubi |
I will take a look at this tomorrow but you may be interested in #15043 and Ericson2314@ee2a484 |
# want to avoid a meaningless mass rebuild. These variables get | ||
# overridden via crossAttrs in an actual cross-build. | ||
// { crossMingw = false; crossStageStatic = 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.
So this is only required one time for the transition? If yes I think we should remove and deal with one mass-rebuild 😉
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 thought that adding this would make it simpler and easier for my pull request to be merged, and it also helped me ensure that I did not accidentally screw something up. I used Nix assertions to assert that the native GCC 5 in my pull request and in the upstream commit it is based on are the same 😉.
This is kind of a subjective decision, so I would mainly be concerned with what the people in charge of nixpkgs think. @groxxda, do you have the authority to merge my pull request?
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 in the position to merge but nixpkgs is a community project and I consider myself part of the community just like any other contributor 😉
This is my subjective view:
Avoiding a single mass rebuild does not weight out the cons of "dead code" (whereas during testing it is very valid), and one mass rebuild is not a blocker for pull requests to get merged.
Since we only need this code to make the test work, it should be moved into the test file.
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 instances in the past where we chose to do a mass rebuild so we could remove one line of dead code?
Also, does your subjective opinion change if I point out that the recipe for GCC 5 will be deleted some day when nothing depends on it any more?
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.
This can be merged with an update that requires a mass-rebuild on it's own so the extra cost could be minimal.
This line needs to be duplicated into every gcc expression that should be asserted inside the tests, right? Imo that's an even stronger argument for moving it inside the tests file and make it generic.
For me it's as simple as: If you only need it for the tests, put it inside the tests file.
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's only needed to make my outside-of-tree tests pass and to avoid a mass rebuild. The tests in the tree would not be able to detect that a mass rebuild is happening because they only look at the current commit of nixpkgs. The tests in the tree just make sure that a few native derivations don't get changed when crossSystem is specified.
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 also in favor of mass rebuild here. Mass-rebuild patches are merged into staging, so they don't disturb normal flow much.
Also if we consider the fact that we'll remove that dead code in the future, that will cause mass rebuild anyway. Don't see any reason to wait.
@Ericson2314 I haven't looked in detail at your pull request but it's good to see that some other people care about getting cross-compiling to work. In my pull request, I wanted to avoid the circular importing between I can see my pull request touches only 7 files compared to the 16 files touched in #15043 , and my pull request actually does make cross-compiling work, so I hope we can get it merged in faster. 🙏 |
Please don't get me wrong, I'm really 👍 to see this merged, since as far as I can tell cross compilation is broken and most of the other work got stale before it was ready to merge. |
@DavidEGrayson Do you know if anyone who has had cross-compilation working in the past now sees it failing? Note that it's definitely worked before, even if it doesn't currently, so it may just be something documented wrong. |
@DavidEGrayson did you take into account the bootstrap phases? the stdenvs themselves still call all packages, so as far as I can tell the importing in both directions occurs. I'd agree that let's just get something merged at this point, but I believe insofar that you do attack the circular imports stuff, we fix it in opposite ways. I believe mine patch does fix cross-compiling, full stop, but I haven't tested this in a while. There is also no mass rebuild risk with mine I believe, but perhaps I haven't done enough work on cross compiling itself? |
@shlevy In my experience it does work, but there is pointless rebuilding currently. |
@shlevy: No I don't, but I'll try to look. Maybe I'll try to figure out how to build |
@Ericson2314: Yes, the What do you mean when you say there is no mass-rebuild risk? You're talking about your own pull request? |
@DavidEGrayson on the second part, yeah, talking about my own. |
@rasendubi: This pull request moves nixpkgs closer to the point that you would want it to be, right? So would you support merging the pull request as is? (After this gets merged, you could make a small pull request where you argue for the mass-rebuild.) |
CC @vcunat and @Mathnerd314, who were interested in these sort of things. |
I'm looking at the commits in detail now. |
@DavidEGrayson I like the first two commits and the tests, for sure. I think the 3rd commit may be better addressed in by adding a stage to the cross stdenv like in my PR, and using |
@DavidEGrayson I'm no way blocking the pull request. Though, I don't support it (yet), as I would like to test/review it first. (Hope to do that at weekend.) |
My TODO list:
Thank you to everyone who has contributed to the discussion so far! |
about allowedRequisites that I did not write.
using a set instead of a list of strings. This is more flexible and looks nicer.
Thanks to some info from @shlevy, I have looked at But here is a concrete example of some cross-compiling issues on nixpkgs master. Suppose I check out a recent commit on master, d4eac02, and add this file in the
This file is not supposed to be valid, but it sort of emulates what I was trying to do when I first looked into cross-compiling with Nix. I was trying to compile for a new system that does not use glibc, and I needed to fetch some sources from git to support building the compiler for this system. If I run nix-build on this new file, the abridged result is:
So we can see that because of some values I chose for the crossSystem, nixpkgs thinks it needs to build a native libiconv for its native git package (when in fact it should use the libiconv features of the glibc), and it fails to build the native libiconv. When that happened, I decided that even though my crossSystem values were not completely valid, nixpkgs was behaving badly and I needed to debug nixpkgs itself to make progress. I hope you can now understand my motivation for this pull request. |
@DavidEGrayson To be clear, technically nixpkgs is not buggy but is poorly documented and has a bad interface, right? So you're improving the interface? (have not yet had time to fully review) |
@shlevy I am improving the internal interface between However, saying "nixpkgs is buggy" would be a somewhat subjective: it depends on what list of features you think nixpkgs should have. If you say that the only supported cross-compilation scenarios are the currently-passing jobs in the nixpkgs:cross-trunk jobset, then by that measure nixpkgs is not buggy, and this pull request is just adding new features. |
The GCC 5 documentation says that --with-headers is obsolete and deprecated in favor of --with-sysroot. Also, this seems to fix a problem I was having where the configure script could not find glibc's limit.h, so it did not add the administrivia at the top and bottom of include-fixed/limits.h which tell it to #include_next the real limits.h, which resulted in limits.h defining the wrong value for MB_LEN_MAX, which caused an error while cross-building coreutils.
So actually the I am still working on fixing up this pull request as described above in my TODO list. |
Hey, the https://github.com/gcc-mirror/gcc/blob/gcc-5_4_0-release/gcc/doc/install.texi#L2020-L2022 The documentation says you are supposed to use |
@DavidEGrayson 👍 on switching configure option |
… and more likely to be correct.
…as having trouble finding the headers.
My Raspberry Pi bootstrap tools (compiled from DavidEGrayson@9cedf1b ) are compiling for "armv5t" instead of "arm" for some reason, even though the compiler is named armv6l-unknown-linux-gnueabi-gcc. Debugging the cross GCC is harder than it needs to be because of this issue which I just reported: #19151 I will keep debugging it though; I am not stuck. I suppose my next step would be to see if this is just a GCC issue or also a binutils issue. |
Any news? |
Not much. But I started building a drvdiff utility to help me figure out why my Raspberry Pi cross-compiler would behave so differently than the upstream nixpkgs one (producing output for the wrong ARM architecture). |
@DavidEGrayson @bjornfor My company is offering sponsored on-demand ARM64 hardware if you're interested in testing your build on AARCH64. WE can support standard CI tools to deploy the hosts automatically, etc, so DM me if you're in need of access for NIX. |
Status on this? Please ping me when you think this is ready |
The status of this pull request is still the same as last time: I am (slowly) working on this drvdiff utility so I can efficient debug why my cross toolchain would compile for the wrong ARM architecture when I try to compile "hello" for the Raspberry Pi. Pull request #19940 has been merged recently, so this pull request will need some work to avoid conflicts when we finally get it working. I think the right order to do things is to get drvdiff working, figure out why this pull request did not work, fix it, and then work on rebasing the whole thing onto the latest nixpkgs master and resolving conflicts. I did some more work for this pull request back in September but I had not pushed those commits to the pull request branch because I was intending to clean them up. Well, to make it easier for other people who want to help out, I have now pushed those commits to the pull request branch (updating that branch from 873da5a to 9cedf1b). |
Here are my rough notes and test NIX expression for the GCC ARM architecture problem in case anyone wants to investigate, but I am not stuck and can probably figure it out given enough time. |
In
After your changes |
7a5dade
to
7bed7fb
Compare
because stdenv.cross is nullwhen we build the cross compiler.
7bed7fb
to
9fde656
Compare
Thanks for figuring that out, @dezgeg! After I fixed that (commit 9fde656 of this PR), I was able to successfully cross-compile a "Hello world" program for the Raspberry Pi and run it. I fixed it by changing |
I rebased this (untested though) as https://github.com/Ericson2314/nixpkgs/tree/deg-cross |
My rebase of this pull request onto a modern nixpkgs master commit is almost finished. But while testing it, I noticed that six days ago there was a change that broke 31 of the cross-compilation jobs: |
I'm closing this because it's stale. Anyone interested in the changes from this pull request should discuss them in the new version of the pull request (v2) here: #21388 |
This should fix the coreutils cross building breakage: 30074dd |
Motivation for this change
I would like to be able to compile software for systems that do not have Nix. It looks like nixpkgs has a
crossSystem
argument that should allow this, but when I tried to use it, I encountered a bunch of problems.The main problem was that the
crossSystem
argument affected a bunch of native derivations, such as gcc5, so when I tried to cross-compile, Nix would needlessly try to rebuild the stdenv, and encounter some error.Another issue was that the cross compilers were built using the bootstrap tools instead of the normal stdenv, and they were built using gcc.cc.override which seems invalid to me. Fixing this issue was the final thing that allowed me to successfully cross-compile for the Raspberry Pi.
See my detailed commit messages for more info. (I actually redid the commit history before submitting this pull request to make it easy for reviewers to follow.) Thanks!
Things done
(nix.useSandbox on NixOS,
or option
build-use-sandbox
innix.conf
on non-NixOS)
nix-shell -p nox --run "nox-review wip --against d4eac027"
but its error message did not make much sense to me. It looks like it tried to evaluatelibcCross1
without specifying acrossSystem
argument, which is invalid (just like it would also be invalid to evaluate libcCross)../result/bin/
)The main way I tested this PR was by applying
nix-build
to this Nix expression. That Nix expression does several things: it ensures that the gcc5 in my pull request does not get affected by the crossSystem argument. It also ensures that my pull request does not affect any native GCC derivations, so we will not need a mass rebuild. It also compiles the "hello" package for the Raspberry Pi.Future work
test
should be automatically run by Hydra. I do not know how to set that up.