From 57e9a2fd0adf437c4b357da8b524dc1001501c4e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Nov 2013 01:29:09 -0800 Subject: [PATCH] Make -Z gen-crate-map usable for I/O In #10422, I didn't actually test to make sure that the '-Z gen-crate-map' option was usable before I implemented it. The crate map was indeed generated when '-Z gen-crate-map' was specified, but the I/O factory slot was empty because of an extra check in trans about filling in that location. This commit both fixes that location, and checks in a "fancy test" which does lots of fun stuff. The test will use the rustc library to compile a rust crate, and then compile a C program to link against that crate and run the C program. To my knowledge this is the first test of its kind, so it's a little ad-hoc, but it seems to get the job done. We could perhaps generalize running tests like this, but for now I think it's fine to have this sort of functionality tucked away in a test. --- src/librustc/middle/trans/base.rs | 21 ++--- .../run-pass-fulldeps/bootstrap-from-c.rs | 88 +++++++++++++++++++ .../run-pass-fulldeps/bootstrap-from-c/lib.rs | 25 ++++++ .../run-pass-fulldeps/bootstrap-from-c/main.c | 16 ++++ 4 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 src/test/run-pass-fulldeps/bootstrap-from-c.rs create mode 100644 src/test/run-pass-fulldeps/bootstrap-from-c/lib.rs create mode 100644 src/test/run-pass-fulldeps/bootstrap-from-c/main.c diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index a6e71b22bf582..caca1e0ce3230 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -77,7 +77,7 @@ use extra::time; use extra::sort; use syntax::ast::Name; use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_name}; -use syntax::ast_util::{local_def}; +use syntax::ast_util::{local_def, is_local}; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; @@ -2979,7 +2979,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, return map; } -pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) { +pub fn fill_crate_map(ccx: @mut CrateContext, map: ValueRef) { let mut subcrates: ~[ValueRef] = ~[]; let mut i = 1; let cstore = ccx.sess.cstore; @@ -2997,19 +2997,20 @@ pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) { subcrates.push(p2i(ccx, cr)); i += 1; } - let event_loop_factory = if !*ccx.sess.building_library { - match ccx.tcx.lang_items.event_loop_factory() { - Some(did) => unsafe { + let event_loop_factory = match ccx.tcx.lang_items.event_loop_factory() { + Some(did) => unsafe { + if is_local(did) { + llvm::LLVMConstPointerCast(get_item_val(ccx, did.node), + ccx.int_type.ptr_to().to_ref()) + } else { let name = csearch::get_symbol(ccx.sess.cstore, did); let global = do name.with_c_str |buf| { llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) }; global - }, - None => C_null(ccx.int_type.ptr_to()) - } - } else { - C_null(ccx.int_type.ptr_to()) + } + }, + None => C_null(ccx.int_type.ptr_to()) }; unsafe { let maptype = Type::array(&ccx.int_type, subcrates.len() as u64); diff --git a/src/test/run-pass-fulldeps/bootstrap-from-c.rs b/src/test/run-pass-fulldeps/bootstrap-from-c.rs new file mode 100644 index 0000000000000..88f9e9dadec18 --- /dev/null +++ b/src/test/run-pass-fulldeps/bootstrap-from-c.rs @@ -0,0 +1,88 @@ +// 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. + +// This test exercises bootstrapping the runtime from C to make sure that this +// continues to work. The runtime is expected to have all local I/O services +// that one would normally expect. + +#[feature(managed_boxes)]; + +extern mod extra; +extern mod rustc; +extern mod syntax; + +use extra::glob; +use extra::tempfile::TempDir; +use rustc::back::link; +use rustc::driver::driver; +use rustc::driver::session; +use std::os; +use std::rt::io::fs; +use std::run; +use std::str; +use syntax::diagnostic; + +fn main() { + // Sketchily figure out where our sysroot is + let mut sysroot = Path::new(os::self_exe_path().unwrap()); + sysroot.pop(); + sysroot.pop(); + sysroot.push("stage2"); + + // Give ourselves a little workspace + let d = TempDir::new("mytest").unwrap(); + let d = d.path(); + + // Figure out where we are + let mut me = Path::new(file!()); + me.pop(); + let srcfile = me.join("bootstrap-from-c/lib.rs"); + let cfile = me.join("bootstrap-from-c/main.c"); + + // Compile the rust crate + let options = @session::options { + maybe_sysroot: Some(@sysroot), + debugging_opts: session::gen_crate_map, + ..(*session::basic_options()).clone() + }; + let diagnostic = @diagnostic::DefaultEmitter as @diagnostic::Emitter; + let session = driver::build_session(options, diagnostic); + driver::compile_input(session, ~[], &driver::file_input(srcfile), + &Some(d.clone()), &None); + + // Copy the C source into place + let cdst = d.join("main.c"); + let exe = d.join("out" + os::consts::EXE_SUFFIX); + fs::copy(&cfile, &cdst); + + // Figure out where we put the dynamic library + let dll = os::dll_filename("boot-*"); + let dll = glob::glob(d.as_str().unwrap() + "/" + dll).next().unwrap(); + + // Compile the c program with all the appropriate arguments. We're compiling + // the cfile and the library together, and may have to do some linker rpath + // magic to make sure that the dll can get found when the executable is + // running. + let cc = link::get_cc_prog(session); + let mut cc_args = session.targ_cfg.target_strs.cc_args.clone(); + cc_args.push_all([~"-o", exe.as_str().unwrap().to_owned()]); + cc_args.push(cdst.as_str().unwrap().to_owned()); + cc_args.push(dll.as_str().unwrap().to_owned()); + if cfg!(target_os = "macos") { + cc_args.push("-Wl,-rpath," + d.as_str().unwrap().to_owned()); + } + let status = run::process_status(cc, cc_args); + assert!(status.success()); + + // Finally, run the program and make sure that it tells us hello. + let res = run::process_output(exe.as_str().unwrap().to_owned(), []); + assert!(res.status.success()); + assert_eq!(str::from_utf8(res.output), ~"hello\n"); +} diff --git a/src/test/run-pass-fulldeps/bootstrap-from-c/lib.rs b/src/test/run-pass-fulldeps/bootstrap-from-c/lib.rs new file mode 100644 index 0000000000000..e35f88009668f --- /dev/null +++ b/src/test/run-pass-fulldeps/bootstrap-from-c/lib.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. + +#[link(package_id = "boot", name = "boot", vers = "0.1")]; + +extern mod rustuv; // pull in uvio + +use std::rt; +use std::ptr; + +#[no_mangle] // this needs to get called from C +pub extern "C" fn foo(argc: int, argv: **u8) -> int { + do rt::start(argc, argv) { + do spawn { + println!("hello"); + } + } +} diff --git a/src/test/run-pass-fulldeps/bootstrap-from-c/main.c b/src/test/run-pass-fulldeps/bootstrap-from-c/main.c new file mode 100644 index 0000000000000..1872c1ea43b11 --- /dev/null +++ b/src/test/run-pass-fulldeps/bootstrap-from-c/main.c @@ -0,0 +1,16 @@ +// 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. + +// this is the rust entry point that we're going to call. +int foo(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + return foo(argc, argv); +}