auto merge of : catamorphism/rust/rustpkg, r=catamorphism

r? @graydon
This commit is contained in:
bors 2013-04-18 16:06:52 -07:00
commit 50cd218c1e
20 changed files with 526 additions and 238 deletions
src/librustpkg
path_util.rsrustpkg.rc
testsuite
fail/no-inferred-crates
pass
util.rs

@ -11,7 +11,8 @@
// rustpkg utilities having to do with paths and directories
use core::path::*;
use core::os;
use core::{os, str};
use core::option::*;
use util::PkgId;
/// Returns the output directory to use.
@ -50,6 +51,24 @@ pub fn default_dest_dir(pkg_dir: &Path) -> Path {
}
}
/// Replace all occurrences of '-' in the stem part of path with '_'
/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux
/// as the same name
pub fn normalize(p: ~Path) -> ~Path {
match p.filestem() {
None => p,
Some(st) => {
let replaced = str::replace(st, "-", "_");
if replaced != st {
~p.with_filestem(replaced)
}
else {
p
}
}
}
}
#[cfg(test)]
mod test {
use core::{os, rand};

@ -33,11 +33,11 @@ use core::hashmap::HashMap;
use core::io::WriterUtil;
use rustc::driver::{driver, session};
use rustc::metadata::filesearch;
use std::net::url;
use std::{getopts};
use syntax::{ast, diagnostic};
use util::{ExitCode, Pkg, PkgId};
use path_util::dest_dir;
use util::*;
use path_util::{dest_dir, normalize};
use rustc::driver::session::{lib_crate, bin_crate, unknown_crate, crate_type};
mod conditions;
mod usage;
@ -117,9 +117,12 @@ impl PkgScript {
Ok(r) => {
let root = r.pop().pop().pop().pop(); // :-\
debug!("Root is %s, calling compile_rest", root.to_str());
util::compile_crate_from_input(self.input, Some(self.build_dir),
sess, Some(crate), os::args()[0]);
let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
util::compile_crate_from_input(self.input, self.id,
Some(self.build_dir),
sess, Some(crate),
exe, os::args()[0],
driver::cu_everything);
debug!("Running program: %s %s %s", exe.to_str(), root.to_str(), what);
let status = run::run_program(exe.to_str(), ~[root.to_str(), what]);
if status != 0 {
@ -199,15 +202,15 @@ impl Ctx {
// relative to the CWD. In the future, we should search
// paths
let cwd = os::getcwd().normalize();
debug!("Current working directory = %?", cwd);
debug!("Current working directory = %s", cwd.to_str());
// Find crates inside the workspace
// Create the package source
let mut src = PkgSrc::new(&cwd, &dst_dir, &pkgid);
debug!("Package src = %?", src);
src.find_crates();
// Is there custom build logic? If so, use it
let pkg_src_dir = cwd.push_rel(&pkgid.path);
let mut custom = false;;
debug!("Package source directory = %s", pkg_src_dir.to_str());
let cfgs = match src.package_script_option(&pkg_src_dir) {
Some(package_script_path) => {
@ -221,6 +224,7 @@ impl Ctx {
if hook_result != 0 {
fail!(fmt!("Error running custom build command"))
}
custom = true;
// otherwise, the package script succeeded
cfgs
}
@ -229,19 +233,32 @@ impl Ctx {
~[]
}
};
src.build(&dst_dir, cfgs);
// If there was a package script, it should have finished
// the build already. Otherwise...
if !custom {
// Find crates inside the workspace
src.find_crates();
// Build it!
src.build(&dst_dir, cfgs);
}
}
~"clean" => {
self.clean();
if args.len() < 1 {
return usage::build();
}
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0]);
self.clean(pkgid);
}
~"do" => {
if args.len() < 2 {
return usage::do_cmd();
}
if !self.do_cmd(args[0], args[1]) {
fail!(~"a command failed!");
}
self.do_cmd(args[0], args[1]);
}
~"info" => {
self.info();
@ -286,12 +303,11 @@ impl Ctx {
}
}
fn do_cmd(&self, cmd: ~str, pkgname: ~str) -> bool {
fn do_cmd(&self, cmd: ~str, pkgname: ~str) {
match cmd {
~"build" | ~"test" => {
util::error(~"that command cannot be manually called");
return false;
fail!(~"do_cmd");
}
_ => {}
}
@ -307,16 +323,15 @@ impl Ctx {
Some(script_path) => {
let script = PkgScript::parse(script_path, pkgid);
let (_, status) = script.run_custom(cmd); // Ignore cfgs?
if status == 42 { // ???
if status == 42 {
util::error(~"no fns are listening for that cmd");
return false;
fail!(~"do_cmd");
}
status == 0
}
None => {
util::error(fmt!("invoked `do`, but there is no package script in %s",
cwd.to_str()));
false
fail!(~"do_cmd");
}
}
}
@ -329,128 +344,44 @@ impl Ctx {
}
fn compile(&self, _crate: &Path, _dir: &Path, _flags: ~[~str],
_cfgs: ~[~str], _opt: bool, _test: bool) -> bool {
_cfgs: ~[~str], _opt: bool, _test: bool) {
// What's the difference between build and compile?
fail!(~"compile not yet implemented");
}
fn clean(&self) -> bool {
// stub
fail!();
fn clean(&self, id: PkgId) {
// 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 = dest_dir(id);
util::note(fmt!("Cleaning package %s (removing directory %s)",
id.to_str(), dir.to_str()));
if os::path_exists(&dir) {
util::remove_dir_r(&dir);
util::note(fmt!("Removed directory %s", dir.to_str()));
}
util::note(fmt!("Cleaned package %s", id.to_str()));
}
fn info(&self) {
// stub
fail!();
fail!(~"info not yet implemented");
}
fn install(&self, url: Option<~str>,
target: Option<~str>, cache: bool) -> bool {
let dir = match url {
None => {
util::note(~"installing from the cwd");
os::getcwd()
}
Some(url) => {
let hash = util::hash(if !target.is_none() {
url + target.get()
}
else { url });
if self.dep_cache.contains_key(&hash) {
util::warn(~"already installed dep this run");
return true;
}
self.dep_cache.insert(hash, true);
let dir = util::root().push(~"tmp").push(hash);
if cache && os::path_exists(&dir) {
return true;
}
if !self.fetch(&dir, url, target) {
return false;
}
dir
}
};
let script = match self.build(&dir, false, true, false) {
Some(script) => script,
None => {
return false;
}
};
let work_dir = script.build_dir;
let from_bin_dir = work_dir.push(~"bin");
let from_lib_dir = work_dir.push(~"lib");
let to_bin_dir = util::root().push(~"bin");
let to_lib_dir = util::root().push(~"lib");
let mut bins = ~[];
let mut libs = ~[];
for os::walk_dir(&from_bin_dir) |bin| {
let to = to_bin_dir.push_rel(&bin.file_path());
os::copy_file(bin, &to);
bins.push(to.to_str());
}
for os::walk_dir(&from_lib_dir) |lib| {
let to = to_lib_dir.push_rel(&lib.file_path());
os::copy_file(lib, &to);
libs.push(to.to_str());
}
let package = Pkg {
id: script.id,
bins: bins,
libs: libs
};
util::note(fmt!("installed %s", script.id.to_str()));
util::add_pkg(&package);
true
fn install(&self, _url: Option<~str>,
_target: Option<~str>, _cache: bool) {
// stub
fail!(~"install not yet implemented");
}
fn fetch(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool {
let url = if str::find_str(url, "://").is_none() {
~"http://" + url }
else { url };
let url = match url::from_str(url) {
result::Ok(url) => url,
result::Err(err) => {
util::error(fmt!("failed parsing %s", err.to_lower()));
return false;
}
};
let str = url.to_str();
match Path(url.path).filetype() {
Some(ext) => {
if ext == ~".git" {
return self.fetch_git(dir, str, target);
}
}
None => {}
}
match url.scheme {
~"git" => self.fetch_git(dir, str, target),
~"http" | ~"ftp" | ~"file" => self.fetch_curl(dir, str),
_ => {
util::warn(~"unknown url scheme to fetch, using curl");
self.fetch_curl(dir, str)
}
}
fn fetch(&self, _dir: &Path, _url: ~str, _target: Option<~str>) {
// stub
fail!(~"fetch not yet implemented");
}
fn fetch_curl(&self, dir: &Path, url: ~str) -> bool {
fn fetch_curl(&self, dir: &Path, url: ~str) {
util::note(fmt!("fetching from %s using curl", url));
let tar = dir.dir_path().push(&dir.file_path().to_str() + ~".tar");
@ -460,7 +391,7 @@ impl Ctx {
url]).status != 0 {
util::error(~"fetching failed: downloading using curl failed");
return false;
fail!();
}
if run::program_output(~"tar", ~[~"-x", ~"--strip-components=1",
@ -469,13 +400,11 @@ impl Ctx {
util::error(~"fetching failed: extracting using tar failed" +
~"(is it a valid tar archive?)");
return false;
fail!();
}
true
}
fn fetch_git(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool {
fn fetch_git(&self, dir: &Path, url: ~str, target: Option<~str>) {
util::note(fmt!("fetching from %s using git", url));
// Git can't clone into a non-empty directory
@ -484,8 +413,7 @@ impl Ctx {
if run::program_output(~"git", ~[~"clone", url,
dir.to_str()]).status != 0 {
util::error(~"fetching failed: can't clone repository");
return false;
fail!();
}
if !target.is_none() {
@ -499,21 +427,17 @@ impl Ctx {
if !success {
util::error(~"fetching failed: can't checkout target");
return false;
fail!();
}
}
true
}
fn prefer(&self, id: ~str, vers: Option<~str>) -> bool {
fn prefer(&self, id: ~str, vers: Option<~str>) {
let package = match util::get_pkg(id, vers) {
result::Ok(package) => package,
result::Err(err) => {
util::error(err);
return false;
fail!(); // Condition?
}
};
let name = package.id.path.to_str(); // ???
@ -536,29 +460,18 @@ impl Ctx {
}
util::note(fmt!("preferred %s v%s", name, package.id.version.to_str()));
true
}
fn test(&self) -> bool {
let script = match self.build(&os::getcwd(), false, false, true) {
Some(script) => script,
None => {
return false;
}
};
// To do
util::note(fmt!("Would test %s, but this is a dry run",
script.id.to_str()));
false
fn test(&self) {
// stub
fail!(~"test not yet implemented");
}
fn uninstall(&self, _id: ~str, _vers: Option<~str>) -> bool {
fn uninstall(&self, _id: ~str, _vers: Option<~str>) {
fail!(~"uninstall not yet implemented");
}
fn unprefer(&self, _id: ~str, _vers: Option<~str>) -> bool {
fn unprefer(&self, _id: ~str, _vers: Option<~str>) {
fail!(~"unprefer not yet implemented");
}
}
@ -728,7 +641,6 @@ condition! {
impl PkgSrc {
fn new(src_dir: &Path, dst_dir: &Path,
id: &PkgId) -> PkgSrc {
PkgSrc {
@ -765,12 +677,6 @@ impl PkgSrc {
dir
}
fn has_pkg_file(&self) -> bool {
let dir = self.check_dir();
dir.push("pkg.rs").exists()
}
// If a file named "pkg.rs" in the current directory exists,
// return the path for it. Otherwise, None
fn package_script_option(&self, cwd: &Path) -> Option<Path> {
@ -786,14 +692,16 @@ impl PkgSrc {
/// True if the given path's stem is self's pkg ID's stem
/// or if the pkg ID's stem is <rust-foo> and the given path's
/// stem is foo
/// Requires that dashes in p have already been normalized to
/// underscores
fn stem_matches(&self, p: &Path) -> bool {
let self_id = self.id.path.filestem();
let self_id = normalize(~self.id.path).filestem();
if self_id == p.filestem() {
return true;
}
else {
for self_id.each |pth| {
if pth.starts_with("rust-")
if pth.starts_with("rust_") // because p is already normalized
&& match p.filestem() {
Some(s) => str::eq_slice(s, pth.slice(5, pth.len())),
None => false
@ -814,17 +722,14 @@ impl PkgSrc {
cs.push(Crate::new(&sub));
}
/// Infers crates to build. Called only in the case where there
/// is no custom build logic
fn find_crates(&mut self) {
use PkgSrc::push_crate;
let dir = self.check_dir();
let prefix = dir.components.len();
// This is ugly, but can go away once we get rid
// of .rc files
let mut saw_rs = false;
let mut saw_rc = false;
debug!("Matching against %?",
self.id.path.filestem());
debug!("Matching against %?", self.id.path.filestem());
for os::walk_dir(&dir) |pth| {
match pth.filename() {
Some(~"lib.rs") => push_crate(&mut self.libs,
@ -835,34 +740,19 @@ impl PkgSrc {
prefix, pth),
Some(~"bench.rs") => push_crate(&mut self.benchs,
prefix, pth),
_ => {
// If the file stem is the same as the
// package ID, with an .rs or .rc extension,
// consider it to be a crate
let ext = pth.filetype();
let matches = |p: &Path| {
self.stem_matches(p) && (ext == Some(~".rc")
|| ext == Some(~".rs"))
};
debug!("Checking %? which %s and ext = %? %? %?", pth.filestem(),
if matches(pth) { "matches" } else { "does not match" },
ext, saw_rs, saw_rc);
if matches(pth) &&
// Avoid pushing foo.rc *and* foo.rs
!((ext == Some(~".rc") && saw_rs) ||
(ext == Some(~".rs") && saw_rc)) {
push_crate(&mut self.libs, // ????
prefix, pth);
if ext == Some(~".rc") {
saw_rc = true;
}
else if ext == Some(~".rs") {
saw_rs = true;
}
}
}
_ => ()
}
}
if self.libs.is_empty() && self.mains.is_empty()
&& self.tests.is_empty() && self.benchs.is_empty() {
util::note(~"Couldn't infer any crates to build.\n\
Try naming a crate `main.rs`, `lib.rs`, \
`test.rs`, or `bench.rs`.");
fail!(~"Failed to infer crates to build");
}
debug!("found %u libs, %u mains, %u tests, %u benchs",
self.libs.len(),
self.mains.len(),
@ -870,22 +760,22 @@ impl PkgSrc {
self.benchs.len())
}
fn build_crates(dst_dir: &Path,
fn build_crates(&self, dst_dir: &Path,
src_dir: &Path,
crates: &[Crate],
cfgs: ~[~str],
test: bool) {
test: bool, crate_type: crate_type) {
for crates.each |&crate| {
let path = &src_dir.push_rel(&crate.file).normalize();
util::note(fmt!("build_crates: compiling %s", path.to_str()));
util::note(fmt!("build_crates: destination dir is %s", dst_dir.to_str()));
let result = util::compile_crate(None, path,
let result = util::compile_crate(None, self.id, path,
dst_dir,
crate.flags,
crate.cfgs + cfgs,
false, test);
false, test, crate_type);
if !result {
build_err::cond.raise(fmt!("build failure on %s",
path.to_str()));
@ -898,12 +788,12 @@ impl PkgSrc {
fn build(&self, dst_dir: &Path, cfgs: ~[~str]) {
let dir = self.check_dir();
debug!("Building libs");
PkgSrc::build_crates(dst_dir, &dir, self.libs, cfgs, false);
self.build_crates(dst_dir, &dir, self.libs, cfgs, false, lib_crate);
debug!("Building mains");
PkgSrc::build_crates(dst_dir, &dir, self.mains, cfgs, false);
self.build_crates(dst_dir, &dir, self.mains, cfgs, false, bin_crate);
debug!("Building tests");
PkgSrc::build_crates(dst_dir, &dir, self.tests, cfgs, true);
self.build_crates(dst_dir, &dir, self.tests, cfgs, true, bin_crate);
debug!("Building benches");
PkgSrc::build_crates(dst_dir, &dir, self.benchs, cfgs, true);
self.build_crates(dst_dir, &dir, self.benchs, cfgs, true, bin_crate);
}
}

@ -0,0 +1,22 @@
// 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
*/
use core::io;
fn main() {
io::println(~"Hello world!");
}

@ -0,0 +1,35 @@
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

@ -0,0 +1,18 @@
// 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() {}

@ -0,0 +1,21 @@
// 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:
* ./.rust/external_crate exists and is an executable
*/
extern mod foo; // refers to deeply/nested/path/foo
fn main() {}

@ -0,0 +1,13 @@
// 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);
}

@ -0,0 +1,24 @@
// 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/generated.rs"] pub mod generated;

@ -0,0 +1,12 @@
// 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() {
}

@ -0,0 +1,23 @@
// 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 core::run;
pub fn main() {
let cwd = os::getcwd();
debug!("cwd = %s", cwd.to_str());
let file = io::file_writer(&Path(~"fancy-lib/build/generated.rs"),
[io::Create]).get();
file.write_str("pub fn wheeeee() { for [1, 2, 3].each() |_| { assert!(true); } }");
// now compile the crate itself
run::run_program("rustc", ~[~"fancy-lib/fancy-lib.rs", ~"--lib",
~"-o", ~"fancy-lib/build/fancy_lib"]);
}

@ -0,0 +1,25 @@
// 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
*/
use core::io;
fn main() {
io::println(~"Hello world!");
}

@ -0,0 +1,17 @@
// 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]
fn g() {
let mut x = 0;
while(x < 1000) {
x += 1;
}
}

@ -0,0 +1,11 @@
// 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.
fn f() -> int { 42 }

@ -0,0 +1,22 @@
// 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
*/
fn main() {}

@ -0,0 +1,14 @@
// 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!(2 + 2 == 4);
}

@ -0,0 +1,13 @@
// 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);
}

@ -0,0 +1,12 @@
// 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() {
}

@ -0,0 +1,21 @@
// 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;

@ -0,0 +1,21 @@
// 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;

@ -12,16 +12,20 @@ use core::*;
use core::cmp::Ord;
use core::hash::Streaming;
use rustc::driver::{driver, session};
use rustc::driver::session::{lib_crate, bin_crate, unknown_crate};
use rustc::metadata::filesearch;
use std::getopts::groups::getopts;
use std::semver;
use std::{json, term, getopts};
use syntax::ast_util::*;
use syntax::codemap::{dummy_sp};
use syntax::codemap::{dummy_sp, spanned, dummy_spanned};
use syntax::ext::base::{mk_ctxt, ext_ctxt};
use syntax::ext::build;
use syntax::{ast, attr, codemap, diagnostic, fold};
use syntax::ast::{meta_name_value, meta_list, attribute, crate_};
use syntax::attr::{mk_attr};
use rustc::back::link::output_type_exe;
use rustc::driver::session::{lib_crate, bin_crate, unknown_crate, crate_type};
pub type ExitCode = int; // For now
@ -112,7 +116,7 @@ pub impl PkgId {
impl ToStr for PkgId {
fn to_str(&self) -> ~str {
// should probably use the filestem and not the whole path
fmt!("%s-v%s", self.path.to_str(), self.version.to_str())
fmt!("%s-%s", self.path.to_str(), self.version.to_str())
}
}
@ -425,44 +429,51 @@ pub fn add_pkg(pkg: &Pkg) -> bool {
// FIXME (#4432): Use workcache to only compile when needed
pub fn compile_input(sysroot: Option<Path>,
pkg_id: PkgId,
in_file: &Path,
out_dir: &Path,
flags: ~[~str],
cfgs: ~[~str],
opt: bool,
test: bool) -> bool {
test: bool,
crate_type: session::crate_type) -> bool {
let short_name = pkg_id.to_str();
assert!(in_file.components.len() > 1);
let input = driver::file_input(copy *in_file);
debug!("compile_input: %s", in_file.to_str());
debug!("compile_input: %s / %?", in_file.to_str(), crate_type);
// tjc: by default, use the package ID name as the link name
// not sure if we should support anything else
let short_name = in_file.filestem().expect("Can't compile a directory!");
debug!("short_name = %s", short_name.to_str());
// Right now we're always assuming that we're building a library.
// What we should do is parse the crate and infer whether it's a library
// from the absence or presence of a main fn
let out_file = out_dir.push(os::dll_filename(short_name));
let building_library = true;
let binary = os::args()[0];
let building_library = match crate_type {
lib_crate | unknown_crate => true,
_ => false
};
let out_file = if building_library {
out_dir.push(os::dll_filename(short_name))
}
else {
out_dir.push(short_name + if test { ~"test" } else { ~"" }
+ os::EXE_SUFFIX)
};
debug!("compiling %s into %s",
in_file.to_str(),
out_file.to_str());
let binary = os::args()[0];
debug!("flags: %s", str::connect(flags, ~" "));
debug!("cfgs: %s", str::connect(cfgs, ~" "));
// Again, we assume we're building a library
let matches = getopts(~[~"-Z", ~"time-passes"]
+ if building_library { ~[~"--lib"] } else { ~[] }
+ if building_library { ~[~"--lib"] }
else { ~[] }
+ flags
+ cfgs.flat_map(|&c| { ~[~"--cfg", c] }),
driver::optgroups()).get();
let options = @session::options {
crate_type: if building_library { session::lib_crate }
else { session::bin_crate },
crate_type: crate_type,
optimize: if opt { session::Aggressive } else { session::No },
test: test,
maybe_sysroot: sysroot,
@ -485,7 +496,9 @@ pub fn compile_input(sysroot: Option<Path>,
debug!("calling compile_crate_from_input, out_dir = %s,
building_library = %?", out_dir.to_str(), sess.building_library);
compile_crate_from_input(input, Some(*out_dir), sess, None, binary);
let _ = compile_crate_from_input(input, pkg_id, Some(*out_dir), sess, None,
out_file, binary,
driver::cu_everything);
true
}
@ -493,24 +506,46 @@ pub fn compile_input(sysroot: Option<Path>,
// 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
pub fn compile_crate_from_input(input: driver::input, build_dir_opt: Option<Path>,
sess: session::Session, crate_opt: Option<@ast::crate>,
binary: ~str) -> @ast::crate {
// also, too many arguments
pub fn compile_crate_from_input(input: driver::input,
pkg_id: PkgId,
build_dir_opt: Option<Path>,
sess: session::Session,
crate_opt: Option<@ast::crate>,
out_file: Path,
binary: ~str,
what: driver::compile_upto) -> @ast::crate {
debug!("Calling build_output_filenames with %?", build_dir_opt);
let outputs = driver::build_output_filenames(input, &build_dir_opt, &None, sess);
let outputs = driver::build_output_filenames(input, &build_dir_opt, &Some(out_file), sess);
debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type);
let cfg = driver::build_configuration(sess, binary, input);
match crate_opt {
Some(c) => {
debug!("Calling compile_rest, outputs = %?", outputs);
assert!(what == driver::cu_everything);
driver::compile_rest(sess, cfg, driver::cu_everything, Some(outputs), Some(c));
c
}
None => {
debug!("Calling compile_upto, outputs = %?", outputs);
let (crate, _) = driver::compile_upto(sess, cfg, input, driver::cu_parse,
Some(outputs));
crate
let (crate, _) = driver::compile_upto(sess, cfg, input,
driver::cu_parse, Some(outputs));
// Inject the inferred link_meta info if it's not already there
// (assumes that name and vers are the only linkage metas)
let mut crate_to_use = crate;
if attr::find_linkage_metas(crate.node.attrs).is_empty() {
crate_to_use = add_attrs(*crate, ~[mk_attr(@dummy_spanned(meta_list(@~"link",
// change PkgId to have a <shortname> field?
~[@dummy_spanned(meta_name_value(@~"name",
mk_string_lit(@pkg_id.path.filestem().get()))),
@dummy_spanned(meta_name_value(@~"vers",
mk_string_lit(@pkg_id.version.to_str())))])))]);
}
driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use));
crate_to_use
}
}
}
@ -525,17 +560,30 @@ pub fn exe_suffix() -> ~str { ~".exe" }
pub fn exe_suffix() -> ~str { ~"" }
/// Returns a copy of crate `c` with attributes `attrs` added to its
/// attributes
fn add_attrs(c: ast::crate, new_attrs: ~[attribute]) -> @ast::crate {
@spanned {
node: crate_ {
attrs: c.node.attrs + new_attrs, ..c.node
},
span: c.span
}
}
// Called by build_crates
// FIXME (#4432): Use workcache to only compile when needed
pub fn compile_crate(sysroot: Option<Path>, crate: &Path, dir: &Path,
pub fn compile_crate(sysroot: Option<Path>, pkg_id: PkgId,
crate: &Path, dir: &Path,
flags: ~[~str], cfgs: ~[~str], opt: bool,
test: bool) -> bool {
test: bool, crate_type: crate_type) -> bool {
debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str());
debug!("compile_crate: flags =...");
debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
for flags.each |&fl| {
debug!("+++ %s", fl);
}
compile_input(sysroot, crate, dir, flags, cfgs, opt, test)
compile_input(sysroot, pkg_id,
crate, dir, flags, cfgs, opt, test, crate_type)
}
@ -563,6 +611,13 @@ pub fn link_exe(src: &Path, dest: &Path) -> bool {
}
}
pub fn mk_string_lit(s: @~str) -> ast::lit {
spanned {
node: ast::lit_str(s),
span: dummy_sp()
}
}
#[cfg(test)]
mod test {
use super::{is_cmd, parse_name};