Skip to content
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

Closed

Conversation

KennethAdamMiller
Copy link

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 mentioned rust 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.

@rust-highfive
Copy link
Collaborator

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
Copy link
Member

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?

Copy link
Author

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?

Copy link
Member

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).

Copy link
Author

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(),
Copy link
Member

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?

Copy link
Author

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.

@japaric
Copy link
Member

japaric commented Aug 3, 2016

If I am correct, I'll be asked to update the nightly build and travis configuration

Cross compilation targets are tested with the buildbots not with Travis. We @alexcrichton will have to set up a build job to test this. We'll have to update the linux-cross Dockerfile to add a uclibc cross toolchain (I can do that).

@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.

@KennethAdamMiller
Copy link
Author

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!

@KennethAdamMiller
Copy link
Author

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.
@nagisa
Copy link
Member

nagisa commented Aug 3, 2016

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.

@KennethAdamMiller
Copy link
Author

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.

@japaric
Copy link
Member

japaric commented Aug 4, 2016

@nagisa

Why? Do we really want to have builtin targets for every possible libc implementation out there?

I think it's not currently possible to use either build system (Makefiles or rustbuild) to build std for "custom" targets (i.e. from a x86_64-unknown-linux-uclibc.json file). Though that feature would suffice for this use case.

@KennethAdamMiller

@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).

Ok, so I tested the rustc compiler against some libc functions, and it at least fully compiles them.

Just compiling them is not a a test at all; you have to actually run them to verify their libc definition is correct. If the definitions are not correct the binaries will segfault or flat out misbehave, but testing it this way it's hard to tell if the binary is behaving correctly and also it's too time consuming. The libc-test test suite can verify the correctness of the libc definitions in a much easier and faster way.

@nagisa
Copy link
Member

nagisa commented Aug 4, 2016

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?

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?


@japaric

I think it's not currently possible to use either build system (Makefiles or rustbuild) to build std for "custom" targets (i.e. from a x86_64-unknown-linux-uclibc.json file).

cd src/libstd
cargo build --target=<whatever you want>

does not work? If it doesn’t, we probably should fix it.

@japaric
Copy link
Member

japaric commented Aug 4, 2016

cargo build --target=
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, libcompiler-rt.a is missing. #35021 should fix that, but only for targets whose triple looks very similar to existing built-in targets -- this uclibc target should work once that PR lands.

@KennethAdamMiller
Copy link
Author

@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

@japaric
Copy link
Member

japaric commented Aug 4, 2016

Ok, I'll be running those tests as soon as I find out how.

IIRC, to run the libc-test test suite you only have to cd libc-test && cargo build --target $TARGET on the host system, copy the produced binary to the target system and run that binary on the target system.

@KennethAdamMiller
Copy link
Author

Ah! Ok.

On Aug 4, 2016 3:57 PM, "Jorge Aparicio" [email protected] wrote:

Ok, I'll be running those tests as soon as I find out how.

IIRC, to run the libc-test test suite you only have to cd libc-test &&
cargo build --target $TARGET on the host system, copy the produced binary
to the target system and run that binary on the target system.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#35242 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/ACUb3ldxdeZ1w6fkEXGFjmMNm4UjgoS2ks5qckQrgaJpZM4JbzyU
.

@alexcrichton
Copy link
Member

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:

  • First, we land this target in-tree to get you bootstrapping and working easily.
  • Next, we get libc-test compiling and running successfully, and then upstream those changes to the rust-lang/rust repo
  • At this point if you build from source you should be able to get a uclibc target, but we can optionally go farther and produce nightly binaries as well, which looks like:
    • Update one of the rust-lang/rust-buildbot images with all build tools needed
    • Update the buildbot configuration in rust-lang/rust-buildbot to add a new nightly target
    • Rebuild images and deploy buildbot configuration changes
    • Wait for a nightly to succeed
  • If that all happens then we also have the option of running tests on every commit for the target. This is probably super far down the road though, so I'm not sure I'd recommend planning for it yet.

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.

@sanxiyn
Copy link
Member

sanxiyn commented Aug 7, 2016

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.

@KennethAdamMiller
Copy link
Author

@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.

@alexcrichton
Copy link
Member

alexcrichton commented Aug 8, 2016

@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:

./configure --target=x86_64-unknown-linux-uclibc --enable-rustbuild
make
echo 'fn main() {}' > foo.rs
./build/x86_64-unknown-linux-gnu/stage2/bin/rustc foo.rs --target x86_64-unknown-linux-uclibc

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?).

@KennethAdamMiller
Copy link
Author

| 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;

rustup toolchain link stage1 build/x86_64-unknown-linux-gnu/stage1
rustup default stage1

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, find ~/build -name "*sysroot*" and it pulled up only a stage0-sysroot, where there is a std built, but which is not the version that I need, since it's the rustc compiler used to build my version.

| 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.

@nagisa
Copy link
Member

nagisa commented Aug 8, 2016

@KennethAdamMiller I had similar problems using stage 1 rustc. python bootstrap.py --stage 1 --step libstd should give you a fully working sysroot. If all else fails, you may also try python bootstrap.py --stage 2 --step rustc (you cannot compile anything in stage 2 without a fully functional stage1 compiler)

