diff mbox

rust work in progress conflicts

Message ID 20160728203144.7df4bb8c@itchy
State New
Headers show

Commit Message

Eric Le Bihan July 28, 2016, 6:31 p.m. UTC
Hi ng0, all!

Le Thu, 28 Jul 2016 08:28:18 +0000,
ng0 <ng0@we.make.ritual.n0.is> a écrit :

> ng0 <ng0@libertad.pw> writes:
[...]
>
> So I picked up rust.scm again and forgot about this thread, only a
> search for rust brought it up again.
> As this will be a long task obviously, however we finish it, can we
> file a bug on it so it is obvious that work is being done on it and
> there'll be no dual work on this?
> 
> Recently released version 1.10.0 of rust merged the
> "--disable-codegen-tests" I needed back when i worked on it.

It happens that I tried to package Rust, as an introduction to Guix.
Here is my version, inspired by the Haskell package, where Rust 1.10.0
is built, bootstrapped by a binary version of rustc 1.9.0. It uses the
"cc" wrapper trick previously presented.

Some questions, though:

1. I can compile a sample program in a guix environment created using
`guix environment gcc glibc binutils rust`, but the program
generated fails to run because libgcc_s.so.1 can not be found. How can
it be added to the environment?

2. Having a Rust compiler is cool, but having Cargo, the Rust package
manager, would be even better. Cargo is also bootstrapped, and it is
also built using zillions of crates (Rust packages) downloaded from the
Internet. How could this case be handled in Guix?

Best regards,

Comments

Andreas Enge July 29, 2016, 9:03 a.m. UTC | #1
Hello,

On Thu, Jul 28, 2016 at 08:31:44PM +0200, Eric Le Bihan wrote:
> 1. I can compile a sample program in a guix environment created using
> `guix environment gcc glibc binutils rust`, but the program
> generated fails to run because libgcc_s.so.1 can not be found. How can
> it be added to the environment?

I would suggest to replace "gcc glibc binutils" by "gcc-toolchain", which
installs a specially modified linker.

Andreas
Vincent Legoll July 29, 2016, 11:40 a.m. UTC | #2
> On Thu, Jul 28, 2016 at 08:31:44PM +0200, Eric Le Bihan wrote:
>> 1. I can compile a sample program in a guix environment created using
>> `guix environment gcc glibc binutils rust`, but the program
>> generated fails to run because libgcc_s.so.1 can not be found. How can
>> it be added to the environment?
>
> I would suggest to replace "gcc glibc binutils" by "gcc-toolchain", which
> installs a specially modified linker.

Looks like I'm not alone doing the gcc mistake. Maybe this should be explained
in the doc.

WDYT
non such July 29, 2016, 2:37 p.m. UTC | #3
Vincent Legoll <vincent.legoll@gmail.com> writes:

>> On Thu, Jul 28, 2016 at 08:31:44PM +0200, Eric Le Bihan wrote:
>>> 1. I can compile a sample program in a guix environment created using
>>> `guix environment gcc glibc binutils rust`, but the program
>>> generated fails to run because libgcc_s.so.1 can not be found. How can
>>> it be added to the environment?
>>
>> I would suggest to replace "gcc glibc binutils" by "gcc-toolchain", which
>> installs a specially modified linker.
>
> Looks like I'm not alone doing the gcc mistake. Maybe this should be explained
> in the doc.
>
> WDYT
>
> -- 
> Vincent Legoll
>

Yes, definitely from what I read and watched in the time involved here
and my own experiences.
Can you try and come up with an addition?

Thanks.
Ludovic Courtès July 29, 2016, 3:16 p.m. UTC | #4
Hello,

Eric Le Bihan <eric.le.bihan.dev@free.fr> skribis:

> It happens that I tried to package Rust, as an introduction to Guix.
> Here is my version, inspired by the Haskell package, where Rust 1.10.0
> is built, bootstrapped by a binary version of rustc 1.9.0. It uses the
> "cc" wrapper trick previously presented.

As you might have seen from previous discussions, we try hard to reduce
the number of binary blobs needed to bootstrap packages, such that we
have a full source-to-binary path that everyone can audit.
Unfortunately, this usually hard to achieve for self-hosted compilers.

Do you know what’s Rust’s bootstrapping story is?  Can we reasonably
expect to bootstrap it from source, using a series of previous Rust
versions, or using an alternative implementation?

