rustpkg: Support arbitrary dependencies in the install API
api::install_pkg now accepts an argument that's a list of (kind, path) dependency pairs. This allows custom package scripts to declare C dependencies, as is demonstrated in rustpkg::tests::test_c_dependency_ok. Closes #6403
This commit is contained in:
parent
22a5ebdc6b
commit
c97957588b
|
@ -370,6 +370,7 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \
|
||||||
$$(SREQ$(1)_T_$(2)_H_$(3)) \
|
$$(SREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \
|
||||||
|
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(2)) \
|
||||||
$$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) \
|
$$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) \
|
||||||
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(2))
|
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(2))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
|
|
|
@ -12,22 +12,35 @@ use context::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use package_id::*;
|
use package_id::*;
|
||||||
use package_source::*;
|
use package_source::*;
|
||||||
|
use path_util::{platform_library_name, target_build_dir};
|
||||||
use target::*;
|
use target::*;
|
||||||
use version::Version;
|
use version::Version;
|
||||||
|
use workspace::pkg_parent_workspaces;
|
||||||
use workcache_support::*;
|
use workcache_support::*;
|
||||||
|
pub use path_util::default_workspace;
|
||||||
|
|
||||||
pub use source_control::{safe_git_clone, git_clone_url};
|
pub use source_control::{safe_git_clone, git_clone_url};
|
||||||
|
|
||||||
use std::os;
|
use std::{os, run};
|
||||||
use extra::arc::{Arc,RWArc};
|
use extra::arc::{Arc,RWArc};
|
||||||
use extra::workcache;
|
use extra::workcache;
|
||||||
use extra::workcache::{Database, Logger, FreshnessMap};
|
use extra::workcache::{Database, Logger, FreshnessMap};
|
||||||
use extra::treemap::TreeMap;
|
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
|
/// Convenience functions intended for calling from pkg.rs
|
||||||
/// p is where to put the cache file for dependencies
|
/// p is where to put the cache file for dependencies
|
||||||
pub fn default_context(p: Path) -> BuildContext {
|
pub fn default_context(sysroot: Path, p: Path) -> BuildContext {
|
||||||
new_default_context(new_workcache_context(&p), p)
|
new_default_context(new_workcache_context(&p), sysroot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
|
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
|
||||||
|
@ -68,7 +81,7 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
|
||||||
|
|
||||||
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
lib: Path) {
|
lib: Path) {
|
||||||
let cx = default_context(sysroot);
|
let cx = default_context(sysroot, root.clone());
|
||||||
let pkg_src = PkgSrc {
|
let pkg_src = PkgSrc {
|
||||||
source_workspace: root.clone(),
|
source_workspace: root.clone(),
|
||||||
build_in_destination: false,
|
build_in_destination: false,
|
||||||
|
@ -81,12 +94,12 @@ pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
tests: ~[],
|
tests: ~[],
|
||||||
benchs: ~[]
|
benchs: ~[]
|
||||||
};
|
};
|
||||||
pkg_src.build(&cx, ~[]);
|
pkg_src.build(&cx, ~[], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
main: Path) {
|
main: Path) {
|
||||||
let cx = default_context(sysroot);
|
let cx = default_context(sysroot, root.clone());
|
||||||
let pkg_src = PkgSrc {
|
let pkg_src = PkgSrc {
|
||||||
source_workspace: root.clone(),
|
source_workspace: root.clone(),
|
||||||
build_in_destination: false,
|
build_in_destination: false,
|
||||||
|
@ -100,13 +113,76 @@ pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
benchs: ~[]
|
benchs: ~[]
|
||||||
};
|
};
|
||||||
|
|
||||||
pkg_src.build(&cx, ~[]);
|
pkg_src.build(&cx, ~[], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
|
pub fn install_pkg(cx: &BuildContext,
|
||||||
let cx = default_context(sysroot);
|
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 pkgid = PkgId{ version: version, ..PkgId::new(name)};
|
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
|
||||||
cx.install(PkgSrc::new(workspace.clone(), workspace, false, pkgid), &Everything);
|
cx.install(PkgSrc::new(workspace.clone(), workspace, false, pkgid),
|
||||||
|
&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.
|
||||||
|
pub fn build_library_in_workspace(exec: &mut workcache::Exec,
|
||||||
|
context: &mut Context,
|
||||||
|
package_name: &str,
|
||||||
|
tool: &str,
|
||||||
|
flags: &[~str],
|
||||||
|
paths: &[~str],
|
||||||
|
output: &str) -> ~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 pkgid = PkgId::new(package_name);
|
||||||
|
let absolute_paths = paths.map(|s| {
|
||||||
|
let whatever = workspace.join_many([~"src",
|
||||||
|
pkgid.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()];
|
||||||
|
let exit_code = run::process_status(tool, all_args);
|
||||||
|
if exit_code != 0 {
|
||||||
|
command_failed.raise((tool.to_owned(), all_args, exit_code))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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());
|
||||||
|
out_name_str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 pkgid = PkgId::new(package_name);
|
||||||
|
let workspaces = pkg_parent_workspaces(context, &pkgid);
|
||||||
|
if workspaces.is_empty() {
|
||||||
|
bad_pkg_id.raise((Path::new(package_name), package_name.to_owned()));
|
||||||
|
}
|
||||||
|
workspaces[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_crate(p: Path) -> Crate {
|
fn mk_crate(p: Path) -> Crate {
|
||||||
|
|
|
@ -54,3 +54,9 @@ condition! {
|
||||||
condition! {
|
condition! {
|
||||||
pub git_checkout_failed: (~str, Path) -> ();
|
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], int) -> ~str;
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,15 @@ impl BuildContext {
|
||||||
pub fn compile_upto(&self) -> StopBefore {
|
pub fn compile_upto(&self) -> StopBefore {
|
||||||
self.context.compile_upto()
|
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) -> ~[Path] {
|
||||||
|
self.context.rustc_flags.additional_library_paths.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,6 +94,9 @@ pub struct RustcFlags {
|
||||||
target: Option<~str>,
|
target: Option<~str>,
|
||||||
// Target CPU (defaults to rustc's default target CPU)
|
// Target CPU (defaults to rustc's default target CPU)
|
||||||
target_cpu: Option<~str>,
|
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: ~[Path],
|
||||||
// Any -Z features
|
// Any -Z features
|
||||||
experimental_features: Option<~[~str]>
|
experimental_features: Option<~[~str]>
|
||||||
}
|
}
|
||||||
|
@ -99,6 +111,7 @@ impl Clone for RustcFlags {
|
||||||
save_temps: self.save_temps,
|
save_temps: self.save_temps,
|
||||||
target: self.target.clone(),
|
target: self.target.clone(),
|
||||||
target_cpu: self.target_cpu.clone(),
|
target_cpu: self.target_cpu.clone(),
|
||||||
|
additional_library_paths: self.additional_library_paths.clone(),
|
||||||
experimental_features: self.experimental_features.clone()
|
experimental_features: self.experimental_features.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,6 +161,10 @@ impl Context {
|
||||||
pub fn compile_upto(&self) -> StopBefore {
|
pub fn compile_upto(&self) -> StopBefore {
|
||||||
self.rustc_flags.compile_upto
|
self.rustc_flags.compile_upto
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_library_path(&mut self, p: Path) {
|
||||||
|
self.rustc_flags.additional_library_paths.push(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We assume that if ../../rustc exists, then we're running
|
/// We assume that if ../../rustc exists, then we're running
|
||||||
|
@ -210,6 +227,7 @@ impl RustcFlags {
|
||||||
save_temps: false,
|
save_temps: false,
|
||||||
target: None,
|
target: None,
|
||||||
target_cpu: None,
|
target_cpu: None,
|
||||||
|
additional_library_paths: ~[],
|
||||||
experimental_features: None
|
experimental_features: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use path_util::{find_dir_using_rust_path_hack, make_dir_rwx_recursive, default_w
|
||||||
use path_util::{target_build_dir, versionize, dir_has_crate_file};
|
use path_util::{target_build_dir, versionize, dir_has_crate_file};
|
||||||
use util::{compile_crate, DepMap};
|
use util::{compile_crate, DepMap};
|
||||||
use workcache_support;
|
use workcache_support;
|
||||||
use workcache_support::crate_tag;
|
use workcache_support::{digest_only_date, digest_file_with_date, crate_tag};
|
||||||
use extra::workcache;
|
use extra::workcache;
|
||||||
use extra::treemap::TreeMap;
|
use extra::treemap::TreeMap;
|
||||||
|
|
||||||
|
@ -390,7 +390,8 @@ impl PkgSrc {
|
||||||
deps: &mut DepMap,
|
deps: &mut DepMap,
|
||||||
crates: &[Crate],
|
crates: &[Crate],
|
||||||
cfgs: &[~str],
|
cfgs: &[~str],
|
||||||
what: OutputType) {
|
what: OutputType,
|
||||||
|
inputs_to_discover: &[(~str, Path)]) {
|
||||||
for crate in crates.iter() {
|
for crate in crates.iter() {
|
||||||
let path = self.start_dir.join(&crate.file);
|
let path = self.start_dir.join(&crate.file);
|
||||||
debug!("build_crates: compiling {}", path.display());
|
debug!("build_crates: compiling {}", path.display());
|
||||||
|
@ -408,7 +409,19 @@ impl PkgSrc {
|
||||||
let sub_dir = self.build_workspace().clone();
|
let sub_dir = self.build_workspace().clone();
|
||||||
let sub_flags = crate.flags.clone();
|
let sub_flags = crate.flags.clone();
|
||||||
let sub_deps = deps.clone();
|
let sub_deps = deps.clone();
|
||||||
|
let inputs = inputs_to_discover.map(|&(ref k, ref p)|
|
||||||
|
(k.clone(), p.as_str().unwrap().to_owned()));
|
||||||
do prep.exec |exec| {
|
do prep.exec |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")
|
||||||
|
});
|
||||||
|
}
|
||||||
let result = compile_crate(&subcx,
|
let result = compile_crate(&subcx,
|
||||||
exec,
|
exec,
|
||||||
&id,
|
&id,
|
||||||
|
@ -452,22 +465,43 @@ impl PkgSrc {
|
||||||
build_context: &BuildContext,
|
build_context: &BuildContext,
|
||||||
// DepMap is a map from str (crate name) to (kind, name) --
|
// DepMap is a map from str (crate name) to (kind, name) --
|
||||||
// it tracks discovered dependencies per-crate
|
// it tracks discovered dependencies per-crate
|
||||||
cfgs: ~[~str]) -> DepMap {
|
cfgs: ~[~str],
|
||||||
|
inputs_to_discover: &[(~str, Path)]) -> DepMap {
|
||||||
let mut deps = TreeMap::new();
|
let mut deps = TreeMap::new();
|
||||||
|
|
||||||
let libs = self.libs.clone();
|
let libs = self.libs.clone();
|
||||||
let mains = self.mains.clone();
|
let mains = self.mains.clone();
|
||||||
let tests = self.tests.clone();
|
let tests = self.tests.clone();
|
||||||
let benchs = self.benchs.clone();
|
let benchs = self.benchs.clone();
|
||||||
debug!("Building libs in {}, destination = {}",
|
debug!("Building libs in {}, destination = {}",
|
||||||
self.source_workspace.display(), self.build_workspace().display());
|
self.destination_workspace.display(),
|
||||||
self.build_crates(build_context, &mut deps, libs, cfgs, Lib);
|
self.destination_workspace.display());
|
||||||
|
self.build_crates(build_context,
|
||||||
|
&mut deps,
|
||||||
|
libs,
|
||||||
|
cfgs,
|
||||||
|
Lib,
|
||||||
|
inputs_to_discover);
|
||||||
debug!("Building mains");
|
debug!("Building mains");
|
||||||
self.build_crates(build_context, &mut deps, mains, cfgs, Main);
|
self.build_crates(build_context,
|
||||||
|
&mut deps,
|
||||||
|
mains,
|
||||||
|
cfgs,
|
||||||
|
Main,
|
||||||
|
inputs_to_discover);
|
||||||
debug!("Building tests");
|
debug!("Building tests");
|
||||||
self.build_crates(build_context, &mut deps, tests, cfgs, Test);
|
self.build_crates(build_context,
|
||||||
|
&mut deps,
|
||||||
|
tests,
|
||||||
|
cfgs,
|
||||||
|
Test,
|
||||||
|
inputs_to_discover);
|
||||||
debug!("Building benches");
|
debug!("Building benches");
|
||||||
self.build_crates(build_context, &mut deps, benchs, cfgs, Bench);
|
self.build_crates(build_context,
|
||||||
|
&mut deps,
|
||||||
|
benchs,
|
||||||
|
cfgs,
|
||||||
|
Bench,
|
||||||
|
inputs_to_discover);
|
||||||
deps
|
deps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -461,7 +461,6 @@ pub fn versionize(p: &Path, v: &Version) -> Path {
|
||||||
p.with_filename(q)
|
p.with_filename(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(target_os = "win32")]
|
#[cfg(target_os = "win32")]
|
||||||
pub fn chmod_read_only(p: &Path) -> bool {
|
pub fn chmod_read_only(p: &Path) -> bool {
|
||||||
#[fixed_stack_segment];
|
#[fixed_stack_segment];
|
||||||
|
@ -483,3 +482,6 @@ pub fn chmod_read_only(p: &Path) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn platform_library_name(s: &str) -> ~str {
|
||||||
|
format!("{}{}{}", os::consts::DLL_PREFIX, s, os::consts::DLL_SUFFIX)
|
||||||
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ use rustc::metadata::filesearch;
|
||||||
use rustc::metadata::filesearch::rust_path;
|
use rustc::metadata::filesearch::rust_path;
|
||||||
use extra::{getopts};
|
use extra::{getopts};
|
||||||
use syntax::{ast, diagnostic};
|
use syntax::{ast, diagnostic};
|
||||||
use util::*;
|
|
||||||
use messages::{error, warn, note};
|
use messages::{error, warn, note};
|
||||||
use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
|
use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
|
||||||
use path_util::{U_RWX, in_rust_path};
|
use path_util::{U_RWX, in_rust_path};
|
||||||
|
@ -47,15 +46,16 @@ use context::{Context, BuildContext,
|
||||||
LLVMAssemble, LLVMCompileBitcode};
|
LLVMAssemble, LLVMCompileBitcode};
|
||||||
use package_id::PkgId;
|
use package_id::PkgId;
|
||||||
use package_source::PkgSrc;
|
use package_source::PkgSrc;
|
||||||
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench, Tests};
|
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
|
||||||
|
use target::{Tests, MaybeCustom, Inferred, JustOne};
|
||||||
use workcache_support::digest_only_date;
|
use workcache_support::digest_only_date;
|
||||||
use exit_codes::{COPY_FAILED_CODE, BAD_FLAG_CODE};
|
use exit_codes::{COPY_FAILED_CODE, BAD_FLAG_CODE};
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
mod conditions;
|
mod conditions;
|
||||||
mod context;
|
pub mod context;
|
||||||
mod crate;
|
mod crate;
|
||||||
mod exit_codes;
|
pub mod exit_codes;
|
||||||
mod installed_packages;
|
mod installed_packages;
|
||||||
mod messages;
|
mod messages;
|
||||||
mod package_id;
|
mod package_id;
|
||||||
|
@ -67,7 +67,7 @@ mod target;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
mod util;
|
mod util;
|
||||||
mod version;
|
pub mod version;
|
||||||
pub mod workcache_support;
|
pub mod workcache_support;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ impl<'self> PkgScript<'self> {
|
||||||
/// Given the path name for a package script
|
/// Given the path name for a package script
|
||||||
/// and a package ID, parse the package script into
|
/// and a package ID, parse the package script into
|
||||||
/// a PkgScript that we can then execute
|
/// a PkgScript that we can then execute
|
||||||
fn parse<'a>(sysroot: @Path,
|
fn parse<'a>(sysroot: Path,
|
||||||
script: Path,
|
script: Path,
|
||||||
workspace: &Path,
|
workspace: &Path,
|
||||||
id: &'a PkgId) -> PkgScript<'a> {
|
id: &'a PkgId) -> PkgScript<'a> {
|
||||||
|
@ -107,7 +107,7 @@ impl<'self> PkgScript<'self> {
|
||||||
debug!("pkgscript parse: {}", sysroot.display());
|
debug!("pkgscript parse: {}", sysroot.display());
|
||||||
let options = @session::options {
|
let options = @session::options {
|
||||||
binary: binary,
|
binary: binary,
|
||||||
maybe_sysroot: Some(sysroot),
|
maybe_sysroot: Some(@sysroot),
|
||||||
crate_type: session::bin_crate,
|
crate_type: session::bin_crate,
|
||||||
.. (*session::basic_options()).clone()
|
.. (*session::basic_options()).clone()
|
||||||
};
|
};
|
||||||
|
@ -132,12 +132,7 @@ impl<'self> PkgScript<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the contents of this package script, where <what>
|
fn build_custom(&mut self, exec: &mut workcache::Exec) -> ~str {
|
||||||
/// 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
|
|
||||||
fn run_custom(&mut self, exec: &mut workcache::Exec,
|
|
||||||
sysroot: &Path) -> (~[~str], ExitCode) {
|
|
||||||
let sess = self.sess;
|
let sess = self.sess;
|
||||||
|
|
||||||
debug!("Working directory = {}", self.build_dir.display());
|
debug!("Working directory = {}", self.build_dir.display());
|
||||||
|
@ -152,17 +147,28 @@ impl<'self> PkgScript<'self> {
|
||||||
&self.build_dir,
|
&self.build_dir,
|
||||||
sess,
|
sess,
|
||||||
crate);
|
crate);
|
||||||
debug!("Running program: {} {} {}", exe.display(),
|
|
||||||
sysroot.display(), "install");
|
|
||||||
// Discover the output
|
// Discover the output
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||||
exec.discover_output("binary", exe.as_str().unwrap(), digest_only_date(&exe));
|
// 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
|
||||||
|
fn run_custom(exe: &Path, sysroot: &Path) -> (~[~str], int) {
|
||||||
|
debug!("Running program: {} {} {}", exe.as_str().unwrap().to_owned(),
|
||||||
|
sysroot.display(), "install");
|
||||||
// FIXME #7401 should support commands besides `install`
|
// FIXME #7401 should support commands besides `install`
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||||
let status = run::process_status(exe.as_str().unwrap(),
|
let status = run::process_status(exe.as_str().unwrap(),
|
||||||
[sysroot.as_str().unwrap().to_owned(), ~"install"]);
|
[sysroot.as_str().unwrap().to_owned(), ~"install"]);
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
return (~[], status);
|
debug!("run_custom: first pkg command failed with {:?}", status);
|
||||||
|
(~[], status)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
debug!("Running program (configs): {} {} {}",
|
debug!("Running program (configs): {} {} {}",
|
||||||
|
@ -170,6 +176,7 @@ impl<'self> PkgScript<'self> {
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||||
let output = run::process_output(exe.as_str().unwrap(),
|
let output = run::process_output(exe.as_str().unwrap(),
|
||||||
[sysroot.as_str().unwrap().to_owned(), ~"configs"]);
|
[sysroot.as_str().unwrap().to_owned(), ~"configs"]);
|
||||||
|
debug!("run_custom: second pkg command did {:?}", output.status);
|
||||||
// Run the configs() function to get the configs
|
// Run the configs() function to get the configs
|
||||||
let cfgs = str::from_utf8_slice(output.output).word_iter()
|
let cfgs = str::from_utf8_slice(output.output).word_iter()
|
||||||
.map(|w| w.to_owned()).collect();
|
.map(|w| w.to_owned()).collect();
|
||||||
|
@ -263,7 +270,7 @@ impl CtxMethods for BuildContext {
|
||||||
let cwd = os::getcwd();
|
let cwd = os::getcwd();
|
||||||
match cmd {
|
match cmd {
|
||||||
"build" => {
|
"build" => {
|
||||||
self.build_args(args, &Everything);
|
self.build_args(args, &WhatToBuild::new(MaybeCustom, Everything));
|
||||||
}
|
}
|
||||||
"clean" => {
|
"clean" => {
|
||||||
if args.len() < 1 {
|
if args.len() < 1 {
|
||||||
|
@ -301,12 +308,14 @@ impl CtxMethods for BuildContext {
|
||||||
let inferred_pkgid =
|
let inferred_pkgid =
|
||||||
PkgId::new(cwd.filename_str().unwrap());
|
PkgId::new(cwd.filename_str().unwrap());
|
||||||
self.install(PkgSrc::new(cwd, default_workspace(),
|
self.install(PkgSrc::new(cwd, default_workspace(),
|
||||||
true, inferred_pkgid), &Everything);
|
true, inferred_pkgid),
|
||||||
|
&WhatToBuild::new(MaybeCustom, Everything));
|
||||||
}
|
}
|
||||||
None => { usage::install(); return; }
|
None => { usage::install(); return; }
|
||||||
Some((ws, pkgid)) => {
|
Some((ws, pkgid)) => {
|
||||||
let pkg_src = PkgSrc::new(ws.clone(), ws.clone(), false, pkgid);
|
let pkg_src = PkgSrc::new(ws.clone(), ws.clone(), false, pkgid);
|
||||||
self.install(pkg_src, &Everything);
|
self.install(pkg_src, &WhatToBuild::new(MaybeCustom,
|
||||||
|
Everything));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +329,7 @@ impl CtxMethods for BuildContext {
|
||||||
if workspaces.is_empty() {
|
if workspaces.is_empty() {
|
||||||
let d = default_workspace();
|
let d = default_workspace();
|
||||||
let src = PkgSrc::new(d.clone(), d, false, pkgid.clone());
|
let src = PkgSrc::new(d.clone(), d, false, pkgid.clone());
|
||||||
self.install(src, &Everything);
|
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for workspace in workspaces.iter() {
|
for workspace in workspaces.iter() {
|
||||||
|
@ -331,7 +340,7 @@ impl CtxMethods for BuildContext {
|
||||||
dest,
|
dest,
|
||||||
self.context.use_rust_path_hack,
|
self.context.use_rust_path_hack,
|
||||||
pkgid.clone());
|
pkgid.clone());
|
||||||
self.install(src, &Everything);
|
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,7 +363,8 @@ impl CtxMethods for BuildContext {
|
||||||
}
|
}
|
||||||
"test" => {
|
"test" => {
|
||||||
// Build the test executable
|
// Build the test executable
|
||||||
let maybe_id_and_workspace = self.build_args(args, &Tests);
|
let maybe_id_and_workspace = self.build_args(args,
|
||||||
|
&WhatToBuild::new(MaybeCustom, Tests));
|
||||||
match maybe_id_and_workspace {
|
match maybe_id_and_workspace {
|
||||||
Some((pkg_id, workspace)) => {
|
Some((pkg_id, workspace)) => {
|
||||||
// Assuming it's built, run the tests
|
// Assuming it's built, run the tests
|
||||||
|
@ -420,6 +430,7 @@ impl CtxMethods for BuildContext {
|
||||||
pkgid = {} pkgsrc start_dir = {}", workspace.display(),
|
pkgid = {} pkgsrc start_dir = {}", workspace.display(),
|
||||||
in_rust_path(&workspace), is_git_dir(&workspace.join(&pkgid.path)),
|
in_rust_path(&workspace), is_git_dir(&workspace.join(&pkgid.path)),
|
||||||
pkgid.to_str(), pkg_src.start_dir.display());
|
pkgid.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,
|
// 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
|
// then clone it into the first entry in RUST_PATH, and repeat
|
||||||
|
@ -448,27 +459,27 @@ impl CtxMethods for BuildContext {
|
||||||
debug!("Package source directory = {}", pkg_src.to_str());
|
debug!("Package source directory = {}", pkg_src.to_str());
|
||||||
let opt = pkg_src.package_script_option();
|
let opt = pkg_src.package_script_option();
|
||||||
debug!("Calling pkg_script_option on {:?}", opt);
|
debug!("Calling pkg_script_option on {:?}", opt);
|
||||||
let cfgs = match pkg_src.package_script_option() {
|
let cfgs = match (pkg_src.package_script_option(), what_to_build.build_type) {
|
||||||
Some(package_script_path) => {
|
(Some(package_script_path), MaybeCustom) => {
|
||||||
let sysroot = self.sysroot_to_use();
|
let sysroot = self.sysroot_to_use();
|
||||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
// Build the package script if needed
|
||||||
let pkg_script_path_str = package_script_path.as_str().unwrap();
|
let script_build = format!("build_package_script({})",
|
||||||
let (cfgs, hook_result) =
|
package_script_path.display());
|
||||||
do self.workcache_context.with_prep(pkg_script_path_str) |prep| {
|
let pkg_exe = do self.workcache_context.with_prep(script_build) |prep| {
|
||||||
let sub_sysroot = sysroot.clone();
|
let subsysroot = sysroot.clone();
|
||||||
let package_script_path_clone = package_script_path.clone();
|
let psp = package_script_path.clone();
|
||||||
let sub_ws = workspace.clone();
|
let ws = workspace.clone();
|
||||||
let sub_id = pkgid.clone();
|
let pid = pkgid.clone();
|
||||||
declare_package_script_dependency(prep, &*pkg_src);
|
|
||||||
do prep.exec |exec| {
|
do prep.exec |exec| {
|
||||||
let mut pscript = PkgScript::parse(@sub_sysroot.clone(),
|
let mut pscript = PkgScript::parse(subsysroot.clone(),
|
||||||
package_script_path_clone.clone(),
|
psp.clone(),
|
||||||
&sub_ws,
|
&ws,
|
||||||
&sub_id);
|
&pid);
|
||||||
|
pscript.build_custom(exec)
|
||||||
pscript.run_custom(exec, &sub_sysroot)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// We always *run* the package script
|
||||||
|
let (cfgs, hook_result) = PkgScript::run_custom(&Path::new(pkg_exe), &sysroot);
|
||||||
debug!("Command return code = {:?}", hook_result);
|
debug!("Command return code = {:?}", hook_result);
|
||||||
if hook_result != 0 {
|
if hook_result != 0 {
|
||||||
fail!("Error running custom build command")
|
fail!("Error running custom build command")
|
||||||
|
@ -477,7 +488,11 @@ impl CtxMethods for BuildContext {
|
||||||
// otherwise, the package script succeeded
|
// otherwise, the package script succeeded
|
||||||
cfgs
|
cfgs
|
||||||
}
|
}
|
||||||
None => {
|
(Some(_), Inferred) => {
|
||||||
|
debug!("There is a package script, but we're ignoring it");
|
||||||
|
~[]
|
||||||
|
}
|
||||||
|
(None, _) => {
|
||||||
debug!("No package script, continuing");
|
debug!("No package script, continuing");
|
||||||
~[]
|
~[]
|
||||||
}
|
}
|
||||||
|
@ -486,13 +501,13 @@ impl CtxMethods for BuildContext {
|
||||||
// If there was a package script, it should have finished
|
// If there was a package script, it should have finished
|
||||||
// the build already. Otherwise...
|
// the build already. Otherwise...
|
||||||
if !custom {
|
if !custom {
|
||||||
match what_to_build {
|
match what_to_build.sources {
|
||||||
// Find crates inside the workspace
|
// Find crates inside the workspace
|
||||||
&Everything => pkg_src.find_crates(),
|
Everything => pkg_src.find_crates(),
|
||||||
// Find only tests
|
// Find only tests
|
||||||
&Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path::new(s)) }),
|
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
|
// Don't infer any crates -- just build the one that was requested
|
||||||
&JustOne(ref p) => {
|
JustOne(ref p) => {
|
||||||
// We expect that p is relative to the package source's start directory,
|
// We expect that p is relative to the package source's start directory,
|
||||||
// so check that assumption
|
// so check that assumption
|
||||||
debug!("JustOne: p = {}", p.display());
|
debug!("JustOne: p = {}", p.display());
|
||||||
|
@ -512,7 +527,7 @@ impl CtxMethods for BuildContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Build it!
|
// Build it!
|
||||||
pkg_src.build(self, cfgs);
|
pkg_src.build(self, cfgs, []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,6 +566,8 @@ impl CtxMethods for BuildContext {
|
||||||
// just means inferring all the crates in it, then building each one.
|
// just means inferring all the crates in it, then building each one.
|
||||||
self.build(&mut pkg_src, what);
|
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(),
|
let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
|
||||||
pkg_src.tests.clone(), pkg_src.benchs.clone()];
|
pkg_src.tests.clone(), pkg_src.benchs.clone()];
|
||||||
debug!("In declare inputs for {}", id.to_str());
|
debug!("In declare inputs for {}", id.to_str());
|
||||||
|
@ -823,6 +840,7 @@ pub fn main_args(args: &[~str]) -> int {
|
||||||
save_temps: save_temps,
|
save_temps: save_temps,
|
||||||
target: target,
|
target: target,
|
||||||
target_cpu: target_cpu,
|
target_cpu: target_cpu,
|
||||||
|
additional_library_paths: ~[], // No way to set this from the rustpkg command line
|
||||||
experimental_features: experimental_features
|
experimental_features: experimental_features
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -895,7 +913,8 @@ pub fn main_args(args: &[~str]) -> int {
|
||||||
use_rust_path_hack: use_rust_path_hack,
|
use_rust_path_hack: use_rust_path_hack,
|
||||||
sysroot: sroot.clone(), // Currently, only tests override this
|
sysroot: sroot.clone(), // Currently, only tests override this
|
||||||
},
|
},
|
||||||
workcache_context: api::default_context(default_workspace()).workcache_context
|
workcache_context: api::default_context(sroot.clone(),
|
||||||
|
default_workspace()).workcache_context
|
||||||
}.run(sub_cmd, rm_args.clone())
|
}.run(sub_cmd, rm_args.clone())
|
||||||
};
|
};
|
||||||
// FIXME #9262: This is using the same error code for all errors,
|
// FIXME #9262: This is using the same error code for all errors,
|
||||||
|
|
|
@ -23,7 +23,31 @@ pub enum Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Eq, Clone)]
|
#[deriving(Eq, Clone)]
|
||||||
pub enum WhatToBuild {
|
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
|
/// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
|
||||||
JustOne(Path),
|
JustOne(Path),
|
||||||
/// Build any test.rs files that can be recursively found in the active workspace
|
/// Build any test.rs files that can be recursively found in the active workspace
|
||||||
|
|
|
@ -28,7 +28,7 @@ use path_util::{target_executable_in_workspace, target_test_in_workspace,
|
||||||
library_in_workspace, installed_library_in_workspace,
|
library_in_workspace, installed_library_in_workspace,
|
||||||
built_bench_in_workspace, built_test_in_workspace,
|
built_bench_in_workspace, built_test_in_workspace,
|
||||||
built_library_in_workspace, built_executable_in_workspace, target_build_dir,
|
built_library_in_workspace, built_executable_in_workspace, target_build_dir,
|
||||||
chmod_read_only};
|
chmod_read_only, platform_library_name};
|
||||||
use rustc::back::link::get_cc_prog;
|
use rustc::back::link::get_cc_prog;
|
||||||
use rustc::metadata::filesearch::rust_path;
|
use rustc::metadata::filesearch::rust_path;
|
||||||
use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
|
use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
|
||||||
|
@ -299,12 +299,6 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
|
||||||
cmd, args, str::from_utf8(output.output),
|
cmd, args, str::from_utf8(output.output),
|
||||||
str::from_utf8(output.error),
|
str::from_utf8(output.error),
|
||||||
output.status);
|
output.status);
|
||||||
/*
|
|
||||||
By the way, rustpkg *won't* return a nonzero exit code if it fails --
|
|
||||||
see #4547
|
|
||||||
So tests that use this need to check the existence of a file
|
|
||||||
to make sure the command succeeded
|
|
||||||
*/
|
|
||||||
if output.status != 0 {
|
if output.status != 0 {
|
||||||
debug!("Command {} {:?} failed with exit code {:?}; its output was --- {} ---",
|
debug!("Command {} {:?} failed with exit code {:?}; its output was --- {} ---",
|
||||||
cmd, args, output.status,
|
cmd, args, output.status,
|
||||||
|
@ -600,7 +594,7 @@ fn test_install_valid() {
|
||||||
temp_workspace.clone(),
|
temp_workspace.clone(),
|
||||||
false,
|
false,
|
||||||
temp_pkg_id.clone());
|
temp_pkg_id.clone());
|
||||||
ctxt.install(src, &Everything);
|
ctxt.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||||
// Check that all files exist
|
// Check that all files exist
|
||||||
let exec = target_executable_in_workspace(&temp_pkg_id, temp_workspace);
|
let exec = target_executable_in_workspace(&temp_pkg_id, temp_workspace);
|
||||||
debug!("exec = {}", exec.display());
|
debug!("exec = {}", exec.display());
|
||||||
|
@ -639,7 +633,7 @@ fn test_install_invalid() {
|
||||||
temp_workspace.clone(),
|
temp_workspace.clone(),
|
||||||
false,
|
false,
|
||||||
pkgid.clone());
|
pkgid.clone());
|
||||||
ctxt.install(pkg_src, &Everything);
|
ctxt.install(pkg_src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||||
};
|
};
|
||||||
// Not the best test -- doesn't test that we failed in the right way.
|
// Not the best test -- doesn't test that we failed in the right way.
|
||||||
// Best we can do for now.
|
// Best we can do for now.
|
||||||
|
@ -897,14 +891,14 @@ fn rustpkg_local_pkg() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore (reason = "test makes bogus assumptions about build directory layout: issue #8690")]
|
|
||||||
fn package_script_with_default_build() {
|
fn package_script_with_default_build() {
|
||||||
let dir = create_local_package(&PkgId::new("fancy-lib"));
|
let dir = create_local_package(&PkgId::new("fancy-lib"));
|
||||||
let dir = dir.path();
|
let dir = dir.path();
|
||||||
debug!("dir = {}", dir.display());
|
debug!("dir = {}", dir.display());
|
||||||
let mut source = test_sysroot().dir_path();
|
let mut source = test_sysroot().dir_path();
|
||||||
source.pop(); source.pop();
|
source.pop(); source.pop();
|
||||||
source.push_many(["src", "librustpkg", "testsuite", "pass", "src", "fancy-lib", "pkg.rs"]);
|
let source = Path::new(file!()).dir_path().join_many(
|
||||||
|
[~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"pkg.rs"]);
|
||||||
debug!("package_script_with_default_build: {}", source.display());
|
debug!("package_script_with_default_build: {}", source.display());
|
||||||
if !os::copy_file(&source,
|
if !os::copy_file(&source,
|
||||||
&dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])) {
|
&dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])) {
|
||||||
|
@ -912,7 +906,10 @@ fn package_script_with_default_build() {
|
||||||
}
|
}
|
||||||
command_line_test([~"install", ~"fancy-lib"], dir);
|
command_line_test([~"install", ~"fancy-lib"], dir);
|
||||||
assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion);
|
assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion);
|
||||||
assert!(os::path_exists(&target_build_dir(dir).join_many(["fancy-lib", "generated.rs"])));
|
assert!(os::path_exists(&target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"])));
|
||||||
|
let generated_path = target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]);
|
||||||
|
debug!("generated path = {}", generated_path.display());
|
||||||
|
assert!(os::path_exists(&generated_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -2251,6 +2248,106 @@ fn find_sources_in_cwd() {
|
||||||
assert_executable_exists(&source_dir.join(".rust"), "foo");
|
assert_executable_exists(&source_dir.join(".rust"), "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_c_dependency_ok() {
|
||||||
|
// Pkg has a custom build script that adds a single C file as a dependency, and
|
||||||
|
// registers a hook to build it if it's not fresh
|
||||||
|
// After running `build`, test that the C library built
|
||||||
|
|
||||||
|
let dir = create_local_package(&PkgId::new("cdep"));
|
||||||
|
let dir = dir.path();
|
||||||
|
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
|
||||||
|
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
|
||||||
|
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
|
||||||
|
writeFile(&dir.join_many(["src", "cdep-0.1", "foo.c"]), "void f() {}");
|
||||||
|
|
||||||
|
debug!("dir = {}", dir.display());
|
||||||
|
let source = Path::new(file!()).dir_path().join_many(
|
||||||
|
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
|
||||||
|
if !os::copy_file(&source,
|
||||||
|
&dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) {
|
||||||
|
fail!("Couldn't copy file");
|
||||||
|
}
|
||||||
|
command_line_test([~"build", ~"cdep"], dir);
|
||||||
|
assert_executable_exists(dir, "cdep");
|
||||||
|
let out_dir = target_build_dir(dir).join("cdep");
|
||||||
|
let c_library_path = out_dir.join(platform_library_name("foo"));
|
||||||
|
debug!("c library path: {}", c_library_path.display());
|
||||||
|
assert!(os::path_exists(&c_library_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_c_dependency_no_rebuilding() {
|
||||||
|
let dir = create_local_package(&PkgId::new("cdep"));
|
||||||
|
let dir = dir.path();
|
||||||
|
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
|
||||||
|
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
|
||||||
|
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
|
||||||
|
writeFile(&dir.join_many(["src", "cdep-0.1", "foo.c"]), "void f() {}");
|
||||||
|
|
||||||
|
debug!("dir = {}", dir.display());
|
||||||
|
let source = Path::new(file!()).dir_path().join_many(
|
||||||
|
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
|
||||||
|
if !os::copy_file(&source,
|
||||||
|
&dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) {
|
||||||
|
fail!("Couldn't copy file");
|
||||||
|
}
|
||||||
|
command_line_test([~"build", ~"cdep"], dir);
|
||||||
|
assert_executable_exists(dir, "cdep");
|
||||||
|
let out_dir = target_build_dir(dir).join("cdep");
|
||||||
|
let c_library_path = out_dir.join(platform_library_name("foo"));
|
||||||
|
debug!("c library path: {}", c_library_path.display());
|
||||||
|
assert!(os::path_exists(&c_library_path));
|
||||||
|
|
||||||
|
// Now, make it read-only so rebuilding will fail
|
||||||
|
assert!(chmod_read_only(&c_library_path));
|
||||||
|
|
||||||
|
match command_line_test_partial([~"build", ~"cdep"], dir) {
|
||||||
|
Success(*) => (), // ok
|
||||||
|
Fail(status) if status == 65 => fail!("test_c_dependency_no_rebuilding failed: \
|
||||||
|
it tried to rebuild foo.c"),
|
||||||
|
Fail(_) => fail!("test_c_dependency_no_rebuilding failed for some other reason")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_c_dependency_yes_rebuilding() {
|
||||||
|
let dir = create_local_package(&PkgId::new("cdep"));
|
||||||
|
let dir = dir.path();
|
||||||
|
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
|
||||||
|
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
|
||||||
|
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
|
||||||
|
let c_file_name = dir.join_many(["src", "cdep-0.1", "foo.c"]);
|
||||||
|
writeFile(&c_file_name, "void f() {}");
|
||||||
|
|
||||||
|
let source = Path::new(file!()).dir_path().join_many(
|
||||||
|
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
|
||||||
|
let target = dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"]);
|
||||||
|
debug!("Copying {} -> {}", source.display(), target.display());
|
||||||
|
if !os::copy_file(&source, &target) {
|
||||||
|
fail!("Couldn't copy file");
|
||||||
|
}
|
||||||
|
command_line_test([~"build", ~"cdep"], dir);
|
||||||
|
assert_executable_exists(dir, "cdep");
|
||||||
|
let out_dir = target_build_dir(dir).join("cdep");
|
||||||
|
let c_library_path = out_dir.join(platform_library_name("foo"));
|
||||||
|
debug!("c library path: {}", c_library_path.display());
|
||||||
|
assert!(os::path_exists(&c_library_path));
|
||||||
|
|
||||||
|
// Now, make the Rust library read-only so rebuilding will fail
|
||||||
|
match built_library_in_workspace(&PkgId::new("cdep"), dir) {
|
||||||
|
Some(ref pth) => assert!(chmod_read_only(pth)),
|
||||||
|
None => assert_built_library_exists(dir, "cdep")
|
||||||
|
}
|
||||||
|
|
||||||
|
match command_line_test_partial([~"build", ~"cdep"], dir) {
|
||||||
|
Success(*) => fail!("test_c_dependency_yes_rebuilding failed: \
|
||||||
|
it didn't rebuild and should have"),
|
||||||
|
Fail(status) if status == 65 => (),
|
||||||
|
Fail(_) => fail!("test_c_dependency_yes_rebuilding failed for some other reason")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if p exists and is executable
|
/// Returns true if p exists and is executable
|
||||||
fn is_executable(p: &Path) -> bool {
|
fn is_executable(p: &Path) -> bool {
|
||||||
use std::libc::consts::os::posix88::{S_IXUSR};
|
use std::libc::consts::os::posix88::{S_IXUSR};
|
||||||
|
|
|
@ -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,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.
|
||||||
|
|
||||||
|
extern mod std;
|
||||||
|
|
||||||
|
pub mod foo;
|
||||||
|
pub mod bar;
|
|
@ -0,0 +1,83 @@
|
||||||
|
// 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::{io, os, task};
|
||||||
|
use rustpkg::api;
|
||||||
|
use rustpkg::version::NoVersion;
|
||||||
|
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 !os::path_exists(&sysroot) {
|
||||||
|
fail!("Package script requires a sysroot that exists; {} doesn't", sysroot.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
if args[2] != ~"install" {
|
||||||
|
io::println(format!("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.1", "foo.c"]);
|
||||||
|
|
||||||
|
let out_lib_path = do 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 = do 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);
|
||||||
|
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 = do task::try {
|
||||||
|
let mut cc = context_clone.clone();
|
||||||
|
api::install_pkg(&mut cc,
|
||||||
|
os::getcwd(),
|
||||||
|
~"cdep",
|
||||||
|
NoVersion,
|
||||||
|
~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]);
|
||||||
|
};
|
||||||
|
|
||||||
|
if task_res.is_err() {
|
||||||
|
os::set_exit_status(COPY_FAILED_CODE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,4 +21,4 @@ extern mod std;
|
||||||
|
|
||||||
pub mod foo;
|
pub mod foo;
|
||||||
pub mod bar;
|
pub mod bar;
|
||||||
#[path = "../../build/fancy_lib/generated.rs"] pub mod generated;
|
#[path = "../../build/fancy-lib/generated.rs"] pub mod generated;
|
||||||
|
|
|
@ -15,42 +15,37 @@ use std::{io, os};
|
||||||
use rustpkg::api;
|
use rustpkg::api;
|
||||||
use rustpkg::version::NoVersion;
|
use rustpkg::version::NoVersion;
|
||||||
|
|
||||||
use rustc::metadata::filesearch;
|
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
|
||||||
let args = os::args();
|
let args = os::args();
|
||||||
|
|
||||||
// by convention, first arg is sysroot
|
// by convention, first arg is sysroot
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
|
debug!("Failing, arg len");
|
||||||
fail!("Package script requires a directory where rustc libraries live as the first \
|
fail!("Package script requires a directory where rustc libraries live as the first \
|
||||||
argument");
|
argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
let sysroot_arg = args[1].clone();
|
let sysroot_arg = args[1].clone();
|
||||||
let sysroot = Path(sysroot_arg);
|
let sysroot = Path::new(sysroot_arg);
|
||||||
if !os::path_exists(&sysroot) {
|
if !os::path_exists(&sysroot) {
|
||||||
fail!("Package script requires a sysroot that exists; %s doesn't", sysroot.to_str());
|
debug!("Failing, sysroot");
|
||||||
|
fail!("Package script requires a sysroot that exists;{} doesn't", sysroot.display());
|
||||||
}
|
}
|
||||||
|
|
||||||
if args[2] != ~"install" {
|
if args[2] != ~"install" {
|
||||||
|
debug!("Failing, weird command");
|
||||||
println!("Warning: I don't know how to {}", args[2]);
|
println!("Warning: I don't know how to {}", args[2]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let out_path = Path("build/fancy-lib");
|
debug!("Checking self_exe_path");
|
||||||
if !os::path_exists(&out_path) {
|
let out_path = os::self_exe_path().expect("Couldn't get self_exe path");
|
||||||
assert!(os::make_dir(&out_path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
|
|
||||||
}
|
|
||||||
|
|
||||||
let file = io::file_writer(&out_path.push("generated.rs"),
|
debug!("Writing file");
|
||||||
[io::Create]).unwrap();
|
let file = io::file_writer(&out_path.join("generated.rs"), [io::Create]).unwrap();
|
||||||
file.write_str("pub fn wheeeee() { for [1, 2, 3].each() |_| { assert!(true); } }");
|
file.write_str("pub fn wheeeee() { let xs = [1, 2, 3]; \
|
||||||
|
for _ in xs.iter() { assert!(true); } }");
|
||||||
|
|
||||||
|
let context = api::default_context(sysroot, api::default_workspace());
|
||||||
debug!("api_____install_____lib, my sysroot:");
|
api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]);
|
||||||
debug!(sysroot.to_str());
|
|
||||||
|
|
||||||
api::install_lib(@sysroot, os::getcwd(), ~"fancy-lib", Path("lib.rs"),
|
|
||||||
NoVersion);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,13 @@ use context::{in_target, StopBefore, Link, Assemble, BuildContext};
|
||||||
use package_id::PkgId;
|
use package_id::PkgId;
|
||||||
use package_source::PkgSrc;
|
use package_source::PkgSrc;
|
||||||
use workspace::pkg_parent_workspaces;
|
use workspace::pkg_parent_workspaces;
|
||||||
use path_util::{U_RWX, system_library, target_build_dir};
|
use path_util::{system_library, target_build_dir};
|
||||||
use path_util::{default_workspace, built_library_in_workspace};
|
use path_util::{default_workspace, built_library_in_workspace};
|
||||||
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
|
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
|
||||||
pub use target::{Target, Build, Install};
|
pub use target::{Target, Build, Install};
|
||||||
use extra::treemap::TreeMap;
|
use extra::treemap::TreeMap;
|
||||||
|
use path_util::U_RWX;
|
||||||
|
pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
|
||||||
use workcache_support::{digest_file_with_date, digest_only_date};
|
use workcache_support::{digest_file_with_date, digest_only_date};
|
||||||
|
|
||||||
// It would be nice to have the list of commands in just one place -- for example,
|
// It would be nice to have the list of commands in just one place -- for example,
|
||||||
|
@ -233,12 +235,14 @@ pub fn compile_input(context: &BuildContext,
|
||||||
Nothing => link::output_type_exe
|
Nothing => link::output_type_exe
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Output type = {:?}", output_type);
|
||||||
|
|
||||||
let options = @session::options {
|
let options = @session::options {
|
||||||
crate_type: crate_type,
|
crate_type: crate_type,
|
||||||
optimize: if opt { session::Aggressive } else { session::No },
|
optimize: if opt { session::Aggressive } else { session::No },
|
||||||
test: what == Test || what == Bench,
|
test: what == Test || what == Bench,
|
||||||
maybe_sysroot: Some(sysroot_to_use),
|
maybe_sysroot: Some(sysroot_to_use),
|
||||||
addl_lib_search_paths: @mut (~[]),
|
addl_lib_search_paths: @mut context.additional_library_paths(),
|
||||||
output_type: output_type,
|
output_type: output_type,
|
||||||
.. (*driver::build_session_options(binary,
|
.. (*driver::build_session_options(binary,
|
||||||
&matches,
|
&matches,
|
||||||
|
@ -246,6 +250,8 @@ pub fn compile_input(context: &BuildContext,
|
||||||
@diagnostic::Emitter)).clone()
|
@diagnostic::Emitter)).clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Created options...");
|
||||||
|
|
||||||
let addl_lib_search_paths = @mut options.addl_lib_search_paths;
|
let addl_lib_search_paths = @mut options.addl_lib_search_paths;
|
||||||
// Make sure all the library directories actually exist, since the linker will complain
|
// Make sure all the library directories actually exist, since the linker will complain
|
||||||
// otherwise
|
// otherwise
|
||||||
|
@ -258,16 +264,22 @@ pub fn compile_input(context: &BuildContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("About to build session...");
|
||||||
|
|
||||||
let sess = driver::build_session(options,
|
let sess = driver::build_session(options,
|
||||||
@diagnostic::DefaultEmitter as
|
@diagnostic::DefaultEmitter as
|
||||||
@diagnostic::Emitter);
|
@diagnostic::Emitter);
|
||||||
|
|
||||||
|
debug!("About to build config...");
|
||||||
|
|
||||||
// Infer dependencies that rustpkg needs to build, by scanning for
|
// Infer dependencies that rustpkg needs to build, by scanning for
|
||||||
// `extern mod` directives.
|
// `extern mod` directives.
|
||||||
let cfg = driver::build_configuration(sess);
|
let cfg = driver::build_configuration(sess);
|
||||||
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||||
crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
|
crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
|
||||||
|
|
||||||
|
debug!("About to call find_and_install_dependencies...");
|
||||||
|
|
||||||
find_and_install_dependencies(context, pkg_id, in_file, sess, exec, &crate, deps,
|
find_and_install_dependencies(context, pkg_id, in_file, sess, exec, &crate, deps,
|
||||||
|p| {
|
|p| {
|
||||||
debug!("a dependency: {}", p.display());
|
debug!("a dependency: {}", p.display());
|
||||||
|
@ -377,7 +389,6 @@ pub fn compile_crate_from_input(input: &Path,
|
||||||
|
|
||||||
debug!("Built {}, date = {:?}", outputs.out_filename.display(),
|
debug!("Built {}, date = {:?}", outputs.out_filename.display(),
|
||||||
datestamp(&outputs.out_filename));
|
datestamp(&outputs.out_filename));
|
||||||
|
|
||||||
Some(outputs.out_filename)
|
Some(outputs.out_filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +442,9 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
|
||||||
};
|
};
|
||||||
debug!("Finding and installing... {}", lib_name);
|
debug!("Finding and installing... {}", lib_name);
|
||||||
// Check standard Rust library path first
|
// Check standard Rust library path first
|
||||||
match system_library(&self.context.sysroot(), lib_name) {
|
let whatever = system_library(&self.context.sysroot(), lib_name);
|
||||||
|
debug!("system library returned {:?}", whatever);
|
||||||
|
match whatever {
|
||||||
Some(ref installed_path) => {
|
Some(ref installed_path) => {
|
||||||
debug!("It exists: {}", installed_path.display());
|
debug!("It exists: {}", installed_path.display());
|
||||||
// Say that [path for c] has a discovered dependency on
|
// Say that [path for c] has a discovered dependency on
|
||||||
|
@ -478,7 +491,10 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
|
||||||
self.context.context.use_rust_path_hack,
|
self.context.context.use_rust_path_hack,
|
||||||
pkg_id.clone());
|
pkg_id.clone());
|
||||||
let (outputs_disc, inputs_disc) =
|
let (outputs_disc, inputs_disc) =
|
||||||
self.context.install(pkg_src, &JustOne(Path::new(lib_crate_filename)));
|
self.context.install(
|
||||||
|
pkg_src,
|
||||||
|
&WhatToBuild::new(Inferred,
|
||||||
|
JustOne(Path::new(lib_crate_filename))));
|
||||||
debug!("Installed {}, returned {:?} dependencies and \
|
debug!("Installed {}, returned {:?} dependencies and \
|
||||||
{:?} transitive dependencies",
|
{:?} transitive dependencies",
|
||||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
lib_name, outputs_disc.len(), inputs_disc.len());
|
||||||
|
|
Loading…
Reference in New Issue