@alexcrichton
Copy link
Member

@KennethAdamMiller

But I can't get the liblibc tests to compile because cargo can't find the standard libraries.

The way I'd recommend doing this is:

./configure --enable-rustbuild --target=x86_64-unknown-linux-uclibc

# Rinse and repeat this command until the compile of libstd works will likely require
# local modifications to liblibc and libstd
python src/bootstrap/bootstrap.py --stage 1 --step libtest --target x86_64-unknown-linux-uclibc

# Build the standard library for the host
python src/bootstrap/bootstrap.py --stage 1 --step libtest --target x86_64-unknown-linux-gnu

# point Cargo at that compiler
export RUSTC=`pwd`/build/x86_64-unkown-linux-gnu/stage1/bin/rustc

# Get liblibc tests working
cd path/to/libc/libc-test
cargo run --target x86_64-unknown-linux-uclibc

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.

In any case, I really really need the ability to dynamically link with uclibc

Sounds good to me! Targets today just choose whether they're most appropriate, and so your choice seems fine to me :)

@alexcrichton
Copy link
Member

@KennethAdamMiller also feel free to reach out to me on IRC (I'm acrichto) and I can try to help you debug problems in real time as they come up

@brson
Copy link
Contributor

brson commented Aug 8, 2016

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.

@brson brson added the relnotes Marks issues that should be documented in the release notes of the next release. label Aug 8, 2016
@KennethAdamMiller
Copy link
Author

@nagisa @alexcrichton I'll try both python bootstrap.py --stage 2 --step rustc and Alex's instructions and get back with the results.

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?

@KennethAdamMiller
Copy link
Author

@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 rustup default nightly. I can change it to rustup default stage in case I'm wrong.

@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.

@japaric
Copy link
Member

japaric commented Aug 8, 2016

@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.

@KennethAdamMiller
Copy link
Author

Ok, well, I left my machine building the stage 2 command that should give
me a sysroot. Ill let you know what the results are when it's done.

Basically, I have to have the std and core done before I can continue my
buildroot build, since I need the bzImage it will generate to line up with
the same uclibc so that the libc tests line up with the environment.

On Aug 8, 2016 3:32 PM, "Jorge Aparicio" [email protected] wrote:

@KennethAdamMiller https://github.com/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.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#35242 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/ACUb3kD1fESZRrN0rhCxycgA6CGSnar4ks5qd4Q8gaJpZM4JbzyU
.

@alexcrichton
Copy link
Member

@KennethAdamMiller

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 target_env = "uclibc" will end up compiling the glibc bindings I think.

Once you have a bootstrapped target though you can run libc-test to verify either way.

@KennethAdamMiller
Copy link
Author

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.

@KennethAdamMiller
Copy link
Author

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.

@brson
Copy link
Contributor

brson commented Aug 9, 2016

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.

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 std only relies on a small, common subset of libc so it wouldn't be too surprising if it basically appears to work, even if a lot of details are bogus.

@KennethAdamMiller
Copy link
Author

KennethAdamMiller commented Aug 12, 2016

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:

rust@563768380f6b:~/rust/src/liblibc/libc-test$ cargo build --target=x86_64-unknown-linux-uclibc
   Compiling libc v0.1.12
   Compiling libc v0.2.14 (file:///home/rust/rust/src/liblibc)
   Compiling bitflags v0.3.3
   Compiling gcc v0.3.28
   Compiling winapi v0.2.6
   Compiling log v0.3.6
   Compiling winapi-build v0.1.1
   Compiling unicode-xid v0.0.3
   Compiling kernel32-sys v0.2.2
   Compiling rustc-serialize v0.3.19
   Compiling term v0.2.14
   Compiling syntex_syntax v0.19.1
   Compiling ctest v0.1.0 (https://github.com/alexcrichton/ctest#a6becb6d)
   Compiling libc-test v0.1.0 (file:///home/rust/rust/src/liblibc/libc-test)
error: failed to run custom build command for `libc-test v0.1.0 (file:///home/rust/rust/src/liblibc/libc-test)`
process didn't exit successfully: `/home/rust/rust/src/liblibc/libc-test/target/debug/build/libc-test-daf5ba52955de10b/build-script-build` (exit code: 101)
--- stderr
thread 'main' panicked at 'unknown os/family width: x86_64-unknown-linux-uclibc', /home/rust/.cargo/git/checkouts/ctest-2cf90b4dc49563d8/master/src/lib.rs:791
note: Run with `RUST_BACKTRACE=1` for a backtrace.



rust@563768380f6b:~/rust/src/liblibc/libc-test$ RUST_BACKTRACE=1 cargo build --target=x86_64-unknown-linux-uclibc
   Compiling libc-test v0.1.0 (file:///home/rust/rust/src/liblibc/libc-test)
error: failed to run custom build command for `libc-test v0.1.0 (file:///home/rust/rust/src/liblibc/libc-test)`
process didn't exit successfully: `/home/rust/rust/src/liblibc/libc-test/target/debug/build/libc-test-daf5ba52955de10b/build-script-build` (exit code: 101)
--- stderr
thread 'main' panicked at 'unknown os/family width: x86_64-unknown-linux-uclibc', /home/rust/.cargo/git/checkouts/ctest-2cf90b4dc49563d8/master/src/lib.rs:791
stack backtrace:
   1:     0x7f43fdb214cd - std::sys::backtrace::tracing::imp::write::hb62d33c95f81ee87
   2:     0x7f43fdb287f1 - std::panicking::default_hook::_{{closure}}::h984c8a8683e109de
   3:     0x7f43fdb27a99 - std::panicking::default_hook::h99544c6f1463c3a6
   4:     0x7f43fdb280ba - std::panicking::rust_panic_with_hook::h4c9bf4384c12710c
   5:     0x7f43fdb27f72 - std::panicking::begin_panic::h4dfbfe1d1e09435b
   6:     0x7f43fdb27ea0 - std::panicking::begin_panic_fmt::h4e62fd66a38d7059
   7:     0x7f43fd6195df - ctest::default_cfg::he26fe8398e914530
                        at /home/rust/.cargo/git/checkouts/ctest-2cf90b4dc49563d8/master/src/lib.rs:8
   8:     0x7f43fd616be1 - ctest::TestGenerator::_generate_files::h6f1fafd9c082fca5
                        at /home/rust/.cargo/git/checkouts/ctest-2cf90b4dc49563d8/master/src/lib.rs:628
   9:     0x7f43fd616083 - ctest::TestGenerator::generate_files::h75f1b6fca14356cc
                        at /home/rust/.cargo/git/checkouts/ctest-2cf90b4dc49563d8/master/src/lib.rs:598
  10:     0x7f43fd6155f5 - ctest::TestGenerator::_generate::h8a208e6161ffbf61
                        at /home/rust/.cargo/git/checkouts/ctest-2cf90b4dc49563d8/master/src/lib.rs:553
  11:     0x7f43fd5c67de - ctest::TestGenerator::generate::hbf4b58da33afc291
                        at /home/rust/.cargo/git/checkouts/ctest-2cf90b4dc49563d8/master/src/lib.rs:549
  12:     0x7f43fd5ca818 - build_script_build::main::h72505fc50186b65e
                        at /home/rust/rust/src/liblibc/libc-test/build.rs:449
  13:     0x7f43fdb27dc7 - std::panicking::try::call::ha4131bda48c7b34e
  14:     0x7f43fdb2e786 - __rust_maybe_catch_panic
  15:     0x7f43fdb27259 - std::rt::lang_start::hef67681f86ca295c
  16:     0x7f43fd5ccae3 - main
  17:     0x7f43fcfd382f - __libc_start_main
  18:     0x7f43fd5bf248 - _start
  19:                0x0 - <unknown>

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?

    linux-vdso.so.1 =>  (0x00007ffe997ca000)
    libdl.so.1 => not found
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f6a13bfa000)
    libpthread.so.1 => not found
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f6a139e4000)
    libc.so.1 => not found
    ld64-uClibc.so.1 => not found
    libm.so.1 => not found
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f6a137c7000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6a133fe000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f6a1420a000)

@KennethAdamMiller
Copy link
Author

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.

@alexcrichton
Copy link
Member

@KennethAdamMiller ah for that problem in ctest you'll need to update this block and then update the commit used in libc-test via cargo update -p libc-test

Does this appear correct?

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

@KennethAdamMiller
Copy link
Author

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.

@KennethAdamMiller
Copy link
Author

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..."

@KennethAdamMiller
Copy link
Author

@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.

@alexcrichton
Copy link
Member

@KennethAdamMiller unfortunately I don't know anything about uclibc so I may not be of much help to debug that issue :(

@bors
Copy link
Contributor

bors commented Aug 18, 2016

☔ The latest upstream changes (presumably #35769) made this pull request unmergeable. Please resolve the merge conflicts.

@KennethAdamMiller
Copy link
Author

@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?
Are there any steps I'm missing in trying to compile libc-tests?

@japaric
Copy link
Member

japaric commented Aug 20, 2016

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.

@KennethAdamMiller
Copy link
Author

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.

@japaric
Copy link
Member

japaric commented Aug 20, 2016

Well, I tried to comment out cfg.header("locale.h")

I don't know ctest well enough but if I had to guess I'd say you want to use cfg.skip_fn and cfg.skip_const somehow. @alexcrichton should be able to give you better advise though!

As in select/deselect that in the crosstool configuration?

I meant in libc itself. Simply "cfg" it away with cfg(not(target_env = "uclibc")).

@alexcrichton
Copy link
Member

@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 build.rs of libc-test to just avoid headers files on uclibc if they don't exist, and that's totally ok! The intent of liblibc is to match the current platform, not be cross platform in any way shape or form.

@KennethAdamMiller
Copy link
Author

@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.

@KennethAdamMiller
Copy link
Author

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.

@alexcrichton
Copy link
Member

Closing due to inactivity, but feel free to resubmit with a rebase!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
relnotes Marks issues that should be documented in the release notes of the next release.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants