-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Add tested uclibc target #35242
Add tested uclibc target #35242
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
@@ -0,0 +1,29 @@ | |||
# x86_64-unknown-linux-uclibc configuration | |||
CC_x86_64-unknown-linux-uclibc=$(CFG_UCLIBC_ROOT)/bin/uclibc-gcc |
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 think CFG_UCLIBC_ROOT is not defined anywhere?
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.
Is there a way that I can error the build out if the variable CC_x86_64-unknown-linux-uclibc
is not set in this 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.
Probably. FWIW, the convention is to set these variables to x86_64-linux-uclibc-gcc
(no unknown
component) and the user is supposed to make x86_64-linux-uclibc-gcc
somehow (usually by symlinks somewhere in PATH).
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, I'll fix it.
target_pointer_width: "64".to_string(), | ||
arch: "x86_64".to_string(), | ||
target_os: "linux".to_string(), | ||
target_env: "uclibc".to_string(), |
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.
The libc
crate doesn't know about target_env = uclibc
so I guess would be mostly empty?
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 believe I will need to add that to the libc crate.
Cross compilation targets are tested with the buildbots not with Travis. @KennethAdamMiller By the way, did you manage to test this new target with libc-test? We don't have proper tests for cross targets in rust-lang/rust (we only test cross compiling std for them). Being able to cross compile std for a target doesn't mean that the target correctly works in all cases. Testing with libc-test will reveal how much of libc will have to be updated (constants, function signatures, etc) to properly support this new target. |
No, but I most certainly will. I am retesting in a docker instance locally for the requested changes. While I don't think the few tiny commits that I made should break things, you can never know until you test. I'll let you know when I'm done with some libc testing. I appreciate your comments and support enormously! |
Ok, so I tested the rustc compiler against some libc functions, and it at least fully compiles them. I'll be booting up some uclibc bzImages to test the results in there. At the same time, I am working on a buildroot feature/rust-v5 instance so that we can test this further. |
The new type expected from each target is now TargetResult, which I didn't expect to change. This fixes the compile error.
Why? Do we really want to have builtin targets for every possible libc implementation out there? I’m totally fine with making changes to the makefiles/rustbuild to ease compiling your own rustc with uclibc, though. |
As far as I know, there are only three main libc implementations available, and they serve different purposes. Uclibc is a micro libc implementation designed at least for embedded devices whose hardware may not have a mmu. Musl is even smaller than uclibc, but aims for a very very minimal code base and absolutely no other dependencies. They aren't the same, and they suit discrete software development purposes. I'd be really surprised if everybody who wants rust for its safety and for the market it is aiming for just decided to switch their entire build environment, like yocto or buildroot (which can be gigabytes), just because someone thought it was tacky to obey the fundamental motivation that was behind llvm this entire time-retargetability with only the machine specifics that are pertinent to the architecture desired. That's a huge win, and rust wants to be a systems engineering language. This targetability is like a fundamental thesis, sort of, for what rust is meant to do. Why wouldnt you offer users the ability to easily target their desired environment triples? If you do what you're talking about for generating the code needed for target triples, we'll probably get some result that might work for a few architectures, but we have no guarantee as to what to generate in regards to specifiable retargetability remaining uniform or regular. This point is especially true because the rust compiler code will change a lot, in which case testing it would be about the same as keeping the target. These files are miniscule and seem to be working so far in allowing me to get a cross compiler with uclibc working. Are they really so much of a burden? And furthermore, do you think what I have tested and working will produce less groans than going down the route of expecting users to know what internal values to put for specifying the requirements of a target? Because I certainly think that asking users for that would just result in a headache for each side. Also, I got the target environment set to "uclibc" and it compiled just fine, even with an external call to some libc functions, as I said earlier. |
I think it's not currently possible to use either build system (Makefiles or rustbuild) to build @nagisa didn't mean that "Rust shouldn't support uclibc" but rather than there may be other ways to support it without adding a built-in target (and presumably having binary releases for it).
Just compiling them is not a a test at all; you have to actually run them to verify their |
I’m not telling we shouldn’t allow this particular libc to be used. I’m asking whether µclibc is relevant enough to expand the matrix of our built-in targets with it. The way I see it, you probably won’t be running rustc itself on your mmu-less system, and all you’d care about is having a libcore/libstd. Why, then, having a custom json target specification and compiling your own libcore/std is not enough? Is there more than a dozen of people who will be actively using this target? If not, who will maintain it? Why only the x86_64 target and not i686 too?
does not work? If it doesn’t, we probably should fix it. |
Ah, not quite (yet). It doesn't produce the same artifacts as rustbuild. In particular, |
@japaric | 'nagisa didn't mean that "Rust shouldn't support uclibc"' Oh! I apologize for the misunderstanding. I hope I wasn't abrasive anywhere within, but I will admit I was rather aghast at what I thought I read. | "Just compiling them is not a test at all" Ok, I'll be running those tests as soon as I find out how. @nagisa "... I’m asking whether µclibc is relevant enough to expand the matrix of our built-in targets with it." Well, in all honesty, I think that using musl would suit the interests that are behind my side better, because it is smaller. MUSL vs uclibc is a debate that only libc authors on each side would be well versed enough to really answer. :/ So it's hard for me to justify irrefutably which suits our interests more, even though I can look up quite a lot about each. They both seem to work really well, and I'm sure if I switched over to musl things would work. The one gotcha here is that must-rust does not support dynamic library targets. This dynamic linking ability is pretty much a hard requirement for our ends, since we want to call out to rust code from many other languages. I have a parallel task going to try and get a musl rust build to deliver dynamic shared libraries, but I want to execute it in lower priority. @nagisa | "Is there more than a dozen of people who will be actively using this target?" It is expected that this solution that I am developing will be in use for years to come on a very well funded project. On another note, so long as all the necessary components can be generated in an environment like buildroot, and the configurations can be saved so that combinations of the respective triples can be specified by the user and have a build functioning reliably, I'm not against the buildroot user's building their own toolchains from scratch. This is done at least once for the gcc bootstrap that it provides. The question that I have is, what are the difficulties of maintaining an extra libc target specification? How bad is it to just let travis build the binaries that are needed for a std or bootstrapped rustc, and just distribute it? I'm ok with adopting more of the burden of maintaining the libc target for rust that makes sense for our ends, so long as, provided guidance, I can accomplish it. @nagisa | "Why only x86_64..."? Well, I'm not against doing the other platforms, but I think that it would be good to get support for one going in order that I know the ends and outs. Then I'll add support for any others that I can test for, but I don't think I have hardware for anything other than x86_32 and x86_64 |
IIRC, to run the libc-test test suite you only have to |
Ah! Ok. On Aug 4, 2016 3:57 PM, "Jorge Aparicio" [email protected] wrote:
|
Oh man, thanks so much for the PR @KennethAdamMiller! I'm personall a fan of accepting basically whatever targets we can into the compiler and source tree so long as they don't come with an undue maintenance burden. Here it looks like the "burden" is quite small, if at all, so I'm down for adding a new target! As I'm sure @japaric has mentioned a bunch and you've found out as well, adding a well tested target isn't easy though! We have multiple tiers of support for various targets, so adding a new one doesn't require we set up CI, infrastructure, etc, per se. I'd imagine that the steps for this would look like:
I'd recommend taking @japaric's advice and avoiding adding makefile support for now, rustbuild should be more than sufficient for building this target (and it's also more easily configurable). We can go ahead and land that and then update the libc repo with fixes for constants and such once it's ready to go as well. |
I think this case is analogous to #35427. Just like existing OpenEmbedded Rust support only supports make and not rustbuild, existing Buildroot Rust support only supports make and not rustbuild. |
@alexcrichton Thanks Alex. Sorry for the wait, I just had to drive to Texas (16 hrs), as this is my break and I'm visiting family. I do plan to kick off a buildroot build with the bzImages and I have some bzImages I was going to run in QEMU to test libc-test at the same time. I'm pretty sure I need globally consistent bzImages, linked by the same compiler, but the uclibc version hasn't changed, so it's possible that running a binary that dynamically loads, built by a different compiler version, will not introduce it's own headaches anyway. I have to get the buildroot builds going anyway, as it's a parallel task. That means the whole nightly process with the update of rust-lang and rust-buildroot is effectively what I am going for. | super far down the road. I have about two weeks to be able to deliver a working rustc cross compiler that links with uclibc. I don't have to use all the components of libc, to be honest, so long as we have a binary we know reliably works for our ends we'll be ok. But it is very important to be able to get this minimally functional very fast. I will of course devote my time to guarantee further down the road that more improvements can come, but I really need this to be functional. I am fine with using rustbuild within buildroot, and I think that since I already have a working script to pull from, integrating it with buildroot shouldn't be too hard. The output binaries just need to be consistent with the target system. How do I replicate the process of packaging up the standard libraries so that I can have a cargo that has the extra std part and that builds with just the --target spec? Also, cargo build --target=x86_64-unknown-linux-uclibc complains of unavailable std, but I know that the standard library was compiled. It must be some setting that I'm missing with cargo in order to tell it where the standard libraries are. I have the rustup commands from japaric, but I think I'm missing something. |
@KennethAdamMiller no worries! And to be clear when I say "super far down the road" for testing artifacts I just mean that it's a pretty significant infrastructure investment on our part. Producing nightlies is relatively cheap, but gating all commits on a new platform is a pretty big hammer. Also for us to easily produce nightlies it'll be best to go through rustbuild rather than the makefiles as well because many of our nightlies go through that I believe. I'd also be pretty stoked to see a well tested and new in-production target in the compiler, so that'd be awesome! So let's say the next step for landing this PR is to get the following to work:
How does that sound? I think that at minimum this PR is missing updates to liblibc as well as updates to the build system to statically link uclibc (I think it'll be statically linked, right?). |
| Also for us to easily produce nightlies it'll be best to go through rustbuild rather than the makefiles ... I agree, and I'm going to do what I can to improve the buildroot rust system to use that. That's awesome that we're on the same page about our excitement for it, because I basically am being paid to add this. The next step is actually already passing, and those commands complete just fine. But I can't get the liblibc tests to compile because cargo can't find the standard libraries. I was asking about how to point cargo toward them and how to build them because of that error, because until I know how, I can't move forward. I did find @japaric's repositories for helping to cross compile std, and landed on using xargo. I tried that, and xargo seemed to be skipping the step that I needed it to perform, which is build and cache a std for uclibc. The only steps I've followed for setting my rustc instance is the rustup commands that are in japaric's script;
I went back over the steps he gave me, and it would seem that the python bootstrap.py command should have built the std for uclibc target, since that seems to be what the command settings are. Since what xargo tries to do behind the scenes, which is set the sysroot, I tried to find all sysroot folders with a command, | How does that sound? I think that at minimum this PR is missing updates to liblibc as well as updates to the build system to statically link uclibc (I think it'll be statically linked, right?). Well, it sounds good, but I could make the merge request more comprehensive and will move forward with that as soon as I can get std and core cross compiled. In any case, I really really need the ability to dynamically link with uclibc, and for the rustc compiler to spit out some .so files, because I'm aiming for being able to write rust code and have other languages call through to it. I don't need static compilation with uclibc at all as far as I know. |
@KennethAdamMiller I had similar problems using stage 1 rustc. |
The way I'd recommend doing this is:
Lots of modifications are likely going to be needed to liblibc to get anything to compile, but you can follow the same pattern as musl most likely! I wouldn't worry too much about xargo and/or link-local in rustup just yet. Initially bootstrapping a target from zero is likely going to be easiest if you just work out of the build directory as you'll be modifying all the source all the time.
Sounds good to me! Targets today just choose whether they're most appropriate, and so your choice seems fine to me :) |
@KennethAdamMiller also feel free to reach out to me on IRC (I'm |
Pretty cool @KennethAdamMiller. With uclibc we'll pretty much cover all the libc's that matter. I wouldn't expect the maintenance burden to be particularly great here. Most of the work is in the libc crate. |
@nagisa @alexcrichton I'll try both Thanks, Alex, for the offer. @brson Thanks, I hope to add a helping hand in making sure that liblibc compiles. How much work do you think is entailed in getting liblibc working with uclibc? |
@alexcrichton Ok, so I ran the steps you gave me, they all succeeded in very short order. I'm not fully certain though, that my settings on the docker instance that I'm using were in fact fully correct; I think I had changed the rustup default. But I'm not sure that that should make a difference since we had set the target for the output by the configure and bootstrap.py commands. I'm pretty sure that I want a cross compiler from gnu to uclibc, and that I'll get it with the settings that I have, which is @nagisa I have that command you gave for getting a complete sysroot running, and I'll try and set the environment variable according to the way xargo should have whenever it completes. @japaric I think xargo didn't set try to build the uclibc std and core because the rustc that I was using was the rustc built for cross compiling according to the instructions you gave me. On the xargo page, it says that it ignores compiling for the platforms that are supported, in which case rustup should be used. So, I'm thinking that the rustc cross compiler has confused it into not doing it, since uclibc is probably seen as supported now. |
@KennethAdamMiller Xargo is not the right tool to use here. For starters, it only works with a nightly rustc and you like have a "dev" rustc. Also, it will compile a few standard crates that live "below" std from scratch. This is not what you want to do. You want to use the std crates you've already built using rustbuild. I'd suggest rustup or the commands Alex posted. |
Ok, well, I left my machine building the stage 2 command that should give Basically, I have to have the std and core done before I can continue my On Aug 8, 2016 3:32 PM, "Jorge Aparicio" [email protected] wrote:
|
Does uclibc strive for binary compatibility with glibc? I'm a little surprised that this PR along is enough to bootstrap uclibc, I'd have guessed that there'd be a lot of changes to constants/structs and such in liblibc b/c otherwise Once you have a bootstrapped target though you can run libc-test to verify either way. |
Well, my thinking was that, there'd be no reasonable libc author that would change the value of a particular enum or some such from the advertised interface that is standard. What motivation would there be for them to alter the value of an enum item from the norm, aside from careless reordering? I can't think of any. In terms of the internals of the library, it would of course be free game. Official binary compatibility is addressed here, where they state that binary compatibility is not even an attempt. So it may be that I've not fully specified somehow, and the toolchain is linking incorrectly. Or it could be my rustup setting, I'm not certain. We'll just have to see when I get the buildroot build completed and the libc tests run a QEMU instance. |
As it turns out, I thought I had left it with the command that @nagisa left me, but it was actually the command that Alex gave me. In any case, I ran both to completion, because I need to have a complete compiler before I can move forward, with std and the core for building for uclibc, because my buildroot has to run to the finish, and I have buildroot packages that need a uclibc rustc to compile for it. @nagisa That command you gave did not produce another folder to match "sysroot" in my build directory. I'm wondering if I should have included --target=x86_64-unknown-linux-uclibc, but I'm pretty sure that that would be effectively premature, and that the compilation being performed needs to produce a compiler that runs on gnu and produces uclibc linked binaries. Cargo is still complaining of lack of a std, and although it appears that a stage1-std folder was compiled, (and also that in fact that a stage2 as well) I don't know how to get cargo to look there for std. So, my buildroot packages that use rust can't be built, and therefore I can't get a complete bzImage to work with. I will disable my packages for the time being in order to allow the bzImage to build, in which case I can run the libc tests, but in either the case that I don't have libc working or my buildroot things aren't complete for our purposes. I also tried adding a stage2 with rustup, according to the script japaric gave, those two rustup commands, first to link and then to set the default to stage2, but that didn't help. |
There is actually a surprising amount of variation among libc definitions even on the same platform and architecture. Keeping them all straight requires a lot of effort, but the libc crate has some sophisticated regression testing to do so. A key insight perhaps is that what the C standard defines for the most part is the source interface, while the actual binary interface can involve some sneaky shenanigans that have to be encoded into the Rust libc crate (just as an example, the actual integer value of many constants will differ slightly between implementations). Some parts of the libc crate are also not particularly well specified by any standard and vary wildly from one implementation to the next, though |
So, I was able to get a stage2 working after about 15 minutes when I came back to the keyboard from a couple days break. I got my software compiled, but then ran into some issues while trying to build the libc tests:
In addition, I wanted to post the ldd output of the .so file that has been produced in one of my projects. Does this appear correct?
|
Oh, actually I got past those with a fork of alexcrichton/ctest and think that I got to the real issues, and libc-test is certainly not passing. Probably, what caused my previous build with Alex's commands to run to completion was the lack of a target set in ~/.cargo/config for uclibc. Then the linker would trivially default back to linking with host gcc. |
@KennethAdamMiller ah for that problem in ctest you'll need to update this block and then update the commit used in libc-test via
The "not found" is a little worrisome, especially when "libc.so.6" is also in there (which I think is glibc?). I don't know what a "good" uclibc binary looks like though, so this may be normal |
I updated, but I started getting problems with things being undefined wrt the headers from crosstool-ng vs what rust expects, since I'm using it as the linker. So I've kind of moved on, and I found where a lot of the missing pieces would be in terms of the header files, but then when I included them, I got naming conflicts. It may be because of a GNU define that had been being passed to the compiler with glibc, but that that the particular code block is being missed because the parameters to build.rs are different. The not found part is probably (I mean I hope anyway) going to be because the ldd command wasn't run within the QEMU environment. |
I'm just chugging through now, is what I mean, I had updated just before I posted: "Oh, actually I got past those with a fork..." |
@alexcrichton So, I got a bit further with the libc-test compilation, but I'm still having that problem where the cross compile is linking with both uclibc and libc, as per the output I had given you some time back. Is there any way that we could debug this together? I don't think that I can ship this code without a fix for that. |
@KennethAdamMiller unfortunately I don't know anything about uclibc so I may not be of much help to debug that issue :( |
☔ The latest upstream changes (presumably #35769) made this pull request unmergeable. Please resolve the merge conflicts. |
@alexcrichton Well, the libc-tests are complaining about a lot of undefined references. In particular, there is a lot of constants that have to do with locale. Is there any way that I could disable the tests from being generated for locale? I tried to do so by removing the line cfg.header("locale.h") from the file src/liblibc/libc-test/build.rs first by putting a guard around it for uclibc and then by commenting it out entirely. The tests still generate references to locale; I think probably because some other headers include locale in a kind of inter-dependency thing. So I tried to build a crosstool that had locale support in order that, when the cross compiler would be invoked, it would have the necessary references. That didn't work, but really because crosstool doesn't try to support that. The crosstool mailing list pointed me toward using a buildroot internal cross compiler since they have that. But now I'm thinking that if a uclibc-mips target got merged in, that there must be something that I'm missing in trying to compile the libc-tests with the cross compiler that I'm doing wrong. Can or should I disable locale centric generated tests in the libc-tests? |
If locale is optional in uclibc. I would start by having libc not expose functions/contants related to locale for uclibc targets and just test everything else. Later, locale support can be added behind a Cargo feature for uclibc targets; locale for uclibc would then be tested if that Cargo feature is enabled. |
Well, I tried to comment out cfg.header("locale.h"), but that didn't stop the references from being made and therefore link errors. How do I disable locale centric tests from being generated then? | By having libc not expose functions/constants related to locale for uclibc targets... As in select/deselect that in the crosstool configuration? The thing is that they aren't selected in crosstool, and when I would select it, it gave me errors related to locale where en_US wasn't detected while trying to build a cross compiler. |
I don't know
I meant in libc itself. Simply "cfg" it away with |
@KennethAdamMiller these references are being generated because there's code in liblibc that's exporting them. That is, the ctest crate is testing that the API of a crate matches the C API on the other side. Basically what needs to happen here is that liblibc today will expose a certain API when compiled for uclibc. That API is most likely wrong and/or incomplete (as it's just matching other C libraries). It needs to be trimmed down and corrected to match uclibc wherever possible. You can do this by reorganizing the contents of the liblibc crate in the same manner they're organized today. It's fine to modify the liblibc crate as much as you need, it just needs to not delete exports found on other platforms! And yes you'll likely need to modify the |
@alexcrichton I thought the tests were auto generated by the headers and that if something weren't exported by a libc then the header would just either not be there or not contain it. That's what I thought the cfg.header part was about, it was adding things per libc implementation. The build was failing on the compilation of the auto generated .c file however, so that's why I thought that it had to do with the cfg.header part within build.rs, since the .c file is generated from that. Ok, I'll go back and try and work on things that way then. |
Ok, so after rebuilding with buildroot's internal cross compiler, I made significant progress in that I was both able to obtain correct ldd output and I was able to run a shared object in a buildroot build image with QEMU, which ended up calling out to the kernel through libc. So, at least a good portion works correctly. I still have some changes to the tests that I need to push up and will continue altering. I haven't had the chance to devote much time to the tests because they are lower in priority, but I intend to do them. |
Closing due to inactivity, but feel free to resubmit with a rebase! |
Hi
I've been working with Japaric on a uclibc target, and I've tested it locally quite a bit, as he has, and used his script to build a working rust cross compiler. The only difference in steps there and in this branch is that the environment variables exported need to be added to the
~/.bashrc
of the mentionedrust
user. It's rather straight forward in fact.If I am correct, I'll be asked to update the nightly build and travis configuration, which I am totally down for, but if I could please get acceptance requirements regarding that and any demands for further changes up front that would help. This way, I give what is wanted, and the travis build can be altered to add uclibc target testing; otherwise, the merge would go in build passing, but with this code untested in order that others can see verification of it working. Further, I think it beneficial that I add files for alternative uclibc architectures since I've already done this, I can test and replicate the targets quickly in order to deliver more for others. But before I do that, I need to test further with travis and rust-buildroot, so I want to leave those for later steps.