diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index c821281184d3b..140d9ced5808d 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_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}; diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index f8805142769c1..206404ae2040c 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -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 { @@ -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 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); } } diff --git a/src/librustpkg/testsuite/fail/no-inferred-crates/zzyzx.rs b/src/librustpkg/testsuite/fail/no-inferred-crates/zzyzx.rs new file mode 100644 index 0000000000000..c9c1f00fb082a --- /dev/null +++ b/src/librustpkg/testsuite/fail/no-inferred-crates/zzyzx.rs @@ -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 or the MIT license +// , 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!"); +} diff --git a/src/librustpkg/testsuite/pass/commands.txt b/src/librustpkg/testsuite/pass/commands.txt new file mode 100644 index 0000000000000..e1a1b2462b253 --- /dev/null +++ b/src/librustpkg/testsuite/pass/commands.txt @@ -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 + diff --git a/src/librustpkg/testsuite/pass/deeply/nested/path/foo/main.rs b/src/librustpkg/testsuite/pass/deeply/nested/path/foo/main.rs new file mode 100644 index 0000000000000..41041ccb50912 --- /dev/null +++ b/src/librustpkg/testsuite/pass/deeply/nested/path/foo/main.rs @@ -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 or the MIT license +// , 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() {} + diff --git a/src/librustpkg/testsuite/pass/external-crate/main.rs b/src/librustpkg/testsuite/pass/external-crate/main.rs new file mode 100644 index 0000000000000..d094bcd6bba62 --- /dev/null +++ b/src/librustpkg/testsuite/pass/external-crate/main.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/librustpkg/testsuite/pass/fancy-lib/bar.rs b/src/librustpkg/testsuite/pass/fancy-lib/bar.rs new file mode 100644 index 0000000000000..ffbc6e2a7f9b2 --- /dev/null +++ b/src/librustpkg/testsuite/pass/fancy-lib/bar.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn assert_true() { + assert!(true); +} diff --git a/src/librustpkg/testsuite/pass/fancy-lib/fancy-lib.rs b/src/librustpkg/testsuite/pass/fancy-lib/fancy-lib.rs new file mode 100644 index 0000000000000..55261a820981a --- /dev/null +++ b/src/librustpkg/testsuite/pass/fancy-lib/fancy-lib.rs @@ -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 or the MIT license +// , 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; diff --git a/src/librustpkg/testsuite/pass/fancy-lib/foo.rs b/src/librustpkg/testsuite/pass/fancy-lib/foo.rs new file mode 100644 index 0000000000000..542a6af402d05 --- /dev/null +++ b/src/librustpkg/testsuite/pass/fancy-lib/foo.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn do_nothing() { +} \ No newline at end of file diff --git a/src/librustpkg/testsuite/pass/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/fancy-lib/pkg.rs new file mode 100644 index 0000000000000..be3c68d731b23 --- /dev/null +++ b/src/librustpkg/testsuite/pass/fancy-lib/pkg.rs @@ -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 or the MIT license +// , 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"]); +} \ No newline at end of file diff --git a/src/librustpkg/testsuite/pass/hello-world/main.rs b/src/librustpkg/testsuite/pass/hello-world/main.rs new file mode 100644 index 0000000000000..2ef387d962000 --- /dev/null +++ b/src/librustpkg/testsuite/pass/hello-world/main.rs @@ -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 or the MIT license +// , 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!"); +} diff --git a/src/librustpkg/testsuite/pass/install-paths/bench.rs b/src/librustpkg/testsuite/pass/install-paths/bench.rs new file mode 100644 index 0000000000000..e1641ccf07493 --- /dev/null +++ b/src/librustpkg/testsuite/pass/install-paths/bench.rs @@ -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 or the MIT license +// , 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; + } +} \ No newline at end of file diff --git a/src/librustpkg/testsuite/pass/install-paths/lib.rs b/src/librustpkg/testsuite/pass/install-paths/lib.rs new file mode 100644 index 0000000000000..baf90446f7aac --- /dev/null +++ b/src/librustpkg/testsuite/pass/install-paths/lib.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f() -> int { 42 } diff --git a/src/librustpkg/testsuite/pass/install-paths/main.rs b/src/librustpkg/testsuite/pass/install-paths/main.rs new file mode 100644 index 0000000000000..37e606dcb1ab3 --- /dev/null +++ b/src/librustpkg/testsuite/pass/install-paths/main.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/librustpkg/testsuite/pass/install-paths/test.rs b/src/librustpkg/testsuite/pass/install-paths/test.rs new file mode 100644 index 0000000000000..acfae9e04fb59 --- /dev/null +++ b/src/librustpkg/testsuite/pass/install-paths/test.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/librustpkg/testsuite/pass/simple-lib/bar.rs b/src/librustpkg/testsuite/pass/simple-lib/bar.rs new file mode 100644 index 0000000000000..ffbc6e2a7f9b2 --- /dev/null +++ b/src/librustpkg/testsuite/pass/simple-lib/bar.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn assert_true() { + assert!(true); +} diff --git a/src/librustpkg/testsuite/pass/simple-lib/foo.rs b/src/librustpkg/testsuite/pass/simple-lib/foo.rs new file mode 100644 index 0000000000000..542a6af402d05 --- /dev/null +++ b/src/librustpkg/testsuite/pass/simple-lib/foo.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn do_nothing() { +} \ No newline at end of file diff --git a/src/librustpkg/testsuite/pass/simple-lib/lib.rs b/src/librustpkg/testsuite/pass/simple-lib/lib.rs new file mode 100644 index 0000000000000..1cdca6cdd5d87 --- /dev/null +++ b/src/librustpkg/testsuite/pass/simple-lib/lib.rs @@ -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 or the MIT license +// , 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; diff --git a/src/librustpkg/testsuite/pass/simple-lib/simple-lib.rc b/src/librustpkg/testsuite/pass/simple-lib/simple-lib.rc new file mode 100644 index 0000000000000..1cdca6cdd5d87 --- /dev/null +++ b/src/librustpkg/testsuite/pass/simple-lib/simple-lib.rc @@ -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 or the MIT license +// , 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; diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 19938e8c5f178..bb162974e035d 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -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, + 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, 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, // 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, - 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, + 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 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, crate: &Path, dir: &Path, +pub fn compile_crate(sysroot: Option, 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};