rust/src/librustpkg/api.rs
2014-01-11 15:10:28 +09:00

203 lines
7.4 KiB
Rust

// 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 crate_id::*;
use package_source::*;
use path_util::{platform_library_name, target_build_dir};
use target::*;
use version::Version;
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;
// 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, version: Version,
lib: Path) {
build_lib_with_cfgs(sysroot, root, name, version, lib, ~[])
}
pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str,
version: Version, lib: Path, cfgs: ~[~str]) {
let cx = default_context(sysroot, root.clone());
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: CrateId{ version: version, ..CrateId::new(name)},
// 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, version: Version,
main: Path) {
build_exe_with_cfgs(sysroot, root, name, version, main, ~[])
}
pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str,
version: Version, main: Path, cfgs: ~[~str]) {
let cx = default_context(sysroot, root.clone());
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: CrateId{ version: version, ..CrateId::new(name)},
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,
version: Version,
// For now, these inputs are assumed to be inputs to each of the crates
more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path
let crateid = CrateId{ version: version, ..CrateId::new(name)};
cx.install(PkgSrc::new(workspace.clone(), workspace, false, crateid),
&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::new(package_name);
let absolute_paths = paths.map(|s| {
let whatever = workspace.join_many([~"src",
crateid.to_str(),
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 = CrateId::new(package_name);
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: ~[] }
}