> Some questions, though:
>
> 1. I can compile a sample program in a guix environment created using
> `guix environment gcc glibc binutils rust`, but the program
> generated fails to run because libgcc_s.so.1 can not be found. How can
> it be added to the environment?

As Andreas notes, ‘gcc-toolchain’, which includes ‘ld-wrapper’, should
fix this.

Does Rust use GCC, or just ld?

> 2. Having a Rust compiler is cool, but having Cargo, the Rust package
> manager, would be even better. Cargo is also bootstrapped, and it is
> also built using zillions of crates (Rust packages) downloaded from the
> Internet. How could this case be handled in Guix?

Assuming Cargo itself is just a regular Rust program, it should be
possible to make a Guix package of Cargo.  Then, Guix users can install
it and use it the normal way; we won’t be able to use Cargo in package
recipes though, because our package build environments purposefully
lacks network access.

Besides, I would encourage you or anyone interested to write a crate
importer, like we do for most other language packages:

  https://www.gnu.org/software/guix/manual/html_node/Invoking-guix-import.html

Having crates available as normal Guix packages is the best option for
Guix users: uniform interface, the ability to use ‘guix environment’ and
all the tools, transactional upgrade and rollback, etc.

> From fb1fbc92cd68331b3dea94c238274f8a01b98afa Mon Sep 17 00:00:00 2001
> From: Eric Le Bihan <eric.le.bihan.dev@free.fr>
> Date: Thu, 28 Jul 2016 20:09:01 +0200
> Subject: [PATCH 1/1] gnu: Add rust
>
> * gnu/packages/rust.scm(rust): New variable.
>
> Signed-off-by: Eric Le Bihan <eric.le.bihan.dev@free.fr>

Apart from the bootstrapping thing discussed above, this looks good to
me (and a great first package!).

> +            ;; Tell where to find libgcc_s.so
> +            (setenv "LD_LIBRARY_PATH" (string-append gcc-lib "/lib"))

“LIBRARY_PATH” may be enough.

> +            ;; Remove reference to "/lib64/ld-linux-x86-64.so.2" from binary
> +            (zero? (system*
> +                    "patchelf"
> +                    "--set-interpreter" ld-so
> +                    (string-append (getcwd) "/rustc/bin/rustc")))

“rustc/bin/rustc” is enough here.

