parent
3e39e3e80d
commit
25fe2cadb1
59 changed files with 14 additions and 8480 deletions
|
@ -370,7 +370,6 @@ SREQ$(1)_T_$(2)_H_$(3) = \
|
||||||
# libraries
|
# libraries
|
||||||
CSREQ$(1)_T_$(2)_H_$(3) = \
|
CSREQ$(1)_T_$(2)_H_$(3) = \
|
||||||
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
|
|
||||||
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||||
$$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
|
$$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
|
||||||
$$(foreach dep,$$(HOST_CRATES),$$(HLIB$(1)_H_$(3))/stamp.$$(dep))
|
$$(foreach dep,$$(HOST_CRATES),$$(HLIB$(1)_H_$(3))/stamp.$$(dep))
|
||||||
|
|
|
@ -52,8 +52,8 @@ documentation.
|
||||||
> options are also supported, pass `--help` for more information on them.
|
> options are also supported, pass `--help` for more information on them.
|
||||||
|
|
||||||
When complete, `make install` will place several programs into
|
When complete, `make install` will place several programs into
|
||||||
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
|
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||||
API-documentation tool, and `rustpkg`, the Rust package manager and build
|
API-documentation tool.
|
||||||
system.
|
system.
|
||||||
3. Read the [tutorial].
|
3. Read the [tutorial].
|
||||||
4. Enjoy!
|
4. Enjoy!
|
||||||
|
|
|
@ -1,270 +0,0 @@
|
||||||
% The Rust Packaging Guide
|
|
||||||
|
|
||||||
# Introduction
|
|
||||||
|
|
||||||
Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to
|
|
||||||
package up your Rust code and share it with other people. This guide will
|
|
||||||
get you started on all of the concepts and commands you need to give the gift
|
|
||||||
of Rust code to someone else.
|
|
||||||
|
|
||||||
# Installing External Packages
|
|
||||||
|
|
||||||
First, let's try to use an external package somehow. I've made a sample package
|
|
||||||
called `hello` to demonstrate how to do so. Here's how `hello` is used:
|
|
||||||
|
|
||||||
~~~~
|
|
||||||
extern mod hello;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
hello::world();
|
|
||||||
}
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Easy! But if you try to compile this, you'll get an error:
|
|
||||||
|
|
||||||
~~~~ {.notrust}
|
|
||||||
$ rustc main.rs
|
|
||||||
main.rs:1:0: 1:17 error: can't find crate for `hello`
|
|
||||||
main.rs:1 extern mod hello;
|
|
||||||
^~~~~~~~~~~~~~~~~
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
This makes sense, as we haven't gotten it from anywhere yet! Luckily for us,
|
|
||||||
`rustpkg` has an easy way to fetch others' code: the `install` command. It's
|
|
||||||
used like this:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ rustpkg install PKG_ID
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This will install a package named `PKG_ID` into your current Rust environment.
|
|
||||||
I called it `PKG_ID` in this example because `rustpkg` calls this a 'package
|
|
||||||
identifier.' When using it with an external package like this, it's often a
|
|
||||||
URI fragment. You see, Rust has no central authority for packages. You can
|
|
||||||
build your own `hello` library if you want, and that's fine. We'd both host
|
|
||||||
them in different places and different projects would rely on whichever version
|
|
||||||
they preferred.
|
|
||||||
|
|
||||||
To install the `hello` library, simply run this in your terminal:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ rustpkg install github.com/steveklabnik/hello
|
|
||||||
~~~
|
|
||||||
|
|
||||||
You should see a message that looks like this:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Now, compiling our example should work:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ rustc main.rs
|
|
||||||
$ ./main
|
|
||||||
Hello, world.
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Simple! That's all it takes.
|
|
||||||
|
|
||||||
# Workspaces
|
|
||||||
|
|
||||||
Before we can talk about how to make packages of your own, you have to
|
|
||||||
understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply
|
|
||||||
a directory that has certain sub-directories that `rustpkg` expects. Different
|
|
||||||
Rust projects will go into different workspaces.
|
|
||||||
|
|
||||||
A workspace consists of any directory that has the following
|
|
||||||
directories:
|
|
||||||
|
|
||||||
* `src`: The directory where all the source code goes.
|
|
||||||
* `build`: This directory contains all of the build output.
|
|
||||||
* `lib`: The directory where any libraries distributed with the package go.
|
|
||||||
* `bin`: This directory holds any binaries distributed with the package.
|
|
||||||
|
|
||||||
There are also default file names you'll want to follow as well:
|
|
||||||
|
|
||||||
* `main.rs`: A file that's going to become an executable.
|
|
||||||
* `lib.rs`: A file that's going to become a library.
|
|
||||||
|
|
||||||
# Building your own Package
|
|
||||||
|
|
||||||
Now that you've got workspaces down, let's build your own copy of `hello`. Go
|
|
||||||
to wherever you keep your personal projects, and let's make all of the
|
|
||||||
directories we'll need. I'll refer to this personal project directory as
|
|
||||||
`~/src` for the rest of this guide.
|
|
||||||
|
|
||||||
## Creating our workspace
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ cd ~/src
|
|
||||||
$ mkdir -p hello/src/hello
|
|
||||||
$ cd hello
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Easy enough! Let's do one or two more things that are nice to do:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ git init .
|
|
||||||
$ cat > README.md
|
|
||||||
# hello
|
|
||||||
|
|
||||||
A simple package for Rust.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```
|
|
||||||
$ rustpkg install github.com/YOUR_USERNAME/hello
|
|
||||||
```
|
|
||||||
^D
|
|
||||||
$ cat > .gitignore
|
|
||||||
.rust
|
|
||||||
build
|
|
||||||
^D
|
|
||||||
$ git commit -am "Initial commit."
|
|
||||||
~~~
|
|
||||||
|
|
||||||
If you're not familliar with the `cat >` idiom, it will make files with the
|
|
||||||
text you type inside. Control-D (`^D`) ends the text for the file.
|
|
||||||
|
|
||||||
Anyway, we've got a README and a `.gitignore`. Let's talk about that
|
|
||||||
`.gitignore` for a minute: we are ignoring two directories, `build` and
|
|
||||||
`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't
|
|
||||||
want to check those into a repository. `.rust` is a directory that `rustpkg`
|
|
||||||
uses to keep track of its own settings, as well as the source code of any other
|
|
||||||
external packages that this workspace uses. This is where that `rustpkg
|
|
||||||
install` puts all of its files. Those are also not to go into our repository,
|
|
||||||
so we ignore it all as well.
|
|
||||||
|
|
||||||
Next, let's add a source file:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
#[desc = "A hello world Rust package."];
|
|
||||||
#[license = "MIT"];
|
|
||||||
|
|
||||||
pub fn world() {
|
|
||||||
println!("Hello, world.");
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Put this into `src/hello/lib.rs`. Let's talk about each of these attributes:
|
|
||||||
|
|
||||||
## Crate attributes for packages
|
|
||||||
|
|
||||||
`license` is equally simple: the license we want this code to have. I chose MIT
|
|
||||||
here, but you should pick whatever license makes the most sense for you.
|
|
||||||
|
|
||||||
`desc` is a description of the package and what it does. This should just be a
|
|
||||||
sentence or two.
|
|
||||||
|
|
||||||
## Building your package
|
|
||||||
|
|
||||||
Building your package is simple:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ rustpkg build hello
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This will compile `src/hello/lib.rs` into a library. After this process
|
|
||||||
completes, you'll want to check out `build`:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ ls build/x86_64-unknown-linux-gnu/hello/
|
|
||||||
libhello-ed8619dad9ce7d58-0.1.0.so
|
|
||||||
~~~
|
|
||||||
|
|
||||||
This directory naming structure is called a 'build triple,' and is because I'm
|
|
||||||
on 64 bit Linux. Yours may differ based on platform.
|
|
||||||
|
|
||||||
You'll also notice that `src/hello/lib.rs` turned into
|
|
||||||
`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the
|
|
||||||
library name, a hash of its content, and the version.
|
|
||||||
|
|
||||||
Now that your library builds, you'll want to commit:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ git add src
|
|
||||||
$ git commit -m "Adding source code."
|
|
||||||
~~~
|
|
||||||
|
|
||||||
If you're using GitHub, after creating the project, do this:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ git remote add origin git@github.com:YOUR_USERNAME/hello.git
|
|
||||||
$ git push origin -u master
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Now you can install and use it! Go anywhere else in your filesystem:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ cd ~/src/foo
|
|
||||||
$ rustpkg install github.com/YOUR_USERNAME/hello
|
|
||||||
WARNING: The Rust package manager is experimental and may be unstable
|
|
||||||
note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust
|
|
||||||
~~~
|
|
||||||
|
|
||||||
That's it!
|
|
||||||
|
|
||||||
# Testing your Package
|
|
||||||
|
|
||||||
Testing your package is simple as well. First, let's change `src/hello/lib.rs` to contain
|
|
||||||
a function that can be sensibly tested:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
#[desc = "A Rust package for determining whether unsigned integers are even."];
|
|
||||||
#[license = "MIT"];
|
|
||||||
|
|
||||||
pub fn is_even(i: uint) -> bool {
|
|
||||||
i % 2 == 0
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Once you've edited `lib.rs`, you can create a second crate file, `src/hello/test.rs`,
|
|
||||||
to put tests in:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
#[license = "MIT"];
|
|
||||||
extern mod hello;
|
|
||||||
use hello::is_even;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_even() {
|
|
||||||
assert!(is_even(0));
|
|
||||||
assert!(!is_even(1));
|
|
||||||
assert!(is_even(2));
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Note that you have to import the crate you just created in `lib.rs` with the
|
|
||||||
`extern mod hello` directive. That's because you're putting the tests in a different
|
|
||||||
crate from the main library that you created.
|
|
||||||
|
|
||||||
Now, you can use the `rustpkg test` command to build this test crate (and anything else
|
|
||||||
it depends on) and run the tests, all in one step:
|
|
||||||
|
|
||||||
~~~ {.notrust}
|
|
||||||
$ rustpkg test hello
|
|
||||||
WARNING: The Rust package manager is experimental and may be unstable
|
|
||||||
note: Installed package hello-0.1 to /Users/tjc/.rust
|
|
||||||
|
|
||||||
running 1 test
|
|
||||||
test test_is_even ... ok
|
|
||||||
|
|
||||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
|
||||||
~~~
|
|
||||||
|
|
||||||
# More resources
|
|
||||||
|
|
||||||
There's a lot more going on with `rustpkg`, this is just to get you started.
|
|
||||||
Check out [the rustpkg manual](rustpkg.html) for the full details on how to
|
|
||||||
customize `rustpkg`.
|
|
||||||
|
|
||||||
A tag was created on GitHub specifically for `rustpkg`-related issues. You can
|
|
||||||
[see all the Issues for rustpkg
|
|
||||||
here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open),
|
|
||||||
with bugs as well as new feature plans. `rustpkg` is still under development,
|
|
||||||
and so may be a bit flaky at the moment.
|
|
||||||
|
|
||||||
You may also want to check out [this blog
|
|
||||||
post](http://tim.dreamwidth.org/1820526.html), which contains some of the early
|
|
||||||
design decisions and justifications.
|
|
|
@ -1,112 +0,0 @@
|
||||||
# Japanese translations for Rust package
|
|
||||||
# Copyright (C) 2014 The Rust Project Developers
|
|
||||||
# This file is distributed under the same license as the Rust package.
|
|
||||||
# Automatically generated, 2014.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: Rust 0.10-pre\n"
|
|
||||||
"POT-Creation-Date: 2014-01-13 12:01+0900\n"
|
|
||||||
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
|
|
||||||
"Last-Translator: Automatically generated\n"
|
|
||||||
"Language-Team: none\n"
|
|
||||||
"Language: ja\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-conditions.md:4 doc/guide-ffi.md:4 doc/guide-lifetimes.md:4
|
|
||||||
#: doc/guide-macros.md:4 doc/guide-rustpkg.md:4 doc/guide-tasks.md:4
|
|
||||||
#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
|
|
||||||
msgid "# Introduction"
|
|
||||||
msgstr "# イントロダクション"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:2
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "% The Rust Language Tutorial"
|
|
||||||
msgid "% The Rust Packaging Guide"
|
|
||||||
msgstr "% Rust 言語チュートリアル"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:11
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "## Using other crates"
|
|
||||||
msgid "# Installing External Packages"
|
|
||||||
msgstr "## 他のクレートの利用"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:22
|
|
||||||
#, fuzzy, no-wrap
|
|
||||||
#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
|
|
||||||
msgid ""
|
|
||||||
"fn main() {\n"
|
|
||||||
" hello::world();\n"
|
|
||||||
"}\n"
|
|
||||||
"~~~~\n"
|
|
||||||
msgstr ""
|
|
||||||
"~~~~ {.ignore}\n"
|
|
||||||
"// main.rs\n"
|
|
||||||
"extern mod world;\n"
|
|
||||||
"fn main() { println(~\"hello \" + world::explore()); }\n"
|
|
||||||
"~~~~"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:91
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "## Using other crates"
|
|
||||||
msgid "# Building your own Package"
|
|
||||||
msgstr "## 他のクレートの利用"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:98
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "## Using other crates"
|
|
||||||
msgid "## Creating our workspace"
|
|
||||||
msgstr "## 他のクレートの利用"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:115
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "# Introduction"
|
|
||||||
msgid "## Installation"
|
|
||||||
msgstr "# イントロダクション"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:149
|
|
||||||
#, fuzzy, no-wrap
|
|
||||||
#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
|
|
||||||
msgid ""
|
|
||||||
"pub fn world() {\n"
|
|
||||||
" println!(\"Hello, world.\");\n"
|
|
||||||
"}\n"
|
|
||||||
"~~~\n"
|
|
||||||
msgstr ""
|
|
||||||
"~~~~ {.ignore}\n"
|
|
||||||
"// main.rs\n"
|
|
||||||
"extern mod world;\n"
|
|
||||||
"fn main() { println(~\"hello \" + world::explore()); }\n"
|
|
||||||
"~~~~"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:161
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "## Using other crates"
|
|
||||||
msgid "## Building your package"
|
|
||||||
msgstr "## 他のクレートの利用"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:209
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "## Using other crates"
|
|
||||||
msgid "# Testing your Package"
|
|
||||||
msgstr "## 他のクレートの利用"
|
|
||||||
|
|
||||||
#. type: Plain text
|
|
||||||
#: doc/guide-rustpkg.md:257
|
|
||||||
#, fuzzy
|
|
||||||
#| msgid "## Managed boxes"
|
|
||||||
msgid "# More resources"
|
|
||||||
msgstr "## マネージドボックス"
|
|
|
@ -791,7 +791,7 @@ extern mod extra; // equivalent to: extern mod extra = "extra";
|
||||||
|
|
||||||
extern mod rustextra = "extra"; // linking to 'extra' under another name
|
extern mod rustextra = "extra"; // linking to 'extra' under another name
|
||||||
|
|
||||||
extern mod foo = "some/where/rust-foo#foo:1.0"; // a full package ID for rustpkg
|
extern mod foo = "some/where/rust-foo#foo:1.0"; // a full package ID for external tools
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
##### Use declarations
|
##### Use declarations
|
||||||
|
|
164
doc/rustpkg.md
164
doc/rustpkg.md
|
@ -1,164 +0,0 @@
|
||||||
% Rustpkg Reference Manual
|
|
||||||
|
|
||||||
# Introduction
|
|
||||||
|
|
||||||
This document is the reference manual for the Rustpkg packaging and build tool for the Rust programming language.
|
|
||||||
|
|
||||||
## Disclaimer
|
|
||||||
|
|
||||||
Rustpkg is a work in progress, as is this reference manual.
|
|
||||||
If the actual behavior of rustpkg differs from the behavior described in this reference,
|
|
||||||
that reflects either an incompleteness or a bug in rustpkg.
|
|
||||||
|
|
||||||
# Package searching
|
|
||||||
|
|
||||||
rustpkg searches for packages using the `RUST_PATH` environment variable,
|
|
||||||
which is a colon-separated list (semicolon-separated on Windows) of directories.
|
|
||||||
|
|
||||||
Each directory in this list is a *workspace* for rustpkg.
|
|
||||||
|
|
||||||
`RUST_PATH` implicitly contains an entry for `./.rust` (as well as
|
|
||||||
`../.rust`, `../../.rust`,
|
|
||||||
and so on for every parent of `.` up to the filesystem root).
|
|
||||||
That means that if `RUST_PATH` is not set,
|
|
||||||
then rustpkg will still search for workspaces in `./.rust` and so on.
|
|
||||||
`RUST_PATH` also implicitly contains an entry for the system path:
|
|
||||||
`/usr/local` or the equivalent on Windows.
|
|
||||||
This entry comes after the implicit entries for `./.rust` and so on.
|
|
||||||
Finally, the last implicit entry in `RUST_PATH` is `~/.rust`
|
|
||||||
or the equivalent on Windows.
|
|
||||||
|
|
||||||
Each workspace may contain one or more packages.
|
|
||||||
|
|
||||||
When building code that contains one or more directives of the form `extern mod P`,
|
|
||||||
rustpkg automatically searches for packages named `P` in the `RUST_PATH` (as described above).
|
|
||||||
It builds those dependencies if necessary.
|
|
||||||
Thus, when using rustpkg,
|
|
||||||
there is no need for `-L` flags to tell the linker where to find libraries for external crates.
|
|
||||||
|
|
||||||
# Package structure
|
|
||||||
|
|
||||||
A valid workspace must contain each of the following subdirectories:
|
|
||||||
|
|
||||||
* 'src/': contains one subdirectory per package. Each subdirectory contains source files for a given package.
|
|
||||||
|
|
||||||
For example, if `foo` is a workspace containing the package `bar`,
|
|
||||||
then `foo/src/bar/main.rs` could be the `main` entry point for
|
|
||||||
building a `bar` executable.
|
|
||||||
* 'lib/': `rustpkg install` installs libraries into a target-specific subdirectory of this directory.
|
|
||||||
|
|
||||||
For example, on a 64-bit machine running Mac OS X,
|
|
||||||
if `foo` is a workspace containing the package `bar`,
|
|
||||||
rustpkg will install libraries for bar to `foo/lib/x86_64-apple-darwin/`.
|
|
||||||
The libraries will have names of the form `foo/lib/x86_64-apple-darwin/libbar-[hash].dylib`,
|
|
||||||
where [hash] is a hash of the package ID.
|
|
||||||
* 'bin/': `rustpkg install` installs executable binaries into this directory.
|
|
||||||
|
|
||||||
For example, rustpkg will install executables for `bar` to
|
|
||||||
`foo/bin`.
|
|
||||||
The executables will have names of the form `foo/bin/bar`.
|
|
||||||
* 'build/': `rustpkg build` stores temporary build artifacts in a target-specific subdirectory of this directory.
|
|
||||||
|
|
||||||
For example, on a 64-bit machine running Mac OS X,
|
|
||||||
if `foo` is a workspace containing the package `bar` and `foo/src/bar/main.rs` exists,
|
|
||||||
then `rustpkg build` will create `foo/build/x86_64-apple-darwin/bar/main.o`.
|
|
||||||
|
|
||||||
# Package identifiers
|
|
||||||
|
|
||||||
A package identifier identifies a package uniquely.
|
|
||||||
A package can be stored in a workspace on the local file system,
|
|
||||||
or on a remote Web server, in which case the package ID resembles a URL.
|
|
||||||
For example, `github.com/mozilla/rust` is a package ID
|
|
||||||
that would refer to the git repository browsable at `http://github.com/mozilla/rust`.
|
|
||||||
A package ID can also specify a version, like:
|
|
||||||
`github.com/mozilla/rust#0.3`.
|
|
||||||
In this case, `rustpkg` will check that the repository `github.com/mozilla/rust` has a tag named `0.3`,
|
|
||||||
and report an error otherwise.
|
|
||||||
A package ID can also specify a particular revision of a repository, like:
|
|
||||||
`github.com/mozilla/rust#release-0.7`.
|
|
||||||
When the refspec (portion of the package ID after the `#`) can't be parsed as a decimal number,
|
|
||||||
rustpkg passes the refspec along to the version control system without interpreting it.
|
|
||||||
rustpkg also interprets any dependencies on such a package ID literally
|
|
||||||
(as opposed to versions, where a newer version satisfies a dependency on an older version).
|
|
||||||
Thus, `github.com/mozilla/rust#5c4cd30f80` is also a valid package ID,
|
|
||||||
since git can deduce that 5c4cd30f80 refers to a revision of the desired repository.
|
|
||||||
|
|
||||||
A package identifier can name a subdirectory of another package.
|
|
||||||
For example, if `foo` is a workspace, and `foo/src/bar/lib.rs` exists,
|
|
||||||
as well as `foo/src/bar/extras/baz/lib.rs`,
|
|
||||||
then both `bar` and `bar/extras/baz` are valid package identifiers
|
|
||||||
in the workspace `foo`.
|
|
||||||
|
|
||||||
Because rustpkg uses generic source file names as the main inputs, you will
|
|
||||||
need to specify the package identifier in them using the `crate_id` attribute
|
|
||||||
on the crate.
|
|
||||||
|
|
||||||
## Source files
|
|
||||||
|
|
||||||
rustpkg searches for four different fixed filenames in order to determine the crates to build:
|
|
||||||
|
|
||||||
* `main.rs`: Assumed to be a main entry point for building an executable.
|
|
||||||
* `lib.rs`: Assumed to be a library crate.
|
|
||||||
* `test.rs`: Assumed to contain tests declared with the `#[test]` attribute.
|
|
||||||
* `bench.rs`: Assumed to contain benchmarks declared with the `#[bench]` attribute.
|
|
||||||
|
|
||||||
## Versions
|
|
||||||
|
|
||||||
`rustpkg` packages do not need to declare their versions with an attribute inside one of the source files,
|
|
||||||
because `rustpkg` infers it from the version control system.
|
|
||||||
When building a package that is in a `git` repository,
|
|
||||||
`rustpkg` assumes that the most recent tag specifies the current version.
|
|
||||||
When building a package that is not under version control,
|
|
||||||
or that has no tags, `rustpkg` assumes the intended version is 0.1.
|
|
||||||
|
|
||||||
> **Note:** A future version of rustpkg will support semantic versions.
|
|
||||||
|
|
||||||
# Dependencies
|
|
||||||
|
|
||||||
rustpkg infers dependencies from `extern mod` directives.
|
|
||||||
Thus, there should be no need to pass a `-L` flag to rustpkg to tell it where to find a library.
|
|
||||||
(In the future, it will also be possible to write an `extern mod` directive referring to a remote package.)
|
|
||||||
|
|
||||||
# Custom build scripts
|
|
||||||
|
|
||||||
A file called `pkg.rs` at the root level in a package directory is called a *package script*.
|
|
||||||
If a package script exists, rustpkg executes it to build the package
|
|
||||||
rather than inferring crates as described previously.
|
|
||||||
|
|
||||||
Inside `pkg.rs`, it's possible to call back into rustpkg to finish up the build.
|
|
||||||
`rustpkg::api` contains functions to build, install, or clean libraries and executables
|
|
||||||
in the way rustpkg normally would without custom build logic.
|
|
||||||
|
|
||||||
# Command reference
|
|
||||||
|
|
||||||
## build
|
|
||||||
|
|
||||||
`rustpkg build foo` searches for a package with ID `foo`
|
|
||||||
and builds it in any workspace(s) where it finds one.
|
|
||||||
Supposing such packages are found in workspaces X, Y, and Z,
|
|
||||||
the command leaves behind files in `X`'s, `Y`'s, and `Z`'s `build` directories,
|
|
||||||
but not in their `lib` or `bin` directories.
|
|
||||||
(The exception is when rustpkg fetches a package `foo`'s sources from a remote repository.
|
|
||||||
In that case, it stores both the sources *and* the build artifacts for `foo`
|
|
||||||
in the workspace that `foo` will install to (see ##install below)).
|
|
||||||
|
|
||||||
## clean
|
|
||||||
|
|
||||||
`rustpkg clean foo` deletes the contents of `foo`'s `build` directory.
|
|
||||||
|
|
||||||
## install
|
|
||||||
|
|
||||||
`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`.
|
|
||||||
If `RUST_PATH` is declared as an environment variable, then rustpkg installs the
|
|
||||||
libraries and executables into the `lib` and `bin` subdirectories
|
|
||||||
of the first entry in `RUST_PATH`.
|
|
||||||
Otherwise, if the current working directory CWD is a workspace,
|
|
||||||
it installs them into CWD's `lib` and `bin` subdirectories.
|
|
||||||
Otherwise, if the current working directory is CWD,
|
|
||||||
it installs them into the .rust/lib and .rust/bin subdirectories of CWD
|
|
||||||
(creating them if necessary).
|
|
||||||
|
|
||||||
## test
|
|
||||||
|
|
||||||
`rustpkg test foo` builds `foo`'s `test.rs` file if necessary,
|
|
||||||
then runs the resulting test executable.
|
|
|
@ -117,8 +117,8 @@ can be adjusted by passing a `--prefix` argument to
|
||||||
for more information on them.
|
for more information on them.
|
||||||
|
|
||||||
When complete, `make install` will place several programs into
|
When complete, `make install` will place several programs into
|
||||||
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
|
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||||
API-documentation tool; and `rustpkg`, the Rust package manager.
|
API-documentation tool.
|
||||||
|
|
||||||
[tarball]: http://static.rust-lang.org/dist/rust-0.9.tar.gz
|
[tarball]: http://static.rust-lang.org/dist/rust-0.9.tar.gz
|
||||||
[win-exe]: http://static.rust-lang.org/dist/rust-0.9-install.exe
|
[win-exe]: http://static.rust-lang.org/dist/rust-0.9-install.exe
|
||||||
|
@ -3087,15 +3087,6 @@ they model most closely what people expect to shadow.
|
||||||
If you use `extern mod`, per default `rustc` will look for libraries in the library search path (which you can
|
If you use `extern mod`, per default `rustc` will look for libraries in the library search path (which you can
|
||||||
extend with the `-L` switch).
|
extend with the `-L` switch).
|
||||||
|
|
||||||
However, Rust also ships with rustpkg, a package manager that is able to automatically download and build
|
|
||||||
libraries if you use it for building your crate. How it works is explained [here][rustpkg],
|
|
||||||
but for this tutorial it's only important to know that you can optionally annotate an
|
|
||||||
`extern mod` statement with a package id that rustpkg can use to identify it:
|
|
||||||
|
|
||||||
~~~ {.ignore}
|
|
||||||
extern mod rust = "github.com/mozilla/rust"; // pretend Rust is a simple library
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## Crate metadata and settings
|
## Crate metadata and settings
|
||||||
|
|
||||||
For every crate you can define a number of metadata items, such as link name, version or author.
|
For every crate you can define a number of metadata items, such as link name, version or author.
|
||||||
|
@ -3146,11 +3137,6 @@ or setting the crate type (library or executable) explicitly:
|
||||||
# fn farm() {}
|
# fn farm() {}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
> ***Note:*** The rules regarding package IDs, both as attributes and as used
|
|
||||||
in `extern mod`, as well as their interaction with `rustpkg` are
|
|
||||||
currently not clearly defined and will likely change in the
|
|
||||||
future.
|
|
||||||
|
|
||||||
## A minimal example
|
## A minimal example
|
||||||
|
|
||||||
Now for something that you can actually compile yourself.
|
Now for something that you can actually compile yourself.
|
||||||
|
@ -3253,7 +3239,8 @@ library. You can use them by linking to `extra` with an `extern mod extra;`.
|
||||||
[extra library]: extra/index.html
|
[extra library]: extra/index.html
|
||||||
|
|
||||||
Right now `extra` contains those definitions directly, but in the future it will likely just
|
Right now `extra` contains those definitions directly, but in the future it will likely just
|
||||||
re-export a bunch of 'officially blessed' crates that get managed with `rustpkg`.
|
re-export a bunch of 'officially blessed' crates that get managed with a
|
||||||
|
package manager.
|
||||||
|
|
||||||
# What next?
|
# What next?
|
||||||
|
|
||||||
|
@ -3267,7 +3254,6 @@ guides on individual topics.
|
||||||
* [The foreign function interface][ffi]
|
* [The foreign function interface][ffi]
|
||||||
* [Containers and iterators][container]
|
* [Containers and iterators][container]
|
||||||
* [Error-handling and Conditions][conditions]
|
* [Error-handling and Conditions][conditions]
|
||||||
* [Packaging up Rust code][rustpkg]
|
|
||||||
* [Documenting Rust code][rustdoc]
|
* [Documenting Rust code][rustdoc]
|
||||||
* [Testing Rust code][testing]
|
* [Testing Rust code][testing]
|
||||||
* [The Rust Runtime][runtime]
|
* [The Rust Runtime][runtime]
|
||||||
|
@ -3281,7 +3267,6 @@ There is further documentation on the [wiki], however those tend to be even more
|
||||||
[ffi]: guide-ffi.html
|
[ffi]: guide-ffi.html
|
||||||
[container]: guide-container.html
|
[container]: guide-container.html
|
||||||
[conditions]: guide-conditions.html
|
[conditions]: guide-conditions.html
|
||||||
[rustpkg]: guide-rustpkg.html
|
|
||||||
[testing]: guide-testing.html
|
[testing]: guide-testing.html
|
||||||
[runtime]: guide-runtime.html
|
[runtime]: guide-runtime.html
|
||||||
[rustdoc]: rustdoc.html
|
[rustdoc]: rustdoc.html
|
||||||
|
|
|
@ -130,7 +130,7 @@ To build an executable with debug info (experimental):
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
|
|
||||||
rustdoc, rustpkg
|
rustdoc
|
||||||
|
|
||||||
.SH "BUGS"
|
.SH "BUGS"
|
||||||
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
||||||
|
|
|
@ -84,7 +84,7 @@ The generated HTML can be viewed with any standard web browser.
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
|
|
||||||
rustc, rustpkg
|
rustc
|
||||||
|
|
||||||
.SH "BUGS"
|
.SH "BUGS"
|
||||||
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
||||||
|
|
195
man/rustpkg.1
195
man/rustpkg.1
|
@ -1,195 +0,0 @@
|
||||||
.TH RUSTPKG "1" "July 2013" "rustpkg 0.7" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
rustpkg \- package manager for Rust applications
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B rustpkg
|
|
||||||
[\fICOMMAND\fR] [\fIOPTIONS\fR] \fIINPUT\fR
|
|
||||||
|
|
||||||
.SH DESCRIPTION
|
|
||||||
|
|
||||||
This tool is a package manager for applications written in the Rust language,
|
|
||||||
available at <\fBhttps://www.rust-lang.org\fR>. It provides commands to build,
|
|
||||||
install and test Rust programs.
|
|
||||||
|
|
||||||
\fBrustpkg\fR is still a work in progress. See \fBdoc/rustpkg.md\fR in the Rust source distribution for future plans.
|
|
||||||
|
|
||||||
.SH COMMANDS
|
|
||||||
|
|
||||||
.TP
|
|
||||||
\fBbuild\fR
|
|
||||||
Searches for a package with the specified name and builds it in the workspace in
|
|
||||||
which it is found.
|
|
||||||
.TP
|
|
||||||
\fBclean\fR
|
|
||||||
Remove all generated files from the \fIbuild\fR directory in the target's workspace.
|
|
||||||
.TP
|
|
||||||
\fBinstall\fR
|
|
||||||
Builds the specified target, and all its dependencies, and then installs the
|
|
||||||
build products into the \fIlib\fR and \fIbin\fR directories of their respective
|
|
||||||
workspaces.
|
|
||||||
.TP
|
|
||||||
\fBinit\fR
|
|
||||||
Initializes the current working directory into a workspace.
|
|
||||||
|
|
||||||
.SS "BUILD COMMAND"
|
|
||||||
|
|
||||||
rustpkg build \fI[pkgname]\fR
|
|
||||||
|
|
||||||
The \fBbuild\fR command searches for a package with specified package name and
|
|
||||||
builds it in any workspace(s) where it finds one. Any dependent packages are
|
|
||||||
also built. The output files produced by the build phase are stored in the
|
|
||||||
\fIbuild\fR subdirectories of each package. The executables and libraries are
|
|
||||||
not copied to the 'bin' or 'lib' directories; that is the purpose of the
|
|
||||||
\fBinstall\fR command.
|
|
||||||
|
|
||||||
.SS "CLEAN COMMAND"
|
|
||||||
|
|
||||||
rustpkg clean \fI[pkgname]\fR
|
|
||||||
|
|
||||||
deletes the contents of package's build directory.
|
|
||||||
|
|
||||||
.SS "INSTALL COMMAND"
|
|
||||||
|
|
||||||
rustpkg install \fI[url]\fR
|
|
||||||
|
|
||||||
builds the libraries and/or executables that are targets for the specified
|
|
||||||
package name or URL, and then installs them either into package's \fIlib\fR
|
|
||||||
and \fIbin\fR directories, or into the \fIlib\fR and \fIbin\fR subdirectories
|
|
||||||
of the first entry in RUST_PATH.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ rustpkg install github.com/mozilla/servo.git#1.2
|
|
||||||
$ rustpkg install rust-glfw
|
|
||||||
|
|
||||||
.SS "INIT COMMAND"
|
|
||||||
|
|
||||||
rustpkg init
|
|
||||||
|
|
||||||
This will turn the current working directory into a workspace. The first
|
|
||||||
command you run when starting off a new project.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
$ rustpkg init
|
|
||||||
|
|
||||||
.SH "ENVIRONMENT"
|
|
||||||
|
|
||||||
.TP
|
|
||||||
RUST_PATH
|
|
||||||
A colon-separated (semicolon-separated) list of paths denoting workspaces
|
|
||||||
to search for Rust source files. See the section \fBPATHS\fR for full details.
|
|
||||||
|
|
||||||
.SH "PATHS"
|
|
||||||
|
|
||||||
The \fBrustpkg\fR tool searches for packages in the folders specified by the
|
|
||||||
\fBRUST_PATH\fR environment variable. Each folder constitutes a
|
|
||||||
\fIworkspace\fR, which contains one or more modules available to import.
|
|
||||||
|
|
||||||
In addition to the RUST_PATH settings, the following implicit paths are
|
|
||||||
\fIalways\fR searched, in the following order:
|
|
||||||
|
|
||||||
1. Any folders named ".rust" in the current directory, \fIand every parent\fR
|
|
||||||
of the curent directory, up to the filesystem root;
|
|
||||||
|
|
||||||
2. The system path "/usr/local" on Unix-style systems, or the equivalent on
|
|
||||||
Windows; and
|
|
||||||
|
|
||||||
3. A folder named ".rust" in the user's home directory (ie. "~/.rust" on Unix-
|
|
||||||
style systems or the equivalent on Windows).
|
|
||||||
|
|
||||||
.SH "PACKAGE STRUCTURE"
|
|
||||||
|
|
||||||
A valid workspace must contain each of the following subdirectories:
|
|
||||||
|
|
||||||
.TP
|
|
||||||
\fBsrc/\fR
|
|
||||||
Contains the Rust source code, with one subdirectory per package. Each
|
|
||||||
subdirectory contains source files for a given package.
|
|
||||||
.TP
|
|
||||||
\fBlib/\fR
|
|
||||||
"rustpkg install" installs libraries into a target-specific subdirectory of this directory.
|
|
||||||
.TP
|
|
||||||
\fBbin/\fR
|
|
||||||
"rustpkg install" installs executable binaries into a target-specific subdirectory of this directory.
|
|
||||||
.TP
|
|
||||||
\fBbuild/\fR
|
|
||||||
"rustpkg build" stores temporary build artifacts in a target-specific subdirectory of this directory.
|
|
||||||
|
|
||||||
For example, if "foo" is a workspace containing the package "bar", then
|
|
||||||
"foo/src/bar/main.rs" would be the "main" entry point for building a "bar"
|
|
||||||
executable.
|
|
||||||
|
|
||||||
.SH "PACKAGE IDENTIFIERS"
|
|
||||||
|
|
||||||
A package identifier uniquely identifies a package. A package can be stored in
|
|
||||||
a workspace on the local file system, or on a remote Web server, in which case
|
|
||||||
the package ID resembles a URL.
|
|
||||||
|
|
||||||
For example, \fIgithub.com/mozilla/rust\fR is a package ID
|
|
||||||
that would refer to the git repository browsable at \fIhttp://github.com/mozilla/rust\fR.
|
|
||||||
|
|
||||||
A package ID can also specify a version, like:
|
|
||||||
\fIgithub.com/mozilla/rust#0.3\fR. In this case, \fBrustpkg\fR will check that
|
|
||||||
the repository \fIgithub.com/mozilla/rust\fR has a tag named \fI0.3\fR, and
|
|
||||||
report an error otherwise.
|
|
||||||
|
|
||||||
.SH "SPECIAL MODULES"
|
|
||||||
|
|
||||||
\fBrustpkg\fR searches for four different known filenames in the src directory
|
|
||||||
in order to determine which crates to build:
|
|
||||||
|
|
||||||
.TP
|
|
||||||
\fBmain.rs\fR
|
|
||||||
Assumed to be a main entry point for building an executable (install destination is 'bin' directory).
|
|
||||||
.TP
|
|
||||||
\fBlib.rs\fR
|
|
||||||
Assumed to be a library crate (install destination is 'lib' directory).
|
|
||||||
.TP
|
|
||||||
\fBtest.rs\fR
|
|
||||||
Assumed to contain tests declared with the \fI#[test]\fR attribute.
|
|
||||||
.TP
|
|
||||||
\fBbench.rs\fR
|
|
||||||
Assumed to contain benchmarks declared with the \fI#[bench]\fR attribute.
|
|
||||||
|
|
||||||
.SH "CRATE VERSIONS"
|
|
||||||
|
|
||||||
\fBrustpkg\fR packages do not need to declare their versions with an attribute
|
|
||||||
inside one of the source files, because rustpkg infers it from the version
|
|
||||||
control system. When building a package that is in a git repository,
|
|
||||||
rustpkg assumes that the most recent tag specifies the current version. When
|
|
||||||
building a package that is not under version control, or that has no tags,
|
|
||||||
rustpkg defaults the version to 0.1.
|
|
||||||
|
|
||||||
.SH "DEPENDENCIES"
|
|
||||||
|
|
||||||
rustpkg infers dependencies from "extern mod" directives. Thus, there should
|
|
||||||
be no need to pass a "-L" flag to rustpkg to tell it where to find a library.
|
|
||||||
(In the future, it will also be possible to write an "extern mod" directive
|
|
||||||
referring to a remote package.)
|
|
||||||
|
|
||||||
.SH "CUSTOM BUILD SCRIPTS"
|
|
||||||
|
|
||||||
A file called \fIpkg.rs\fR at the root level in a workspace is called a \fIpackage
|
|
||||||
script\fR. If a package script exists, rustpkg executes it to build the
|
|
||||||
package rather than inferring crates as described previously.
|
|
||||||
|
|
||||||
Inside \fIpkg.rs\fR, it's possible to call back into rustpkg to finish up the
|
|
||||||
build. The \fIrustpkg::api\fR module contains functions to build, install, or
|
|
||||||
clean libraries and executables in the way rustpkg normally would without
|
|
||||||
custom build logic.
|
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
|
|
||||||
rustc, rustdoc
|
|
||||||
|
|
||||||
.SH "BUGS"
|
|
||||||
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
|
||||||
|
|
||||||
.SH "AUTHOR"
|
|
||||||
See \fBAUTHORS.txt\fR in the Rust source distribution. Graydon Hoare
|
|
||||||
<\fIgraydon@mozilla.com\fR> is the project leader.
|
|
||||||
|
|
||||||
.SH "COPYRIGHT"
|
|
||||||
This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR
|
|
||||||
file in the rust source distribution.
|
|
|
@ -50,9 +50,9 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
TARGET_CRATES := std extra green rustuv native flate arena glob
|
TARGET_CRATES := std extra green rustuv native flate arena glob
|
||||||
HOST_CRATES := syntax rustc rustdoc rustpkg
|
HOST_CRATES := syntax rustc rustdoc
|
||||||
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
||||||
TOOLS := compiletest rustpkg rustdoc rustc
|
TOOLS := compiletest rustdoc rustc
|
||||||
|
|
||||||
DEPS_std := native:rustrt
|
DEPS_std := native:rustrt
|
||||||
DEPS_extra := std
|
DEPS_extra := std
|
||||||
|
@ -62,17 +62,14 @@ DEPS_native := std
|
||||||
DEPS_syntax := std extra
|
DEPS_syntax := std extra
|
||||||
DEPS_rustc := syntax native:rustllvm flate arena
|
DEPS_rustc := syntax native:rustllvm flate arena
|
||||||
DEPS_rustdoc := rustc native:sundown
|
DEPS_rustdoc := rustc native:sundown
|
||||||
DEPS_rustpkg := rustc
|
|
||||||
DEPS_flate := std native:miniz
|
DEPS_flate := std native:miniz
|
||||||
DEPS_arena := std extra
|
DEPS_arena := std extra
|
||||||
DEPS_glob := std
|
DEPS_glob := std
|
||||||
|
|
||||||
TOOL_DEPS_compiletest := extra green rustuv
|
TOOL_DEPS_compiletest := extra green rustuv
|
||||||
TOOL_DEPS_rustpkg := rustpkg green rustuv
|
|
||||||
TOOL_DEPS_rustdoc := rustdoc green rustuv
|
TOOL_DEPS_rustdoc := rustdoc green rustuv
|
||||||
TOOL_DEPS_rustc := rustc green rustuv
|
TOOL_DEPS_rustc := rustc green rustuv
|
||||||
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
|
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
|
||||||
TOOL_SOURCE_rustpkg := $(S)src/driver/driver.rs
|
|
||||||
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
|
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
|
||||||
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ PKG_FILES := \
|
||||||
$(addprefix $(S)src/, \
|
$(addprefix $(S)src/, \
|
||||||
README.txt \
|
README.txt \
|
||||||
driver \
|
driver \
|
||||||
librustpkg \
|
|
||||||
librustc \
|
librustc \
|
||||||
compiletest \
|
compiletest \
|
||||||
etc \
|
etc \
|
||||||
|
|
12
mk/docs.mk
12
mk/docs.mk
|
@ -89,12 +89,6 @@ doc/rust.epub: rust.md
|
||||||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||||
$(CFG_PANDOC) $(EPUB_OPTS) --output=$@
|
$(CFG_PANDOC) $(EPUB_OPTS) --output=$@
|
||||||
|
|
||||||
DOCS += doc/rustpkg.html
|
|
||||||
doc/rustpkg.html: rustpkg.md $(HTML_DEPS)
|
|
||||||
@$(call E, pandoc: $@)
|
|
||||||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
|
||||||
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
|
|
||||||
|
|
||||||
DOCS += doc/rustdoc.html
|
DOCS += doc/rustdoc.html
|
||||||
doc/rustdoc.html: rustdoc.md $(HTML_DEPS)
|
doc/rustdoc.html: rustdoc.md $(HTML_DEPS)
|
||||||
@$(call E, pandoc: $@)
|
@$(call E, pandoc: $@)
|
||||||
|
@ -212,12 +206,6 @@ doc/guide-conditions.html: $(S)doc/guide-conditions.md $(HTML_DEPS)
|
||||||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||||
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
|
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
|
||||||
|
|
||||||
DOCS += doc/guide-rustpkg.html
|
|
||||||
doc/guide-rustpkg.html: $(S)doc/guide-rustpkg.md $(HTML_DEPS)
|
|
||||||
@$(call E, pandoc: $@)
|
|
||||||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
|
||||||
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
|
|
||||||
|
|
||||||
DOCS += doc/guide-pointers.html
|
DOCS += doc/guide-pointers.html
|
||||||
doc/guide-pointers.html: $(S)doc/guide-pointers.md $(HTML_DEPS)
|
doc/guide-pointers.html: $(S)doc/guide-pointers.md $(HTML_DEPS)
|
||||||
@$(call E, pandoc: $@)
|
@$(call E, pandoc: $@)
|
||||||
|
|
13
mk/tests.mk
13
mk/tests.mk
|
@ -185,7 +185,6 @@ check-test: cleantestlibs cleantmptestlogs all check-stage2-rfail
|
||||||
check-lite: cleantestlibs cleantmptestlogs \
|
check-lite: cleantestlibs cleantmptestlogs \
|
||||||
check-stage2-std check-stage2-extra check-stage2-rpass \
|
check-stage2-std check-stage2-extra check-stage2-rpass \
|
||||||
check-stage2-rustuv check-stage2-native check-stage2-green \
|
check-stage2-rustuv check-stage2-native check-stage2-green \
|
||||||
check-stage2-rustpkg \
|
|
||||||
check-stage2-rfail check-stage2-cfail check-stage2-rmake
|
check-stage2-rfail check-stage2-cfail check-stage2-rmake
|
||||||
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
|
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
|
||||||
|
|
||||||
|
@ -423,18 +422,6 @@ $(foreach host,$(CFG_HOST), \
|
||||||
$(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))) \
|
$(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))) \
|
||||||
))))))
|
))))))
|
||||||
|
|
||||||
# FIXME (#10104): Raise the stack size to work around rustpkg bypassing
|
|
||||||
# the code in rustc that would take care of it.
|
|
||||||
define DEF_RUSTPKG_STACK_FIX
|
|
||||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),rustpkg): export RUST_MIN_STACK=8000000
|
|
||||||
endef
|
|
||||||
|
|
||||||
$(foreach host,$(CFG_HOST), \
|
|
||||||
$(foreach target,$(CFG_TARGET), \
|
|
||||||
$(foreach stage,$(STAGES), \
|
|
||||||
$(eval $(call DEF_RUSTPKG_STACK_FIX,$(stage),$(target),$(host))))))
|
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Rules for the compiletest tests (rpass, rfail, etc.)
|
# Rules for the compiletest tests (rpass, rfail, etc.)
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
|
@ -30,7 +30,6 @@ Source layout:
|
||||||
| `test/auxiliary` | - Dependencies of tests |
|
| `test/auxiliary` | - Dependencies of tests |
|
||||||
| ------------------- | --------------------------------------------------------- |
|
| ------------------- | --------------------------------------------------------- |
|
||||||
| `librustdoc/` | The Rust API documentation tool |
|
| `librustdoc/` | The Rust API documentation tool |
|
||||||
| `librustpkg/` | The package manager and build system |
|
|
||||||
| `libuv/` | The libuv submodule |
|
| `libuv/` | The libuv submodule |
|
||||||
| ------------------- | --------------------------------------------------------- |
|
| ------------------- | --------------------------------------------------------- |
|
||||||
| `llvm/` | The LLVM submodule |
|
| `llvm/` | The LLVM submodule |
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#[cfg(rustpkg)]
|
|
||||||
extern mod this = "rustpkg";
|
|
||||||
|
|
||||||
#[cfg(rustdoc)]
|
#[cfg(rustdoc)]
|
||||||
extern mod this = "rustdoc";
|
extern mod this = "rustdoc";
|
||||||
|
|
||||||
|
|
|
@ -150,8 +150,9 @@ pub struct Options {
|
||||||
lint_opts: ~[(lint::Lint, lint::level)],
|
lint_opts: ~[(lint::Lint, lint::level)],
|
||||||
save_temps: bool,
|
save_temps: bool,
|
||||||
output_type: back::link::OutputType,
|
output_type: back::link::OutputType,
|
||||||
// This is mutable for rustpkg, which updates search paths based on the
|
// This was mutable for rustpkg, which updates search paths based on the
|
||||||
// parsed code.
|
// parsed code. It remains mutable in case its replacements wants to use
|
||||||
|
// this.
|
||||||
addl_lib_search_paths: @RefCell<HashSet<Path>>,
|
addl_lib_search_paths: @RefCell<HashSet<Path>>,
|
||||||
ar: Option<~str>,
|
ar: Option<~str>,
|
||||||
linker: Option<~str>,
|
linker: Option<~str>,
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
Right now, commands that work are "build" and "clean".
|
|
||||||
|
|
||||||
`rustpkg build` and `rustpkg clean` should work
|
|
||||||
|
|
||||||
for example:
|
|
||||||
$ cd ~/rust/src/librustpkg/testsuite/pass
|
|
||||||
$ rustpkg build hello-world
|
|
||||||
... some output ...
|
|
||||||
$ rustpkg clean hello-world
|
|
||||||
|
|
||||||
-------------
|
|
||||||
the following test packages in librustpkg/testsuite/pass:
|
|
||||||
* hello-world
|
|
||||||
* install-paths
|
|
||||||
* simple-lib
|
|
||||||
* deeply/nested/path
|
|
||||||
* fancy-lib
|
|
||||||
|
|
||||||
It fails on the following test packages:
|
|
||||||
* external-crate (no support for `extern mod` inference yet)
|
|
||||||
|
|
||||||
and should fail with proper error messages
|
|
||||||
on all of the test packages in librustpkg/testsuite/fail
|
|
||||||
* no-inferred-crates
|
|
|
@ -1,199 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use CtxMethods;
|
|
||||||
use context::*;
|
|
||||||
use crate::*;
|
|
||||||
use package_source::*;
|
|
||||||
use path_util::{platform_library_name, target_build_dir};
|
|
||||||
use target::*;
|
|
||||||
use workspace::pkg_parent_workspaces;
|
|
||||||
use workcache_support::*;
|
|
||||||
pub use path_util::default_workspace;
|
|
||||||
|
|
||||||
pub use source_control::{safe_git_clone, git_clone_url};
|
|
||||||
|
|
||||||
use std::run;
|
|
||||||
use extra::arc::{Arc,RWArc};
|
|
||||||
use extra::workcache;
|
|
||||||
use extra::workcache::{Database, FreshnessMap};
|
|
||||||
use extra::treemap::TreeMap;
|
|
||||||
use syntax::crateid::CrateId;
|
|
||||||
|
|
||||||
// A little sad -- duplicated from rustc::back::*
|
|
||||||
#[cfg(target_arch = "arm")]
|
|
||||||
fn cc_args() -> ~[~str] { ~[~"-marm"] }
|
|
||||||
#[cfg(target_arch = "mips")]
|
|
||||||
fn cc_args() -> ~[~str] { ~[] }
|
|
||||||
#[cfg(target_arch = "x86")]
|
|
||||||
fn cc_args() -> ~[~str] { ~[~"-m32"] }
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
fn cc_args() -> ~[~str] { ~[~"-m64"] }
|
|
||||||
|
|
||||||
/// Convenience functions intended for calling from pkg.rs
|
|
||||||
/// p is where to put the cache file for dependencies
|
|
||||||
pub fn default_context(sysroot: Path, p: Path) -> BuildContext {
|
|
||||||
new_default_context(new_workcache_context(&p), sysroot)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
|
|
||||||
BuildContext {
|
|
||||||
context: Context {
|
|
||||||
cfgs: ~[],
|
|
||||||
rustc_flags: RustcFlags::default(),
|
|
||||||
use_rust_path_hack: false,
|
|
||||||
},
|
|
||||||
sysroot: p,
|
|
||||||
workcache_context: c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file_is_fresh(path: &str, in_hash: &str) -> bool {
|
|
||||||
let path = Path::new(path);
|
|
||||||
path.exists() && in_hash == digest_file_with_date(&path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn binary_is_fresh(path: &str, in_hash: &str) -> bool {
|
|
||||||
let path = Path::new(path);
|
|
||||||
path.exists() && in_hash == digest_only_date(&path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_workcache_context(p: &Path) -> workcache::Context {
|
|
||||||
let db_file = p.join("rustpkg_db.json"); // ??? probably wrong
|
|
||||||
debug!("Workcache database file: {}", db_file.display());
|
|
||||||
let db = RWArc::new(Database::new(db_file));
|
|
||||||
let cfg = Arc::new(TreeMap::new());
|
|
||||||
let mut freshness: FreshnessMap = TreeMap::new();
|
|
||||||
// Set up freshness functions for every type of dependency rustpkg
|
|
||||||
// knows about
|
|
||||||
freshness.insert(~"file", file_is_fresh);
|
|
||||||
freshness.insert(~"binary", binary_is_fresh);
|
|
||||||
workcache::Context::new_with_freshness(db, cfg, Arc::new(freshness))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_lib(sysroot: Path, root: Path, name: ~str, lib: Path) {
|
|
||||||
build_lib_with_cfgs(sysroot, root, name, lib, ~[])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str, lib: Path, cfgs: ~[~str]) {
|
|
||||||
let cx = default_context(sysroot, root.clone());
|
|
||||||
let crate_id: CrateId = from_str(name).expect("valid crate id");
|
|
||||||
let pkg_src = PkgSrc {
|
|
||||||
source_workspace: root.clone(),
|
|
||||||
build_in_destination: false,
|
|
||||||
destination_workspace: root.clone(),
|
|
||||||
start_dir: root.join_many(["src", name.as_slice()]),
|
|
||||||
id: crate_id,
|
|
||||||
// n.b. This assumes the package only has one crate
|
|
||||||
libs: ~[mk_crate(lib)],
|
|
||||||
mains: ~[],
|
|
||||||
tests: ~[],
|
|
||||||
benchs: ~[]
|
|
||||||
};
|
|
||||||
pkg_src.build(&cx, cfgs, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_exe(sysroot: Path, root: Path, name: ~str, main: Path) {
|
|
||||||
build_exe_with_cfgs(sysroot, root, name, main, ~[])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str, main: Path, cfgs: ~[~str]) {
|
|
||||||
let cx = default_context(sysroot, root.clone());
|
|
||||||
let crate_id: CrateId = from_str(name).expect("valid crate id");
|
|
||||||
let pkg_src = PkgSrc {
|
|
||||||
source_workspace: root.clone(),
|
|
||||||
build_in_destination: false,
|
|
||||||
destination_workspace: root.clone(),
|
|
||||||
start_dir: root.join_many(["src", name.as_slice()]),
|
|
||||||
id: crate_id,
|
|
||||||
libs: ~[],
|
|
||||||
// n.b. This assumes the package only has one crate
|
|
||||||
mains: ~[mk_crate(main)],
|
|
||||||
tests: ~[],
|
|
||||||
benchs: ~[]
|
|
||||||
};
|
|
||||||
|
|
||||||
pkg_src.build(&cx, cfgs, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn install_pkg(cx: &BuildContext,
|
|
||||||
workspace: Path,
|
|
||||||
name: ~str,
|
|
||||||
// For now, these inputs are assumed to be inputs to each of the crates
|
|
||||||
more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path
|
|
||||||
let crate_id: CrateId = from_str(name).expect("valid crate id");
|
|
||||||
cx.install(PkgSrc::new(workspace.clone(), workspace, false, crate_id),
|
|
||||||
&WhatToBuild{ build_type: Inferred,
|
|
||||||
inputs_to_discover: more_inputs,
|
|
||||||
sources: Everything });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds an arbitrary library whose short name is `output`,
|
|
||||||
/// by invoking `tool` with arguments `args` plus "-o %s", where %s
|
|
||||||
/// is the platform-specific library name for `output`.
|
|
||||||
/// Returns that platform-specific name, or None if `tool` could not be started.
|
|
||||||
pub fn build_library_in_workspace(exec: &mut workcache::Exec,
|
|
||||||
context: &mut Context,
|
|
||||||
package_name: &str,
|
|
||||||
tool: &str,
|
|
||||||
flags: &[~str],
|
|
||||||
paths: &[~str],
|
|
||||||
output: &str) -> Option<~str> {
|
|
||||||
use command_failed = conditions::command_failed::cond;
|
|
||||||
|
|
||||||
let workspace = my_workspace(context, package_name);
|
|
||||||
let workspace_build_dir = target_build_dir(&workspace);
|
|
||||||
let out_name = workspace_build_dir.join_many([package_name.to_str(),
|
|
||||||
platform_library_name(output)]);
|
|
||||||
// make paths absolute
|
|
||||||
let crateid: CrateId = from_str(package_name).expect("valid crate id");
|
|
||||||
let absolute_paths = paths.map(|s| {
|
|
||||||
let whatever = workspace.join_many([~"src",
|
|
||||||
crateid.short_name_with_version(),
|
|
||||||
s.to_owned()]);
|
|
||||||
whatever.as_str().unwrap().to_owned()
|
|
||||||
});
|
|
||||||
|
|
||||||
let cc_args = cc_args();
|
|
||||||
|
|
||||||
let all_args = flags + absolute_paths + cc_args +
|
|
||||||
~[~"-o", out_name.as_str().unwrap().to_owned()];
|
|
||||||
match run::process_status(tool, all_args) {
|
|
||||||
Some(exit_process) => {
|
|
||||||
if exit_process.success() {
|
|
||||||
let out_name_str = out_name.as_str().unwrap().to_owned();
|
|
||||||
exec.discover_output("binary",
|
|
||||||
out_name_str,
|
|
||||||
digest_only_date(&out_name));
|
|
||||||
context.add_library_path(out_name.dir_path());
|
|
||||||
Some(out_name_str)
|
|
||||||
} else {
|
|
||||||
Some(command_failed.raise((tool.to_owned(), all_args, exit_process)))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn my_workspace(context: &Context, package_name: &str) -> Path {
|
|
||||||
use bad_pkg_id = conditions::bad_pkg_id::cond;
|
|
||||||
|
|
||||||
// (this assumes no particular version is requested)
|
|
||||||
let crateid = from_str(package_name).expect("valid crate id");
|
|
||||||
let workspaces = pkg_parent_workspaces(context, &crateid);
|
|
||||||
if workspaces.is_empty() {
|
|
||||||
bad_pkg_id.raise((Path::new(package_name), package_name.to_owned()));
|
|
||||||
}
|
|
||||||
workspaces[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mk_crate(p: Path) -> Crate {
|
|
||||||
Crate { file: p, flags: ~[], cfgs: ~[] }
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// Useful conditions
|
|
||||||
|
|
||||||
pub use syntax::crateid::CrateId;
|
|
||||||
pub use std::io::FileStat;
|
|
||||||
pub use std::io::process::ProcessExit;
|
|
||||||
pub use std::path::Path;
|
|
||||||
|
|
||||||
condition! {
|
|
||||||
pub bad_path: (Path, ~str) -> Path;
|
|
||||||
}
|
|
||||||
|
|
||||||
condition! {
|
|
||||||
pub nonexistent_package: (CrateId, ~str) -> Path;
|
|
||||||
}
|
|
||||||
|
|
||||||
condition! {
|
|
||||||
pub missing_pkg_files: (CrateId) -> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
condition! {
|
|
||||||
pub bad_pkg_id: (Path, ~str) -> CrateId;
|
|
||||||
}
|
|
||||||
|
|
||||||
condition! {
|
|
||||||
pub failed_to_create_temp_dir: (~str) -> Path;
|
|
||||||
}
|
|
||||||
|
|
||||||
condition! {
|
|
||||||
pub git_checkout_failed: (~str, Path) -> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
condition! {
|
|
||||||
// str is output of applying the command (first component)
|
|
||||||
// to the args (second component)
|
|
||||||
pub command_failed: (~str, ~[~str], ProcessExit) -> ~str;
|
|
||||||
}
|
|
|
@ -1,347 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// Context data structure used by rustpkg
|
|
||||||
|
|
||||||
use extra::workcache;
|
|
||||||
use rustc::driver::session;
|
|
||||||
use rustc::metadata::filesearch::rustlibdir;
|
|
||||||
|
|
||||||
use std::hashmap::HashSet;
|
|
||||||
|
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct Context {
|
|
||||||
// Config strings that the user passed in with --cfg
|
|
||||||
cfgs: ~[~str],
|
|
||||||
// Flags to pass to rustc
|
|
||||||
rustc_flags: RustcFlags,
|
|
||||||
// If use_rust_path_hack is true, rustpkg searches for sources
|
|
||||||
// in *package* directories that are in the RUST_PATH (for example,
|
|
||||||
// FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
|
|
||||||
// rustpkg stores build artifacts.
|
|
||||||
use_rust_path_hack: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct BuildContext {
|
|
||||||
// Context for workcache
|
|
||||||
workcache_context: workcache::Context,
|
|
||||||
// Parsed command line options
|
|
||||||
context: Context,
|
|
||||||
// The root directory containing the Rust standard libraries
|
|
||||||
sysroot: Path
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuildContext {
|
|
||||||
pub fn sysroot(&self) -> Path {
|
|
||||||
self.sysroot.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hack so that rustpkg can run either out of a rustc target dir,
|
|
||||||
// or the host dir
|
|
||||||
pub fn sysroot_to_use(&self) -> Path {
|
|
||||||
if !in_target(&self.sysroot) {
|
|
||||||
self.sysroot.clone()
|
|
||||||
} else {
|
|
||||||
let mut p = self.sysroot.clone();
|
|
||||||
p.pop();
|
|
||||||
p.pop();
|
|
||||||
p.pop();
|
|
||||||
p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the flags to pass to rustc, as a vector of strings
|
|
||||||
pub fn flag_strs(&self) -> ~[~str] {
|
|
||||||
self.context.flag_strs()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_upto(&self) -> StopBefore {
|
|
||||||
self.context.compile_upto()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_library_path(&mut self, p: Path) {
|
|
||||||
debug!("Adding library path: {}", p.display());
|
|
||||||
self.context.add_library_path(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn additional_library_paths(&self) -> HashSet<Path> {
|
|
||||||
self.context.rustc_flags.additional_library_paths.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Deliberately unsupported rustc flags:
|
|
||||||
--bin, --lib inferred from crate file names
|
|
||||||
-L inferred from extern mods
|
|
||||||
--out-dir inferred from RUST_PATH
|
|
||||||
--test use `rustpkg test`
|
|
||||||
-v -h --ls don't make sense with rustpkg
|
|
||||||
-W -A -D -F - use pragmas instead
|
|
||||||
|
|
||||||
rustc flags that aren't implemented yet:
|
|
||||||
--passes
|
|
||||||
--llvm-arg
|
|
||||||
--target-feature
|
|
||||||
--android-cross-path
|
|
||||||
*/
|
|
||||||
pub struct RustcFlags {
|
|
||||||
compile_upto: StopBefore,
|
|
||||||
// Linker to use with the --linker flag
|
|
||||||
linker: Option<~str>,
|
|
||||||
// Extra arguments to pass to rustc with the --link-args flag
|
|
||||||
link_args: Option<~str>,
|
|
||||||
// Optimization level. 0 = default. -O = 2.
|
|
||||||
optimization_level: session::OptLevel,
|
|
||||||
// True if the user passed in --save-temps
|
|
||||||
save_temps: bool,
|
|
||||||
// Target (defaults to rustc's default target)
|
|
||||||
target: Option<~str>,
|
|
||||||
// Target CPU (defaults to rustc's default target CPU)
|
|
||||||
target_cpu: Option<~str>,
|
|
||||||
// Additional library directories, which get passed with the -L flag
|
|
||||||
// This can't be set with a rustpkg flag, only from package scripts
|
|
||||||
additional_library_paths: HashSet<Path>,
|
|
||||||
// Any -Z features
|
|
||||||
experimental_features: Option<~[~str]>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for RustcFlags {
|
|
||||||
fn clone(&self) -> RustcFlags {
|
|
||||||
RustcFlags {
|
|
||||||
compile_upto: self.compile_upto,
|
|
||||||
linker: self.linker.clone(),
|
|
||||||
link_args: self.link_args.clone(),
|
|
||||||
optimization_level: self.optimization_level,
|
|
||||||
save_temps: self.save_temps,
|
|
||||||
target: self.target.clone(),
|
|
||||||
target_cpu: self.target_cpu.clone(),
|
|
||||||
additional_library_paths: self.additional_library_paths.clone(),
|
|
||||||
experimental_features: self.experimental_features.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deriving(Eq)]
|
|
||||||
pub enum StopBefore {
|
|
||||||
Nothing, // compile everything
|
|
||||||
Link, // --no-link
|
|
||||||
LLVMCompileBitcode, // --emit-llvm without -S
|
|
||||||
LLVMAssemble, // -S --emit-llvm
|
|
||||||
Assemble, // -S without --emit-llvm
|
|
||||||
Trans, // --no-trans
|
|
||||||
Pretty, // --pretty
|
|
||||||
Analysis, // --parse-only
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context {
|
|
||||||
|
|
||||||
/// Returns the flags to pass to rustc, as a vector of strings
|
|
||||||
pub fn flag_strs(&self) -> ~[~str] {
|
|
||||||
self.rustc_flags.flag_strs()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_upto(&self) -> StopBefore {
|
|
||||||
self.rustc_flags.compile_upto
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_library_path(&mut self, p: Path) {
|
|
||||||
self.rustc_flags.additional_library_paths.insert(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// We assume that if ../../rustlib exists, then we're running
|
|
||||||
/// rustpkg from a Rust target directory. This is part of a
|
|
||||||
/// kludgy hack used to adjust the sysroot.
|
|
||||||
pub fn in_target(sysroot: &Path) -> bool {
|
|
||||||
debug!("Checking whether {} is in target", sysroot.display());
|
|
||||||
let mut p = sysroot.dir_path();
|
|
||||||
p.pop();
|
|
||||||
p.push(rustlibdir());
|
|
||||||
p.is_dir()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RustcFlags {
|
|
||||||
fn flag_strs(&self) -> ~[~str] {
|
|
||||||
let linker_flag = match self.linker {
|
|
||||||
Some(ref l) => ~[~"--linker", l.clone()],
|
|
||||||
None => ~[]
|
|
||||||
};
|
|
||||||
let link_args_flag = match self.link_args {
|
|
||||||
Some(ref l) => ~[~"--link-args", l.clone()],
|
|
||||||
None => ~[]
|
|
||||||
};
|
|
||||||
let save_temps_flag = if self.save_temps { ~[~"--save-temps"] } else { ~[] };
|
|
||||||
let target_flag = match self.target {
|
|
||||||
Some(ref l) => ~[~"--target", l.clone()],
|
|
||||||
None => ~[]
|
|
||||||
};
|
|
||||||
let target_cpu_flag = match self.target_cpu {
|
|
||||||
Some(ref l) => ~[~"--target-cpu", l.clone()],
|
|
||||||
None => ~[]
|
|
||||||
};
|
|
||||||
let z_flags = match self.experimental_features {
|
|
||||||
Some(ref ls) => ls.flat_map(|s| ~[~"-Z", s.clone()]),
|
|
||||||
None => ~[]
|
|
||||||
};
|
|
||||||
linker_flag
|
|
||||||
+ link_args_flag
|
|
||||||
+ save_temps_flag
|
|
||||||
+ target_flag
|
|
||||||
+ target_cpu_flag
|
|
||||||
+ z_flags + (match self.compile_upto {
|
|
||||||
LLVMCompileBitcode => ~[~"--emit-llvm"],
|
|
||||||
LLVMAssemble => ~[~"--emit-llvm", ~"-S"],
|
|
||||||
Link => ~[~"-c"],
|
|
||||||
Trans => ~[~"--no-trans"],
|
|
||||||
Assemble => ~[~"-S"],
|
|
||||||
// n.b. Doesn't support all flavors of --pretty (yet)
|
|
||||||
Pretty => ~[~"--pretty"],
|
|
||||||
Analysis => ~[~"--parse-only"],
|
|
||||||
Nothing => ~[]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default() -> RustcFlags {
|
|
||||||
RustcFlags {
|
|
||||||
linker: None,
|
|
||||||
link_args: None,
|
|
||||||
compile_upto: Nothing,
|
|
||||||
optimization_level: session::Default,
|
|
||||||
save_temps: false,
|
|
||||||
target: None,
|
|
||||||
target_cpu: None,
|
|
||||||
additional_library_paths: HashSet::new(),
|
|
||||||
experimental_features: None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[deriving(Eq)]
|
|
||||||
pub enum Command {
|
|
||||||
BuildCmd,
|
|
||||||
CleanCmd,
|
|
||||||
DoCmd,
|
|
||||||
HelpCmd,
|
|
||||||
InfoCmd,
|
|
||||||
InitCmd,
|
|
||||||
InstallCmd,
|
|
||||||
ListCmd,
|
|
||||||
PreferCmd,
|
|
||||||
TestCmd,
|
|
||||||
UninstallCmd,
|
|
||||||
UnpreferCmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Command {
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Option<Command> {
|
|
||||||
match s {
|
|
||||||
&"build" => Some(BuildCmd),
|
|
||||||
&"clean" => Some(CleanCmd),
|
|
||||||
&"do" => Some(DoCmd),
|
|
||||||
&"help" => Some(HelpCmd),
|
|
||||||
&"info" => Some(InfoCmd),
|
|
||||||
&"install" => Some(InstallCmd),
|
|
||||||
&"list" => Some(ListCmd),
|
|
||||||
&"prefer" => Some(PreferCmd),
|
|
||||||
&"test" => Some(TestCmd),
|
|
||||||
&"init" => Some(InitCmd),
|
|
||||||
&"uninstall" => Some(UninstallCmd),
|
|
||||||
&"unprefer" => Some(UnpreferCmd),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if any of the flags given are incompatible with the cmd
|
|
||||||
pub fn flags_forbidden_for_cmd(flags: &RustcFlags,
|
|
||||||
cfgs: &[~str],
|
|
||||||
cmd: Command, user_supplied_opt_level: bool) -> bool {
|
|
||||||
let complain = |s| {
|
|
||||||
println!("The {} option can only be used with the `build` command:
|
|
||||||
rustpkg [options..] build {} [package-ID]", s, s);
|
|
||||||
};
|
|
||||||
|
|
||||||
if flags.linker.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
|
||||||
println!("The --linker option can only be used with the build or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if flags.link_args.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
|
||||||
println!("The --link-args option can only be used with the build or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cfgs.is_empty() && cmd != BuildCmd && cmd != InstallCmd && cmd != TestCmd {
|
|
||||||
println!("The --cfg option can only be used with the build, test, or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if user_supplied_opt_level && cmd != BuildCmd && cmd != InstallCmd {
|
|
||||||
println!("The -O and --opt-level options can only be used with the build \
|
|
||||||
or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.save_temps && cmd != BuildCmd && cmd != InstallCmd {
|
|
||||||
println!("The --save-temps option can only be used with the build \
|
|
||||||
or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.target.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
|
||||||
println!("The --target option can only be used with the build \
|
|
||||||
or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if flags.target_cpu.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
|
||||||
println!("The --target-cpu option can only be used with the build \
|
|
||||||
or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if flags.experimental_features.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
|
||||||
println!("The -Z option can only be used with the build or install commands.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
match flags.compile_upto {
|
|
||||||
Link if cmd != BuildCmd => {
|
|
||||||
complain("--no-link");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Trans if cmd != BuildCmd => {
|
|
||||||
complain("--no-trans");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Assemble if cmd != BuildCmd => {
|
|
||||||
complain("-S");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Pretty if cmd != BuildCmd => {
|
|
||||||
complain("--pretty");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Analysis if cmd != BuildCmd => {
|
|
||||||
complain("--parse-only");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
LLVMCompileBitcode if cmd != BuildCmd => {
|
|
||||||
complain("--emit-llvm");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
LLVMAssemble if cmd != BuildCmd => {
|
|
||||||
complain("--emit-llvm");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#[allow(dead_code)];
|
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
use std::vec;
|
|
||||||
|
|
||||||
/// A crate is a unit of Rust code to be compiled into a binary or library
|
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct Crate {
|
|
||||||
file: Path,
|
|
||||||
flags: ~[~str],
|
|
||||||
cfgs: ~[~str]
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Crate {
|
|
||||||
|
|
||||||
pub fn new(p: &Path) -> Crate {
|
|
||||||
Crate {
|
|
||||||
file: (*p).clone(),
|
|
||||||
flags: ~[],
|
|
||||||
cfgs: ~[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flag(&self, flag: ~str) -> Crate {
|
|
||||||
Crate {
|
|
||||||
flags: vec::append(self.flags.clone(), [flag]),
|
|
||||||
.. (*self).clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flags(&self, flags: ~[~str]) -> Crate {
|
|
||||||
Crate {
|
|
||||||
flags: vec::append(self.flags.clone(), flags),
|
|
||||||
.. (*self).clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cfg(&self, cfg: ~str) -> Crate {
|
|
||||||
Crate {
|
|
||||||
cfgs: vec::append(self.cfgs.clone(), [cfg]),
|
|
||||||
.. (*self).clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cfgs(&self, cfgs: ~[~str]) -> Crate {
|
|
||||||
Crate {
|
|
||||||
cfgs: vec::append(self.cfgs.clone(), cfgs),
|
|
||||||
.. (*self).clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub static COPY_FAILED_CODE: int = 65;
|
|
||||||
pub static BAD_FLAG_CODE: int = 67;
|
|
||||||
pub static NONEXISTENT_PACKAGE_CODE: int = 68;
|
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// Listing installed packages
|
|
||||||
|
|
||||||
use rustc::metadata::filesearch::rust_path;
|
|
||||||
use std::os;
|
|
||||||
use std::io;
|
|
||||||
use std::io::fs;
|
|
||||||
use syntax::crateid::CrateId;
|
|
||||||
|
|
||||||
pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool {
|
|
||||||
let workspaces = rust_path();
|
|
||||||
for p in workspaces.iter() {
|
|
||||||
let binfiles = {
|
|
||||||
let _guard = io::ignore_io_error();
|
|
||||||
fs::readdir(&p.join("bin"))
|
|
||||||
};
|
|
||||||
for exec in binfiles.iter() {
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
match exec.filestem_str() {
|
|
||||||
None => (),
|
|
||||||
Some(exec_path) => {
|
|
||||||
let crate_id = from_str(exec_path).expect("valid crate id");
|
|
||||||
if !f(&crate_id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let libfiles = {
|
|
||||||
let _guard = io::ignore_io_error();
|
|
||||||
fs::readdir(&p.join("lib"))
|
|
||||||
};
|
|
||||||
for lib in libfiles.iter() {
|
|
||||||
debug!("Full name: {}", lib.display());
|
|
||||||
match has_library(lib) {
|
|
||||||
Some(basename) => {
|
|
||||||
let parent = p.join("lib");
|
|
||||||
debug!("parent = {}, child = {}",
|
|
||||||
parent.display(), lib.display());
|
|
||||||
let rel_p = lib.path_relative_from(&parent).unwrap();
|
|
||||||
debug!("Rel: {}", rel_p.display());
|
|
||||||
let rel_path = rel_p.join(basename);
|
|
||||||
rel_path.display().with_str(|s| {
|
|
||||||
debug!("Rel name: {}", s);
|
|
||||||
let crate_id = from_str(s).expect("valid crate id");
|
|
||||||
f(&crate_id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_library(p: &Path) -> Option<~str> {
|
|
||||||
let files = {
|
|
||||||
let _guard = io::ignore_io_error();
|
|
||||||
fs::readdir(p)
|
|
||||||
};
|
|
||||||
for path in files.iter() {
|
|
||||||
if path.extension_str() == Some(os::consts::DLL_EXTENSION) {
|
|
||||||
let stuff : &str = path.filestem_str().expect("has_library: weird path");
|
|
||||||
let mut stuff2 = stuff.split_str("-");
|
|
||||||
let stuff3: ~[&str] = stuff2.collect();
|
|
||||||
// argh
|
|
||||||
let chars_to_drop = os::consts::DLL_PREFIX.len();
|
|
||||||
return Some(stuff3[0].slice(chars_to_drop, stuff3[0].len()).to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn package_is_installed(p: &CrateId) -> bool {
|
|
||||||
let mut is_installed = false;
|
|
||||||
list_installed_packages(|installed| {
|
|
||||||
if installed == p {
|
|
||||||
is_installed = true;
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
is_installed
|
|
||||||
}
|
|
|
@ -1,816 +0,0 @@
|
||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// rustpkg - a package manager and build system for Rust
|
|
||||||
|
|
||||||
#[crate_id = "rustpkg#0.10-pre"];
|
|
||||||
#[license = "MIT/ASL2"];
|
|
||||||
#[crate_type = "dylib"];
|
|
||||||
|
|
||||||
#[feature(globs, managed_boxes)];
|
|
||||||
|
|
||||||
extern mod extra;
|
|
||||||
extern mod rustc;
|
|
||||||
extern mod syntax;
|
|
||||||
|
|
||||||
use std::{os, run, str, task};
|
|
||||||
use std::io::process;
|
|
||||||
use std::io;
|
|
||||||
use std::io::fs;
|
|
||||||
pub use std::path::Path;
|
|
||||||
|
|
||||||
use extra::workcache;
|
|
||||||
use rustc::driver::{driver, session};
|
|
||||||
use rustc::metadata::creader::Loader;
|
|
||||||
use rustc::metadata::filesearch;
|
|
||||||
use rustc::metadata::filesearch::rust_path;
|
|
||||||
use rustc::util::sha2;
|
|
||||||
use syntax::{ast, diagnostic};
|
|
||||||
use syntax::crateid::CrateId;
|
|
||||||
use messages::{error, warn, note};
|
|
||||||
use parse_args::{ParseResult, parse_args};
|
|
||||||
use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
|
|
||||||
use path_util::in_rust_path;
|
|
||||||
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
|
|
||||||
use path_util::{target_executable_in_workspace, target_library_in_workspace, dir_has_crate_file};
|
|
||||||
use source_control::{CheckedOutSources, is_git_dir, make_read_only};
|
|
||||||
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
|
|
||||||
use workspace::determine_destination;
|
|
||||||
use context::{BuildContext, Trans, Nothing, Pretty, Analysis,
|
|
||||||
LLVMAssemble, LLVMCompileBitcode};
|
|
||||||
use context::{Command, BuildCmd, CleanCmd, DoCmd, HelpCmd, InfoCmd, InstallCmd, ListCmd,
|
|
||||||
PreferCmd, TestCmd, InitCmd, UninstallCmd, UnpreferCmd};
|
|
||||||
use package_source::PkgSrc;
|
|
||||||
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
|
|
||||||
use target::{Main, Tests, MaybeCustom, Inferred, JustOne};
|
|
||||||
use workcache_support::digest_only_date;
|
|
||||||
use exit_codes::{COPY_FAILED_CODE};
|
|
||||||
|
|
||||||
pub mod api;
|
|
||||||
mod conditions;
|
|
||||||
pub mod context;
|
|
||||||
mod crate;
|
|
||||||
pub mod exit_codes;
|
|
||||||
mod installed_packages;
|
|
||||||
mod messages;
|
|
||||||
pub mod package_source;
|
|
||||||
mod parse_args;
|
|
||||||
mod path_util;
|
|
||||||
mod source_control;
|
|
||||||
mod target;
|
|
||||||
#[cfg(not(windows), test)] // FIXME test failure on windows: #10471
|
|
||||||
mod tests;
|
|
||||||
mod util;
|
|
||||||
pub mod version;
|
|
||||||
pub mod workcache_support;
|
|
||||||
mod workspace;
|
|
||||||
|
|
||||||
pub mod usage;
|
|
||||||
|
|
||||||
/// A PkgScript represents user-supplied custom logic for
|
|
||||||
/// special build hooks. This only exists for packages with
|
|
||||||
/// an explicit package script.
|
|
||||||
struct PkgScript<'a> {
|
|
||||||
/// Uniquely identifies this package
|
|
||||||
id: &'a CrateId,
|
|
||||||
/// File path for the package script
|
|
||||||
input: Path,
|
|
||||||
/// The session to use *only* for compiling the custom
|
|
||||||
/// build script
|
|
||||||
sess: session::Session,
|
|
||||||
/// The config for compiling the custom build script
|
|
||||||
cfg: ast::CrateConfig,
|
|
||||||
/// The crate and ast_map for the custom build script
|
|
||||||
crate_and_map: Option<(ast::Crate, syntax::ast_map::Map)>,
|
|
||||||
/// Directory in which to store build output
|
|
||||||
build_dir: Path
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PkgScript<'a> {
|
|
||||||
/// Given the path name for a package script
|
|
||||||
/// and a package ID, parse the package script into
|
|
||||||
/// a PkgScript that we can then execute
|
|
||||||
fn parse<'a>(sysroot: Path,
|
|
||||||
script: Path,
|
|
||||||
workspace: &Path,
|
|
||||||
id: &'a CrateId) -> PkgScript<'a> {
|
|
||||||
// Get the executable name that was invoked
|
|
||||||
let binary = os::args()[0];
|
|
||||||
// Build the rustc session data structures to pass
|
|
||||||
// to the compiler
|
|
||||||
debug!("pkgscript parse: {}", sysroot.display());
|
|
||||||
let options = @session::Options {
|
|
||||||
binary: binary,
|
|
||||||
maybe_sysroot: Some(@sysroot),
|
|
||||||
outputs: ~[session::OutputExecutable],
|
|
||||||
.. (*session::basic_options()).clone()
|
|
||||||
};
|
|
||||||
let input = driver::FileInput(script.clone());
|
|
||||||
let sess = driver::build_session(options,
|
|
||||||
Some(script.clone()),
|
|
||||||
@diagnostic::DefaultEmitter);
|
|
||||||
let cfg = driver::build_configuration(sess);
|
|
||||||
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
|
||||||
let loader = &mut Loader::new(sess);
|
|
||||||
let crate_and_map = driver::phase_2_configure_and_expand(sess,
|
|
||||||
cfg.clone(),
|
|
||||||
loader,
|
|
||||||
crate);
|
|
||||||
let work_dir = build_pkg_id_in_workspace(id, workspace);
|
|
||||||
|
|
||||||
debug!("Returning package script with id {}", id.to_str());
|
|
||||||
|
|
||||||
PkgScript {
|
|
||||||
id: id,
|
|
||||||
input: script,
|
|
||||||
sess: sess,
|
|
||||||
cfg: cfg,
|
|
||||||
crate_and_map: Some(crate_and_map),
|
|
||||||
build_dir: work_dir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_custom(&mut self, exec: &mut workcache::Exec) -> ~str {
|
|
||||||
let sess = self.sess;
|
|
||||||
|
|
||||||
debug!("Working directory = {}", self.build_dir.display());
|
|
||||||
// Collect together any user-defined commands in the package script
|
|
||||||
let (crate, ast_map) = self.crate_and_map.take_unwrap();
|
|
||||||
let crate = util::ready_crate(sess, crate);
|
|
||||||
debug!("Building output filenames with script name {}",
|
|
||||||
driver::source_name(&driver::FileInput(self.input.clone())));
|
|
||||||
let exe = self.build_dir.join("pkg" + util::exe_suffix());
|
|
||||||
util::compile_crate_from_input(&self.input,
|
|
||||||
exec,
|
|
||||||
Nothing,
|
|
||||||
&self.build_dir,
|
|
||||||
sess,
|
|
||||||
crate,
|
|
||||||
ast_map,
|
|
||||||
Main);
|
|
||||||
// Discover the output
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
// Discover the output
|
|
||||||
exec.discover_output("binary", exe.as_str().unwrap().to_owned(), digest_only_date(&exe));
|
|
||||||
exe.as_str().unwrap().to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the contents of this package script, where <what>
|
|
||||||
/// is the command to pass to it (e.g., "build", "clean", "install")
|
|
||||||
/// Returns a pair of an exit code and list of configs (obtained by
|
|
||||||
/// calling the package script's configs() function if it exists, or
|
|
||||||
/// None if `exe` could not be started.
|
|
||||||
fn run_custom(exe: &Path, sysroot: &Path) -> Option<(~[~str], process::ProcessExit)> {
|
|
||||||
debug!("Running program: {} {} {}", exe.as_str().unwrap().to_owned(),
|
|
||||||
sysroot.display(), "install");
|
|
||||||
// FIXME #7401 should support commands besides `install`
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let opt_status = run::process_status(exe.as_str().unwrap(),
|
|
||||||
[sysroot.as_str().unwrap().to_owned(), ~"install"]);
|
|
||||||
match opt_status {
|
|
||||||
Some(status) => {
|
|
||||||
if !status.success() {
|
|
||||||
debug!("run_custom: first pkg command failed with {:?}", status);
|
|
||||||
Some((~[], status))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
debug!("Running program (configs): {} {} {}",
|
|
||||||
exe.display(), sysroot.display(), "configs");
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let opt_output = run::process_output(exe.as_str().unwrap(),
|
|
||||||
[sysroot.as_str().unwrap().to_owned(),
|
|
||||||
~"configs"]);
|
|
||||||
match opt_output {
|
|
||||||
Some(output) => {
|
|
||||||
debug!("run_custom: second pkg command did {:?}", output.status);
|
|
||||||
// Run the configs() function to get the configs
|
|
||||||
let cfgs = str::from_utf8(output.output).unwrap().words()
|
|
||||||
.map(|w| w.to_owned()).collect();
|
|
||||||
Some((cfgs, output.status))
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
debug!("run_custom: second pkg command failed to start");
|
|
||||||
Some((~[], status))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
debug!("run_custom: first pkg command failed to start");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CtxMethods {
|
|
||||||
fn run(&self, cmd: Command, args: ~[~str]);
|
|
||||||
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
|
|
||||||
/// Returns a pair of the selected package ID, and the destination workspace
|
|
||||||
fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(CrateId, Path)>;
|
|
||||||
/// Returns the destination workspace
|
|
||||||
fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild);
|
|
||||||
fn clean(&self, workspace: &Path, id: &CrateId);
|
|
||||||
fn info(&self);
|
|
||||||
/// Returns a pair. First component is a list of installed paths,
|
|
||||||
/// second is a list of declared and discovered inputs
|
|
||||||
fn install(&self, src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]);
|
|
||||||
/// Returns a list of installed files
|
|
||||||
fn install_no_build(&self,
|
|
||||||
build_workspace: &Path,
|
|
||||||
build_inputs: &[Path],
|
|
||||||
target_workspace: &Path,
|
|
||||||
id: &CrateId) -> ~[~str];
|
|
||||||
fn prefer(&self, _id: &str, _vers: Option<~str>);
|
|
||||||
fn test(&self, id: &CrateId, workspace: &Path);
|
|
||||||
fn uninstall(&self, _id: &str, _vers: Option<~str>);
|
|
||||||
fn unprefer(&self, _id: &str, _vers: Option<~str>);
|
|
||||||
fn init(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CtxMethods for BuildContext {
|
|
||||||
fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(CrateId, Path)> {
|
|
||||||
let cwd = os::getcwd();
|
|
||||||
|
|
||||||
if args.len() < 1 {
|
|
||||||
match cwd_to_workspace() {
|
|
||||||
None if dir_has_crate_file(&cwd) => {
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let crateid = from_str(cwd.filename_str().unwrap()).expect("valid crate id");
|
|
||||||
let mut pkg_src = PkgSrc::new(cwd, default_workspace(), true, crateid);
|
|
||||||
self.build(&mut pkg_src, what);
|
|
||||||
match pkg_src {
|
|
||||||
PkgSrc { destination_workspace: ws,
|
|
||||||
id: id, .. } => {
|
|
||||||
Some((id, ws))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => { usage::build(); None }
|
|
||||||
Some((ws, crateid)) => {
|
|
||||||
let mut pkg_src = PkgSrc::new(ws.clone(), ws, false, crateid);
|
|
||||||
self.build(&mut pkg_src, what);
|
|
||||||
match pkg_src {
|
|
||||||
PkgSrc { destination_workspace: ws,
|
|
||||||
id: id, .. } => {
|
|
||||||
Some((id, ws))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// The package id is presumed to be the first command-line
|
|
||||||
// argument
|
|
||||||
let crateid = from_str(args[0]).expect("valid crate id");
|
|
||||||
let mut dest_ws = default_workspace();
|
|
||||||
each_pkg_parent_workspace(&self.context, &crateid, |workspace| {
|
|
||||||
debug!("found pkg {} in workspace {}, trying to build",
|
|
||||||
crateid.to_str(), workspace.display());
|
|
||||||
dest_ws = determine_destination(os::getcwd(),
|
|
||||||
self.context.use_rust_path_hack,
|
|
||||||
workspace);
|
|
||||||
let mut pkg_src = PkgSrc::new(workspace.clone(), dest_ws.clone(),
|
|
||||||
false, crateid.clone());
|
|
||||||
self.build(&mut pkg_src, what);
|
|
||||||
true
|
|
||||||
});
|
|
||||||
// n.b. If this builds multiple packages, it only returns the workspace for
|
|
||||||
// the last one. The whole building-multiple-packages-with-the-same-ID is weird
|
|
||||||
// anyway and there are no tests for it, so maybe take it out
|
|
||||||
Some((crateid, dest_ws))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, cmd: Command, args: ~[~str]) {
|
|
||||||
let cwd = os::getcwd();
|
|
||||||
match cmd {
|
|
||||||
BuildCmd => {
|
|
||||||
self.build_args(args, &WhatToBuild::new(MaybeCustom, Everything));
|
|
||||||
}
|
|
||||||
CleanCmd => {
|
|
||||||
if args.len() < 1 {
|
|
||||||
match cwd_to_workspace() {
|
|
||||||
None => { usage::clean(); return }
|
|
||||||
// tjc: Maybe clean should clean all the packages in the
|
|
||||||
// current workspace, though?
|
|
||||||
Some((ws, crateid)) => self.clean(&ws, &crateid)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// The package id is presumed to be the first command-line
|
|
||||||
// argument
|
|
||||||
let crateid = from_str(args[0]).expect("valid crate id");
|
|
||||||
self.clean(&cwd, &crateid); // tjc: should use workspace, not cwd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DoCmd => {
|
|
||||||
if args.len() < 2 {
|
|
||||||
return usage::do_cmd();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.do_cmd(args[0].clone(), args[1].clone());
|
|
||||||
}
|
|
||||||
HelpCmd => {
|
|
||||||
if args.len() != 1 {
|
|
||||||
return usage::general();
|
|
||||||
}
|
|
||||||
match FromStr::from_str(args[0]) {
|
|
||||||
Some(help_cmd) => usage::usage_for_command(help_cmd),
|
|
||||||
None => {
|
|
||||||
usage::general();
|
|
||||||
error(format!("{} is not a recognized command", args[0]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InfoCmd => {
|
|
||||||
self.info();
|
|
||||||
}
|
|
||||||
InstallCmd => {
|
|
||||||
if args.len() < 1 {
|
|
||||||
match cwd_to_workspace() {
|
|
||||||
None if dir_has_crate_file(&cwd) => {
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
|
|
||||||
let inferred_crateid =
|
|
||||||
from_str(cwd.filename_str().unwrap()).expect("valid crate id");
|
|
||||||
self.install(PkgSrc::new(cwd, default_workspace(),
|
|
||||||
true, inferred_crateid),
|
|
||||||
&WhatToBuild::new(MaybeCustom, Everything));
|
|
||||||
}
|
|
||||||
None => { usage::install(); return; }
|
|
||||||
Some((ws, crateid)) => {
|
|
||||||
let pkg_src = PkgSrc::new(ws.clone(), ws.clone(), false, crateid);
|
|
||||||
self.install(pkg_src, &WhatToBuild::new(MaybeCustom,
|
|
||||||
Everything));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// The package id is presumed to be the first command-line
|
|
||||||
// argument
|
|
||||||
let crateid = from_str(args[0]).expect("valid crate id");
|
|
||||||
let workspaces = pkg_parent_workspaces(&self.context, &crateid);
|
|
||||||
debug!("package ID = {}, found it in {:?} workspaces",
|
|
||||||
crateid.to_str(), workspaces.len());
|
|
||||||
if workspaces.is_empty() {
|
|
||||||
let d = default_workspace();
|
|
||||||
let src = PkgSrc::new(d.clone(), d, false, crateid.clone());
|
|
||||||
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for workspace in workspaces.iter() {
|
|
||||||
let dest = determine_destination(os::getcwd(),
|
|
||||||
self.context.use_rust_path_hack,
|
|
||||||
workspace);
|
|
||||||
let src = PkgSrc::new(workspace.clone(),
|
|
||||||
dest,
|
|
||||||
self.context.use_rust_path_hack,
|
|
||||||
crateid.clone());
|
|
||||||
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ListCmd => {
|
|
||||||
println!("Installed packages:");
|
|
||||||
installed_packages::list_installed_packages(|pkg_id| {
|
|
||||||
println!("{}", pkg_id.path);
|
|
||||||
true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
PreferCmd => {
|
|
||||||
if args.len() < 1 {
|
|
||||||
return usage::prefer();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.prefer(args[0], None);
|
|
||||||
}
|
|
||||||
TestCmd => {
|
|
||||||
// Build the test executable
|
|
||||||
let maybe_id_and_workspace = self.build_args(args,
|
|
||||||
&WhatToBuild::new(MaybeCustom, Tests));
|
|
||||||
match maybe_id_and_workspace {
|
|
||||||
Some((pkg_id, workspace)) => {
|
|
||||||
// Assuming it's built, run the tests
|
|
||||||
self.test(&pkg_id, &workspace);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
error("Testing failed because building the specified package failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InitCmd => {
|
|
||||||
if args.len() != 0 {
|
|
||||||
return usage::init();
|
|
||||||
} else {
|
|
||||||
self.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UninstallCmd => {
|
|
||||||
if args.len() < 1 {
|
|
||||||
return usage::uninstall();
|
|
||||||
}
|
|
||||||
|
|
||||||
let crateid = from_str(args[0]).expect("valid crate id");
|
|
||||||
if !installed_packages::package_is_installed(&crateid) {
|
|
||||||
warn(format!("Package {} doesn't seem to be installed! \
|
|
||||||
Doing nothing.", args[0]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let rp = rust_path();
|
|
||||||
assert!(!rp.is_empty());
|
|
||||||
each_pkg_parent_workspace(&self.context, &crateid, |workspace| {
|
|
||||||
path_util::uninstall_package_from(workspace, &crateid);
|
|
||||||
note(format!("Uninstalled package {} (was installed in {})",
|
|
||||||
crateid.to_str(), workspace.display()));
|
|
||||||
true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UnpreferCmd => {
|
|
||||||
if args.len() < 1 {
|
|
||||||
return usage::unprefer();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.unprefer(args[0], None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_cmd(&self, _cmd: &str, _pkgname: &str) {
|
|
||||||
// stub
|
|
||||||
fail!("`do` not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) {
|
|
||||||
use conditions::git_checkout_failed::cond;
|
|
||||||
|
|
||||||
let workspace = pkg_src.source_workspace.clone();
|
|
||||||
let crateid = pkg_src.id.clone();
|
|
||||||
|
|
||||||
let path = crateid.path.as_slice();
|
|
||||||
debug!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \
|
|
||||||
crateid = {} pkgsrc start_dir = {}", workspace.display(),
|
|
||||||
in_rust_path(&workspace), is_git_dir(&workspace.join(path)),
|
|
||||||
crateid.to_str(), pkg_src.start_dir.display());
|
|
||||||
debug!("build: what to build = {:?}", what_to_build);
|
|
||||||
|
|
||||||
// If workspace isn't in the RUST_PATH, and it's a git repo,
|
|
||||||
// then clone it into the first entry in RUST_PATH, and repeat
|
|
||||||
if !in_rust_path(&workspace) && is_git_dir(&workspace.join(path)) {
|
|
||||||
let mut out_dir = default_workspace().join("src");
|
|
||||||
out_dir.push(path);
|
|
||||||
let git_result = source_control::safe_git_clone(&workspace.join(path),
|
|
||||||
&crateid.version,
|
|
||||||
&out_dir);
|
|
||||||
match git_result {
|
|
||||||
CheckedOutSources => make_read_only(&out_dir),
|
|
||||||
_ => cond.raise((path.to_owned(), out_dir.clone()))
|
|
||||||
};
|
|
||||||
let default_ws = default_workspace();
|
|
||||||
debug!("Calling build recursively with {:?} and {:?}", default_ws.display(),
|
|
||||||
crateid.to_str());
|
|
||||||
return self.build(&mut PkgSrc::new(default_ws.clone(),
|
|
||||||
default_ws,
|
|
||||||
false,
|
|
||||||
crateid.clone()), what_to_build);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is there custom build logic? If so, use it
|
|
||||||
let mut custom = false;
|
|
||||||
debug!("Package source directory = {}", pkg_src.to_str());
|
|
||||||
let opt = pkg_src.package_script_option();
|
|
||||||
debug!("Calling pkg_script_option on {:?}", opt);
|
|
||||||
let cfgs = match (pkg_src.package_script_option(), what_to_build.build_type) {
|
|
||||||
(Some(package_script_path), MaybeCustom) => {
|
|
||||||
let sysroot = self.sysroot_to_use();
|
|
||||||
// Build the package script if needed
|
|
||||||
let script_build = format!("build_package_script({})",
|
|
||||||
package_script_path.display());
|
|
||||||
let pkg_exe = self.workcache_context.with_prep(script_build, |prep| {
|
|
||||||
let subsysroot = sysroot.clone();
|
|
||||||
let psp = package_script_path.clone();
|
|
||||||
let ws = workspace.clone();
|
|
||||||
let pid = crateid.clone();
|
|
||||||
prep.exec(proc(exec) {
|
|
||||||
let mut pscript = PkgScript::parse(subsysroot.clone(),
|
|
||||||
psp.clone(),
|
|
||||||
&ws,
|
|
||||||
&pid);
|
|
||||||
pscript.build_custom(exec)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
// We always *run* the package script
|
|
||||||
match PkgScript::run_custom(&Path::new(pkg_exe), &sysroot) {
|
|
||||||
Some((cfgs, hook_result)) => {
|
|
||||||
debug!("Command return code = {:?}", hook_result);
|
|
||||||
if !hook_result.success() {
|
|
||||||
fail!("Error running custom build command")
|
|
||||||
}
|
|
||||||
custom = true;
|
|
||||||
// otherwise, the package script succeeded
|
|
||||||
cfgs
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
fail!("Error starting custom build command")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(_), Inferred) => {
|
|
||||||
debug!("There is a package script, but we're ignoring it");
|
|
||||||
~[]
|
|
||||||
}
|
|
||||||
(None, _) => {
|
|
||||||
debug!("No package script, continuing");
|
|
||||||
~[]
|
|
||||||
}
|
|
||||||
} + self.context.cfgs;
|
|
||||||
|
|
||||||
// If there was a package script, it should have finished
|
|
||||||
// the build already. Otherwise...
|
|
||||||
if !custom {
|
|
||||||
match what_to_build.sources {
|
|
||||||
// Find crates inside the workspace
|
|
||||||
Everything => pkg_src.find_crates(),
|
|
||||||
// Find only tests
|
|
||||||
Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path::new(s)) }),
|
|
||||||
// Don't infer any crates -- just build the one that was requested
|
|
||||||
JustOne(ref p) => {
|
|
||||||
// We expect that p is relative to the package source's start directory,
|
|
||||||
// so check that assumption
|
|
||||||
debug!("JustOne: p = {}", p.display());
|
|
||||||
assert!(pkg_src.start_dir.join(p).exists());
|
|
||||||
if is_lib(p) {
|
|
||||||
PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
|
|
||||||
} else if is_main(p) {
|
|
||||||
PkgSrc::push_crate(&mut pkg_src.mains, 0, p);
|
|
||||||
} else if is_test(p) {
|
|
||||||
PkgSrc::push_crate(&mut pkg_src.tests, 0, p);
|
|
||||||
} else if is_bench(p) {
|
|
||||||
PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
|
|
||||||
} else {
|
|
||||||
warn(format!("Not building any crates for dependency {}", p.display()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Build it!
|
|
||||||
pkg_src.build(self, cfgs, []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clean(&self, workspace: &Path, id: &CrateId) {
|
|
||||||
// Could also support a custom build hook in the pkg
|
|
||||||
// script for cleaning files rustpkg doesn't know about.
|
|
||||||
// Do something reasonable for now
|
|
||||||
|
|
||||||
let dir = build_pkg_id_in_workspace(id, workspace);
|
|
||||||
note(format!("Cleaning package {} (removing directory {})",
|
|
||||||
id.to_str(), dir.display()));
|
|
||||||
if dir.exists() {
|
|
||||||
fs::rmdir_recursive(&dir);
|
|
||||||
note(format!("Removed directory {}", dir.display()));
|
|
||||||
}
|
|
||||||
|
|
||||||
note(format!("Cleaned package {}", id.to_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn info(&self) {
|
|
||||||
// stub
|
|
||||||
fail!("info not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
|
|
||||||
|
|
||||||
let id = pkg_src.id.clone();
|
|
||||||
|
|
||||||
let mut installed_files = ~[];
|
|
||||||
let mut inputs = ~[];
|
|
||||||
let mut build_inputs = ~[];
|
|
||||||
|
|
||||||
debug!("Installing package source: {}", pkg_src.to_str());
|
|
||||||
|
|
||||||
// workcache only knows about *crates*. Building a package
|
|
||||||
// just means inferring all the crates in it, then building each one.
|
|
||||||
self.build(&mut pkg_src, what);
|
|
||||||
|
|
||||||
debug!("Done building package source {}", pkg_src.to_str());
|
|
||||||
|
|
||||||
let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
|
|
||||||
pkg_src.tests.clone(), pkg_src.benchs.clone()];
|
|
||||||
debug!("In declare inputs for {}", id.to_str());
|
|
||||||
for cs in to_do.iter() {
|
|
||||||
for c in cs.iter() {
|
|
||||||
let path = pkg_src.start_dir.join(&c.file);
|
|
||||||
debug!("Recording input: {}", path.display());
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
inputs.push((~"file", path.as_str().unwrap().to_owned()));
|
|
||||||
build_inputs.push(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = self.install_no_build(pkg_src.build_workspace(),
|
|
||||||
build_inputs,
|
|
||||||
&pkg_src.destination_workspace,
|
|
||||||
&id).map(|s| Path::new(s.as_slice()));
|
|
||||||
installed_files = installed_files + result;
|
|
||||||
note(format!("Installed package {} to {}",
|
|
||||||
id.to_str(),
|
|
||||||
pkg_src.destination_workspace.display()));
|
|
||||||
(installed_files, inputs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// again, working around lack of Encodable for Path
|
|
||||||
fn install_no_build(&self,
|
|
||||||
build_workspace: &Path,
|
|
||||||
build_inputs: &[Path],
|
|
||||||
target_workspace: &Path,
|
|
||||||
id: &CrateId) -> ~[~str] {
|
|
||||||
|
|
||||||
debug!("install_no_build: assuming {} comes from {} with target {}",
|
|
||||||
id.to_str(), build_workspace.display(), target_workspace.display());
|
|
||||||
|
|
||||||
// Now copy stuff into the install dirs
|
|
||||||
let maybe_executable = built_executable_in_workspace(id, build_workspace);
|
|
||||||
let maybe_library = built_library_in_workspace(id, build_workspace);
|
|
||||||
let target_exec = target_executable_in_workspace(id, target_workspace);
|
|
||||||
let target_lib = maybe_library.as_ref()
|
|
||||||
.map(|_| target_library_in_workspace(id, target_workspace));
|
|
||||||
|
|
||||||
debug!("target_exec = {} target_lib = {:?} \
|
|
||||||
maybe_executable = {:?} maybe_library = {:?}",
|
|
||||||
target_exec.display(), target_lib,
|
|
||||||
maybe_executable, maybe_library);
|
|
||||||
|
|
||||||
let install_tag = format!("install({}-{})", id.path, id.version_or_default());
|
|
||||||
self.workcache_context.with_prep(install_tag, |prep| {
|
|
||||||
for ee in maybe_executable.iter() {
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
prep.declare_input("binary",
|
|
||||||
ee.as_str().unwrap(),
|
|
||||||
workcache_support::digest_only_date(ee));
|
|
||||||
}
|
|
||||||
for ll in maybe_library.iter() {
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
prep.declare_input("binary",
|
|
||||||
ll.as_str().unwrap(),
|
|
||||||
workcache_support::digest_only_date(ll));
|
|
||||||
}
|
|
||||||
let subex = maybe_executable.clone();
|
|
||||||
let sublib = maybe_library.clone();
|
|
||||||
let sub_target_ex = target_exec.clone();
|
|
||||||
let sub_target_lib = target_lib.clone();
|
|
||||||
let sub_build_inputs = build_inputs.to_owned();
|
|
||||||
prep.exec(proc(exe_thing) {
|
|
||||||
let mut outputs = ~[];
|
|
||||||
// Declare all the *inputs* to the declared input too, as inputs
|
|
||||||
for executable in subex.iter() {
|
|
||||||
exe_thing.discover_input("binary",
|
|
||||||
executable.as_str().unwrap().to_owned(),
|
|
||||||
workcache_support::digest_only_date(executable));
|
|
||||||
}
|
|
||||||
for library in sublib.iter() {
|
|
||||||
exe_thing.discover_input("binary",
|
|
||||||
library.as_str().unwrap().to_owned(),
|
|
||||||
workcache_support::digest_only_date(library));
|
|
||||||
}
|
|
||||||
|
|
||||||
for transitive_dependency in sub_build_inputs.iter() {
|
|
||||||
exe_thing.discover_input(
|
|
||||||
"file",
|
|
||||||
transitive_dependency.as_str().unwrap().to_owned(),
|
|
||||||
workcache_support::digest_file_with_date(transitive_dependency));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for exec in subex.iter() {
|
|
||||||
debug!("Copying: {} -> {}", exec.display(), sub_target_ex.display());
|
|
||||||
fs::mkdir_recursive(&sub_target_ex.dir_path(), io::UserRWX);
|
|
||||||
fs::copy(exec, &sub_target_ex);
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
exe_thing.discover_output("binary",
|
|
||||||
sub_target_ex.as_str().unwrap(),
|
|
||||||
workcache_support::digest_only_date(&sub_target_ex));
|
|
||||||
outputs.push(sub_target_ex.as_str().unwrap().to_owned());
|
|
||||||
}
|
|
||||||
for lib in sublib.iter() {
|
|
||||||
let mut target_lib = sub_target_lib
|
|
||||||
.clone().expect(format!("I built {} but apparently \
|
|
||||||
didn't install it!", lib.display()));
|
|
||||||
target_lib.set_filename(lib.filename().expect("weird target lib"));
|
|
||||||
fs::mkdir_recursive(&target_lib.dir_path(), io::UserRWX);
|
|
||||||
fs::copy(lib, &target_lib);
|
|
||||||
debug!("3. discovering output {}", target_lib.display());
|
|
||||||
exe_thing.discover_output("binary",
|
|
||||||
target_lib.as_str().unwrap(),
|
|
||||||
workcache_support::digest_only_date(&target_lib));
|
|
||||||
outputs.push(target_lib.as_str().unwrap().to_owned());
|
|
||||||
}
|
|
||||||
outputs
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prefer(&self, _id: &str, _vers: Option<~str>) {
|
|
||||||
fail!("prefer not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test(&self, crateid: &CrateId, workspace: &Path) {
|
|
||||||
match built_test_in_workspace(crateid, workspace) {
|
|
||||||
Some(test_exec) => {
|
|
||||||
debug!("test: test_exec = {}", test_exec.display());
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let opt_status = run::process_status(test_exec.as_str().unwrap(), [~"--test"]);
|
|
||||||
match opt_status {
|
|
||||||
Some(status) => {
|
|
||||||
if !status.success() {
|
|
||||||
fail!("Some tests failed");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => fail!("Could not exec `{}`", test_exec.display())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
error(format!("Internal error: test executable for package ID {} in workspace {} \
|
|
||||||
wasn't built! Please report this as a bug.",
|
|
||||||
crateid.to_str(), workspace.display()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(&self) {
|
|
||||||
fs::mkdir_recursive(&Path::new("src"), io::UserRWX);
|
|
||||||
fs::mkdir_recursive(&Path::new("bin"), io::UserRWX);
|
|
||||||
fs::mkdir_recursive(&Path::new("lib"), io::UserRWX);
|
|
||||||
fs::mkdir_recursive(&Path::new("build"), io::UserRWX);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uninstall(&self, _id: &str, _vers: Option<~str>) {
|
|
||||||
fail!("uninstall not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unprefer(&self, _id: &str, _vers: Option<~str>) {
|
|
||||||
fail!("unprefer not yet implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
println!("WARNING: The Rust package manager is experimental and may be unstable");
|
|
||||||
os::set_exit_status(main_args(os::args()));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main_args(args: &[~str]) -> int {
|
|
||||||
|
|
||||||
let (command, args, context, supplied_sysroot) = match parse_args(args) {
|
|
||||||
Ok(ParseResult {
|
|
||||||
command: cmd,
|
|
||||||
args: args,
|
|
||||||
context: ctx,
|
|
||||||
sysroot: sroot}) => (cmd, args, ctx, sroot),
|
|
||||||
Err(error_code) => {
|
|
||||||
debug!("Parsing failed. Returning error code {}", error_code);
|
|
||||||
return error_code
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!("Finished parsing commandline args {:?}", args);
|
|
||||||
debug!(" Using command: {:?}", command);
|
|
||||||
debug!(" Using args {:?}", args);
|
|
||||||
debug!(" Using cflags: {:?}", context.rustc_flags);
|
|
||||||
debug!(" Using rust_path_hack {:b}", context.use_rust_path_hack);
|
|
||||||
debug!(" Using cfgs: {:?}", context.cfgs);
|
|
||||||
debug!(" Using supplied_sysroot: {:?}", supplied_sysroot);
|
|
||||||
|
|
||||||
let sysroot = match supplied_sysroot {
|
|
||||||
Some(s) => Path::new(s),
|
|
||||||
_ => filesearch::get_or_default_sysroot()
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("Using sysroot: {}", sysroot.display());
|
|
||||||
let ws = default_workspace();
|
|
||||||
debug!("Will store workcache in {}", ws.display());
|
|
||||||
|
|
||||||
// Wrap the rest in task::try in case of a condition failure in a task
|
|
||||||
let result = task::try(proc() {
|
|
||||||
BuildContext {
|
|
||||||
context: context,
|
|
||||||
sysroot: sysroot.clone(), // Currently, only tests override this
|
|
||||||
workcache_context: api::default_context(sysroot.clone(),
|
|
||||||
default_workspace()).workcache_context
|
|
||||||
}.run(command, args.clone())
|
|
||||||
});
|
|
||||||
// FIXME #9262: This is using the same error code for all errors,
|
|
||||||
// and at least one test case succeeds if rustpkg returns COPY_FAILED_CODE,
|
|
||||||
// when actually, it might set the exit code for that even if a different
|
|
||||||
// unhandled condition got raised.
|
|
||||||
if result.is_err() { return COPY_FAILED_CODE; }
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use extra::term;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
pub fn note(msg: &str) {
|
|
||||||
pretty_message(msg, "note: ", term::color::GREEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn warn(msg: &str) {
|
|
||||||
pretty_message(msg, "warning: ", term::color::YELLOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(msg: &str) {
|
|
||||||
pretty_message(msg, "error: ", term::color::RED);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pretty_message<'a>(msg: &'a str,
|
|
||||||
prefix: &'a str,
|
|
||||||
color: term::color::Color) {
|
|
||||||
let mut term = term::Terminal::new(io::stdout());
|
|
||||||
let mut stdout = io::stdout();
|
|
||||||
match term {
|
|
||||||
Ok(ref mut t) => {
|
|
||||||
t.fg(color);
|
|
||||||
t.write(prefix.as_bytes());
|
|
||||||
t.reset();
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
stdout.write(prefix.as_bytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stdout.write(msg.as_bytes());
|
|
||||||
stdout.write(['\n' as u8]);
|
|
||||||
}
|
|
|
@ -1,554 +0,0 @@
|
||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
extern mod extra;
|
|
||||||
|
|
||||||
use target::*;
|
|
||||||
use std::io;
|
|
||||||
use std::io::fs;
|
|
||||||
use std::os;
|
|
||||||
use context::*;
|
|
||||||
use crate::Crate;
|
|
||||||
use messages::*;
|
|
||||||
use source_control::{safe_git_clone, git_clone_url, DirToUse, CheckedOutSources};
|
|
||||||
use source_control::make_read_only;
|
|
||||||
use path_util::{find_dir_using_rust_path_hack, make_dir_rwx_recursive, default_workspace};
|
|
||||||
use path_util::{target_build_dir, versionize, dir_has_crate_file};
|
|
||||||
use util::{compile_crate, DepMap};
|
|
||||||
use workcache_support;
|
|
||||||
use workcache_support::{digest_only_date, digest_file_with_date, crate_tag};
|
|
||||||
use extra::workcache;
|
|
||||||
use extra::treemap::TreeMap;
|
|
||||||
use syntax::crateid::CrateId;
|
|
||||||
use rustc::driver::session;
|
|
||||||
|
|
||||||
// An enumeration of the unpacked source of a package workspace.
|
|
||||||
// This contains a list of files found in the source workspace.
|
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct PkgSrc {
|
|
||||||
/// Root of where the package source code lives
|
|
||||||
source_workspace: Path,
|
|
||||||
/// If build_in_destination is true, temporary results should
|
|
||||||
/// go in the build/ subdirectory of the destination workspace.
|
|
||||||
/// (Otherwise, they go in the build/ subdirectory of the
|
|
||||||
/// source workspace.) This happens if the "RUST_PATH hack" is
|
|
||||||
/// in effect, or if sources were fetched from a remote
|
|
||||||
/// repository.
|
|
||||||
build_in_destination: bool,
|
|
||||||
/// Where to install the results. May or may not be the same
|
|
||||||
/// as source_workspace
|
|
||||||
destination_workspace: Path,
|
|
||||||
// Directory to start looking in for packages -- normally
|
|
||||||
// this is workspace/src/id but it may be just workspace
|
|
||||||
start_dir: Path,
|
|
||||||
id: CrateId,
|
|
||||||
libs: ~[Crate],
|
|
||||||
mains: ~[Crate],
|
|
||||||
tests: ~[Crate],
|
|
||||||
benchs: ~[Crate],
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum BuildSort { InPlace, Discovered }
|
|
||||||
|
|
||||||
impl ToStr for PkgSrc {
|
|
||||||
fn to_str(&self) -> ~str {
|
|
||||||
format!("Package ID {} in start dir {} [workspaces = {} -> {}]",
|
|
||||||
self.id.to_str(),
|
|
||||||
self.start_dir.display(),
|
|
||||||
self.source_workspace.display(),
|
|
||||||
self.destination_workspace.display())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
condition! {
|
|
||||||
build_err: (~str) -> ~str;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prefixes(p: &Path) -> Prefixes {
|
|
||||||
Prefixes {
|
|
||||||
components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(),
|
|
||||||
remaining: ~[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Prefixes {
|
|
||||||
components: ~[~str],
|
|
||||||
remaining: ~[~str]
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator<(Path, Path)> for Prefixes {
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<(Path, Path)> {
|
|
||||||
if self.components.len() <= 1 {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let last = self.components.pop().unwrap();
|
|
||||||
self.remaining.unshift(last);
|
|
||||||
// converting to str and then back is a little unfortunate
|
|
||||||
Some((Path::new(self.components.connect("/")),
|
|
||||||
Path::new(self.remaining.connect("/"))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PkgSrc {
|
|
||||||
pub fn new(mut source_workspace: Path,
|
|
||||||
destination_workspace: Path,
|
|
||||||
use_rust_path_hack: bool,
|
|
||||||
id: CrateId) -> PkgSrc {
|
|
||||||
use conditions::nonexistent_package::cond;
|
|
||||||
|
|
||||||
debug!("Checking package source for package ID {}, \
|
|
||||||
workspace = {} -> {}, use_rust_path_hack = {:?}",
|
|
||||||
id.to_str(),
|
|
||||||
source_workspace.display(),
|
|
||||||
destination_workspace.display(),
|
|
||||||
use_rust_path_hack);
|
|
||||||
|
|
||||||
let mut destination_workspace = destination_workspace.clone();
|
|
||||||
|
|
||||||
let mut to_try = ~[];
|
|
||||||
let mut output_names = ~[];
|
|
||||||
let build_dir = target_build_dir(&source_workspace);
|
|
||||||
|
|
||||||
if use_rust_path_hack {
|
|
||||||
to_try.push(source_workspace.clone());
|
|
||||||
} else {
|
|
||||||
// We search for sources under both src/ and build/ , because build/ is where
|
|
||||||
// automatically-checked-out sources go.
|
|
||||||
let path = Path::new(id.path.as_slice());
|
|
||||||
let mut result = source_workspace.join("src");
|
|
||||||
result.push(&path.dir_path());
|
|
||||||
result.push(id.short_name_with_version());
|
|
||||||
to_try.push(result);
|
|
||||||
let mut result = source_workspace.join("src");
|
|
||||||
result.push(&path);
|
|
||||||
to_try.push(result);
|
|
||||||
|
|
||||||
let mut result = build_dir.join("src");
|
|
||||||
result.push(&path.dir_path());
|
|
||||||
result.push(id.short_name_with_version());
|
|
||||||
to_try.push(result.clone());
|
|
||||||
output_names.push(result);
|
|
||||||
let mut other_result = build_dir.join("src");
|
|
||||||
other_result.push(&path);
|
|
||||||
to_try.push(other_result.clone());
|
|
||||||
output_names.push(other_result);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("Checking dirs: {:?}", to_try.map(|p| p.display().to_str()).connect(":"));
|
|
||||||
|
|
||||||
let path = to_try.iter().find(|&d| d.is_dir()
|
|
||||||
&& dir_has_crate_file(d));
|
|
||||||
|
|
||||||
// See the comments on the definition of PkgSrc
|
|
||||||
let mut build_in_destination = use_rust_path_hack;
|
|
||||||
debug!("1. build_in_destination = {:?}", build_in_destination);
|
|
||||||
|
|
||||||
let dir: Path = match path {
|
|
||||||
Some(d) => (*d).clone(),
|
|
||||||
None => {
|
|
||||||
// See if any of the prefixes of this package ID form a valid package ID
|
|
||||||
// That is, is this a package ID that points into the middle of a workspace?
|
|
||||||
for (prefix, suffix) in prefixes(&Path::new(id.path.as_slice())) {
|
|
||||||
let crate_id: Option<CrateId> = from_str(prefix.as_str().unwrap());
|
|
||||||
let crate_id = crate_id.expect("valid crate id");
|
|
||||||
let path = build_dir.join(crate_id.path.as_slice());
|
|
||||||
debug!("in loop: checking if {} is a directory", path.display());
|
|
||||||
if path.is_dir() {
|
|
||||||
let ps = PkgSrc::new(source_workspace,
|
|
||||||
destination_workspace,
|
|
||||||
use_rust_path_hack,
|
|
||||||
crate_id);
|
|
||||||
match ps {
|
|
||||||
PkgSrc {
|
|
||||||
source_workspace: source,
|
|
||||||
destination_workspace: destination,
|
|
||||||
start_dir: start,
|
|
||||||
id: id, .. } => {
|
|
||||||
let result = PkgSrc {
|
|
||||||
source_workspace: source.clone(),
|
|
||||||
build_in_destination: build_in_destination,
|
|
||||||
destination_workspace: destination,
|
|
||||||
start_dir: start.join(&suffix),
|
|
||||||
id: id,
|
|
||||||
libs: ~[],
|
|
||||||
mains: ~[],
|
|
||||||
tests: ~[],
|
|
||||||
benchs: ~[]
|
|
||||||
};
|
|
||||||
debug!("pkgsrc: Returning {}", result.to_str());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ok, no prefixes work, so try fetching from git
|
|
||||||
let mut ok_d = None;
|
|
||||||
for w in output_names.iter() {
|
|
||||||
debug!("Calling fetch_git on {}", w.display());
|
|
||||||
let target_dir_opt = PkgSrc::fetch_git(w, &id);
|
|
||||||
for p in target_dir_opt.iter() {
|
|
||||||
ok_d = Some(p.clone());
|
|
||||||
build_in_destination = true;
|
|
||||||
debug!("2. build_in_destination = {:?}", build_in_destination);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
match ok_d {
|
|
||||||
Some(ref d) => {
|
|
||||||
let path = Path::new(id.path.as_slice());
|
|
||||||
if d.is_ancestor_of(&path)
|
|
||||||
|| d.is_ancestor_of(&versionize(id.path, &id.version)) {
|
|
||||||
// Strip off the package ID
|
|
||||||
source_workspace = d.clone();
|
|
||||||
for _ in path.components() {
|
|
||||||
source_workspace.pop();
|
|
||||||
}
|
|
||||||
// Strip off the src/ part
|
|
||||||
source_workspace.pop();
|
|
||||||
// Strip off the build/<target-triple> part to get the workspace
|
|
||||||
destination_workspace = source_workspace.clone();
|
|
||||||
destination_workspace.pop();
|
|
||||||
destination_workspace.pop();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match ok_d {
|
|
||||||
Some(d) => d,
|
|
||||||
None => {
|
|
||||||
// See if the sources are in $CWD
|
|
||||||
let cwd = os::getcwd();
|
|
||||||
if dir_has_crate_file(&cwd) {
|
|
||||||
return PkgSrc {
|
|
||||||
// In this case, source_workspace isn't really a workspace.
|
|
||||||
// This data structure needs yet more refactoring.
|
|
||||||
source_workspace: cwd.clone(),
|
|
||||||
destination_workspace: default_workspace(),
|
|
||||||
build_in_destination: true,
|
|
||||||
start_dir: cwd,
|
|
||||||
id: id,
|
|
||||||
libs: ~[],
|
|
||||||
mains: ~[],
|
|
||||||
benchs: ~[],
|
|
||||||
tests: ~[]
|
|
||||||
}
|
|
||||||
} else if use_rust_path_hack {
|
|
||||||
match find_dir_using_rust_path_hack(&id) {
|
|
||||||
Some(d) => d,
|
|
||||||
None => {
|
|
||||||
cond.raise((id.clone(),
|
|
||||||
~"supplied path for package dir does not \
|
|
||||||
exist, and couldn't interpret it as a URL fragment"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cond.raise((id.clone(),
|
|
||||||
~"supplied path for package dir does not \
|
|
||||||
exist, and couldn't interpret it as a URL fragment"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!("3. build_in_destination = {:?}", build_in_destination);
|
|
||||||
debug!("source: {} dest: {}", source_workspace.display(), destination_workspace.display());
|
|
||||||
|
|
||||||
debug!("For package id {}, returning {}", id.to_str(), dir.display());
|
|
||||||
|
|
||||||
if !dir.is_dir() {
|
|
||||||
cond.raise((id.clone(), ~"supplied path for package dir is a \
|
|
||||||
non-directory"));
|
|
||||||
}
|
|
||||||
|
|
||||||
PkgSrc {
|
|
||||||
source_workspace: source_workspace.clone(),
|
|
||||||
build_in_destination: build_in_destination,
|
|
||||||
destination_workspace: destination_workspace,
|
|
||||||
start_dir: dir,
|
|
||||||
id: id,
|
|
||||||
libs: ~[],
|
|
||||||
mains: ~[],
|
|
||||||
tests: ~[],
|
|
||||||
benchs: ~[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try interpreting self's package id as a git repository, and try
|
|
||||||
/// fetching it and caching it in a local directory. Return the cached directory
|
|
||||||
/// if this was successful, None otherwise. Similarly, if the package id
|
|
||||||
/// refers to a git repo on the local version, also check it out.
|
|
||||||
/// (right now we only support git)
|
|
||||||
pub fn fetch_git(local: &Path, crateid: &CrateId) -> Option<Path> {
|
|
||||||
use conditions::git_checkout_failed::cond;
|
|
||||||
|
|
||||||
let cwd = os::getcwd();
|
|
||||||
let path = Path::new(crateid.path.as_slice());
|
|
||||||
debug!("Checking whether {} (path = {}) exists locally. Cwd = {}, does it? {:?}",
|
|
||||||
crateid.to_str(), crateid.path,
|
|
||||||
cwd.display(),
|
|
||||||
path.exists());
|
|
||||||
|
|
||||||
match safe_git_clone(&path, &crateid.version, local) {
|
|
||||||
CheckedOutSources => {
|
|
||||||
make_read_only(local);
|
|
||||||
Some(local.clone())
|
|
||||||
}
|
|
||||||
DirToUse(clone_target) => {
|
|
||||||
if path.components().nth(1).is_none() {
|
|
||||||
// If a non-URL, don't bother trying to fetch
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let url = format!("https://{}", path.as_str().unwrap());
|
|
||||||
debug!("Fetching package: git clone {} {} [version={}]",
|
|
||||||
url, clone_target.display(), crateid.version_or_default());
|
|
||||||
|
|
||||||
let mut failed = false;
|
|
||||||
|
|
||||||
cond.trap(|_| {
|
|
||||||
failed = true;
|
|
||||||
}).inside(|| git_clone_url(url, &clone_target, &crateid.version));
|
|
||||||
|
|
||||||
if failed {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move clone_target to local.
|
|
||||||
// First, create all ancestor directories.
|
|
||||||
let moved = make_dir_rwx_recursive(&local.dir_path())
|
|
||||||
&& io::result(|| fs::rename(&clone_target, local)).is_ok();
|
|
||||||
if moved { Some(local.clone()) }
|
|
||||||
else { None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a file named "pkg.rs" in the start directory exists,
|
|
||||||
// return the path for it. Otherwise, None
|
|
||||||
pub fn package_script_option(&self) -> Option<Path> {
|
|
||||||
let maybe_path = self.start_dir.join("pkg.rs");
|
|
||||||
debug!("package_script_option: checking whether {} exists", maybe_path.display());
|
|
||||||
if maybe_path.exists() {
|
|
||||||
Some(maybe_path)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
|
|
||||||
let mut it = p.components().peekable();
|
|
||||||
if prefix > 0 {
|
|
||||||
it.nth(prefix-1); // skip elements
|
|
||||||
}
|
|
||||||
assert!(it.peek().is_some());
|
|
||||||
let mut sub = Path::new(".");
|
|
||||||
for c in it {
|
|
||||||
sub.push(c);
|
|
||||||
}
|
|
||||||
debug!("Will compile crate {}", sub.display());
|
|
||||||
cs.push(Crate::new(&sub));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Infers crates to build. Called only in the case where there
|
|
||||||
/// is no custom build logic
|
|
||||||
pub fn find_crates(&mut self) {
|
|
||||||
self.find_crates_with_filter(|_| true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_crates_with_filter(&mut self, filter: |&str| -> bool) {
|
|
||||||
use conditions::missing_pkg_files::cond;
|
|
||||||
|
|
||||||
let prefix = self.start_dir.components().len();
|
|
||||||
debug!("Matching against {}", self.id.name);
|
|
||||||
for pth in fs::walk_dir(&self.start_dir) {
|
|
||||||
let maybe_known_crate_set = match pth.filename_str() {
|
|
||||||
Some(filename) if filter(filename) => match filename {
|
|
||||||
"lib.rs" => Some(&mut self.libs),
|
|
||||||
"main.rs" => Some(&mut self.mains),
|
|
||||||
"test.rs" => Some(&mut self.tests),
|
|
||||||
"bench.rs" => Some(&mut self.benchs),
|
|
||||||
_ => None
|
|
||||||
},
|
|
||||||
_ => None
|
|
||||||
};
|
|
||||||
|
|
||||||
match maybe_known_crate_set {
|
|
||||||
Some(crate_set) => PkgSrc::push_crate(crate_set, prefix, &pth),
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
|
|
||||||
if crate_sets.iter().all(|crate_set| crate_set.is_empty()) {
|
|
||||||
|
|
||||||
note("Couldn't infer any crates to build.\n\
|
|
||||||
Try naming a crate `main.rs`, `lib.rs`, \
|
|
||||||
`test.rs`, or `bench.rs`.");
|
|
||||||
cond.raise(self.id.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("In {}, found {} libs, {} mains, {} tests, {} benchs",
|
|
||||||
self.start_dir.display(),
|
|
||||||
self.libs.len(),
|
|
||||||
self.mains.len(),
|
|
||||||
self.tests.len(),
|
|
||||||
self.benchs.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_crates(&self,
|
|
||||||
ctx: &BuildContext,
|
|
||||||
deps: &mut DepMap,
|
|
||||||
crates: &[Crate],
|
|
||||||
cfgs: &[~str],
|
|
||||||
what: OutputType,
|
|
||||||
inputs_to_discover: &[(~str, Path)]) {
|
|
||||||
for crate in crates.iter() {
|
|
||||||
let path = self.start_dir.join(&crate.file);
|
|
||||||
debug!("build_crates: compiling {}", path.display());
|
|
||||||
let cfgs = crate.cfgs + cfgs;
|
|
||||||
|
|
||||||
ctx.workcache_context.with_prep(crate_tag(&path), |prep| {
|
|
||||||
debug!("Building crate {}, declaring it as an input", path.display());
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
prep.declare_input("file", path.as_str().unwrap(),
|
|
||||||
workcache_support::digest_file_with_date(&path));
|
|
||||||
let subpath = path.clone();
|
|
||||||
let subcfgs = cfgs.clone();
|
|
||||||
let subcx = ctx.clone();
|
|
||||||
let id = self.id.clone();
|
|
||||||
let sub_dir = self.build_workspace().clone();
|
|
||||||
let sub_flags = crate.flags.clone();
|
|
||||||
let sub_deps = deps.clone();
|
|
||||||
let inputs = inputs_to_discover.map(|&(ref k, ref p)|
|
|
||||||
(k.clone(), p.as_str().unwrap().to_owned()));
|
|
||||||
prep.exec(proc(exec) {
|
|
||||||
for &(ref kind, ref p) in inputs.iter() {
|
|
||||||
let pth = Path::new(p.clone());
|
|
||||||
exec.discover_input(*kind, *p, if *kind == ~"file" {
|
|
||||||
digest_file_with_date(&pth)
|
|
||||||
} else if *kind == ~"binary" {
|
|
||||||
digest_only_date(&Path::new(p.clone()))
|
|
||||||
} else {
|
|
||||||
fail!("Bad kind in build_crates")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
debug!("Compiling crate {}; its output will be in {}",
|
|
||||||
subpath.display(), sub_dir.display());
|
|
||||||
let opt: session::OptLevel = subcx.context.rustc_flags.optimization_level;
|
|
||||||
let result = compile_crate(&subcx,
|
|
||||||
exec,
|
|
||||||
&id,
|
|
||||||
&subpath,
|
|
||||||
&sub_dir,
|
|
||||||
&mut (sub_deps.clone()),
|
|
||||||
sub_flags,
|
|
||||||
subcfgs,
|
|
||||||
opt,
|
|
||||||
what);
|
|
||||||
// FIXME: result is an Option<Path>. The following code did not take that
|
|
||||||
// into account. I'm not sure if the workcache really likes seeing the
|
|
||||||
// output as "Some(\"path\")". But I don't know what to do about it.
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let result = result.as_ref().map(|p|p.as_str().unwrap());
|
|
||||||
debug!("Result of compiling {} was {}", subpath.display(), result.to_str());
|
|
||||||
result.to_str()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Declare all the crate files in the package source as inputs
|
|
||||||
/// (to the package)
|
|
||||||
pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
|
|
||||||
let to_do = ~[self.libs.clone(), self.mains.clone(),
|
|
||||||
self.tests.clone(), self.benchs.clone()];
|
|
||||||
debug!("In declare inputs, self = {}", self.to_str());
|
|
||||||
for cs in to_do.iter() {
|
|
||||||
for c in cs.iter() {
|
|
||||||
let path = self.start_dir.join(&c.file);
|
|
||||||
debug!("Declaring input: {}", path.display());
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
prep.declare_input("file", path.as_str().unwrap(),
|
|
||||||
workcache_support::digest_file_with_date(&path.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(&self,
|
|
||||||
build_context: &BuildContext,
|
|
||||||
// DepMap is a map from str (crate name) to (kind, name) --
|
|
||||||
// it tracks discovered dependencies per-crate
|
|
||||||
cfgs: ~[~str],
|
|
||||||
inputs_to_discover: &[(~str, Path)]) -> DepMap {
|
|
||||||
let mut deps = TreeMap::new();
|
|
||||||
let libs = self.libs.clone();
|
|
||||||
let mains = self.mains.clone();
|
|
||||||
let tests = self.tests.clone();
|
|
||||||
let benchs = self.benchs.clone();
|
|
||||||
debug!("Building libs in {}, destination = {}",
|
|
||||||
self.source_workspace.display(),
|
|
||||||
self.build_workspace().display());
|
|
||||||
self.build_crates(build_context,
|
|
||||||
&mut deps,
|
|
||||||
libs,
|
|
||||||
cfgs,
|
|
||||||
Lib,
|
|
||||||
inputs_to_discover);
|
|
||||||
debug!("Building mains");
|
|
||||||
self.build_crates(build_context,
|
|
||||||
&mut deps,
|
|
||||||
mains,
|
|
||||||
cfgs,
|
|
||||||
Main,
|
|
||||||
inputs_to_discover);
|
|
||||||
debug!("Building tests");
|
|
||||||
self.build_crates(build_context,
|
|
||||||
&mut deps,
|
|
||||||
tests,
|
|
||||||
cfgs,
|
|
||||||
Test,
|
|
||||||
inputs_to_discover);
|
|
||||||
debug!("Building benches");
|
|
||||||
self.build_crates(build_context,
|
|
||||||
&mut deps,
|
|
||||||
benchs,
|
|
||||||
cfgs,
|
|
||||||
Bench,
|
|
||||||
inputs_to_discover);
|
|
||||||
deps
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the workspace to put temporary files in. See the comment on `PkgSrc`
|
|
||||||
pub fn build_workspace<'a>(&'a self) -> &'a Path {
|
|
||||||
if self.build_in_destination {
|
|
||||||
&self.destination_workspace
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
&self.source_workspace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Debugging
|
|
||||||
pub fn dump_crates(&self) {
|
|
||||||
let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
|
|
||||||
for crate_set in crate_sets.iter() {
|
|
||||||
for c in crate_set.iter() {
|
|
||||||
debug!("Built crate: {}", c.file.display())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use context::{Context, RustcFlags, Trans, Link, Nothing, Pretty, Analysis, Assemble,
|
|
||||||
LLVMAssemble, LLVMCompileBitcode};
|
|
||||||
use context::{Command, flags_forbidden_for_cmd};
|
|
||||||
use rustc::version;
|
|
||||||
use exit_codes::{BAD_FLAG_CODE};
|
|
||||||
use rustc::driver::{session};
|
|
||||||
|
|
||||||
use usage;
|
|
||||||
|
|
||||||
use extra::{getopts};
|
|
||||||
use std::{result};
|
|
||||||
use std::hashmap::HashSet;
|
|
||||||
|
|
||||||
/// Result of parsing command line arguments
|
|
||||||
pub struct ParseResult {
|
|
||||||
// Command
|
|
||||||
command: Command,
|
|
||||||
// Args
|
|
||||||
args: ~[~str],
|
|
||||||
// Parsed command line flags
|
|
||||||
context: Context,
|
|
||||||
// Path to system root
|
|
||||||
sysroot: Option<~str>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses command line arguments of rustpkg.
|
|
||||||
/// Returns a triplet (command, remaining_args, context)
|
|
||||||
pub fn parse_args(args: &[~str]) -> Result<ParseResult, int> {
|
|
||||||
let opts = ~[ getopts::optflag("h"), getopts::optflag("help"),
|
|
||||||
getopts::optflag("no-link"),
|
|
||||||
getopts::optflag("no-trans"),
|
|
||||||
// n.b. Ignores different --pretty options for now
|
|
||||||
getopts::optflag("pretty"),
|
|
||||||
getopts::optflag("parse-only"),
|
|
||||||
getopts::optflag("S"), getopts::optflag("assembly"),
|
|
||||||
getopts::optmulti("c"), getopts::optmulti("cfg"),
|
|
||||||
getopts::optflag("v"), getopts::optflag("version"),
|
|
||||||
getopts::optflag("r"), getopts::optflag("rust-path-hack"),
|
|
||||||
getopts::optopt("sysroot"),
|
|
||||||
getopts::optflag("emit-llvm"),
|
|
||||||
getopts::optopt("linker"),
|
|
||||||
getopts::optopt("link-args"),
|
|
||||||
getopts::optopt("opt-level"),
|
|
||||||
getopts::optflag("O"),
|
|
||||||
getopts::optflag("save-temps"),
|
|
||||||
getopts::optopt("target"),
|
|
||||||
getopts::optopt("target-cpu"),
|
|
||||||
getopts::optmulti("Z") ];
|
|
||||||
let matches = &match getopts::getopts(args, opts) {
|
|
||||||
result::Ok(m) => m,
|
|
||||||
result::Err(f) => {
|
|
||||||
error!("{}", f.to_err_msg());
|
|
||||||
return Err(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let no_link = matches.opt_present("no-link");
|
|
||||||
let no_trans = matches.opt_present("no-trans");
|
|
||||||
let supplied_sysroot = matches.opt_str("sysroot");
|
|
||||||
let generate_asm = matches.opt_present("S") ||
|
|
||||||
matches.opt_present("assembly");
|
|
||||||
let parse_only = matches.opt_present("parse-only");
|
|
||||||
let pretty = matches.opt_present("pretty");
|
|
||||||
let emit_llvm = matches.opt_present("emit-llvm");
|
|
||||||
|
|
||||||
if matches.opt_present("h") ||
|
|
||||||
matches.opt_present("help") {
|
|
||||||
usage::general();
|
|
||||||
return Err(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches.opt_present("v") ||
|
|
||||||
matches.opt_present("version") {
|
|
||||||
version(args[0]);
|
|
||||||
return Err(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let use_rust_path_hack = matches.opt_present("r") ||
|
|
||||||
matches.opt_present("rust-path-hack");
|
|
||||||
|
|
||||||
let linker = matches.opt_str("linker");
|
|
||||||
let link_args = matches.opt_str("link-args");
|
|
||||||
let cfgs = matches.opt_strs("cfg") + matches.opt_strs("c");
|
|
||||||
let mut user_supplied_opt_level = true;
|
|
||||||
let opt_level = match matches.opt_str("opt-level") {
|
|
||||||
Some(~"0") => session::No,
|
|
||||||
Some(~"1") => session::Less,
|
|
||||||
Some(~"2") => session::Default,
|
|
||||||
Some(~"3") => session::Aggressive,
|
|
||||||
_ if matches.opt_present("O") => session::Default,
|
|
||||||
_ => {
|
|
||||||
user_supplied_opt_level = false;
|
|
||||||
session::No
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let save_temps = matches.opt_present("save-temps");
|
|
||||||
let target = matches.opt_str("target");
|
|
||||||
let target_cpu = matches.opt_str("target-cpu");
|
|
||||||
let experimental_features = {
|
|
||||||
let strs = matches.opt_strs("Z");
|
|
||||||
if matches.opt_present("Z") {
|
|
||||||
Some(strs)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut args = matches.free.clone();
|
|
||||||
args.shift();
|
|
||||||
|
|
||||||
if args.len() < 1 {
|
|
||||||
usage::general();
|
|
||||||
return Err(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let rustc_flags = RustcFlags {
|
|
||||||
linker: linker,
|
|
||||||
link_args: link_args,
|
|
||||||
optimization_level: opt_level,
|
|
||||||
compile_upto: if no_trans {
|
|
||||||
Trans
|
|
||||||
} else if no_link {
|
|
||||||
Link
|
|
||||||
} else if pretty {
|
|
||||||
Pretty
|
|
||||||
} else if parse_only {
|
|
||||||
Analysis
|
|
||||||
} else if emit_llvm && generate_asm {
|
|
||||||
LLVMAssemble
|
|
||||||
} else if generate_asm {
|
|
||||||
Assemble
|
|
||||||
} else if emit_llvm {
|
|
||||||
LLVMCompileBitcode
|
|
||||||
} else {
|
|
||||||
Nothing
|
|
||||||
},
|
|
||||||
save_temps: save_temps,
|
|
||||||
target: target,
|
|
||||||
target_cpu: target_cpu,
|
|
||||||
additional_library_paths:
|
|
||||||
HashSet::new(), // No way to set this from the rustpkg command line
|
|
||||||
experimental_features: experimental_features
|
|
||||||
};
|
|
||||||
|
|
||||||
let cmd_opt = args.iter().filter_map( |s| from_str(s.clone())).next();
|
|
||||||
let command = match cmd_opt {
|
|
||||||
None => {
|
|
||||||
debug!("No legal command. Returning 0");
|
|
||||||
usage::general();
|
|
||||||
return Err(0);
|
|
||||||
}
|
|
||||||
Some(cmd) => {
|
|
||||||
let bad_option = flags_forbidden_for_cmd(&rustc_flags,
|
|
||||||
cfgs,
|
|
||||||
cmd,
|
|
||||||
user_supplied_opt_level);
|
|
||||||
if bad_option {
|
|
||||||
usage::usage_for_command(cmd);
|
|
||||||
debug!("Bad option, returning BAD_FLAG_CODE");
|
|
||||||
return Err(BAD_FLAG_CODE);
|
|
||||||
} else {
|
|
||||||
cmd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pop off all flags, plus the command
|
|
||||||
let mut remaining_args: ~[~str] = args.iter().skip_while(|&s| {
|
|
||||||
let maybe_command: Option<Command> = from_str(*s);
|
|
||||||
maybe_command.is_none()
|
|
||||||
}).map(|s| s.clone()).collect();
|
|
||||||
remaining_args.shift();
|
|
||||||
|
|
||||||
let context = Context{
|
|
||||||
rustc_flags: rustc_flags,
|
|
||||||
cfgs: cfgs,
|
|
||||||
use_rust_path_hack: use_rust_path_hack,
|
|
||||||
};
|
|
||||||
Ok(ParseResult {
|
|
||||||
command: command,
|
|
||||||
args: remaining_args,
|
|
||||||
context: context,
|
|
||||||
sysroot: supplied_sysroot
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,426 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// rustpkg utilities having to do with paths and directories
|
|
||||||
|
|
||||||
#[allow(dead_code)];
|
|
||||||
|
|
||||||
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
|
|
||||||
pub use version::{Version, split_version_general};
|
|
||||||
pub use rustc::metadata::filesearch::rust_path;
|
|
||||||
|
|
||||||
use std::libc;
|
|
||||||
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
|
||||||
use std::os;
|
|
||||||
use std::io;
|
|
||||||
use std::io::fs;
|
|
||||||
use syntax::crateid::CrateId;
|
|
||||||
use rustc::metadata::filesearch::{libdir, relative_target_lib_path};
|
|
||||||
use rustc::driver::driver::host_triple;
|
|
||||||
use messages::*;
|
|
||||||
|
|
||||||
pub fn default_workspace() -> Path {
|
|
||||||
let p = rust_path();
|
|
||||||
if p.is_empty() {
|
|
||||||
fail!("Empty RUST_PATH");
|
|
||||||
}
|
|
||||||
let result = p[0];
|
|
||||||
if !result.is_dir() {
|
|
||||||
fs::mkdir_recursive(&result, io::UserRWX);
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn in_rust_path(p: &Path) -> bool {
|
|
||||||
rust_path().contains(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static U_RWX: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
|
|
||||||
|
|
||||||
/// Creates a directory that is readable, writeable,
|
|
||||||
/// and executable by the user. Returns true iff creation
|
|
||||||
/// succeeded.
|
|
||||||
pub fn make_dir_rwx(p: &Path) -> bool {
|
|
||||||
io::result(|| fs::mkdir(p, io::UserRWX)).is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_dir_rwx_recursive(p: &Path) -> bool {
|
|
||||||
io::result(|| fs::mkdir_recursive(p, io::UserRWX)).is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
// n.b. The next three functions ignore the package version right
|
|
||||||
// now. Should fix that.
|
|
||||||
|
|
||||||
/// True if there's a directory in <workspace> with
|
|
||||||
/// crateid's short name
|
|
||||||
pub fn workspace_contains_crate_id(crateid: &CrateId, workspace: &Path) -> bool {
|
|
||||||
workspace_contains_crate_id_(crateid, workspace, |p| p.join("src")).is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn workspace_contains_crate_id_(crateid: &CrateId, workspace: &Path,
|
|
||||||
// Returns the directory it was actually found in
|
|
||||||
workspace_to_src_dir: |&Path| -> Path) -> Option<Path> {
|
|
||||||
if !workspace.is_dir() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let src_dir = workspace_to_src_dir(workspace);
|
|
||||||
if !src_dir.is_dir() { return None }
|
|
||||||
|
|
||||||
let mut found = None;
|
|
||||||
for p in fs::walk_dir(&src_dir) {
|
|
||||||
if p.is_dir() {
|
|
||||||
if p == src_dir.join(crateid.path.as_slice()) || {
|
|
||||||
let pf = p.filename_str();
|
|
||||||
pf.iter().any(|&g| {
|
|
||||||
match split_version_general(g, '-') {
|
|
||||||
None => false,
|
|
||||||
Some((ref might_match, ref vers)) => {
|
|
||||||
*might_match == crateid.name
|
|
||||||
&& (crateid.version == *vers || crateid.version == None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} {
|
|
||||||
found = Some(p.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if found.is_some() {
|
|
||||||
debug!("Found {} in {}", crateid.to_str(), workspace.display());
|
|
||||||
} else {
|
|
||||||
debug!("Didn't find {} in {}", crateid.to_str(), workspace.display());
|
|
||||||
}
|
|
||||||
found
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the target-specific build subdirectory, pushed onto `base`;
|
|
||||||
/// doesn't check that it exists or create it
|
|
||||||
pub fn target_build_dir(workspace: &Path) -> Path {
|
|
||||||
let mut dir = workspace.join("build");
|
|
||||||
dir.push(host_triple());
|
|
||||||
dir
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the target-specific lib subdirectory, pushed onto `base`;
|
|
||||||
/// doesn't check that it exists or create it
|
|
||||||
fn target_lib_dir(workspace: &Path) -> Path {
|
|
||||||
let mut dir = workspace.join(libdir());
|
|
||||||
dir.push(host_triple());
|
|
||||||
dir
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the bin subdirectory, pushed onto `base`;
|
|
||||||
/// doesn't check that it exists or create it
|
|
||||||
/// note: this isn't target-specific
|
|
||||||
fn target_bin_dir(workspace: &Path) -> Path {
|
|
||||||
workspace.join("bin")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Figure out what the executable name for <crateid> in <workspace>'s build
|
|
||||||
/// directory is, and if the file exists, return it.
|
|
||||||
pub fn built_executable_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
|
||||||
let mut result = target_build_dir(workspace);
|
|
||||||
result = mk_output_path(Main, Build, crateid, result);
|
|
||||||
debug!("built_executable_in_workspace: checking whether {} exists",
|
|
||||||
result.display());
|
|
||||||
if result.exists() {
|
|
||||||
Some(result)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
debug!("built_executable_in_workspace: {} does not exist", result.display());
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Figure out what the test name for <crateid> in <workspace>'s build
|
|
||||||
/// directory is, and if the file exists, return it.
|
|
||||||
pub fn built_test_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
|
||||||
output_in_workspace(crateid, workspace, Test)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Figure out what the test name for <crateid> in <workspace>'s build
|
|
||||||
/// directory is, and if the file exists, return it.
|
|
||||||
pub fn built_bench_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
|
||||||
output_in_workspace(crateid, workspace, Bench)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_in_workspace(crateid: &CrateId, workspace: &Path, what: OutputType) -> Option<Path> {
|
|
||||||
let mut result = target_build_dir(workspace);
|
|
||||||
// should use a target-specific subdirectory
|
|
||||||
result = mk_output_path(what, Build, crateid, result);
|
|
||||||
debug!("output_in_workspace: checking whether {} exists",
|
|
||||||
result.display());
|
|
||||||
if result.exists() {
|
|
||||||
Some(result)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
error!("output_in_workspace: {} does not exist", result.display());
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Figure out what the library name for <crateid> in <workspace>'s build
|
|
||||||
/// directory is, and if the file exists, return it.
|
|
||||||
pub fn built_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
|
||||||
library_in_workspace(crateid, Build, workspace)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Does the actual searching stuff
|
|
||||||
pub fn installed_library_in_workspace(crate_id: &CrateId, workspace: &Path) -> Option<Path> {
|
|
||||||
// This could break once we're handling multiple versions better -- I should add a test for it
|
|
||||||
let path = Path::new(crate_id.path.as_slice());
|
|
||||||
match path.filename_str() {
|
|
||||||
None => None,
|
|
||||||
Some(_short_name) => library_in_workspace(crate_id, Install, workspace)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `workspace` is used to figure out the directory to search.
|
|
||||||
/// `name` is taken as the link name of the library.
|
|
||||||
pub fn library_in_workspace(crate_id: &CrateId, where: Target, workspace: &Path) -> Option<Path> {
|
|
||||||
debug!("library_in_workspace: checking whether a library named {} exists",
|
|
||||||
crate_id.name);
|
|
||||||
|
|
||||||
let dir_to_search = match where {
|
|
||||||
Build => target_build_dir(workspace).join(crate_id.path.as_slice()),
|
|
||||||
Install => target_lib_dir(workspace)
|
|
||||||
};
|
|
||||||
|
|
||||||
library_in(crate_id, &dir_to_search)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn system_library(sysroot: &Path, crate_id: &CrateId) -> Option<Path> {
|
|
||||||
library_in(crate_id, &sysroot.join(relative_target_lib_path(host_triple())))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn library_in(crate_id: &CrateId, dir_to_search: &Path) -> Option<Path> {
|
|
||||||
let version_str = match crate_id.version {
|
|
||||||
Some(ref v) => format!("-{}", *v),
|
|
||||||
None => ~"",
|
|
||||||
};
|
|
||||||
let patterns = ~[
|
|
||||||
(format!("lib{}", crate_id.name), format!("{}.rlib", version_str)),
|
|
||||||
(format!("{}{}", os::consts::DLL_PREFIX, crate_id.name),
|
|
||||||
format!("{}{}", version_str, os::consts::DLL_SUFFIX)),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (prefix, suffix) in patterns.move_iter() {
|
|
||||||
let files = match io::result(|| fs::readdir(dir_to_search)) {
|
|
||||||
Ok(dir) => dir, Err(..) => continue,
|
|
||||||
};
|
|
||||||
for file in files.move_iter() {
|
|
||||||
let filename = match file.filename_str() {
|
|
||||||
Some(s) => s, None => continue,
|
|
||||||
};
|
|
||||||
if filename.starts_with(prefix) && filename.ends_with(suffix) {
|
|
||||||
return Some(file.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug!("warning: library_in_workspace didn't find a library in {} for {}",
|
|
||||||
dir_to_search.display(), crate_id.to_str());
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the executable that would be installed for <crateid>
|
|
||||||
/// in <workspace>
|
|
||||||
/// As a side effect, creates the bin-dir if it doesn't exist
|
|
||||||
pub fn target_executable_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
|
||||||
target_file_in_workspace(crateid, workspace, Main, Install)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns the executable that would be installed for <crateid>
|
|
||||||
/// in <workspace>
|
|
||||||
/// As a side effect, creates the lib-dir if it doesn't exist
|
|
||||||
pub fn target_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
|
||||||
use conditions::bad_path::cond;
|
|
||||||
if !workspace.is_dir() {
|
|
||||||
cond.raise(((*workspace).clone(),
|
|
||||||
format!("Workspace supplied to target_library_in_workspace \
|
|
||||||
is not a directory! {}", workspace.display())));
|
|
||||||
}
|
|
||||||
target_file_in_workspace(crateid, workspace, Lib, Install)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the test executable that would be installed for <crateid>
|
|
||||||
/// in <workspace>
|
|
||||||
/// note that we *don't* install test executables, so this is just for unit testing
|
|
||||||
pub fn target_test_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
|
||||||
target_file_in_workspace(crateid, workspace, Test, Install)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the bench executable that would be installed for <crateid>
|
|
||||||
/// in <workspace>
|
|
||||||
/// note that we *don't* install bench executables, so this is just for unit testing
|
|
||||||
pub fn target_bench_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
|
||||||
target_file_in_workspace(crateid, workspace, Bench, Install)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns the path that crateid `crateid` would have if placed `where`
|
|
||||||
/// in `workspace`
|
|
||||||
fn target_file_in_workspace(crateid: &CrateId, workspace: &Path,
|
|
||||||
what: OutputType, where: Target) -> Path {
|
|
||||||
use conditions::bad_path::cond;
|
|
||||||
|
|
||||||
let subdir = match what {
|
|
||||||
Lib => "lib", Main | Test | Bench => "bin"
|
|
||||||
};
|
|
||||||
// Artifacts in the build directory live in a package-ID-specific subdirectory,
|
|
||||||
// but installed ones don't.
|
|
||||||
let result = match (where, what) {
|
|
||||||
(Build, _) => target_build_dir(workspace).join(crateid.path.as_slice()),
|
|
||||||
(Install, Lib) => target_lib_dir(workspace),
|
|
||||||
(Install, _) => target_bin_dir(workspace)
|
|
||||||
};
|
|
||||||
if io::result(|| fs::mkdir_recursive(&result, io::UserRWX)).is_err() {
|
|
||||||
cond.raise((result.clone(), format!("target_file_in_workspace couldn't \
|
|
||||||
create the {} dir (crateid={}, workspace={}, what={:?}, where={:?}",
|
|
||||||
subdir, crateid.to_str(), workspace.display(), what, where)));
|
|
||||||
}
|
|
||||||
mk_output_path(what, where, crateid, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the directory for <crateid>'s build artifacts in <workspace>.
|
|
||||||
/// Creates it if it doesn't exist.
|
|
||||||
pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
|
||||||
let mut result = target_build_dir(workspace);
|
|
||||||
result.push(crateid.path.as_slice());
|
|
||||||
debug!("Creating build dir {} for package id {}", result.display(),
|
|
||||||
crateid.to_str());
|
|
||||||
fs::mkdir_recursive(&result, io::UserRWX);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the output file for a given directory name,
|
|
||||||
/// given whether we're building a library and whether we're building tests
|
|
||||||
pub fn mk_output_path(what: OutputType, where: Target,
|
|
||||||
crate_id: &CrateId, workspace: Path) -> Path {
|
|
||||||
let short_name_with_version = crate_id.short_name_with_version();
|
|
||||||
// Not local_path.dir_path()! For package foo/bar/blat/, we want
|
|
||||||
// the executable blat-0.5 to live under blat/
|
|
||||||
let dir = match where {
|
|
||||||
// If we're installing, it just goes under <workspace>...
|
|
||||||
Install => workspace,
|
|
||||||
// and if we're just building, it goes in a package-specific subdir
|
|
||||||
Build => workspace.join(crate_id.path.as_slice())
|
|
||||||
};
|
|
||||||
debug!("[{:?}:{:?}] mk_output_path: name = {}, path = {}", what, where,
|
|
||||||
if what == Lib { short_name_with_version.clone() } else { crate_id.name.clone() },
|
|
||||||
dir.display());
|
|
||||||
let mut output_path = match what {
|
|
||||||
// this code is duplicated from elsewhere; fix this
|
|
||||||
Lib => dir.join(os::dll_filename(short_name_with_version)),
|
|
||||||
// executable names *aren't* versioned
|
|
||||||
_ => dir.join(format!("{}{}{}", crate_id.name,
|
|
||||||
match what {
|
|
||||||
Test => "test",
|
|
||||||
Bench => "bench",
|
|
||||||
_ => ""
|
|
||||||
},
|
|
||||||
os::consts::EXE_SUFFIX))
|
|
||||||
};
|
|
||||||
if !output_path.is_absolute() {
|
|
||||||
output_path = os::getcwd().join(&output_path);
|
|
||||||
}
|
|
||||||
debug!("mk_output_path: returning {}", output_path.display());
|
|
||||||
output_path
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes files for the package `crateid`, assuming it's installed in workspace `workspace`
|
|
||||||
pub fn uninstall_package_from(workspace: &Path, crateid: &CrateId) {
|
|
||||||
let mut did_something = false;
|
|
||||||
let installed_bin = target_executable_in_workspace(crateid, workspace);
|
|
||||||
if installed_bin.exists() {
|
|
||||||
fs::unlink(&installed_bin);
|
|
||||||
did_something = true;
|
|
||||||
}
|
|
||||||
let installed_lib = target_library_in_workspace(crateid, workspace);
|
|
||||||
if installed_lib.exists() {
|
|
||||||
fs::unlink(&installed_lib);
|
|
||||||
did_something = true;
|
|
||||||
}
|
|
||||||
if !did_something {
|
|
||||||
warn(format!("Warning: there don't seem to be any files for {} installed in {}",
|
|
||||||
crateid.to_str(), workspace.display()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dir_has_crate_file(dir: &Path) -> bool {
|
|
||||||
dir_has_file(dir, "lib.rs") || dir_has_file(dir, "main.rs")
|
|
||||||
|| dir_has_file(dir, "test.rs") || dir_has_file(dir, "bench.rs")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dir_has_file(dir: &Path, file: &str) -> bool {
|
|
||||||
assert!(dir.is_absolute());
|
|
||||||
dir.join(file).exists()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_dir_using_rust_path_hack(p: &CrateId) -> Option<Path> {
|
|
||||||
let rp = rust_path();
|
|
||||||
let path = Path::new(p.path.as_slice());
|
|
||||||
for dir in rp.iter() {
|
|
||||||
// Require that the parent directory match the package ID
|
|
||||||
// Note that this only matches if the package ID being searched for
|
|
||||||
// has a name that's a single component
|
|
||||||
if dir.ends_with_path(&path) || dir.ends_with_path(&versionize(p.path, &p.version)) {
|
|
||||||
debug!("In find_dir_using_rust_path_hack: checking dir {}", dir.display());
|
|
||||||
if dir_has_crate_file(dir) {
|
|
||||||
debug!("Did find id {} in dir {}", p.to_str(), dir.display());
|
|
||||||
return Some(dir.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug!("Didn't find id {} in dir {}", p.to_str(), dir.display())
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// True if the user set RUST_PATH to something non-empty --
|
|
||||||
/// as opposed to the default paths that rustpkg adds automatically
|
|
||||||
pub fn user_set_rust_path() -> bool {
|
|
||||||
match os::getenv("RUST_PATH") {
|
|
||||||
None | Some(~"") => false,
|
|
||||||
Some(_) => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Append the version string onto the end of the path's filename
|
|
||||||
pub fn versionize(p: &str, v: &Version) -> Path {
|
|
||||||
let p = Path::new(p);
|
|
||||||
let q = p.filename().expect("path is a directory");
|
|
||||||
let mut q = q.to_owned();
|
|
||||||
q.push('-' as u8);
|
|
||||||
let vs = match v { &Some(ref s) => s.to_owned(), &None => ~"0.0" };
|
|
||||||
q.push_all(vs.as_bytes());
|
|
||||||
p.with_filename(q)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "win32")]
|
|
||||||
pub fn chmod_read_only(p: &Path) -> bool {
|
|
||||||
unsafe {
|
|
||||||
p.with_c_str(|src_buf| libc::chmod(src_buf, S_IRUSR as libc::c_int) == 0 as libc::c_int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "win32"))]
|
|
||||||
pub fn chmod_read_only(p: &Path) -> bool {
|
|
||||||
unsafe {
|
|
||||||
p.with_c_str(|src_buf| libc::chmod(src_buf, S_IRUSR as libc::mode_t) == 0 as libc::c_int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn platform_library_name(s: &str) -> ~str {
|
|
||||||
format!("{}{}{}", os::consts::DLL_PREFIX, s, os::consts::DLL_SUFFIX)
|
|
||||||
}
|
|
|
@ -1,633 +0,0 @@
|
||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* An implementation of the SHA-1 cryptographic hash.
|
|
||||||
*
|
|
||||||
* First create a `sha1` object using the `sha1` constructor, then
|
|
||||||
* feed it input using the `input` or `input_str` methods, which may be
|
|
||||||
* called any number of times.
|
|
||||||
*
|
|
||||||
* After the entire input has been fed to the hash read the result using
|
|
||||||
* the `result` or `result_str` methods.
|
|
||||||
*
|
|
||||||
* The `sha1` object may be reused to create multiple hashes by calling
|
|
||||||
* the `reset` method.
|
|
||||||
*
|
|
||||||
* This implementation has not been reviewed for cryptographic uses.
|
|
||||||
* As such, all cryptographic uses of this implementation are strongly
|
|
||||||
* discouraged.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::num::Zero;
|
|
||||||
use std::vec;
|
|
||||||
use std::vec::bytes::{MutableByteVector, copy_memory};
|
|
||||||
use extra::hex::ToHex;
|
|
||||||
|
|
||||||
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
|
|
||||||
/// format.
|
|
||||||
fn write_u32_be(dst: &mut[u8], input: u32) {
|
|
||||||
use std::cast::transmute;
|
|
||||||
use std::unstable::intrinsics::to_be32;
|
|
||||||
assert!(dst.len() == 4);
|
|
||||||
unsafe {
|
|
||||||
let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
|
|
||||||
*x = to_be32(input as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
|
|
||||||
fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
|
|
||||||
use std::cast::transmute;
|
|
||||||
use std::unstable::intrinsics::to_be32;
|
|
||||||
assert!(dst.len() * 4 == input.len());
|
|
||||||
unsafe {
|
|
||||||
let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
|
|
||||||
let mut y: *i32 = transmute(input.unsafe_ref(0));
|
|
||||||
for _ in range(0, dst.len()) {
|
|
||||||
*x = to_be32(*y);
|
|
||||||
x = x.offset(1);
|
|
||||||
y = y.offset(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ToBits {
|
|
||||||
/// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
|
|
||||||
/// high-order value and the 2nd item is the low order value.
|
|
||||||
fn to_bits(self) -> (Self, Self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToBits for u64 {
|
|
||||||
fn to_bits(self) -> (u64, u64) {
|
|
||||||
return (self >> 61, self << 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
|
|
||||||
/// overflow.
|
|
||||||
fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
|
|
||||||
let (new_high_bits, new_low_bits) = bytes.to_bits();
|
|
||||||
|
|
||||||
if new_high_bits > Zero::zero() {
|
|
||||||
fail!("Numeric overflow occured.")
|
|
||||||
}
|
|
||||||
|
|
||||||
match bits.checked_add(&new_low_bits) {
|
|
||||||
Some(x) => return x,
|
|
||||||
None => fail!("Numeric overflow occured.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
|
|
||||||
/// must be processed. The input() method takes care of processing and then clearing the buffer
|
|
||||||
/// automatically. However, other methods do not and require the caller to process the buffer. Any
|
|
||||||
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
|
|
||||||
/// results in those bytes being marked as used by the buffer.
|
|
||||||
trait FixedBuffer {
|
|
||||||
/// Input a vector of bytes. If the buffer becomes full, process it with the provided
|
|
||||||
/// function and then clear the buffer.
|
|
||||||
fn input(&mut self, input: &[u8], func: |&[u8]|);
|
|
||||||
|
|
||||||
/// Reset the buffer.
|
|
||||||
fn reset(&mut self);
|
|
||||||
|
|
||||||
/// Zero the buffer up until the specified index. The buffer position currently must not be
|
|
||||||
/// greater than that index.
|
|
||||||
fn zero_until(&mut self, idx: uint);
|
|
||||||
|
|
||||||
/// Get a slice of the buffer of the specified size. There must be at least that many bytes
|
|
||||||
/// remaining in the buffer.
|
|
||||||
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8];
|
|
||||||
|
|
||||||
/// Get the current buffer. The buffer must already be full. This clears the buffer as well.
|
|
||||||
fn full_buffer<'s>(&'s mut self) -> &'s [u8];
|
|
||||||
|
|
||||||
/// Get the current position of the buffer.
|
|
||||||
fn position(&self) -> uint;
|
|
||||||
|
|
||||||
/// Get the number of bytes remaining in the buffer until it is full.
|
|
||||||
fn remaining(&self) -> uint;
|
|
||||||
|
|
||||||
/// Get the size of the buffer
|
|
||||||
fn size(&self) -> uint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A fixed size buffer of 64 bytes useful for cryptographic operations.
|
|
||||||
struct FixedBuffer64 {
|
|
||||||
priv buffer: [u8, ..64],
|
|
||||||
priv buffer_idx: uint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FixedBuffer64 {
|
|
||||||
/// Create a new buffer
|
|
||||||
fn new() -> FixedBuffer64 {
|
|
||||||
return FixedBuffer64 {
|
|
||||||
buffer: [0u8, ..64],
|
|
||||||
buffer_idx: 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FixedBuffer for FixedBuffer64 {
|
|
||||||
fn input(&mut self, input: &[u8], func: |&[u8]|) {
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
let size = 64;
|
|
||||||
|
|
||||||
// If there is already data in the buffer, copy as much as we can into it and process
|
|
||||||
// the data if the buffer becomes full.
|
|
||||||
if self.buffer_idx != 0 {
|
|
||||||
let buffer_remaining = size - self.buffer_idx;
|
|
||||||
if input.len() >= buffer_remaining {
|
|
||||||
copy_memory(
|
|
||||||
self.buffer.mut_slice(self.buffer_idx, size),
|
|
||||||
input.slice_to(buffer_remaining));
|
|
||||||
self.buffer_idx = 0;
|
|
||||||
func(self.buffer);
|
|
||||||
i += buffer_remaining;
|
|
||||||
} else {
|
|
||||||
copy_memory(
|
|
||||||
self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + input.len()),
|
|
||||||
input);
|
|
||||||
self.buffer_idx += input.len();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// While we have at least a full buffer size chunks's worth of data, process that data
|
|
||||||
// without copying it into the buffer
|
|
||||||
while input.len() - i >= size {
|
|
||||||
func(input.slice(i, i + size));
|
|
||||||
i += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy any input data into the buffer. At this point in the method, the ammount of
|
|
||||||
// data left in the input vector will be less than the buffer size and the buffer will
|
|
||||||
// be empty.
|
|
||||||
let input_remaining = input.len() - i;
|
|
||||||
copy_memory(
|
|
||||||
self.buffer.mut_slice(0, input_remaining),
|
|
||||||
input.slice_from(i));
|
|
||||||
self.buffer_idx += input_remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.buffer_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn zero_until(&mut self, idx: uint) {
|
|
||||||
assert!(idx >= self.buffer_idx);
|
|
||||||
self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0);
|
|
||||||
self.buffer_idx = idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
|
|
||||||
self.buffer_idx += len;
|
|
||||||
return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
|
|
||||||
assert!(self.buffer_idx == 64);
|
|
||||||
self.buffer_idx = 0;
|
|
||||||
return self.buffer.slice_to(64);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn position(&self) -> uint { self.buffer_idx }
|
|
||||||
|
|
||||||
fn remaining(&self) -> uint { 64 - self.buffer_idx }
|
|
||||||
|
|
||||||
fn size(&self) -> uint { 64 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
|
|
||||||
/// struct.
|
|
||||||
trait StandardPadding {
|
|
||||||
/// Add standard padding to the buffer. The buffer must not be full when this method is called
|
|
||||||
/// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
|
|
||||||
/// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
|
|
||||||
/// filled with zeros again until only rem bytes are remaining.
|
|
||||||
fn standard_padding(&mut self, rem: uint, func: |&[u8]|);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T: FixedBuffer> StandardPadding for T {
|
|
||||||
fn standard_padding(&mut self, rem: uint, func: |&[u8]|) {
|
|
||||||
let size = self.size();
|
|
||||||
|
|
||||||
self.next(1)[0] = 128;
|
|
||||||
|
|
||||||
if self.remaining() < rem {
|
|
||||||
self.zero_until(size);
|
|
||||||
func(self.full_buffer());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.zero_until(size - rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
|
|
||||||
* family of digest functions.
|
|
||||||
*/
|
|
||||||
pub trait Digest {
|
|
||||||
/**
|
|
||||||
* Provide message data.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * input - A vector of message data
|
|
||||||
*/
|
|
||||||
fn input(&mut self, input: &[u8]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the digest result. This method may be called multiple times.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * out - the vector to hold the result. Must be large enough to contain output_bits().
|
|
||||||
*/
|
|
||||||
fn result(&mut self, out: &mut [u8]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the digest. This method must be called after result() and before supplying more
|
|
||||||
* data.
|
|
||||||
*/
|
|
||||||
fn reset(&mut self);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the output size in bits.
|
|
||||||
*/
|
|
||||||
fn output_bits(&self) -> uint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience function that feeds a string into a digest.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * `input` The string to feed into the digest
|
|
||||||
*/
|
|
||||||
fn input_str(&mut self, input: &str) {
|
|
||||||
self.input(input.as_bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience function that retrieves the result of a digest as a
|
|
||||||
* newly allocated vec of bytes.
|
|
||||||
*/
|
|
||||||
fn result_bytes(&mut self) -> ~[u8] {
|
|
||||||
let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
|
|
||||||
self.result(buf);
|
|
||||||
buf
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience function that retrieves the result of a digest as a
|
|
||||||
* ~str in hexadecimal format.
|
|
||||||
*/
|
|
||||||
fn result_str(&mut self) -> ~str {
|
|
||||||
self.result_bytes().to_hex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A SHA-1 implementation derived from Paul E. Jones's reference
|
|
||||||
* implementation, which is written for clarity, not speed. At some
|
|
||||||
* point this will want to be rewritten.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Some unexported constants
|
|
||||||
static DIGEST_BUF_LEN: uint = 5u;
|
|
||||||
static WORK_BUF_LEN: uint = 80u;
|
|
||||||
static K0: u32 = 0x5A827999u32;
|
|
||||||
static K1: u32 = 0x6ED9EBA1u32;
|
|
||||||
static K2: u32 = 0x8F1BBCDCu32;
|
|
||||||
static K3: u32 = 0xCA62C1D6u32;
|
|
||||||
|
|
||||||
/// Structure representing the state of a Sha1 computation
|
|
||||||
pub struct Sha1 {
|
|
||||||
priv h: [u32, ..DIGEST_BUF_LEN],
|
|
||||||
priv length_bits: u64,
|
|
||||||
priv buffer: FixedBuffer64,
|
|
||||||
priv computed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_input(st: &mut Sha1, msg: &[u8]) {
|
|
||||||
assert!((!st.computed));
|
|
||||||
// Assumes that msg.len() can be converted to u64 without overflow
|
|
||||||
st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
|
|
||||||
st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_msg_block(data: &[u8], h: &mut [u32, ..DIGEST_BUF_LEN]) {
|
|
||||||
let mut t: int; // Loop counter
|
|
||||||
|
|
||||||
let mut w = [0u32, ..WORK_BUF_LEN];
|
|
||||||
|
|
||||||
// Initialize the first 16 words of the vector w
|
|
||||||
read_u32v_be(w.mut_slice(0, 16), data);
|
|
||||||
|
|
||||||
// Initialize the rest of vector w
|
|
||||||
t = 16;
|
|
||||||
while t < 80 {
|
|
||||||
let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
|
|
||||||
w[t] = circular_shift(1, val);
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
let mut a = h[0];
|
|
||||||
let mut b = h[1];
|
|
||||||
let mut c = h[2];
|
|
||||||
let mut d = h[3];
|
|
||||||
let mut e = h[4];
|
|
||||||
let mut temp: u32;
|
|
||||||
t = 0;
|
|
||||||
while t < 20 {
|
|
||||||
temp = circular_shift(5, a) + (b & c | !b & d) + e + w[t] + K0;
|
|
||||||
e = d;
|
|
||||||
d = c;
|
|
||||||
c = circular_shift(30, b);
|
|
||||||
b = a;
|
|
||||||
a = temp;
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
while t < 40 {
|
|
||||||
temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K1;
|
|
||||||
e = d;
|
|
||||||
d = c;
|
|
||||||
c = circular_shift(30, b);
|
|
||||||
b = a;
|
|
||||||
a = temp;
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
while t < 60 {
|
|
||||||
temp =
|
|
||||||
circular_shift(5, a) + (b & c | b & d | c & d) + e + w[t] +
|
|
||||||
K2;
|
|
||||||
e = d;
|
|
||||||
d = c;
|
|
||||||
c = circular_shift(30, b);
|
|
||||||
b = a;
|
|
||||||
a = temp;
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
while t < 80 {
|
|
||||||
temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K3;
|
|
||||||
e = d;
|
|
||||||
d = c;
|
|
||||||
c = circular_shift(30, b);
|
|
||||||
b = a;
|
|
||||||
a = temp;
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
h[0] += a;
|
|
||||||
h[1] += b;
|
|
||||||
h[2] += c;
|
|
||||||
h[3] += d;
|
|
||||||
h[4] += e;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn circular_shift(bits: u32, word: u32) -> u32 {
|
|
||||||
return word << bits | word >> 32u32 - bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
|
|
||||||
if !st.computed {
|
|
||||||
st.buffer.standard_padding(8, |d: &[u8]| { process_msg_block(d, &mut st.h) });
|
|
||||||
write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
|
|
||||||
write_u32_be(st.buffer.next(4), st.length_bits as u32);
|
|
||||||
process_msg_block(st.buffer.full_buffer(), &mut st.h);
|
|
||||||
|
|
||||||
st.computed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
write_u32_be(rs.mut_slice(0, 4), st.h[0]);
|
|
||||||
write_u32_be(rs.mut_slice(4, 8), st.h[1]);
|
|
||||||
write_u32_be(rs.mut_slice(8, 12), st.h[2]);
|
|
||||||
write_u32_be(rs.mut_slice(12, 16), st.h[3]);
|
|
||||||
write_u32_be(rs.mut_slice(16, 20), st.h[4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sha1 {
|
|
||||||
/// Construct a `sha` object
|
|
||||||
pub fn new() -> Sha1 {
|
|
||||||
let mut st = Sha1 {
|
|
||||||
h: [0u32, ..DIGEST_BUF_LEN],
|
|
||||||
length_bits: 0u64,
|
|
||||||
buffer: FixedBuffer64::new(),
|
|
||||||
computed: false,
|
|
||||||
};
|
|
||||||
st.reset();
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Digest for Sha1 {
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.length_bits = 0;
|
|
||||||
self.h[0] = 0x67452301u32;
|
|
||||||
self.h[1] = 0xEFCDAB89u32;
|
|
||||||
self.h[2] = 0x98BADCFEu32;
|
|
||||||
self.h[3] = 0x10325476u32;
|
|
||||||
self.h[4] = 0xC3D2E1F0u32;
|
|
||||||
self.buffer.reset();
|
|
||||||
self.computed = false;
|
|
||||||
}
|
|
||||||
fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
|
|
||||||
fn result(&mut self, out: &mut [u8]) { return mk_result(self, out); }
|
|
||||||
fn output_bits(&self) -> uint { 160 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use std::num::Bounded;
|
|
||||||
use std::rand::{IsaacRng, Rng};
|
|
||||||
use std::vec;
|
|
||||||
use extra::hex::FromHex;
|
|
||||||
use super::{Digest, Sha1, add_bytes_to_bits};
|
|
||||||
|
|
||||||
#[deriving(Clone)]
|
|
||||||
struct Test {
|
|
||||||
input: ~str,
|
|
||||||
output: ~[u8],
|
|
||||||
output_str: ~str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
// Test messages from FIPS 180-1
|
|
||||||
|
|
||||||
let fips_180_1_tests = ~[
|
|
||||||
Test {
|
|
||||||
input: ~"abc",
|
|
||||||
output: ~[
|
|
||||||
0xA9u8, 0x99u8, 0x3Eu8, 0x36u8,
|
|
||||||
0x47u8, 0x06u8, 0x81u8, 0x6Au8,
|
|
||||||
0xBAu8, 0x3Eu8, 0x25u8, 0x71u8,
|
|
||||||
0x78u8, 0x50u8, 0xC2u8, 0x6Cu8,
|
|
||||||
0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8,
|
|
||||||
],
|
|
||||||
output_str: ~"a9993e364706816aba3e25717850c26c9cd0d89d"
|
|
||||||
},
|
|
||||||
Test {
|
|
||||||
input:
|
|
||||||
~"abcdbcdecdefdefgefghfghighij" +
|
|
||||||
"hijkijkljklmklmnlmnomnopnopq",
|
|
||||||
output: ~[
|
|
||||||
0x84u8, 0x98u8, 0x3Eu8, 0x44u8,
|
|
||||||
0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8,
|
|
||||||
0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8,
|
|
||||||
0xF9u8, 0x51u8, 0x29u8, 0xE5u8,
|
|
||||||
0xE5u8, 0x46u8, 0x70u8, 0xF1u8,
|
|
||||||
],
|
|
||||||
output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1"
|
|
||||||
},
|
|
||||||
];
|
|
||||||
// Examples from wikipedia
|
|
||||||
|
|
||||||
let wikipedia_tests = ~[
|
|
||||||
Test {
|
|
||||||
input: ~"The quick brown fox jumps over the lazy dog",
|
|
||||||
output: ~[
|
|
||||||
0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8,
|
|
||||||
0x7au8, 0x2du8, 0x28u8, 0xfcu8,
|
|
||||||
0xedu8, 0x84u8, 0x9eu8, 0xe1u8,
|
|
||||||
0xbbu8, 0x76u8, 0xe7u8, 0x39u8,
|
|
||||||
0x1bu8, 0x93u8, 0xebu8, 0x12u8,
|
|
||||||
],
|
|
||||||
output_str: ~"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
|
|
||||||
},
|
|
||||||
Test {
|
|
||||||
input: ~"The quick brown fox jumps over the lazy cog",
|
|
||||||
output: ~[
|
|
||||||
0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8,
|
|
||||||
0xd2u8, 0x5eu8, 0x1bu8, 0x3au8,
|
|
||||||
0xfau8, 0xd3u8, 0xe8u8, 0x5au8,
|
|
||||||
0x0bu8, 0xd1u8, 0x7du8, 0x9bu8,
|
|
||||||
0x10u8, 0x0du8, 0xb4u8, 0xb3u8,
|
|
||||||
],
|
|
||||||
output_str: ~"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
let tests = fips_180_1_tests + wikipedia_tests;
|
|
||||||
|
|
||||||
// Test that it works when accepting the message all at once
|
|
||||||
|
|
||||||
let mut out = [0u8, ..20];
|
|
||||||
|
|
||||||
let mut sh = ~Sha1::new();
|
|
||||||
for t in tests.iter() {
|
|
||||||
(*sh).input_str(t.input);
|
|
||||||
sh.result(out);
|
|
||||||
assert!(t.output.as_slice() == out);
|
|
||||||
|
|
||||||
let out_str = (*sh).result_str();
|
|
||||||
assert_eq!(out_str.len(), 40);
|
|
||||||
assert!(out_str == t.output_str);
|
|
||||||
|
|
||||||
sh.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Test that it works when accepting the message in pieces
|
|
||||||
for t in tests.iter() {
|
|
||||||
let len = t.input.len();
|
|
||||||
let mut left = len;
|
|
||||||
while left > 0u {
|
|
||||||
let take = (left + 1u) / 2u;
|
|
||||||
(*sh).input_str(t.input.slice(len - left, take + len - left));
|
|
||||||
left = left - take;
|
|
||||||
}
|
|
||||||
sh.result(out);
|
|
||||||
assert!(t.output.as_slice() == out);
|
|
||||||
|
|
||||||
let out_str = (*sh).result_str();
|
|
||||||
assert_eq!(out_str.len(), 40);
|
|
||||||
assert!(out_str == t.output_str);
|
|
||||||
|
|
||||||
sh.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
|
|
||||||
/// correct.
|
|
||||||
fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: uint, expected: &str) {
|
|
||||||
let total_size = 1000000;
|
|
||||||
let buffer = vec::from_elem(blocksize * 2, 'a' as u8);
|
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
|
||||||
let mut count = 0;
|
|
||||||
|
|
||||||
digest.reset();
|
|
||||||
|
|
||||||
while count < total_size {
|
|
||||||
let next: uint = rng.gen_range(0, 2 * blocksize + 1);
|
|
||||||
let remaining = total_size - count;
|
|
||||||
let size = if next > remaining { remaining } else { next };
|
|
||||||
digest.input(buffer.slice_to(size));
|
|
||||||
count += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result_str = digest.result_str();
|
|
||||||
let result_bytes = digest.result_bytes();
|
|
||||||
|
|
||||||
assert_eq!(expected, result_str.as_slice());
|
|
||||||
assert_eq!(expected.from_hex().unwrap(), result_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_1million_random_sha1() {
|
|
||||||
let mut sh = Sha1::new();
|
|
||||||
test_digest_1million_random(
|
|
||||||
&mut sh,
|
|
||||||
64,
|
|
||||||
"34aa973cd4c4daa4f61eeb2bdbad27316534016f");
|
|
||||||
}
|
|
||||||
|
|
||||||
// A normal addition - no overflow occurs
|
|
||||||
#[test]
|
|
||||||
fn test_add_bytes_to_bits_ok() {
|
|
||||||
assert!(add_bytes_to_bits::<u64>(100, 10) == 180);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A simple failure case - adding 1 to the max value
|
|
||||||
#[test]
|
|
||||||
#[should_fail]
|
|
||||||
fn test_add_bytes_to_bits_overflow() {
|
|
||||||
add_bytes_to_bits::<u64>(Bounded::max_value(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod bench {
|
|
||||||
use extra::test::BenchHarness;
|
|
||||||
use super::Sha1;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
pub fn sha1_10(bh: & mut BenchHarness) {
|
|
||||||
let mut sh = Sha1::new();
|
|
||||||
let bytes = [1u8, ..10];
|
|
||||||
bh.iter(|| sh.input(bytes));
|
|
||||||
bh.bytes = bytes.len() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
pub fn sha1_1k(bh: & mut BenchHarness) {
|
|
||||||
let mut sh = Sha1::new();
|
|
||||||
let bytes = [1u8, ..1024];
|
|
||||||
bh.iter(|| sh.input(bytes));
|
|
||||||
bh.bytes = bytes.len() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
pub fn sha1_64k(bh: & mut BenchHarness) {
|
|
||||||
let mut sh = Sha1::new();
|
|
||||||
let bytes = [1u8, ..65536];
|
|
||||||
bh.iter(|| sh.input(bytes));
|
|
||||||
bh.bytes = bytes.len() as u64;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// Utils for working with version control repositories. Just git right now.
|
|
||||||
|
|
||||||
use std::{run, str};
|
|
||||||
use std::run::{ProcessOutput, ProcessOptions, Process};
|
|
||||||
use std::io::fs;
|
|
||||||
use extra::tempfile::TempDir;
|
|
||||||
use path_util::chmod_read_only;
|
|
||||||
|
|
||||||
/// Attempts to clone `source`, a local git repository, into `target`, a local
|
|
||||||
/// directory that doesn't exist.
|
|
||||||
/// Returns `DirToUse(p)` if the clone fails, where `p` is a newly created temporary
|
|
||||||
/// directory (that the callee may use, for example, to check out remote sources into).
|
|
||||||
/// Returns `CheckedOutSources` if the clone succeeded.
|
|
||||||
pub fn safe_git_clone(source: &Path, v: &Option<~str>, target: &Path) -> CloneResult {
|
|
||||||
if source.exists() {
|
|
||||||
debug!("{} exists locally! Cloning it into {}",
|
|
||||||
source.display(), target.display());
|
|
||||||
// Ok to use target here; we know it will succeed
|
|
||||||
assert!(source.is_dir());
|
|
||||||
assert!(is_git_dir(source));
|
|
||||||
|
|
||||||
if !target.exists() {
|
|
||||||
debug!("Running: git clone {} {}", source.display(), target.display());
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let opt_outp = run::process_output("git", [~"clone",
|
|
||||||
source.as_str().unwrap().to_owned(),
|
|
||||||
target.as_str().unwrap().to_owned()]);
|
|
||||||
let outp = opt_outp.expect("Failed to exec `git`");
|
|
||||||
if !outp.status.success() {
|
|
||||||
println!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
|
||||||
println!("{}", str::from_utf8_owned(outp.error).unwrap());
|
|
||||||
return DirToUse(target.clone());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
match v {
|
|
||||||
&Some(ref s) => {
|
|
||||||
let git_dir = target.join(".git");
|
|
||||||
debug!("`Running: git --work-tree={} --git-dir={} checkout {}",
|
|
||||||
*s, target.display(), git_dir.display());
|
|
||||||
// FIXME (#9639: This needs to handle non-utf8 paths
|
|
||||||
let outp = run::process_output("git",
|
|
||||||
[format!("--work-tree={}", target.as_str().unwrap().to_owned()),
|
|
||||||
format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()),
|
|
||||||
~"checkout", format!("{}", *s)]).expect("Failed to exec `git`");
|
|
||||||
if !outp.status.success() {
|
|
||||||
println!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
|
||||||
println!("{}", str::from_utf8_owned(outp.error).unwrap());
|
|
||||||
return DirToUse(target.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Check that no version was specified. There's no reason to not handle the
|
|
||||||
// case where a version was requested, but I haven't implemented it.
|
|
||||||
assert!(*v == None);
|
|
||||||
let git_dir = target.join(".git");
|
|
||||||
debug!("Running: git --work-tree={} --git-dir={} pull --no-edit {}",
|
|
||||||
target.display(), git_dir.display(), source.display());
|
|
||||||
// FIXME (#9639: This needs to handle non-utf8 paths
|
|
||||||
let args = [format!("--work-tree={}", target.as_str().unwrap().to_owned()),
|
|
||||||
format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()),
|
|
||||||
~"pull", ~"--no-edit", source.as_str().unwrap().to_owned()];
|
|
||||||
let opt_outp = run::process_output("git", args);
|
|
||||||
let outp = opt_outp.expect("Failed to exec `git`");
|
|
||||||
assert!(outp.status.success());
|
|
||||||
}
|
|
||||||
CheckedOutSources
|
|
||||||
} else {
|
|
||||||
use conditions::failed_to_create_temp_dir::cond;
|
|
||||||
|
|
||||||
let scratch_dir = TempDir::new("rustpkg");
|
|
||||||
let clone_target = match scratch_dir {
|
|
||||||
Some(d) => d.unwrap().join("rustpkg_temp"),
|
|
||||||
None => cond.raise(~"Failed to create temporary directory for fetching git sources")
|
|
||||||
};
|
|
||||||
|
|
||||||
DirToUse(clone_target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum CloneResult {
|
|
||||||
DirToUse(Path), // Created this empty directory to use as the temp dir for git
|
|
||||||
CheckedOutSources // Successfully checked sources out into the given target dir
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_read_only(target: &Path) {
|
|
||||||
// Now, make all the files in the target dir read-only
|
|
||||||
for p in fs::walk_dir(target) {
|
|
||||||
if !p.is_dir() {
|
|
||||||
assert!(chmod_read_only(&p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Source can be either a URL or a local file path.
|
|
||||||
pub fn git_clone_url(source: &str, target: &Path, v: &Option<~str>) {
|
|
||||||
use conditions::git_checkout_failed::cond;
|
|
||||||
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let opt_outp = run::process_output("git", [~"clone", source.to_owned(),
|
|
||||||
target.as_str().unwrap().to_owned()]);
|
|
||||||
let outp = opt_outp.expect("Failed to exec `git`");
|
|
||||||
if !outp.status.success() {
|
|
||||||
debug!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
|
||||||
debug!("{}", str::from_utf8_owned(outp.error).unwrap());
|
|
||||||
cond.raise((source.to_owned(), target.clone()))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
match v {
|
|
||||||
&Some(ref s) => {
|
|
||||||
let opt_outp = process_output_in_cwd("git", [~"checkout", s.to_owned()],
|
|
||||||
target);
|
|
||||||
let outp = opt_outp.expect("Failed to exec `git`");
|
|
||||||
if !outp.status.success() {
|
|
||||||
debug!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
|
||||||
debug!("{}", str::from_utf8_owned(outp.error).unwrap());
|
|
||||||
cond.raise((source.to_owned(), target.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
|
|
||||||
let mut opt_prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
|
|
||||||
,..ProcessOptions::new()});
|
|
||||||
match opt_prog {
|
|
||||||
Some(ref mut prog) => Some(prog.finish_with_output()),
|
|
||||||
None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_git_dir(p: &Path) -> bool {
|
|
||||||
p.join(".git").is_dir()
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
|
|
||||||
// Data types that express build artifacts
|
|
||||||
|
|
||||||
#[deriving(Eq)]
|
|
||||||
pub enum OutputType { Main, Lib, Bench, Test }
|
|
||||||
|
|
||||||
#[deriving(Eq)]
|
|
||||||
pub enum Target {
|
|
||||||
/// In-place build
|
|
||||||
Build,
|
|
||||||
/// Install to bin/ or lib/ dir
|
|
||||||
Install
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deriving(Eq, Clone)]
|
|
||||||
pub struct WhatToBuild {
|
|
||||||
build_type: BuildType, // Whether or not to ignore the pkg.rs file
|
|
||||||
sources: SourceType, // Which crates to build
|
|
||||||
inputs_to_discover: ~[(~str, Path)] // Inputs to these crates to be discovered
|
|
||||||
// (For now all of these inputs will be taken as discovered inputs
|
|
||||||
// for all of the crates)
|
|
||||||
// (Paired with their kinds)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WhatToBuild {
|
|
||||||
pub fn new(build_type: BuildType, sources: SourceType) -> WhatToBuild {
|
|
||||||
WhatToBuild { build_type: build_type,
|
|
||||||
sources: sources,
|
|
||||||
inputs_to_discover: ~[] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deriving(Eq, Clone)]
|
|
||||||
pub enum BuildType {
|
|
||||||
Inferred, // Ignore the pkg.rs file even if one exists
|
|
||||||
MaybeCustom // Use the pkg.rs file if it exists
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deriving(Eq, Clone)]
|
|
||||||
pub enum SourceType {
|
|
||||||
/// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
|
|
||||||
JustOne(Path),
|
|
||||||
/// Build any test.rs files that can be recursively found in the active workspace
|
|
||||||
Tests,
|
|
||||||
/// Build everything
|
|
||||||
Everything
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_lib(p: &Path) -> bool {
|
|
||||||
file_is(p, "lib")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_main(p: &Path) -> bool {
|
|
||||||
file_is(p, "main")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_test(p: &Path) -> bool {
|
|
||||||
file_is(p, "test")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_bench(p: &Path) -> bool {
|
|
||||||
file_is(p, "bench")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file_is(p: &Path, stem: &str) -> bool {
|
|
||||||
match p.filestem() {
|
|
||||||
Some(s) if s == stem.as_bytes() => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn lib_name_of(p: &Path) -> Path {
|
|
||||||
p.join("lib.rs")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static lib_crate_filename: &'static str = "lib.rs";
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,20 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The test runner should check that, after `rustpkg build hello-world`:
|
|
||||||
* testsuite/hello-world/build/ exists
|
|
||||||
* testsuite/hello-world/build/ contains an executable named hello-world
|
|
||||||
* testsuite/hello-world/build/ does not contain a library
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("Hello world!");
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
Commands that should succeed:
|
|
||||||
|
|
||||||
1. rustpkg install github.com/mozilla-servo/rust-http-client
|
|
||||||
|
|
||||||
2. Create a git repo containing a package "foo", add a tag called "1.0" -- `rustpkg install foo` should install a library called "libfoo-....-1.0..."
|
|
||||||
|
|
||||||
3. rustpkg install foo, if ./.rust/foo exists and is a valid package directory
|
|
||||||
|
|
||||||
4. RUST_PATH=/home/rust rustpkg install foo installs an executable in /home/rust/foo if ./foo exists and is a valid package directory
|
|
||||||
|
|
||||||
5. RUST_PATH=/home/rust:/home/more_rust rustpkg install foo succeeds if /home/more_rust/foo exists and is a valid package directory
|
|
||||||
|
|
||||||
6. rustpkg install foo; rustpkg install bar; rustpkg install quux; rustpkg list should show foo, bar, and quux
|
|
||||||
6a. then, rustpkg remove foo; rustpkg list should show bar and quux, but not foo
|
|
||||||
|
|
||||||
7. Execute `rustpkg build foo`. Check the datestamp on build/foo. Execute the same command again. Make sure the datestamp hasn't changed.
|
|
||||||
|
|
||||||
8. Execute `rustpkg build foo` where foo has a dependency on bar, which hasn't been built before. Check the datestamps on build/foo and build/bar and make sure bar's datestamp is earlier than foo's.
|
|
||||||
|
|
||||||
9. Execute `rustpkg build foo` where foo has a dependency on bar, which hasn't been built before. Then, change one of the source files in bar. Execute `rustpkg build foo` again. Make sure, based on datestamps, that foo was really rebuilt.
|
|
||||||
|
|
||||||
10. Repeat test 9 in the case where the contents of the source file in bar change but its datestamp doesn't change.
|
|
||||||
|
|
||||||
11. If the current directory contains package directories for foo-0.1 and foo.0.2, `rustpkg install foo#0.1` installs foo#0.1 and doesn't install foo#0.2.
|
|
||||||
|
|
||||||
12. `rustpkg do fancy-pkg frob` succeeds if `fancy-pkg` has a package script that defines a custom build hook named `frob`.
|
|
||||||
|
|
||||||
13. `rustpkg info foo` prints out something about foo, if foo is installed.
|
|
||||||
|
|
||||||
14. (Not sure what prefer and unprefer do)
|
|
||||||
|
|
||||||
15. `rustpkg test foo` runs tests and prints their output, if foo contains #[test]s.
|
|
||||||
|
|
||||||
16. If foo is installed, `rustpkg uninstall foo; rustpkg list` doesn't include foo in the list
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn assert_true() {
|
|
||||||
assert!(true);
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn do_nothing() {
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
extern mod std;
|
|
||||||
|
|
||||||
pub mod foo;
|
|
||||||
pub mod bar;
|
|
|
@ -1,83 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
extern mod rustpkg;
|
|
||||||
extern mod rustc;
|
|
||||||
|
|
||||||
use std::{os, task};
|
|
||||||
use rustpkg::api;
|
|
||||||
use rustpkg::version::None;
|
|
||||||
use rustpkg::workcache_support::digest_file_with_date;
|
|
||||||
use rustpkg::exit_codes::COPY_FAILED_CODE;
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let args = os::args();
|
|
||||||
|
|
||||||
// by convention, first arg is sysroot
|
|
||||||
if args.len() < 2 {
|
|
||||||
fail!("Package script requires a directory where rustc libraries live as the first \
|
|
||||||
argument");
|
|
||||||
}
|
|
||||||
|
|
||||||
let path_for_db = api::default_workspace();
|
|
||||||
debug!("path_for_db = {}", path_for_db.display());
|
|
||||||
|
|
||||||
let sysroot_arg = args[1].clone();
|
|
||||||
let sysroot = Path::new(sysroot_arg);
|
|
||||||
if !sysroot.exists() {
|
|
||||||
fail!("Package script requires a sysroot that exists; {} doesn't", sysroot.display());
|
|
||||||
}
|
|
||||||
|
|
||||||
if args[2] != ~"install" {
|
|
||||||
println!("Warning: I don't know how to {}", args[2]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut context = api::default_context(sysroot, path_for_db);
|
|
||||||
let my_workspace = api::my_workspace(&context.context, "cdep");
|
|
||||||
let foo_c_name = my_workspace.join_many(["src", "cdep-0.0", "foo.c"]);
|
|
||||||
|
|
||||||
let out_lib_path = context.workcache_context.with_prep("foo.c", |prep| {
|
|
||||||
let sub_cx = context.context.clone();
|
|
||||||
debug!("foo_c_name = {}", foo_c_name.display());
|
|
||||||
prep.declare_input("file",
|
|
||||||
foo_c_name.as_str().unwrap().to_owned(),
|
|
||||||
digest_file_with_date(&foo_c_name));
|
|
||||||
let out_path = prep.exec(|exec| {
|
|
||||||
let out_path = api::build_library_in_workspace(exec,
|
|
||||||
&mut sub_cx.clone(),
|
|
||||||
"cdep",
|
|
||||||
"gcc",
|
|
||||||
[~"-c"],
|
|
||||||
[~"foo.c"],
|
|
||||||
"foo");
|
|
||||||
let out_p = Path::new(out_path.unwrap());
|
|
||||||
out_p.as_str().unwrap().to_owned()
|
|
||||||
});
|
|
||||||
out_path
|
|
||||||
});
|
|
||||||
let out_lib_path = Path::new(out_lib_path);
|
|
||||||
debug!("out_lib_path = {}", out_lib_path.display());
|
|
||||||
context.add_library_path(out_lib_path.dir_path());
|
|
||||||
|
|
||||||
let context_clone = context.clone();
|
|
||||||
let task_res = task::try(proc() {
|
|
||||||
let mut cc = context_clone.clone();
|
|
||||||
api::install_pkg(&mut cc,
|
|
||||||
os::getcwd(),
|
|
||||||
~"cdep",
|
|
||||||
None,
|
|
||||||
~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]);
|
|
||||||
});
|
|
||||||
|
|
||||||
if task_res.is_err() {
|
|
||||||
os::set_exit_status(COPY_FAILED_CODE);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The test runner should check that, after `rustpkg install deeply/nested/path/foo`:
|
|
||||||
with RUST_PATH undefined in the environment:
|
|
||||||
* ./deeply/nested/path/foo exists and is an executable
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The test runner should check that, after `rustpkg install external crate`
|
|
||||||
with RUST_PATH undefined in the environment
|
|
||||||
and with `rustpkg install deeply/nested/path/foo` already
|
|
||||||
executed:
|
|
||||||
* ../bin/external_crate exists and is an executable
|
|
||||||
|
|
||||||
tjc: Also want a test like this where foo is an external URL,
|
|
||||||
which requires the `extern mod` changes
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern mod foo;
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn assert_true() {
|
|
||||||
assert!(true);
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn do_nothing() {
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The test runner should check that, after `rustpkg build fancy-lib`:
|
|
||||||
* testsuite/fancy-lib/build/ exists
|
|
||||||
* testsuite/fancy-lib/build/ contains a file called generated.rs
|
|
||||||
* testsuite/fancy-lib/build/ contains a library named libfancy_lib
|
|
||||||
* testsuite/fancy-lib/build/ does not contain an executable
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern mod std;
|
|
||||||
|
|
||||||
pub mod foo;
|
|
||||||
pub mod bar;
|
|
||||||
#[path = "../../build/fancy-lib/generated.rs"] pub mod generated;
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
extern mod rustpkg;
|
|
||||||
extern mod rustc;
|
|
||||||
|
|
||||||
use std::os;
|
|
||||||
use std::io::File;
|
|
||||||
use rustpkg::api;
|
|
||||||
use rustpkg::version::None;
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let args = os::args();
|
|
||||||
|
|
||||||
// by convention, first arg is sysroot
|
|
||||||
if args.len() < 2 {
|
|
||||||
debug!("Failing, arg len");
|
|
||||||
fail!("Package script requires a directory where rustc libraries live as the first \
|
|
||||||
argument");
|
|
||||||
}
|
|
||||||
|
|
||||||
let sysroot_arg = args[1].clone();
|
|
||||||
let sysroot = Path::new(sysroot_arg);
|
|
||||||
if !sysroot.exists() {
|
|
||||||
debug!("Failing, sysroot");
|
|
||||||
fail!("Package script requires a sysroot that exists;{} doesn't", sysroot.display());
|
|
||||||
}
|
|
||||||
|
|
||||||
if args[2] != ~"install" {
|
|
||||||
debug!("Failing, weird command");
|
|
||||||
println!("Warning: I don't know how to {}", args[2]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("Checking self_exe_path");
|
|
||||||
let out_path = os::self_exe_path().expect("Couldn't get self_exe path");
|
|
||||||
|
|
||||||
debug!("Writing file");
|
|
||||||
let mut file = File::create(&out_path.join("generated.rs"));
|
|
||||||
file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \
|
|
||||||
for _ in xs.iter() { assert!(true); } }".as_bytes());
|
|
||||||
|
|
||||||
let context = api::default_context(sysroot, api::default_workspace());
|
|
||||||
api::install_pkg(&context, os::getcwd(), ~"fancy-lib", None, ~[]);
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn f() {}
|
|
|
@ -1,23 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The test runner should check that, after `rustpkg build hello-world`:
|
|
||||||
* testsuite/pass/hello-world/build/ exists
|
|
||||||
* testsuite/pass/hello-world/build/ contains an executable named hello-world
|
|
||||||
* testsuite/pass/hello-world/build/ does not contain a library
|
|
||||||
|
|
||||||
It should also check that after `rustpkg clean hello-world`:
|
|
||||||
* testsuite/pass/hello-world/build is empty
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("Hello world!");
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
pub fn g() {
|
|
||||||
let mut x = 0;
|
|
||||||
while x < 1000 {
|
|
||||||
x += 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn f() -> int { 42 }
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The test runner should check that, after `rustpkg install install-paths`
|
|
||||||
with RUST_PATH undefined in the environment:
|
|
||||||
* ./.rust/install_paths exists and is an executable
|
|
||||||
* ./.rust/libinstall_paths exists and is a library
|
|
||||||
* ./.rust/install_pathstest does not exist
|
|
||||||
* ./.rust/install_pathsbench does not exist
|
|
||||||
* install-paths/build/install_pathstest exists and is an executable
|
|
||||||
* install-paths/build/install_pathsbench exists and is an executable
|
|
||||||
*/
|
|
||||||
|
|
||||||
use lib::f;
|
|
||||||
|
|
||||||
mod lib;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
f();
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_two_plus_two() {
|
|
||||||
assert_eq!(2 + 2, 4);
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn assert_true() {
|
|
||||||
assert!(true);
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
pub fn do_nothing() {
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The test runner should check that, after `rustpkg build simple-lib`:
|
|
||||||
* testsuite/simple-lib/build/ exists
|
|
||||||
* testsuite/simple-lib/build/ contains a library named libsimple_lib
|
|
||||||
* testsuite/simple-lib/build/ does not contain an executable
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern mod std;
|
|
||||||
|
|
||||||
pub mod foo;
|
|
||||||
pub mod bar;
|
|
|
@ -1,181 +0,0 @@
|
||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use context::Command;
|
|
||||||
|
|
||||||
pub fn general() {
|
|
||||||
println!("Usage: rustpkg [options] <cmd> [args..]
|
|
||||||
|
|
||||||
Where <cmd> is one of:
|
|
||||||
build, clean, do, info, install, list, prefer, test, uninstall, unprefer
|
|
||||||
|
|
||||||
For more help on a given command, you can run:
|
|
||||||
rustpkg help <cmd>
|
|
||||||
|
|
||||||
Options:
|
|
||||||
|
|
||||||
-h, --help Display this message
|
|
||||||
--sysroot PATH Override the system root
|
|
||||||
<cmd> -h, <cmd> --help Display help for <cmd>");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build() {
|
|
||||||
println!("rustpkg build [options..] [package-ID]
|
|
||||||
|
|
||||||
Build the given package ID if specified. With no package ID argument,
|
|
||||||
build the package in the current directory. In that case, the current
|
|
||||||
directory must be a direct child of an `src` directory in a workspace.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c, --cfg Pass a cfg flag to the package script
|
|
||||||
--no-link Compile and assemble, but don't link (like -c in rustc)
|
|
||||||
--no-trans Parse and translate, but don't generate any code
|
|
||||||
--pretty Pretty-print the code, but don't generate output
|
|
||||||
--parse-only Parse the code, but don't typecheck or generate code
|
|
||||||
-S Generate assembly code, but don't assemble or link it
|
|
||||||
-S --emit-llvm Generate LLVM assembly code
|
|
||||||
--emit-llvm Generate LLVM bitcode
|
|
||||||
--linker PATH Use a linker other than the system linker
|
|
||||||
--link-args [ARG..] Extra arguments to pass to the linker
|
|
||||||
--opt-level=n Set the optimization level (0 <= n <= 3)
|
|
||||||
-O Equivalent to --opt-level=2
|
|
||||||
--save-temps Don't delete temporary files
|
|
||||||
--target TRIPLE Set the target triple
|
|
||||||
--target-cpu CPU Set the target CPU
|
|
||||||
-Z FLAG Enable an experimental rustc feature (see `rustc --help`)");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clean() {
|
|
||||||
println!("rustpkg clean
|
|
||||||
|
|
||||||
Remove all build files in the work cache for the package in the current
|
|
||||||
directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_cmd() {
|
|
||||||
println!(r"rustpkg do <cmd>
|
|
||||||
|
|
||||||
Runs a command in the package script. You can listen to a command
|
|
||||||
by tagging a function with the attribute `\#[pkg_do(cmd)]`.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn info() {
|
|
||||||
println!("rustpkg [options..] info
|
|
||||||
|
|
||||||
Probe the package script in the current directory for information.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-j, --json Output the result as JSON");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list() {
|
|
||||||
println!("rustpkg list
|
|
||||||
|
|
||||||
List all installed packages.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn install() {
|
|
||||||
println!(r"rustpkg install [options..] [package-ID]
|
|
||||||
|
|
||||||
Install the given package ID if specified. With no package ID
|
|
||||||
argument, install the package in the current directory.
|
|
||||||
In that case, the current directory must be a direct child of a
|
|
||||||
`src` directory in a workspace.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
rustpkg install
|
|
||||||
rustpkg install github.com/mozilla/servo
|
|
||||||
rustpkg install github.com/mozilla/servo\#0.1.2
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c, --cfg Pass a cfg flag to the package script
|
|
||||||
--emit-llvm Generate LLVM bitcode
|
|
||||||
--linker PATH Use a linker other than the system linker
|
|
||||||
--link-args [ARG..] Extra arguments to pass to the linker
|
|
||||||
--opt-level=n Set the optimization level (0 <= n <= 3)
|
|
||||||
-O Equivalent to --opt-level=2
|
|
||||||
--save-temps Don't delete temporary files
|
|
||||||
--target TRIPLE Set the target triple
|
|
||||||
--target-cpu CPU Set the target CPU
|
|
||||||
-Z FLAG Enable an experimental rustc feature (see `rustc --help`)");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uninstall() {
|
|
||||||
println!("rustpkg uninstall <id|name>[@version]
|
|
||||||
|
|
||||||
Remove a package by id or name and optionally version. If the package(s)
|
|
||||||
is/are depended on by another package then they cannot be removed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prefer() {
|
|
||||||
println!("rustpkg [options..] prefer <id|name>[@version]
|
|
||||||
|
|
||||||
By default all binaries are given a unique name so that multiple versions can
|
|
||||||
coexist. The prefer command will symlink the uniquely named binary to
|
|
||||||
the binary directory under its bare name. If version is not supplied, the
|
|
||||||
latest version of the package will be preferred.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
export PATH=$PATH:/home/user/.rustpkg/bin
|
|
||||||
rustpkg prefer machine@1.2.4
|
|
||||||
machine -v
|
|
||||||
==> v1.2.4
|
|
||||||
rustpkg prefer machine@0.4.6
|
|
||||||
machine -v
|
|
||||||
==> v0.4.6");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unprefer() {
|
|
||||||
println!("rustpkg [options..] unprefer <id|name>[@version]
|
|
||||||
|
|
||||||
Remove all symlinks from the store to the binary directory for a package
|
|
||||||
name and optionally version. If version is not supplied, the latest version
|
|
||||||
of the package will be unpreferred. See `rustpkg prefer -h` for more
|
|
||||||
information.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test() {
|
|
||||||
println!("rustpkg [options..] test
|
|
||||||
|
|
||||||
Build all test crates in the current directory with the test flag.
|
|
||||||
Then, run all the resulting test executables, redirecting the output
|
|
||||||
and exit code.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c, --cfg Pass a cfg flag to the package script");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init() {
|
|
||||||
println!("rustpkg init
|
|
||||||
|
|
||||||
This will turn the current working directory into a workspace. The first
|
|
||||||
command you run when starting off a new project.
|
|
||||||
");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn usage_for_command(command: Command){
|
|
||||||
match command {
|
|
||||||
BuildCmd => build(),
|
|
||||||
CleanCmd => clean(),
|
|
||||||
DoCmd => do_cmd(),
|
|
||||||
HelpCmd => general(),
|
|
||||||
InfoCmd => info(),
|
|
||||||
InstallCmd => install(),
|
|
||||||
ListCmd => list(),
|
|
||||||
PreferCmd => prefer(),
|
|
||||||
TestCmd => test(),
|
|
||||||
InitCmd => init(),
|
|
||||||
UninstallCmd => uninstall(),
|
|
||||||
UnpreferCmd => unprefer(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,699 +0,0 @@
|
||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#[allow(dead_code)];
|
|
||||||
|
|
||||||
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
|
|
||||||
pub use target::{Target, Build, Install};
|
|
||||||
pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::libc;
|
|
||||||
use std::os;
|
|
||||||
use std::io;
|
|
||||||
use std::io::fs;
|
|
||||||
use extra::workcache;
|
|
||||||
use rustc::metadata::creader::Loader;
|
|
||||||
use extra::treemap::TreeMap;
|
|
||||||
use extra::getopts::groups::getopts;
|
|
||||||
use syntax;
|
|
||||||
use syntax::codemap::{DUMMY_SP, Spanned};
|
|
||||||
use syntax::ext::base;
|
|
||||||
use syntax::ext::base::{ExtCtxt, MacroCrate};
|
|
||||||
use syntax::{ast, attr, codemap, diagnostic, fold, visit};
|
|
||||||
use syntax::attr::AttrMetaMethods;
|
|
||||||
use syntax::fold::Folder;
|
|
||||||
use syntax::parse::token::InternedString;
|
|
||||||
use syntax::parse::token;
|
|
||||||
use syntax::visit::Visitor;
|
|
||||||
use syntax::util::small_vector::SmallVector;
|
|
||||||
use syntax::crateid::CrateId;
|
|
||||||
use rustc::back::link::OutputTypeExe;
|
|
||||||
use rustc::back::link;
|
|
||||||
use rustc::driver::{driver, session};
|
|
||||||
use CtxMethods;
|
|
||||||
use context::{in_target, StopBefore, Link, Assemble, BuildContext};
|
|
||||||
use package_source::PkgSrc;
|
|
||||||
use workspace::pkg_parent_workspaces;
|
|
||||||
use path_util::{system_library, target_build_dir};
|
|
||||||
use path_util::{default_workspace, built_library_in_workspace};
|
|
||||||
use workcache_support::{digest_file_with_date, digest_only_date};
|
|
||||||
use messages::error;
|
|
||||||
|
|
||||||
|
|
||||||
pub type ExitCode = int; // For now
|
|
||||||
|
|
||||||
pub struct Pkg {
|
|
||||||
id: CrateId,
|
|
||||||
bins: ~[~str],
|
|
||||||
libs: ~[~str],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToStr for Pkg {
|
|
||||||
fn to_str(&self) -> ~str {
|
|
||||||
self.id.to_str()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ListenerFn {
|
|
||||||
cmds: ~[~str],
|
|
||||||
span: codemap::Span,
|
|
||||||
path: ~[ast::Ident]
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ReadyCtx<'a> {
|
|
||||||
sess: session::Session,
|
|
||||||
ext_cx: ExtCtxt<'a>,
|
|
||||||
path: ~[ast::Ident],
|
|
||||||
fns: ~[ListenerFn]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_mod(m: &ast::Mod, fold: &mut CrateSetup) -> ast::Mod {
|
|
||||||
fn strip_main(item: @ast::Item) -> @ast::Item {
|
|
||||||
@ast::Item {
|
|
||||||
attrs: item.attrs.iter().filter_map(|attr| {
|
|
||||||
if !attr.name().equiv(&("main")) {
|
|
||||||
Some(*attr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}).collect(),
|
|
||||||
.. (*item).clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fold::noop_fold_mod(&ast::Mod {
|
|
||||||
items: m.items.map(|item| strip_main(*item)),
|
|
||||||
.. (*m).clone()
|
|
||||||
}, fold)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_item(item: @ast::Item, fold: &mut CrateSetup)
|
|
||||||
-> SmallVector<@ast::Item> {
|
|
||||||
fold.ctx.path.push(item.ident);
|
|
||||||
|
|
||||||
let mut cmds = ~[];
|
|
||||||
let mut had_pkg_do = false;
|
|
||||||
|
|
||||||
for attr in item.attrs.iter() {
|
|
||||||
if attr.name().equiv(&("pkg_do")) {
|
|
||||||
had_pkg_do = true;
|
|
||||||
match attr.node.value.node {
|
|
||||||
ast::MetaList(_, ref mis) => {
|
|
||||||
for mi in mis.iter() {
|
|
||||||
match mi.node {
|
|
||||||
ast::MetaWord(ref cmd) => {
|
|
||||||
cmds.push(cmd.get().to_owned())
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => cmds.push(~"build")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if had_pkg_do {
|
|
||||||
fold.ctx.fns.push(ListenerFn {
|
|
||||||
cmds: cmds,
|
|
||||||
span: item.span,
|
|
||||||
path: /*bad*/fold.ctx.path.clone()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = fold::noop_fold_item(item, fold);
|
|
||||||
|
|
||||||
fold.ctx.path.pop();
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CrateSetup<'a> {
|
|
||||||
ctx: &'a mut ReadyCtx<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Folder for CrateSetup<'a> {
|
|
||||||
fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
|
|
||||||
fold_item(item, self)
|
|
||||||
}
|
|
||||||
fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod {
|
|
||||||
fold_mod(module, self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate/filter main function, add the list of commands, etc.
|
|
||||||
pub fn ready_crate(sess: session::Session,
|
|
||||||
crate: ast::Crate) -> ast::Crate {
|
|
||||||
let loader = &mut Loader::new(sess);
|
|
||||||
let mut ctx = ReadyCtx {
|
|
||||||
sess: sess,
|
|
||||||
ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone(), loader),
|
|
||||||
path: ~[],
|
|
||||||
fns: ~[]
|
|
||||||
};
|
|
||||||
let mut fold = CrateSetup {
|
|
||||||
ctx: &mut ctx,
|
|
||||||
};
|
|
||||||
fold.fold_crate(crate)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_input(context: &BuildContext,
|
|
||||||
exec: &mut workcache::Exec,
|
|
||||||
crate_id: &CrateId,
|
|
||||||
in_file: &Path,
|
|
||||||
workspace: &Path,
|
|
||||||
deps: &mut DepMap,
|
|
||||||
flags: &[~str],
|
|
||||||
cfgs: &[~str],
|
|
||||||
opt: session::OptLevel,
|
|
||||||
what: OutputType) -> Option<Path> {
|
|
||||||
assert!(in_file.components().nth(1).is_some());
|
|
||||||
let input = driver::FileInput(in_file.clone());
|
|
||||||
debug!("compile_input: {} / {:?}", in_file.display(), what);
|
|
||||||
// tjc: by default, use the package ID name as the link name
|
|
||||||
// not sure if we should support anything else
|
|
||||||
|
|
||||||
let mut out_dir = target_build_dir(workspace);
|
|
||||||
out_dir.push(crate_id.path.as_slice());
|
|
||||||
// Make the output directory if it doesn't exist already
|
|
||||||
fs::mkdir_recursive(&out_dir, io::UserRWX);
|
|
||||||
|
|
||||||
let binary = os::args()[0];
|
|
||||||
|
|
||||||
debug!("flags: {}", flags.connect(" "));
|
|
||||||
debug!("cfgs: {}", cfgs.connect(" "));
|
|
||||||
let csysroot = context.sysroot();
|
|
||||||
debug!("compile_input's sysroot = {}", csysroot.display());
|
|
||||||
|
|
||||||
let matches = getopts(debug_flags()
|
|
||||||
+ match what {
|
|
||||||
Lib => ~[~"--lib"],
|
|
||||||
// --test compiles both #[test] and #[bench] fns
|
|
||||||
Test | Bench => ~[~"--test"],
|
|
||||||
Main => ~[]
|
|
||||||
}
|
|
||||||
+ flags
|
|
||||||
+ context.flag_strs()
|
|
||||||
+ cfgs.flat_map(|c| { ~[~"--cfg", (*c).clone()] }),
|
|
||||||
driver::optgroups()).unwrap();
|
|
||||||
debug!("rustc flags: {:?}", matches);
|
|
||||||
|
|
||||||
// Hack so that rustpkg can run either out of a rustc target dir,
|
|
||||||
// or the host dir
|
|
||||||
let sysroot_to_use = @if !in_target(&context.sysroot()) {
|
|
||||||
context.sysroot()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let mut p = context.sysroot().clone();
|
|
||||||
p.pop();
|
|
||||||
p.pop();
|
|
||||||
p.pop();
|
|
||||||
p
|
|
||||||
};
|
|
||||||
let csysroot = context.sysroot();
|
|
||||||
debug!("compile_input's sysroot = {}", csysroot.display());
|
|
||||||
debug!("sysroot_to_use = {}", sysroot_to_use.display());
|
|
||||||
|
|
||||||
let output_type = match context.compile_upto() {
|
|
||||||
Assemble => link::OutputTypeAssembly,
|
|
||||||
Link => link::OutputTypeObject,
|
|
||||||
Pretty | Trans | Analysis => link::OutputTypeNone,
|
|
||||||
LLVMAssemble => link::OutputTypeLlvmAssembly,
|
|
||||||
LLVMCompileBitcode => link::OutputTypeBitcode,
|
|
||||||
Nothing => link::OutputTypeExe
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("Output type = {:?}", output_type);
|
|
||||||
|
|
||||||
let options = @session::Options {
|
|
||||||
optimize: opt,
|
|
||||||
test: what == Test || what == Bench,
|
|
||||||
maybe_sysroot: Some(sysroot_to_use),
|
|
||||||
addl_lib_search_paths:
|
|
||||||
@RefCell::new(context.additional_library_paths()),
|
|
||||||
output_type: output_type,
|
|
||||||
.. (*driver::build_session_options(binary,
|
|
||||||
&matches,
|
|
||||||
@diagnostic::DefaultEmitter as
|
|
||||||
@diagnostic::Emitter)).clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("Created options...");
|
|
||||||
|
|
||||||
let addl_lib_search_paths = @RefCell::new(options.addl_lib_search_paths);
|
|
||||||
// Make sure all the library directories actually exist, since the linker will complain
|
|
||||||
// otherwise
|
|
||||||
{
|
|
||||||
let mut addl_lib_search_paths = addl_lib_search_paths.borrow_mut();
|
|
||||||
let addl_lib_search_paths = addl_lib_search_paths.get();
|
|
||||||
let mut addl_lib_search_paths = addl_lib_search_paths.borrow_mut();
|
|
||||||
for p in addl_lib_search_paths.get().iter() {
|
|
||||||
if p.exists() {
|
|
||||||
assert!(p.is_dir())
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fs::mkdir_recursive(p, io::UserRWX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("About to build session...");
|
|
||||||
|
|
||||||
let sess = driver::build_session(options,
|
|
||||||
Some(in_file.clone()),
|
|
||||||
@diagnostic::DefaultEmitter as
|
|
||||||
@diagnostic::Emitter);
|
|
||||||
|
|
||||||
debug!("About to build config...");
|
|
||||||
|
|
||||||
// Infer dependencies that rustpkg needs to build, by scanning for
|
|
||||||
// `extern mod` directives.
|
|
||||||
let cfg = driver::build_configuration(sess);
|
|
||||||
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
|
||||||
|
|
||||||
let (mut crate, ast_map) = {
|
|
||||||
let installer = CrateInstaller {
|
|
||||||
context: context,
|
|
||||||
parent: crate_id,
|
|
||||||
parent_crate: in_file,
|
|
||||||
sess: sess,
|
|
||||||
exec: exec,
|
|
||||||
deps: deps,
|
|
||||||
save: |p| {
|
|
||||||
debug!("a dependency: {}", p.display());
|
|
||||||
let mut addl_lib_search_paths =
|
|
||||||
addl_lib_search_paths.borrow_mut();
|
|
||||||
let addl_lib_search_paths =
|
|
||||||
addl_lib_search_paths.get();
|
|
||||||
let mut addl_lib_search_paths =
|
|
||||||
addl_lib_search_paths.borrow_mut();
|
|
||||||
// Pass the directory containing a dependency
|
|
||||||
// as an additional lib search path
|
|
||||||
addl_lib_search_paths.get().insert(p);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let mut loader = CrateLoader {
|
|
||||||
installer: installer,
|
|
||||||
loader: Loader::new(sess),
|
|
||||||
};
|
|
||||||
let (crate, ast_map) = driver::phase_2_configure_and_expand(sess,
|
|
||||||
cfg.clone(),
|
|
||||||
&mut loader,
|
|
||||||
crate);
|
|
||||||
let CrateLoader { mut installer, .. } = loader;
|
|
||||||
debug!("About to call find_and_install_dependencies...");
|
|
||||||
find_and_install_dependencies(&mut installer, &crate);
|
|
||||||
(crate, ast_map)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Inject the crate_id attribute so we get the right package name and version
|
|
||||||
if !attr::contains_name(crate.attrs, "crate_id") {
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
let crateid_attr =
|
|
||||||
attr::mk_name_value_item_str(
|
|
||||||
InternedString::new("crate_id"),
|
|
||||||
token::intern_and_get_ident(crate_id.to_str()));
|
|
||||||
|
|
||||||
debug!("crateid attr: {:?}", crateid_attr);
|
|
||||||
crate.attrs.push(attr::mk_attr(crateid_attr));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("calling compile_crate_from_input, workspace = {},
|
|
||||||
building_library = {:?}", out_dir.display(), sess.building_library);
|
|
||||||
let result = compile_crate_from_input(in_file,
|
|
||||||
exec,
|
|
||||||
context.compile_upto(),
|
|
||||||
&out_dir,
|
|
||||||
sess,
|
|
||||||
crate,
|
|
||||||
ast_map,
|
|
||||||
what);
|
|
||||||
// Discover the output
|
|
||||||
let discovered_output = if what == Lib {
|
|
||||||
built_library_in_workspace(crate_id, workspace) // Huh???
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result
|
|
||||||
};
|
|
||||||
for p in discovered_output.iter() {
|
|
||||||
debug!("About to discover output {}", p.display());
|
|
||||||
if p.exists() {
|
|
||||||
debug!("4. discovering output {}", p.display());
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
exec.discover_output("binary", p.as_str().unwrap(), digest_only_date(p));
|
|
||||||
}
|
|
||||||
// Nothing to do if it doesn't exist -- that could happen if we had the
|
|
||||||
// -S or -emit-llvm flags, etc.
|
|
||||||
}
|
|
||||||
discovered_output
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should use workcache to avoid recompiling when not necessary
|
|
||||||
// Should also rename this to something better
|
|
||||||
// If crate_opt is present, then finish compilation. If it's None, then
|
|
||||||
// call compile_upto and return the crate
|
|
||||||
// also, too many arguments
|
|
||||||
// Returns list of discovered dependencies
|
|
||||||
pub fn compile_crate_from_input(input: &Path,
|
|
||||||
exec: &mut workcache::Exec,
|
|
||||||
stop_before: StopBefore,
|
|
||||||
// should be of the form <workspace>/build/<pkg id's path>
|
|
||||||
out_dir: &Path,
|
|
||||||
sess: session::Session,
|
|
||||||
// Returns None if one of the flags that suppresses compilation output was
|
|
||||||
// given
|
|
||||||
crate: ast::Crate,
|
|
||||||
ast_map: syntax::ast_map::Map,
|
|
||||||
what: OutputType) -> Option<Path> {
|
|
||||||
debug!("Calling build_output_filenames with {}, building library? {:?}",
|
|
||||||
out_dir.display(), sess.building_library);
|
|
||||||
|
|
||||||
// bad copy
|
|
||||||
debug!("out_dir = {}", out_dir.display());
|
|
||||||
let file_input = driver::FileInput(input.clone());
|
|
||||||
let mut outputs = driver::build_output_filenames(&file_input,
|
|
||||||
&Some(out_dir.clone()), &None,
|
|
||||||
crate.attrs, sess);
|
|
||||||
match what {
|
|
||||||
Lib | Main => {}
|
|
||||||
Test => {
|
|
||||||
let mut ofile = outputs.out_filename.filename_str().unwrap().to_owned();
|
|
||||||
ofile.push_str("test");
|
|
||||||
outputs.out_filename.set_filename(ofile);
|
|
||||||
}
|
|
||||||
Bench => {
|
|
||||||
let mut ofile = outputs.out_filename.filename_str().unwrap().to_owned();
|
|
||||||
ofile.push_str("bench");
|
|
||||||
outputs.out_filename.set_filename(ofile);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("Outputs are out_filename: {} and obj_filename: {} and output type = {:?}",
|
|
||||||
outputs.out_filename.display(),
|
|
||||||
outputs.obj_filename.display(),
|
|
||||||
sess.opts.output_type);
|
|
||||||
debug!("additional libraries:");
|
|
||||||
{
|
|
||||||
let addl_lib_search_paths = sess.opts.addl_lib_search_paths.borrow();
|
|
||||||
for lib in addl_lib_search_paths.get().iter() {
|
|
||||||
debug!("an additional library: {}", lib.display());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let analysis = driver::phase_3_run_analysis_passes(sess, &crate, ast_map);
|
|
||||||
if driver::stop_after_phase_3(sess) { return None; }
|
|
||||||
let translation = driver::phase_4_translate_to_llvm(sess, crate,
|
|
||||||
&analysis,
|
|
||||||
outputs);
|
|
||||||
driver::phase_5_run_llvm_passes(sess, &translation, outputs);
|
|
||||||
// The second check shouldn't be necessary, but rustc seems to ignore
|
|
||||||
// -c
|
|
||||||
if driver::stop_after_phase_5(sess)
|
|
||||||
|| stop_before == Link || stop_before == Assemble { return Some(outputs.out_filename); }
|
|
||||||
driver::phase_6_link_output(sess, &translation, outputs);
|
|
||||||
|
|
||||||
// Register dependency on the source file
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
exec.discover_input("file", input.as_str().unwrap(), digest_file_with_date(input));
|
|
||||||
|
|
||||||
debug!("Built {}, date = {:?}", outputs.out_filename.display(),
|
|
||||||
datestamp(&outputs.out_filename));
|
|
||||||
Some(outputs.out_filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn exe_suffix() -> ~str { ~".exe" }
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
#[cfg(target_os = "freebsd")]
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub fn exe_suffix() -> ~str { ~"" }
|
|
||||||
|
|
||||||
// Called by build_crates
|
|
||||||
pub fn compile_crate(ctxt: &BuildContext,
|
|
||||||
exec: &mut workcache::Exec,
|
|
||||||
crate_id: &CrateId,
|
|
||||||
crate: &Path,
|
|
||||||
workspace: &Path,
|
|
||||||
deps: &mut DepMap,
|
|
||||||
flags: &[~str],
|
|
||||||
cfgs: &[~str],
|
|
||||||
opt: session::OptLevel,
|
|
||||||
what: OutputType) -> Option<Path> {
|
|
||||||
debug!("compile_crate: crate={}, workspace={}", crate.display(), workspace.display());
|
|
||||||
debug!("compile_crate: name = {}, flags =...", crate_id.to_str());
|
|
||||||
for fl in flags.iter() {
|
|
||||||
debug!("+++ {}", *fl);
|
|
||||||
}
|
|
||||||
compile_input(ctxt, exec, crate_id, crate, workspace, deps, flags, cfgs, opt, what)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CrateInstaller<'a> {
|
|
||||||
context: &'a BuildContext,
|
|
||||||
parent: &'a CrateId,
|
|
||||||
parent_crate: &'a Path,
|
|
||||||
sess: session::Session,
|
|
||||||
exec: &'a mut workcache::Exec,
|
|
||||||
save: 'a |Path|,
|
|
||||||
deps: &'a mut DepMap
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CrateInstaller<'a> {
|
|
||||||
fn install_crate(&mut self, vi: &ast::ViewItem) {
|
|
||||||
use conditions::nonexistent_package::cond;
|
|
||||||
|
|
||||||
match vi.node {
|
|
||||||
// ignore metadata, I guess
|
|
||||||
ast::ViewItemExternMod(ref lib_ident, ref path_opt, _) => {
|
|
||||||
let lib_name = match *path_opt {
|
|
||||||
Some((ref p, _)) => (*p).clone(),
|
|
||||||
None => token::get_ident(lib_ident.name),
|
|
||||||
};
|
|
||||||
debug!("Finding and installing... {}", lib_name);
|
|
||||||
let crate_id: CrateId =
|
|
||||||
from_str(lib_name.get()).expect("valid crate id");
|
|
||||||
// Check standard Rust library path first
|
|
||||||
let whatever = system_library(&self.context.sysroot_to_use(), &crate_id);
|
|
||||||
debug!("system library returned {:?}", whatever);
|
|
||||||
match whatever {
|
|
||||||
Some(ref installed_path) => {
|
|
||||||
debug!("It exists: {}", installed_path.display());
|
|
||||||
// Say that [path for c] has a discovered dependency on
|
|
||||||
// installed_path
|
|
||||||
// For binary files, we only hash the datestamp, not the contents.
|
|
||||||
// I'm not sure what the right thing is.
|
|
||||||
// Now we know that this crate has a discovered dependency on
|
|
||||||
// installed_path
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
add_dep(self.deps, self.parent_crate.as_str().unwrap().to_owned(),
|
|
||||||
(~"binary", installed_path.as_str().unwrap().to_owned()));
|
|
||||||
self.exec.discover_input("binary",
|
|
||||||
installed_path.as_str().unwrap(),
|
|
||||||
digest_only_date(installed_path));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// FIXME #8711: need to parse version out of path_opt
|
|
||||||
debug!("Trying to install library {}, rebuilding it", crate_id.to_str());
|
|
||||||
// Try to install it
|
|
||||||
// Find all the workspaces in the RUST_PATH that contain this package.
|
|
||||||
let workspaces = pkg_parent_workspaces(&self.context.context,
|
|
||||||
&crate_id);
|
|
||||||
// Three cases:
|
|
||||||
// (a) `workspaces` is empty. That means there's no local source
|
|
||||||
// for this package. In that case, we pass the default workspace
|
|
||||||
// into `PkgSrc::new`, so that if it exists as a remote repository,
|
|
||||||
// its sources will be fetched into it. We also put the output in the
|
|
||||||
// same workspace.
|
|
||||||
// (b) We're using the Rust path hack. In that case, the output goes
|
|
||||||
// in the destination workspace.
|
|
||||||
// (c) `workspaces` is non-empty -- we found a local source for this
|
|
||||||
// package and will build in that workspace.
|
|
||||||
let (source_workspace, dest_workspace) = if workspaces.is_empty() {
|
|
||||||
(default_workspace(), default_workspace())
|
|
||||||
} else {
|
|
||||||
if self.context.context.use_rust_path_hack {
|
|
||||||
(workspaces[0], default_workspace())
|
|
||||||
} else {
|
|
||||||
(workspaces[0].clone(), workspaces[0])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// In this case, the source and destination workspaces are the same:
|
|
||||||
// Either it's a remote package, so the local sources don't exist
|
|
||||||
// and the `PkgSrc` constructor will detect that;
|
|
||||||
// or else it's already in a workspace and we'll build into that
|
|
||||||
// workspace
|
|
||||||
let pkg_src = cond.trap(|_| {
|
|
||||||
// Nonexistent package? Then print a better error
|
|
||||||
error(format!("Package {} depends on {}, but I don't know \
|
|
||||||
how to find it",
|
|
||||||
self.parent.path,
|
|
||||||
crate_id.path));
|
|
||||||
fail!()
|
|
||||||
}).inside(|| {
|
|
||||||
PkgSrc::new(source_workspace.clone(),
|
|
||||||
dest_workspace.clone(),
|
|
||||||
// Use the rust_path_hack to search for dependencies iff
|
|
||||||
// we were already using it
|
|
||||||
self.context.context.use_rust_path_hack,
|
|
||||||
crate_id.clone())
|
|
||||||
});
|
|
||||||
let (outputs_disc, inputs_disc) =
|
|
||||||
self.context.install(
|
|
||||||
pkg_src,
|
|
||||||
&WhatToBuild::new(Inferred,
|
|
||||||
JustOne(Path::new(lib_crate_filename))));
|
|
||||||
debug!("Installed {}, returned {:?} dependencies and \
|
|
||||||
{:?} transitive dependencies",
|
|
||||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
|
||||||
debug!("discovered outputs = {:?} discovered_inputs = {:?}",
|
|
||||||
outputs_disc, inputs_disc);
|
|
||||||
// It must have installed *something*...
|
|
||||||
assert!(!outputs_disc.is_empty());
|
|
||||||
for dep in outputs_disc.iter() {
|
|
||||||
debug!("Discovering a binary input: {}", dep.display());
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
self.exec.discover_input("binary",
|
|
||||||
dep.as_str().unwrap(),
|
|
||||||
digest_only_date(dep));
|
|
||||||
add_dep(self.deps,
|
|
||||||
self.parent_crate.as_str().unwrap().to_owned(),
|
|
||||||
(~"binary", dep.as_str().unwrap().to_owned()));
|
|
||||||
|
|
||||||
// Also, add an additional search path
|
|
||||||
let dep_dir = dep.dir_path();
|
|
||||||
debug!("Installed {} into {}", dep.display(), dep_dir.display());
|
|
||||||
(self.save)(dep_dir);
|
|
||||||
}
|
|
||||||
debug!("Installed {}, returned {} dependencies and \
|
|
||||||
{} transitive dependencies",
|
|
||||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
|
||||||
// It must have installed *something*...
|
|
||||||
assert!(!outputs_disc.is_empty());
|
|
||||||
let mut target_workspace = outputs_disc[0].clone();
|
|
||||||
target_workspace.pop();
|
|
||||||
for &(ref what, ref dep) in inputs_disc.iter() {
|
|
||||||
if *what == ~"file" {
|
|
||||||
add_dep(self.deps,
|
|
||||||
self.parent_crate.as_str().unwrap().to_owned(),
|
|
||||||
(~"file", dep.clone()));
|
|
||||||
self.exec.discover_input(*what,
|
|
||||||
*dep,
|
|
||||||
digest_file_with_date(
|
|
||||||
&Path::new(dep.as_slice())));
|
|
||||||
} else if *what == ~"binary" {
|
|
||||||
add_dep(self.deps,
|
|
||||||
self.parent_crate.as_str().unwrap().to_owned(),
|
|
||||||
(~"binary", dep.clone()));
|
|
||||||
self.exec.discover_input(*what,
|
|
||||||
*dep,
|
|
||||||
digest_only_date(
|
|
||||||
&Path::new(dep.as_slice())));
|
|
||||||
} else {
|
|
||||||
fail!("Bad kind: {}", *what);
|
|
||||||
}
|
|
||||||
// Also, add an additional search path
|
|
||||||
debug!("Installed {} into {}",
|
|
||||||
lib_name, target_workspace.as_str().unwrap().to_owned());
|
|
||||||
(self.save)(target_workspace.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ignore `use`s
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Visitor<()> for CrateInstaller<'a> {
|
|
||||||
fn visit_view_item(&mut self, vi: &ast::ViewItem, env: ()) {
|
|
||||||
self.install_crate(vi);
|
|
||||||
visit::walk_view_item(self, vi, env)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CrateLoader<'a> {
|
|
||||||
installer: CrateInstaller<'a>,
|
|
||||||
loader: Loader,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> base::CrateLoader for CrateLoader<'a> {
|
|
||||||
fn load_crate(&mut self, crate: &ast::ViewItem) -> MacroCrate {
|
|
||||||
self.installer.install_crate(crate);
|
|
||||||
self.loader.load_crate(crate)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_exported_macros(&mut self, cnum: ast::CrateNum) -> ~[~str] {
|
|
||||||
self.loader.get_exported_macros(cnum)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_registrar_symbol(&mut self, cnum: ast::CrateNum) -> Option<~str> {
|
|
||||||
self.loader.get_registrar_symbol(cnum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Collect all `extern mod` directives in `c`, then
|
|
||||||
/// try to install their targets, failing if any target
|
|
||||||
/// can't be found.
|
|
||||||
pub fn find_and_install_dependencies(installer: &mut CrateInstaller,
|
|
||||||
c: &ast::Crate) {
|
|
||||||
debug!("In find_and_install_dependencies...");
|
|
||||||
visit::walk_crate(installer, c, ())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mk_string_lit(s: InternedString) -> ast::Lit {
|
|
||||||
Spanned {
|
|
||||||
node: ast::LitStr(s, ast::CookedStr),
|
|
||||||
span: DUMMY_SP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn option_to_vec<T>(x: Option<T>) -> ~[T] {
|
|
||||||
match x {
|
|
||||||
Some(y) => ~[y],
|
|
||||||
None => ~[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tjc: cheesy
|
|
||||||
fn debug_flags() -> ~[~str] { ~[] }
|
|
||||||
// static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns the last-modified date as an Option
|
|
||||||
pub fn datestamp(p: &Path) -> Option<libc::time_t> {
|
|
||||||
debug!("Scrutinizing datestamp for {} - does it exist? {:?}", p.display(),
|
|
||||||
p.exists());
|
|
||||||
match io::result(|| p.stat()) {
|
|
||||||
Ok(s) => {
|
|
||||||
let out = s.modified;
|
|
||||||
debug!("Date = {:?}", out);
|
|
||||||
Some(out as libc::time_t)
|
|
||||||
}
|
|
||||||
Err(..) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type DepMap = TreeMap<~str, ~[(~str, ~str)]>;
|
|
||||||
|
|
||||||
/// Records a dependency from `parent` to the kind and value described by `info`,
|
|
||||||
/// in `deps`
|
|
||||||
fn add_dep(deps: &mut DepMap, parent: ~str, info: (~str, ~str)) {
|
|
||||||
let mut done = false;
|
|
||||||
let info_clone = info.clone();
|
|
||||||
match deps.find_mut(&parent) {
|
|
||||||
None => { }
|
|
||||||
Some(v) => { done = true; (*v).push(info) }
|
|
||||||
};
|
|
||||||
if !done {
|
|
||||||
deps.insert(parent, ~[info_clone]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/// A version is either an exact revision,
|
|
||||||
/// or a semantic version
|
|
||||||
|
|
||||||
extern mod std;
|
|
||||||
|
|
||||||
use std::char;
|
|
||||||
|
|
||||||
pub type Version = Option<~str>;
|
|
||||||
|
|
||||||
// Being lazy since we don't have a regexp library now
|
|
||||||
#[deriving(Eq)]
|
|
||||||
enum ParseState {
|
|
||||||
Start,
|
|
||||||
SawDigit,
|
|
||||||
SawDot
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_parsing_version(s: &str) -> Option<~str> {
|
|
||||||
let s = s.trim();
|
|
||||||
debug!("Attempting to parse: {}", s);
|
|
||||||
let mut parse_state = Start;
|
|
||||||
for c in s.chars() {
|
|
||||||
if char::is_digit(c) {
|
|
||||||
parse_state = SawDigit;
|
|
||||||
}
|
|
||||||
else if c == '.' && parse_state == SawDigit {
|
|
||||||
parse_state = SawDot;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match parse_state {
|
|
||||||
SawDigit => Some(s.to_owned()),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If s is of the form foo#bar, where bar is a valid version
|
|
||||||
/// number, return the prefix before the # and the version.
|
|
||||||
/// Otherwise, return None.
|
|
||||||
pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
|
|
||||||
// Check for extra '#' characters separately
|
|
||||||
if s.split('#').len() > 2 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
split_version_general(s, '#')
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {
|
|
||||||
match s.rfind(sep) {
|
|
||||||
Some(i) => {
|
|
||||||
let path = s.slice(0, i);
|
|
||||||
// n.b. for now, assuming an exact revision is intended, not a SemVer
|
|
||||||
Some((path, Some(s.slice(i + 1, s.len()).to_owned())))
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_version() {
|
|
||||||
assert!(try_parsing_version("1.2") == Some(~"1.2"));
|
|
||||||
assert!(try_parsing_version("1.0.17") == Some(~"1.0.17"));
|
|
||||||
assert!(try_parsing_version("you're_a_kitty") == None);
|
|
||||||
assert!(try_parsing_version("42..1") == None);
|
|
||||||
assert!(try_parsing_version("17") == Some(~"17"));
|
|
||||||
assert!(try_parsing_version(".1.2.3") == None);
|
|
||||||
assert!(try_parsing_version("2.3.") == None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_split_version() {
|
|
||||||
let s = "a/b/c#0.1";
|
|
||||||
debug!("== {:?} ==", split_version(s));
|
|
||||||
assert!(split_version(s) == Some((s.slice(0, 5), Some(~"0.1"))));
|
|
||||||
assert!(split_version("a/b/c") == None);
|
|
||||||
let s = "a#1.2";
|
|
||||||
assert!(split_version(s) == Some((s.slice(0, 1), Some(~"1.2"))));
|
|
||||||
assert!(split_version("a#a#3.4") == None);
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use std::io;
|
|
||||||
use std::io::File;
|
|
||||||
use extra::workcache;
|
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
|
|
||||||
/// Hashes the file contents along with the last-modified time
|
|
||||||
pub fn digest_file_with_date(path: &Path) -> ~str {
|
|
||||||
use conditions::bad_path::cond;
|
|
||||||
|
|
||||||
match io::result(|| File::open(path).read_to_end()) {
|
|
||||||
Ok(bytes) => {
|
|
||||||
let mut sha = Sha256::new();
|
|
||||||
sha.input(bytes);
|
|
||||||
let st = path.stat();
|
|
||||||
sha.input_str(st.modified.to_str());
|
|
||||||
sha.result_str()
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
cond.raise((path.clone(), format!("Couldn't read file: {}", e.desc)));
|
|
||||||
~""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Hashes only the last-modified time
|
|
||||||
pub fn digest_only_date(path: &Path) -> ~str {
|
|
||||||
let mut sha = Sha256::new();
|
|
||||||
let st = path.stat();
|
|
||||||
sha.input_str(st.modified.to_str());
|
|
||||||
sha.result_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds multiple discovered outputs
|
|
||||||
pub fn discover_outputs(e: &mut workcache::Exec, outputs: ~[Path]) {
|
|
||||||
debug!("Discovering {:?} outputs", outputs.len());
|
|
||||||
for p in outputs.iter() {
|
|
||||||
debug!("Discovering output! {}", p.display());
|
|
||||||
// For now, assume that all discovered outputs are binaries
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
e.discover_output("binary", p.as_str().unwrap(), digest_only_date(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the function name for building a crate
|
|
||||||
pub fn crate_tag(p: &Path) -> ~str {
|
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
|
||||||
p.as_str().unwrap().to_owned() // implicitly, it's "build(p)"...
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// rustpkg utilities having to do with workspaces
|
|
||||||
|
|
||||||
use std::os;
|
|
||||||
use context::Context;
|
|
||||||
use path_util::{workspace_contains_crate_id, find_dir_using_rust_path_hack, default_workspace};
|
|
||||||
use path_util::rust_path;
|
|
||||||
use util::option_to_vec;
|
|
||||||
use syntax::crateid::CrateId;
|
|
||||||
|
|
||||||
pub fn each_pkg_parent_workspace(cx: &Context,
|
|
||||||
crateid: &CrateId,
|
|
||||||
action: |&Path| -> bool)
|
|
||||||
-> bool {
|
|
||||||
// Using the RUST_PATH, find workspaces that contain
|
|
||||||
// this package ID
|
|
||||||
let workspaces = pkg_parent_workspaces(cx, crateid);
|
|
||||||
if workspaces.is_empty() {
|
|
||||||
// tjc: make this a condition
|
|
||||||
fail!("Package {} not found in any of \
|
|
||||||
the following workspaces: {}",
|
|
||||||
crateid.path,
|
|
||||||
rust_path().map(|p| p.display().to_str()).to_str());
|
|
||||||
}
|
|
||||||
for ws in workspaces.iter() {
|
|
||||||
if action(ws) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a package ID, return a vector of all of the workspaces in
|
|
||||||
/// the RUST_PATH that contain it
|
|
||||||
pub fn pkg_parent_workspaces(cx: &Context, crateid: &CrateId) -> ~[Path] {
|
|
||||||
let rs: ~[Path] = rust_path().move_iter()
|
|
||||||
.filter(|ws| workspace_contains_crate_id(crateid, ws))
|
|
||||||
.collect();
|
|
||||||
if cx.use_rust_path_hack {
|
|
||||||
rs + option_to_vec(find_dir_using_rust_path_hack(crateid))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a workspace and package-ID name based on the current directory.
|
|
||||||
/// This gets used when rustpkg gets invoked without a package-ID argument.
|
|
||||||
pub fn cwd_to_workspace() -> Option<(Path, CrateId)> {
|
|
||||||
let cwd = os::getcwd();
|
|
||||||
for path in rust_path().move_iter() {
|
|
||||||
let srcpath = path.join("src");
|
|
||||||
if srcpath.is_ancestor_of(&cwd) {
|
|
||||||
let rel = cwd.path_relative_from(&srcpath);
|
|
||||||
let rel_s = rel.as_ref().and_then(|p|p.as_str());
|
|
||||||
if rel_s.is_some() {
|
|
||||||
let crate_id = from_str(rel_s.unwrap()).expect("valid crate id");
|
|
||||||
return Some((path, crate_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If `workspace` is the same as `cwd`, and use_rust_path_hack is false,
|
|
||||||
/// return `workspace`; otherwise, return the first workspace in the RUST_PATH.
|
|
||||||
pub fn determine_destination(cwd: Path, use_rust_path_hack: bool, workspace: &Path) -> Path {
|
|
||||||
if workspace == &cwd && !use_rust_path_hack {
|
|
||||||
workspace.clone()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
default_workspace()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue