diff --git a/doc/rustpkg.md b/doc/rustpkg.md index 1e6e4e29cb9..399a7642665 100644 --- a/doc/rustpkg.md +++ b/doc/rustpkg.md @@ -52,13 +52,11 @@ A valid workspace must contain each of the following subdirectories: 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 a target-specific subdirectory of this directory. +* 'bin/': `rustpkg install` installs executable binaries into 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 executables for `bar` to - `foo/bin/x86_64-apple-darwin/`. - The executables will have names of the form `foo/bin/x86_64-apple-darwin/bar`. + 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, @@ -85,6 +83,12 @@ rustpkg also interprets any dependencies on such a package ID literally 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`. + ## Source files rustpkg searches for four different fixed filenames in order to determine the crates to build: @@ -140,9 +144,11 @@ but not in their `lib` or `bin` directories. ## install -`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`, -and then installs them either into `foo`'s `lib` and `bin` directories, -or into the `lib` and `bin` subdirectories of the first entry in `RUST_PATH`. +`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, it installs them into `foo`'s `lib` and `bin` directories. ## test diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 757c53354a2..892217988c7 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -77,15 +77,15 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, if !found { let rustpath = rust_path(); for path in rustpath.iter() { - debug!("is %s in visited_dirs? %?", - path.push("lib").to_str(), - visited_dirs.contains(&path.push("lib").to_str())); + let tlib_path = make_rustpkg_target_lib_path(path, self.target_triple); + debug!("is %s in visited_dirs? %?", tlib_path.to_str(), + visited_dirs.contains(&tlib_path.to_str())); - if !visited_dirs.contains(&path.push("lib").to_str()) { - visited_dirs.insert(path.push("lib").to_str()); + if !visited_dirs.contains(&tlib_path.to_str()) { + visited_dirs.insert(tlib_path.to_str()); // Don't keep searching the RUST_PATH if one match turns up -- // if we did, we'd get a "multiple matching crates" error - match f(&path.push("lib")) { + match f(&tlib_path) { FileMatches => { break; } @@ -145,6 +145,11 @@ fn make_target_lib_path(sysroot: &Path, sysroot.push_rel(&relative_target_lib_path(target_triple)) } +fn make_rustpkg_target_lib_path(dir: &Path, + target_triple: &str) -> Path { + dir.push_rel(&Path(libdir()).push(target_triple.to_owned())) +} + fn get_or_default_sysroot() -> Path { match os::self_exe_path() { option::Some(ref p) => (*p).pop(), diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index f8ac7ca11a5..92e5adf09f6 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -14,6 +14,7 @@ pub use package_id::PkgId; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}; pub use version::{Version, NoVersion, split_version_general, try_parsing_version}; pub use rustc::metadata::filesearch::rust_path; +use rustc::driver::driver::host_triple; use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os::mkdir_recursive; @@ -94,10 +95,29 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path, 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 { + workspace.push("build").push(host_triple()) +} + +/// 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 { + workspace.push("lib").push(host_triple()) +} + +/// 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.push("bin") +} + /// Figure out what the executable name for in 's build /// directory is, and if the file exists, return it. pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option { - let mut result = workspace.push("build"); + let mut result = target_build_dir(workspace); // should use a target-specific subdirectory result = mk_output_path(Main, Build, pkgid, result); debug!("built_executable_in_workspace: checking whether %s exists", @@ -124,7 +144,7 @@ pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option } fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option { - let mut result = workspace.push("build"); + let mut result = target_build_dir(workspace); // should use a target-specific subdirectory result = mk_output_path(what, Build, pkgid, result); debug!("output_in_workspace: checking whether %s exists", @@ -172,11 +192,21 @@ pub fn library_in_workspace(path: &Path, short_name: &str, where: Target, prefix = %s", short_name, where, workspace.to_str(), prefix); let dir_to_search = match where { - Build => workspace.push(prefix).push_rel(path), - Install => workspace.push(prefix) + Build => target_build_dir(workspace).push_rel(path), + Install => target_lib_dir(workspace) }; + + library_in(short_name, version, &dir_to_search) +} + +// rustc doesn't use target-specific subdirectories +pub fn system_library(sysroot: &Path, lib_name: &str) -> Option { + library_in(lib_name, &NoVersion, &sysroot.push("lib")) +} + +fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option { debug!("Listing directory %s", dir_to_search.to_str()); - let dir_contents = os::list_dir(&dir_to_search); + let dir_contents = os::list_dir(dir_to_search); debug!("dir has %? entries", dir_contents.len()); let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, short_name); @@ -298,9 +328,10 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, }; // Artifacts in the build directory live in a package-ID-specific subdirectory, // but installed ones don't. - let result = match where { - Build => workspace.push(subdir).push_rel(&pkgid.path), - _ => workspace.push(subdir) + let result = match (where, what) { + (Build, _) => target_build_dir(workspace).push_rel(&pkgid.path), + (Install, Lib) => target_lib_dir(workspace), + (Install, _) => target_bin_dir(workspace) }; if !os::path_exists(&result) && !mkdir_recursive(&result, U_RWX) { cond.raise((result.clone(), fmt!("target_file_in_workspace couldn't \ @@ -315,10 +346,10 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { use conditions::bad_path::cond; - let mut result = workspace.push("build"); - // n.b. Should actually use a target-specific - // subdirectory of build/ + let mut result = target_build_dir(workspace); result = result.push_rel(&pkgid.path); + debug!("Creating build dir %s for package id %s", result.to_str(), + pkgid.to_str()); if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) { result } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 5a3ed7dd59d..e5ca38daeb5 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -27,7 +27,7 @@ use path_util::{target_executable_in_workspace, target_test_in_workspace, target_bench_in_workspace, make_dir_rwx, U_RWX, library_in_workspace, installed_library_in_workspace, built_bench_in_workspace, built_test_in_workspace, - built_library_in_workspace, built_executable_in_workspace}; + built_library_in_workspace, built_executable_in_workspace, target_build_dir}; use rustc::back::link::get_cc_prog; use rustc::metadata::filesearch::rust_path; use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups}; @@ -382,7 +382,7 @@ fn llvm_bitcode_file_exists(repo: &Path, short_name: &str) -> bool { } fn file_exists(repo: &Path, short_name: &str, extension: &str) -> bool { - os::path_exists(&repo.push_many([~"build", short_name.to_owned(), + os::path_exists(&target_build_dir(repo).push_many([short_name.to_owned(), fmt!("%s.%s", short_name, extension)])) } @@ -433,7 +433,7 @@ fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Pat } fn output_file_name(workspace: &Path, short_name: &str) -> Path { - workspace.push("build").push(short_name).push(fmt!("%s%s", short_name, os::EXE_SUFFIX)) + target_build_dir(workspace).push(short_name).push(fmt!("%s%s", short_name, os::EXE_SUFFIX)) } fn touch_source_file(workspace: &Path, pkgid: &PkgId) { @@ -657,11 +657,10 @@ fn test_package_version() { None => false }); assert!(built_executable_in_workspace(&temp_pkg_id, &ws) - == Some(ws.push("build"). - push("mockgithub.com"). - push("catamorphism"). - push("test_pkg_version"). - push("test_pkg_version"))); + == Some(target_build_dir(&ws).push_many([~"mockgithub.com", + ~"catamorphism", + ~"test_pkg_version", + ~"test_pkg_version"]))); } #[test] @@ -755,7 +754,7 @@ fn package_script_with_default_build() { } command_line_test([~"install", ~"fancy-lib"], &dir); assert_lib_exists(&dir, &Path("fancy-lib"), NoVersion); - assert!(os::path_exists(&dir.push("build").push("fancy-lib").push("generated.rs"))); + assert!(os::path_exists(&target_build_dir(&dir).push_many([~"fancy-lib", ~"generated.rs"]))); } #[test] @@ -1121,7 +1120,7 @@ fn test_import_rustpkg() { "extern mod rustpkg; fn main() {}"); command_line_test([~"build", ~"foo"], &workspace); debug!("workspace = %s", workspace.to_str()); - assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s", + assert!(os::path_exists(&target_build_dir(&workspace).push("foo").push(fmt!("pkg%s", os::EXE_SUFFIX)))); } @@ -1133,7 +1132,7 @@ fn test_macro_pkg_script() { "extern mod rustpkg; fn main() { debug!(\"Hi\"); }"); command_line_test([~"build", ~"foo"], &workspace); debug!("workspace = %s", workspace.to_str()); - assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s", + assert!(os::path_exists(&target_build_dir(&workspace).push("foo").push(fmt!("pkg%s", os::EXE_SUFFIX)))); } @@ -1622,6 +1621,33 @@ fn test_install_to_rust_path() { assert!(!executable_exists(&second_workspace, "foo")); } +fn test_target_specific_build_dir() { + let p_id = PkgId::new("foo"); + let workspace = create_local_package(&p_id); + command_line_test([test_sysroot().to_str(), + ~"build", + ~"foo"], + &workspace); + assert!(os::path_is_dir(&target_build_dir(&workspace))); + assert!(built_executable_exists(&workspace, "foo")); + assert!(os::list_dir(&workspace.push("build")).len() == 1); +} + +#[test] +fn test_target_specific_install_dir() { + let p_id = PkgId::new("foo"); + let workspace = create_local_package(&p_id); + command_line_test([test_sysroot().to_str(), + ~"install", + ~"foo"], + &workspace); + assert!(os::path_is_dir(&workspace.push("lib").push(host_triple()))); + assert_lib_exists(&workspace, &Path("foo"), NoVersion); + assert!(os::list_dir(&workspace.push("lib")).len() == 1); + assert!(os::path_is_dir(&workspace.push("bin"))); + assert_executable_exists(&workspace, "foo"); +} + /// Returns true if p exists and is executable fn is_executable(p: &Path) -> bool { use std::libc::consts::os::posix88::{S_IXUSR}; diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 708d50bb537..18928c3f169 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -23,7 +23,7 @@ use context::{in_target, StopBefore, Link, Assemble, BuildContext}; use package_id::PkgId; use package_source::PkgSrc; use workspace::pkg_parent_workspaces; -use path_util::{installed_library_in_workspace, U_RWX, rust_path}; +use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir}; use messages::error; pub use target::{OutputType, Main, Lib, Bench, Test}; @@ -170,7 +170,7 @@ pub fn compile_input(context: &BuildContext, // tjc: by default, use the package ID name as the link name // not sure if we should support anything else - let out_dir = workspace.push("build").push_rel(&pkg_id.path); + let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path); let binary = os::args()[0].to_managed(); @@ -381,7 +381,8 @@ pub fn find_and_install_dependencies(context: &BuildContext, None => sess.str_of(lib_ident) }; debug!("Finding and installing... %s", lib_name); - match installed_library_in_workspace(&Path(lib_name), &context.sysroot()) { + // Check standard Rust library path first + match system_library(&context.sysroot(), lib_name) { Some(ref installed_path) => { debug!("It exists: %s", installed_path.to_str()); // Say that [path for c] has a discovered dependency on