> +        (add-before 'build 'pre-build
> +                    (lambda _
> +                      (let* ((bindir (string-append (getcwd) "/bin"))
> +                             (cc (string-append bindir "/cc")))
> +                        (mkdir bindir)
> +                        (call-with-output-file cc
> +                          (lambda (port)
> +                            (format port
> +                                    "#!~a\n\nexec gcc \"$@\"\n" (which "sh"))))
> +                        (chmod cc #o755))))

Can we avoid this trick using a configure flag
(--with-compiler=/path/to/gcc) or a configure or environment variable
(CC=gcc)?  If not, that’s fine.

> +      (replace 'build
> +               (lambda* (#:key outputs #:allow-other-keys)
> +                 (setenv "PATH"
> +                         (string-append (getcwd) "/bin:" (getenv "PATH")))
> +                 (mkdir (assoc-ref outputs "out"))
> +                 (zero? (system* "make")))))

Rather do:

  (add-before 'build 'change-PATH
    (lambda _
      (setenv …)
      #t))

so we can reuse the normal ‘build’ phase, which passes -jX to ‘make’.

> +      #:tests? #f))

We normally run test suites, unless we have a good reason not to do so.
:-)  Any ideas why “make check” fails?

Thanks!

Ludo’.
Alex Griffin July 29, 2016, 3:34 p.m. UTC | #5
On Fri, Jul 29, 2016, at 10:16 AM, Ludovic Courtès wrote:
> Do you know what’s Rust’s bootstrapping story is?  Can we reasonably
> expect to bootstrap it from source, using a series of previous Rust
> versions, or using an alternative implementation?

Yes, Rust 1.10 builds with the previous stable release (1.9) for the
first time. So we will only need one binary to bootstrap Rust. Although
this will quickly require a long chain of builds because Rust releases
every 6 weeks and 1.11 is only guaranteed to build with 1.10, etc.

So after only two years we may need to compile like 17 different
releases to get the current version.
Jelle Licht July 29, 2016, 4:08 p.m. UTC | #6
I looked into this once;
I found a Rust compiler written in OCaml on the web.
There should be a path from that compiler to the current version of Rust.
The problem lies in the fact that the entire "1.9 build 1.10 builds 1.11"
spiel only become the official policy of the Rust project recently.

disclaimer: the following is how I interpreted my communications with
the rust community. My apologies to anyone involved for any inaccuracies
and/or misrepresentations.

This means that you could be looking at individual commits, as before this,
I believe nightlies (snapshots) were used to compile the Rust compiler.

So, to ad to Alex' point, we would also need to expend (one-time) effort to
find this 'bootstrap-path' from the OCaml-based compiler to a more recent
rustc.

In my admittedly little amounts of experience, the people working on rust
were not really seeing the problem with the current state of affairs, so
good luck getting support with some arcane issues one might encounter
packaging these ancient versions of rustc.

To quote kibwen from [1]:
"We can determine exactly how many builds you'd need by looking at the
master snapshot file:
https://github.com/rust-lang/rust/blob/master/src/snapshots....
<https://github.com/rust-lang/rust/blob/master/src/snapshots.txt>

According to this, there have been 290 snapshots in total. And keep in mind
that you would also need to rebuild LLVM quite a few times as well during
this process, as Rust has continually upgraded its custom LLVM fork over
the years."

Not sure if all this is worth the effort...

- Jelle


[1]: https://news.ycombinator.com/item?id=8732669


2016-07-29 17:34 GMT+02:00 Alex Griffin <a@ajgrf.com>:

> On Fri, Jul 29, 2016, at 10:16 AM, Ludovic Courtès wrote:
> > Do you know what’s Rust’s bootstrapping story is?  Can we reasonably
> > expect to bootstrap it from source, using a series of previous Rust
> > versions, or using an alternative implementation?
>
> Yes, Rust 1.10 builds with the previous stable release (1.9) for the
> first time. So we will only need one binary to bootstrap Rust. Although
> this will quickly require a long chain of builds because Rust releases
> every 6 weeks and 1.11 is only guaranteed to build with 1.10, etc.
>
> So after only two years we may need to compile like 17 different
> releases to get the current version.
> --
> Alex Griffin
>
>
Eric Le Bihan July 30, 2016, 10:04 a.m. UTC | #7
Le Fri, 29 Jul 2016 11:03:41 +0200,
Andreas Enge <andreas@enge.fr> a écrit :

> On Thu, Jul 28, 2016 at 08:31:44PM +0200, Eric Le Bihan wrote:
> > 1. I can compile a sample program in a guix environment created
> > using `guix environment gcc glibc binutils rust`, but the program
> > generated fails to run because libgcc_s.so.1 can not be found. How
> > can it be added to the environment?  
> 
> I would suggest to replace "gcc glibc binutils" by "gcc-toolchain",
> which installs a specially modified linker.

This solves the problem. Thank you.
Eric Le Bihan July 30, 2016, 11:01 a.m. UTC | #8
Le Fri, 29 Jul 2016 17:16:29 +0200,
ludo@gnu.org (Ludovic Courtès) a écrit :

> Eric Le Bihan <eric.le.bihan.dev@free.fr> skribis:
> 
> > It happens that I tried to package Rust, as an introduction to Guix.
> > Here is my version, inspired by the Haskell package, where Rust
> > 1.10.0 is built, bootstrapped by a binary version of rustc 1.9.0.
> > It uses the "cc" wrapper trick previously presented.  
> 
> As you might have seen from previous discussions, we try hard to
> reduce the number of binary blobs needed to bootstrap packages, such
> that we have a full source-to-binary path that everyone can audit.
> Unfortunately, this usually hard to achieve for self-hosted compilers.
> 
> Do you know what’s Rust’s bootstrapping story is?  Can we reasonably
> expect to bootstrap it from source, using a series of previous Rust
> versions, or using an alternative implementation?

As explained by others, starting with version 1.10.0, Rust version N
will be guaranteed to bootstrap with version N-1.

> > Some questions, though:
> >
> > 1. I can compile a sample program in a guix environment created
> > using `guix environment gcc glibc binutils rust`, but the program
> > generated fails to run because libgcc_s.so.1 can not be found. How
> > can it be added to the environment?  
> 
> As Andreas notes, ‘gcc-toolchain’, which includes ‘ld-wrapper’, should
> fix this.

Yes. It solved my problem.
 
> Does Rust use GCC, or just ld?

It only uses the linker, i.e. ld on GNU/Linux.

> > 2. Having a Rust compiler is cool, but having Cargo, the Rust
> > package manager, would be even better. Cargo is also bootstrapped,
> > and it is also built using zillions of crates (Rust packages)
> > downloaded from the Internet. How could this case be handled in
> > Guix?  
> 
> Assuming Cargo itself is just a regular Rust program, it should be
> possible to make a Guix package of Cargo.  Then, Guix users can
> install it and use it the normal way; we won’t be able to use Cargo
> in package recipes though, because our package build environments
> purposefully lacks network access.
> 
> Besides, I would encourage you or anyone interested to write a crate
> importer, like we do for most other language packages:
> 
>   https://www.gnu.org/software/guix/manual/html_node/Invoking-guix-import.html
> 
> Having crates available as normal Guix packages is the best option for
> Guix users: uniform interface, the ability to use ‘guix environment’
> and all the tools, transactional upgrade and rollback, etc.

IIUC, to provide a Guix package for Cargo, the following should be done:

1. write a crate importer.
2. list all the crates needed by Cargo to build itself.
3. package each crate with the importer.
4. add a Cargo package which depends on the newly-imported crates and
uses a binary version of Cargo to bootstrap itself (though this is not
the best option in terms of auditing/reproducibility).

Unlike Rust, Cargo still uses an "anonymous" binary version of itself
for bootstrapping. I hope this may change soon.

> > From fb1fbc92cd68331b3dea94c238274f8a01b98afa Mon Sep 17 00:00:00
> > 2001 From: Eric Le Bihan <eric.le.bihan.dev@free.fr>
> > Date: Thu, 28 Jul 2016 20:09:01 +0200
> > Subject: [PATCH 1/1] gnu: Add rust
> >
> > * gnu/packages/rust.scm(rust): New variable.
> >
> > Signed-off-by: Eric Le Bihan <eric.le.bihan.dev@free.fr>  
> 
> Apart from the bootstrapping thing discussed above, this looks good to
> me (and a great first package!).
> 
> > +            ;; Tell where to find libgcc_s.so
> > +            (setenv "LD_LIBRARY_PATH" (string-append gcc-lib
> > "/lib"))  
> 
> “LIBRARY_PATH” may be enough.

OK.
 
> > +            ;; Remove reference to "/lib64/ld-linux-x86-64.so.2"
> > from binary
> > +            (zero? (system*
> > +                    "patchelf"
> > +                    "--set-interpreter" ld-so
> > +                    (string-append (getcwd) "/rustc/bin/rustc")))  
> 
> “rustc/bin/rustc” is enough here.

OK.

> 
> > +        (add-before 'build 'pre-build
> > +                    (lambda _
> > +                      (let* ((bindir (string-append (getcwd)
> > "/bin"))
> > +                             (cc (string-append bindir "/cc")))
> > +                        (mkdir bindir)
> > +                        (call-with-output-file cc
> > +                          (lambda (port)
> > +                            (format port
> > +                                    "#!~a\n\nexec gcc
> > \"$@\"\n" (which "sh"))))
> > +                        (chmod cc #o755))))  
> 
> Can we avoid this trick using a configure flag
> (--with-compiler=/path/to/gcc) or a configure or environment variable
> (CC=gcc)?  If not, that’s fine.

To build the Rust standard library, only the linker is needed. The
default value is "cc". I thought this could be overridden using the
"--default-linker=" of the ./configure script, but it looks like it is
not properly handled. Hence the need for the wrapper. 

I haven't checked too deeply to know if it is a bug or a feature. On
the Rust issue tracker, an entry [1] relates to this problem, but only
in terms of documentation. I'll bump the topic upstream.

> > +      (replace 'build
> > +               (lambda* (#:key outputs #:allow-other-keys)
> > +                 (setenv "PATH"
> > +                         (string-append (getcwd) "/bin:" (getenv
> > "PATH")))
> > +                 (mkdir (assoc-ref outputs "out"))
> > +                 (zero? (system* "make")))))  
> 
> Rather do:
> 
>   (add-before 'build 'change-PATH
>     (lambda _
>       (setenv …)
>       #t))
> 
> so we can reuse the normal ‘build’ phase, which passes -jX to ‘make’.

OK.

> 
> > +      #:tests? #f))  
> 
> We normally run test suites, unless we have a good reason not to do
> so. :-)  Any ideas why “make check” fails?

Out of laziness, I skipped the tests. I'll give it a look.

[1] https://github.com/rust-lang/rust/issues/32208

Best regards,
Ludovic Courtès July 30, 2016, 1:34 p.m. UTC | #9
Alex Griffin <a@ajgrf.com> skribis:

> On Fri, Jul 29, 2016, at 10:16 AM, Ludovic Courtès wrote:
>> Do you know what’s Rust’s bootstrapping story is?  Can we reasonably
>> expect to bootstrap it from source, using a series of previous Rust
>> versions, or using an alternative implementation?
>
> Yes, Rust 1.10 builds with the previous stable release (1.9) for the
> first time. So we will only need one binary to bootstrap Rust. Although
> this will quickly require a long chain of builds because Rust releases
> every 6 weeks and 1.11 is only guaranteed to build with 1.10, etc.
>
> So after only two years we may need to compile like 17 different
> releases to get the current version.

Bah.  If that were the only problem, we could regularly cut the
dependency graph by storing a pre-built binary built using Guix,
assuming Rust builds are reproducible.  (Note that each node in the
dependency graph contributes to the ‘guix build -d’ time by less than a
hundred milliseconds, so the chain can be quite long before it’s a
practical problem.)

Jelle Licht <jlicht@fsfe.org> skribis:

> So, to ad to Alex' point, we would also need to expend (one-time) effort to
> find this 'bootstrap-path' from the OCaml-based compiler to a more recent
> rustc.

I suspect this one-time effort would be quite huge.

> To quote kibwen from [1]:
> "We can determine exactly how many builds you'd need by looking at the
> master snapshot file:
> https://github.com/rust-lang/rust/blob/master/src/snapshots....
> <https://github.com/rust-lang/rust/blob/master/src/snapshots.txt>
>
> According to this, there have been 290 snapshots in total. And keep in mind
> that you would also need to rebuild LLVM quite a few times as well during
> this process, as Rust has continually upgraded its custom LLVM fork over
> the years."
>
> Not sure if all this is worth the effort...

It’s discouraging, indeed.

We need to find a reasonable way forward.  What about starting from the
version that Eric submitted (bootstrapped from the opaque binary), and
from there on do the “build with previous version” thing?

When the chain becomes too long, we’ll host new bootstrap binaries
produced with Guix and cut the initial part of the chain.

Thoughts?

Obviously not ideal, but at least we’d have a clearer track record of
our binaries: we’d document the Guix commit needed to reproduce a
specific binary, and anyone could verify it.

Ludo’.
Ludovic Courtès July 30, 2016, 1:44 p.m. UTC | #10
Eric Le Bihan <eric.le.bihan.dev@free.fr> skribis:

> Le Fri, 29 Jul 2016 17:16:29 +0200,
> ludo@gnu.org (Ludovic Courtès) a écrit :

[...]

>> > Some questions, though:
>> >
>> > 1. I can compile a sample program in a guix environment created
>> > using `guix environment gcc glibc binutils rust`, but the program
>> > generated fails to run because libgcc_s.so.1 can not be found. How
>> > can it be added to the environment?  
>> 
>> As Andreas notes, ‘gcc-toolchain’, which includes ‘ld-wrapper’, should
>> fix this.
>
> Yes. It solved my problem.
>  
>> Does Rust use GCC, or just ld?
>
> It only uses the linker, i.e. ld on GNU/Linux.

Then it should be enough to add ‘ld-wrapper’ to the inputs (no need for
‘gcc-toolchain’ or ‘gcc’.)  Just make sure Rust captures the absolute
file name of ‘ld’.

> IIUC, to provide a Guix package for Cargo, the following should be done:
>
> 1. write a crate importer.
> 2. list all the crates needed by Cargo to build itself.
> 3. package each crate with the importer.
> 4. add a Cargo package which depends on the newly-imported crates and
> uses a binary version of Cargo to bootstrap itself (though this is not
> the best option in terms of auditing/reproducibility).
>
> Unlike Rust, Cargo still uses an "anonymous" binary version of itself
> for bootstrapping. I hope this may change soon.

Something along these lines, yes.  We may also need a
‘rust-build-system’, like we did for other languages:

  https://www.gnu.org/software/guix/manual/html_node/Build-Systems.html

If that build system works without invoking Cargo, then we probably
don’t need a Cargo binary to build Cargo.

Anyway, we’re not there yet.  :-)

>> > +        (add-before 'build 'pre-build
>> > +                    (lambda _
>> > +                      (let* ((bindir (string-append (getcwd)
>> > "/bin"))
>> > +                             (cc (string-append bindir "/cc")))
>> > +                        (mkdir bindir)
>> > +                        (call-with-output-file cc
>> > +                          (lambda (port)
>> > +                            (format port
>> > +                                    "#!~a\n\nexec gcc
>> > \"$@\"\n" (which "sh"))))
>> > +                        (chmod cc #o755))))  
>> 
>> Can we avoid this trick using a configure flag
>> (--with-compiler=/path/to/gcc) or a configure or environment variable
>> (CC=gcc)?  If not, that’s fine.
>
> To build the Rust standard library, only the linker is needed. The
> default value is "cc". I thought this could be overridden using the
> "--default-linker=" of the ./configure script, but it looks like it is
> not properly handled. Hence the need for the wrapper. 

OK, makes sense.  Please leave this explanation as a comment in the
code.

>> > +      #:tests? #f))  
>> 
>> We normally run test suites, unless we have a good reason not to do
>> so. :-)  Any ideas why “make check” fails?
>
> Out of laziness, I skipped the tests. I'll give it a look.

Let us know how it goes, even if the outcome is “too painful, giving
up”.  :-)

Thanks,
Ludo’.
Pjotr Prins July 30, 2016, 5:57 p.m. UTC | #11
On Sat, Jul 30, 2016 at 03:34:08PM +0200, Ludovic Courtès wrote:
> When the chain becomes too long, we’ll host new bootstrap binaries
> produced with Guix and cut the initial part of the chain.
> 
> Thoughts?

This sounds like a very good approach for compilers written in their
own language. Same will be true for the D compilers. The D compiler
was recently ported to D and the authors say they will aim to keep
support for bootstrapping from C - but they added it may grow
complicated over time. I think the Elixir compiler will also be ported
to Elixer in time... there have been some noises.

The bootstrapping from source is a fine idea(l), but not always
practical for package authors.

Interesting point is if we can share one such cross-building binary
compiler for all target platforms, or are we going to store binaries
for each of them?

Pj.
diff mbox

Patch

From fb1fbc92cd68331b3dea94c238274f8a01b98afa Mon Sep 17 00:00:00 2001
From: Eric Le Bihan <eric.le.bihan.dev@free.fr>
Date: Thu, 28 Jul 2016 20:09:01 +0200
Subject: [PATCH 1/1] gnu: Add rust

* gnu/packages/rust.scm(rust): New variable.

Signed-off-by: Eric Le Bihan <eric.le.bihan.dev@free.fr>
---
 gnu/packages/rust.scm | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)
 create mode 100644 gnu/packages/rust.scm

diff --git a/gnu/packages/rust.scm b/gnu/packages/rust.scm
new file mode 100644
index 0000000..6c6ec0c
--- /dev/null
+++ b/gnu/packages/rust.scm
@@ -0,0 +1,141 @@ 
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2016 Eric Le Bihan <eric.le.bihan.dev@free.fr>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages rust)
+  #:use-module (ice-9 regex)
+  #:use-module ((guix licenses) #:select (asl2.0 x11-style))
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix build-system gnu)
+  #:use-module (gnu packages base)
+  #:use-module (gnu packages bootstrap)
+  #:use-module (gnu packages curl)
+  #:use-module (gnu packages elf)
+  #:use-module (gnu packages gcc)
+  #:use-module (gnu packages jemalloc)
+  #:use-module (gnu packages perl)
+  #:use-module (gnu packages python))
+
+(define rust-bootstrap-x86_64-1.9.0
+  (origin
+   (method url-fetch)
+   (uri
+    "https://static.rust-lang.org/dist/2016-05-24/rustc-1.9.0-x86_64-unknown-linux-gnu.tar.gz")
+   (sha256
+    (base32
+     "1i44rlvvn3pr81sli6bdbkzd78ar1ibybxx6mzpw6rkw4c84sw6h"))))
+
+(define rust-bootstrap-i686-1.9.0
+  (origin
+   (method url-fetch)
+   (uri
+    "https://static.rust-lang.org/dist/2016-05-24/rustc-1.9.0-i686-unknown-linux-gnu.tar.gz")
+   (sha256
+    (base32
+     "0fdf5xvh3g4hdza0y80w1r9vnfczjqnbzbvs7k878yc26p4dwl99"))))
+
+(define-public rust
+  (package
+   (name "rust")
+   (version "1.10.0")
+   (source (origin
+            (method url-fetch)
+            (uri (string-append "https://static.rust-lang.org/dist/rustc-"
+                                version "-src.tar.gz"))
+            (sha256
+             (base32
+              "0sb82xb8y2pzs8l1hk91z228bambwx3dmi2kj8isin7nyjn5l0d4"))))
+   (build-system gnu-build-system)
+   (native-inputs
+    `(("curl" ,curl)
+      ("gcc" ,gcc)
+      ("gcc-lib" ,gcc "lib")
+      ("jemalloc" ,jemalloc)
+      ("patchelf" ,patchelf)
+      ("perl" ,perl)
+      ("python" ,python-2)
+      ("rust-bootstrap"
+       ,(if (string-match "x86_64" (or (%current-target-system) (%current-system)))
+            rust-bootstrap-x86_64-1.9.0
+            rust-bootstrap-i686-1.9.0))
+      ("which" ,which)))
+   (arguments
+    `(#:phases
+      (modify-phases %standard-phases
+        (add-after 'unpack 'unpack-bootstrap
+                   (lambda* (#:key inputs #:allow-other-keys)
+                     (with-directory-excursion (getcwd)
+                       (zero? (system*
+                               "tar"
+                               "--strip-components=1"
+                               "-xzf"
+                               (assoc-ref inputs "rust-bootstrap"))))))
+        (replace 'configure
+                 (lambda* (#:key inputs outputs #:allow-other-keys)
+                   (let ((out (assoc-ref outputs "out"))
+                         (binutils (assoc-ref inputs "binutils"))
+                         (gcc (assoc-ref inputs "gcc"))
+                         (gcc-lib (assoc-ref inputs "gcc-lib"))
+                         (jemalloc (assoc-ref inputs "jemalloc"))
+                         (ld-so (string-append
+                                 (assoc-ref inputs "libc")
+                                 ,(glibc-dynamic-linker)))
+                         (python (assoc-ref inputs "python")))
+            (setenv "SHELL" (which "sh"))
+            (setenv "CONFIG_SHELL" (which "sh"))
+            ;; Tell where to find libgcc_s.so
+            (setenv "LD_LIBRARY_PATH" (string-append gcc-lib "/lib"))
+            ;; Remove reference to "/lib64/ld-linux-x86-64.so.2" from binary
+            (zero? (system*
+                    "patchelf"
+                    "--set-interpreter" ld-so
+                    (string-append (getcwd) "/rustc/bin/rustc")))
+            (zero? (system*
+                    "./configure"
+                    (string-append "--prefix=" out)
+                    (string-append "--default-linker=" gcc "/bin/gcc")
+                    (string-append "--default-ar=" binutils "/bin/ar")
+                    (string-append "--jemalloc-root=" jemalloc "/lib")
+                    (string-append "--enable-rpath")
+                    (string-append "--enable-local-rust")
+                    (string-append "--local-rust-root=" (getcwd) "/rustc")
+                    (string-append "--python=" python "/bin/python2")
+                    "--disable-manage-submodules")))))
+        (add-before 'build 'pre-build
+                    (lambda _
+                      (let* ((bindir (string-append (getcwd) "/bin"))
+                             (cc (string-append bindir "/cc")))
+                        (mkdir bindir)
+                        (call-with-output-file cc
+                          (lambda (port)
+                            (format port
+                                    "#!~a\n\nexec gcc \"$@\"\n" (which "sh"))))
+                        (chmod cc #o755))))
+      (replace 'build
+               (lambda* (#:key outputs #:allow-other-keys)
+                 (setenv "PATH"
+                         (string-append (getcwd) "/bin:" (getenv "PATH")))
+                 (mkdir (assoc-ref outputs "out"))
+                 (zero? (system* "make")))))
+      #:tests? #f))
+   (synopsis "Compiler for the Rust progamming language")
+   (description
+    "Rust is a systems programming language that runs blazingly fast, prevents
+ segfaults, and guarantees thread safety.")
+   (home-page "https://www.rust-lang.org")
+   (license (list asl2.0 (x11-style "file://LICENSE-MIT")))))
-- 
2.4.11