diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index fe22cfdb43f73..0b398fd0d47c5 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -115,9 +115,10 @@ fn calculate_type(sess: &session::Session, // got long ago), so don't bother with anything. config::CrateTypeRlib => return Vec::new(), - // Staticlibs must have all static dependencies. If any fail to be - // found, we generate some nice pretty errors. - config::CrateTypeStaticlib => { + // Staticlibs and cdylibs must have all static dependencies. If any fail + // to be found, we generate some nice pretty errors. + config::CrateTypeStaticlib | + config::CrateTypeCdylib => { match attempt_static(sess) { Some(v) => return v, None => {} diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index bca5af69edfd0..55d75ace08151 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Creates a new reachability computation context. fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> { let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { - *ty != config::CrateTypeExecutable + *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib }); ReachableContext { tcx: tcx, diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index b7dfc86720458..325887684914b 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { let needs_check = sess.crate_types.borrow().iter().any(|kind| { match *kind { config::CrateTypeDylib | + config::CrateTypeCdylib | config::CrateTypeExecutable | config::CrateTypeStaticlib => true, config::CrateTypeRlib => false, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7bb96c5ab2b44..da5555dbd6453 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -300,6 +300,7 @@ pub enum CrateType { CrateTypeDylib, CrateTypeRlib, CrateTypeStaticlib, + CrateTypeCdylib, } #[derive(Clone)] @@ -1326,6 +1327,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateTypeRlib, "staticlib" => CrateTypeStaticlib, "dylib" => CrateTypeDylib, + "cdylib" => CrateTypeCdylib, "bin" => CrateTypeExecutable, _ => { return Err(format!("unknown crate type: `{}`", @@ -1413,7 +1415,8 @@ impl fmt::Display for CrateType { CrateTypeExecutable => "bin".fmt(f), CrateTypeDylib => "dylib".fmt(f), CrateTypeRlib => "rlib".fmt(f), - CrateTypeStaticlib => "staticlib".fmt(f) + CrateTypeStaticlib => "staticlib".fmt(f), + CrateTypeCdylib => "cdylib".fmt(f), } } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1d60c2eb43788..1f3df1ff6f2d8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1174,6 +1174,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { Some(config::CrateTypeDylib) } + Some(ref n) if *n == "cdylib" => { + Some(config::CrateTypeCdylib) + } Some(ref n) if *n == "lib" => { Some(config::default_lib_output()) } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 0eacc0907bc25..aac68cc09bcab 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -744,6 +744,7 @@ impl<'a> CrateReader<'a> { match *ct { config::CrateTypeExecutable => need_exe_alloc = true, config::CrateTypeDylib | + config::CrateTypeCdylib | config::CrateTypeStaticlib => need_lib_alloc = true, config::CrateTypeRlib => {} } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b5248c209a30a..53cc03198292e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -231,6 +231,7 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: config::CrateType) -> bool { match (sess.target.target.options.dynamic_linking, sess.target.target.options.executables, crate_type) { + (false, _, config::CrateTypeCdylib) | (false, _, config::CrateTypeDylib) => true, (_, false, config::CrateTypeExecutable) => true, _ => false @@ -253,6 +254,7 @@ pub fn filename_for_input(sess: &Session, config::CrateTypeRlib => { outputs.out_directory.join(&format!("lib{}.rlib", libname)) } + config::CrateTypeCdylib | config::CrateTypeDylib => { let (prefix, suffix) = (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); @@ -281,9 +283,10 @@ pub fn each_linked_rlib(sess: &Session, f: &mut FnMut(ast::CrateNum, &Path)) { let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter(); let fmts = sess.dependency_formats.borrow(); - let fmts = fmts.get(&config::CrateTypeExecutable).or_else(|| { - fmts.get(&config::CrateTypeStaticlib) - }).unwrap_or_else(|| { + let fmts = fmts.get(&config::CrateTypeExecutable) + .or_else(|| fmts.get(&config::CrateTypeStaticlib)) + .or_else(|| fmts.get(&config::CrateTypeCdylib)); + let fmts = fmts.unwrap_or_else(|| { bug!("could not find formats for rlibs") }); for (cnum, path) in crates { @@ -338,13 +341,9 @@ fn link_binary_output(sess: &Session, config::CrateTypeStaticlib => { link_staticlib(sess, &objects, &out_filename, tmpdir.path()); } - config::CrateTypeExecutable => { - link_natively(sess, false, &objects, &out_filename, trans, outputs, - tmpdir.path()); - } - config::CrateTypeDylib => { - link_natively(sess, true, &objects, &out_filename, trans, outputs, - tmpdir.path()); + _ => { + link_natively(sess, crate_type, &objects, &out_filename, trans, + outputs, tmpdir.path()); } } @@ -612,13 +611,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, // // This will invoke the system linker/cc to create the resulting file. This // links to all upstream files as well. -fn link_natively(sess: &Session, dylib: bool, - objects: &[PathBuf], out_filename: &Path, +fn link_natively(sess: &Session, + crate_type: config::CrateType, + objects: &[PathBuf], + out_filename: &Path, trans: &CrateTranslation, outputs: &OutputFilenames, tmpdir: &Path) { - info!("preparing dylib? ({}) from {:?} to {:?}", dylib, objects, - out_filename); + info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename); // The invocations of cc share some flags across platforms let (pname, mut cmd) = get_linker(sess); @@ -627,10 +627,10 @@ fn link_natively(sess: &Session, dylib: bool, let root = sess.target_filesearch(PathKind::Native).get_lib_path(); cmd.args(&sess.target.target.options.pre_link_args); - let pre_link_objects = if dylib { - &sess.target.target.options.pre_link_objects_dll - } else { + let pre_link_objects = if crate_type == config::CrateTypeExecutable { &sess.target.target.options.pre_link_objects_exe + } else { + &sess.target.target.options.pre_link_objects_dll }; for obj in pre_link_objects { cmd.arg(root.join(obj)); @@ -642,7 +642,7 @@ fn link_natively(sess: &Session, dylib: bool, } else { Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box }; - link_args(&mut *linker, sess, dylib, tmpdir, + link_args(&mut *linker, sess, crate_type, tmpdir, objects, out_filename, trans, outputs); if !sess.target.target.options.no_compiler_rt { linker.link_staticlib("compiler-rt"); @@ -708,7 +708,7 @@ fn link_natively(sess: &Session, dylib: bool, fn link_args(cmd: &mut Linker, sess: &Session, - dylib: bool, + crate_type: config::CrateType, tmpdir: &Path, objects: &[PathBuf], out_filename: &Path, @@ -730,26 +730,28 @@ fn link_args(cmd: &mut Linker, // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. - if dylib { - cmd.export_symbols(sess, trans, tmpdir); + if crate_type != config::CrateTypeExecutable { + cmd.export_symbols(sess, trans, tmpdir, crate_type); } // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main // object file, so we link that in here. - if dylib { + if crate_type == config::CrateTypeDylib { cmd.add_object(&outputs.with_extension("metadata.o")); } // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs if !sess.opts.cg.link_dead_code { - cmd.gc_sections(dylib); + let keep_metadata = crate_type == config::CrateTypeDylib; + cmd.gc_sections(keep_metadata); } let used_link_args = sess.cstore.used_link_args(); - if !dylib && t.options.position_independent_executables { + if crate_type == config::CrateTypeExecutable && + t.options.position_independent_executables { let empty_vec = Vec::new(); let empty_str = String::new(); let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); @@ -804,12 +806,12 @@ fn link_args(cmd: &mut Linker, // in this DAG so far because they're only dylibs and dylibs can only depend // on other dylibs (e.g. other native deps). add_local_native_libraries(cmd, sess); - add_upstream_rust_crates(cmd, sess, dylib, tmpdir); + add_upstream_rust_crates(cmd, sess, crate_type, tmpdir); add_upstream_native_libraries(cmd, sess); // # Telling the linker what we're doing - if dylib { + if crate_type != config::CrateTypeExecutable { cmd.build_dylib(out_filename); } @@ -907,8 +909,10 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { // Rust crates are not considered at all when creating an rlib output. All // dependencies will be linked when producing the final output (instead of // the intermediate rlib version) -fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, - dylib: bool, tmpdir: &Path) { +fn add_upstream_rust_crates(cmd: &mut Linker, + sess: &Session, + crate_type: config::CrateType, + tmpdir: &Path) { // All of the heavy lifting has previously been accomplished by the // dependency_format module of the compiler. This is just crawling the // output of that module, adding crates as necessary. @@ -918,11 +922,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, // involves just passing the right -l flag. let formats = sess.dependency_formats.borrow(); - let data = if dylib { - formats.get(&config::CrateTypeDylib).unwrap() - } else { - formats.get(&config::CrateTypeExecutable).unwrap() - }; + let data = formats.get(&crate_type).unwrap(); // Invoke get_used_crates to ensure that we get a topological sorting of // crates. @@ -937,7 +937,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - add_static_crate(cmd, sess, tmpdir, dylib, &src.rlib.unwrap().0) + add_static_crate(cmd, sess, tmpdir, crate_type, + &src.rlib.unwrap().0) } Linkage::Dynamic => { add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0) @@ -982,9 +983,12 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, // (aka we're making an executable), we can just pass the rlib blindly to // the linker (fast) because it's fine if it's not actually included as // we're at the end of the dependency chain. - fn add_static_crate(cmd: &mut Linker, sess: &Session, tmpdir: &Path, - dylib: bool, cratepath: &Path) { - if !sess.lto() && !dylib { + fn add_static_crate(cmd: &mut Linker, + sess: &Session, + tmpdir: &Path, + crate_type: config::CrateType, + cratepath: &Path) { + if !sess.lto() && crate_type != config::CrateTypeDylib { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return } @@ -1020,7 +1024,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, if any_objects { archive.build(); - if dylib { + if crate_type == config::CrateTypeDylib { cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); } else { cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 8055e97034e3f..50f6366e85c86 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -18,7 +18,7 @@ use std::process::Command; use back::archive; use middle::dependency_format::Linkage; use session::Session; -use session::config::CrateTypeDylib; +use session::config::CrateType; use session::config; use syntax::ast; use CrateTranslation; @@ -42,7 +42,7 @@ pub trait Linker { fn framework_path(&mut self, path: &Path); fn output_filename(&mut self, path: &Path); fn add_object(&mut self, path: &Path); - fn gc_sections(&mut self, is_dylib: bool); + fn gc_sections(&mut self, keep_metadata: bool); fn position_independent_executable(&mut self); fn optimize(&mut self); fn debuginfo(&mut self); @@ -53,8 +53,11 @@ pub trait Linker { fn hint_dynamic(&mut self); fn whole_archives(&mut self); fn no_whole_archives(&mut self); - fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, - tmpdir: &Path); + fn export_symbols(&mut self, + sess: &Session, + trans: &CrateTranslation, + tmpdir: &Path, + crate_type: CrateType); } pub struct GnuLinker<'a> { @@ -113,7 +116,7 @@ impl<'a> Linker for GnuLinker<'a> { } } - fn gc_sections(&mut self, is_dylib: bool) { + fn gc_sections(&mut self, keep_metadata: bool) { // The dead_strip option to the linker specifies that functions and data // unreachable by the entry point will be removed. This is quite useful // with Rust's compilation model of compiling libraries at a time into @@ -139,7 +142,7 @@ impl<'a> Linker for GnuLinker<'a> { // eliminate the metadata. If we're building an executable, however, // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. - } else if !is_dylib { + } else if !keep_metadata { self.cmd.arg("-Wl,--gc-sections"); } } @@ -198,8 +201,46 @@ impl<'a> Linker for GnuLinker<'a> { self.cmd.arg("-Wl,-Bdynamic"); } - fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) { - // noop, visibility in object files takes care of this + fn export_symbols(&mut self, + sess: &Session, + trans: &CrateTranslation, + tmpdir: &Path, + crate_type: CrateType) { + // If we're compiling a dylib, then we let symbol visibility in object + // files to take care of whether they're exported or not. + // + // If we're compiling a cdylib, however, we manually create a list of + // exported symbols to ensure we don't expose any more. The object files + // have far more public symbols than we actually want to export, so we + // hide them all here. + if crate_type == CrateType::CrateTypeDylib { + return + } + + let path = tmpdir.join("list"); + let prefix = if self.sess.target.target.options.is_like_osx { + "_" + } else { + "" + }; + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + for sym in exported_symbols(sess, trans, crate_type) { + writeln!(f, "{}{}", prefix, sym)?; + } + Ok(()) + })(); + if let Err(e) = res { + sess.fatal(&format!("failed to write lib.def file: {}", e)); + } + let mut arg = OsString::new(); + if self.sess.target.target.options.is_like_osx { + arg.push("-Wl,-exported_symbols_list,"); + } else { + arg.push("-Wl,--retain-symbols-file="); + } + arg.push(&path); + self.cmd.arg(arg); } } @@ -220,7 +261,9 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(arg); } - fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); } + fn gc_sections(&mut self, _keep_metadata: bool) { + self.cmd.arg("/OPT:REF,ICF"); + } fn link_dylib(&mut self, lib: &str) { self.cmd.arg(&format!("{}.lib", lib)); @@ -322,8 +365,11 @@ impl<'a> Linker for MsvcLinker<'a> { // crates. Upstream rlibs may be linked statically to this dynamic library, // in which case they may continue to transitively be used and hence need // their symbols exported. - fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, - tmpdir: &Path) { + fn export_symbols(&mut self, + sess: &Session, + trans: &CrateTranslation, + tmpdir: &Path, + crate_type: CrateType) { let path = tmpdir.join("lib.def"); let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); @@ -333,32 +379,10 @@ impl<'a> Linker for MsvcLinker<'a> { writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - // Write out all our local symbols - for sym in trans.reachable.iter() { + for sym in exported_symbols(sess, trans, crate_type) { writeln!(f, " {}", sym)?; } - // Take a look at how all upstream crates are linked into this - // dynamic library. For all statically linked libraries we take all - // their reachable symbols and emit them as well. - let cstore = &sess.cstore; - let formats = sess.dependency_formats.borrow(); - let symbols = formats[&CrateTypeDylib].iter(); - let symbols = symbols.enumerate().filter_map(|(i, f)| { - if *f == Linkage::Static { - Some((i + 1) as ast::CrateNum) - } else { - None - } - }).flat_map(|cnum| { - cstore.reachable_ids(cnum) - }).map(|did| { - cstore.item_symbol(did) - }); - for symbol in symbols { - writeln!(f, " {}", symbol)?; - } - Ok(()) })(); if let Err(e) = res { @@ -369,3 +393,36 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(&arg); } } + +fn exported_symbols(sess: &Session, + trans: &CrateTranslation, + crate_type: CrateType) -> Vec { + let mut symbols = trans.reachable.iter().cloned().collect::>(); + + // If we're producing anything other than a dylib then the `reachable` array + // above is the exhaustive set of symbols we should be exporting. + // + // For dylibs, however, we need to take a look at how all upstream crates + // are linked into this dynamic library. For all statically linked + // libraries we take all their reachable symbols and emit them as well. + if crate_type != CrateType::CrateTypeDylib { + return symbols + } + + let cstore = &sess.cstore; + let formats = sess.dependency_formats.borrow(); + let upstream_symbols = formats[&crate_type].iter(); + symbols.extend(upstream_symbols.enumerate().filter_map(|(i, f)| { + if *f == Linkage::Static { + Some((i + 1) as ast::CrateNum) + } else { + None + } + }).flat_map(|cnum| { + cstore.reachable_ids(cnum) + }).map(|did| { + cstore.item_symbol(did) + })); + + return symbols +} diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 649d37e802d14..31bc11fb215b0 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -30,7 +30,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, output_names: &config::OutputFilenames) { if sess.opts.cg.prefer_dynamic { sess.struct_err("cannot prefer dynamic linking when performing LTO") - .note("only 'staticlib' and 'bin' outputs are supported with LTO") + .note("only 'staticlib', 'bin', and 'cdylib' outputs are \ + supported with LTO") .emit(); sess.abort_if_errors(); } @@ -38,7 +39,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, // Make sure we actually can run LTO for crate_type in sess.crate_types.borrow().iter() { match *crate_type { - config::CrateTypeExecutable | config::CrateTypeStaticlib => {} + config::CrateTypeExecutable | + config::CrateTypeCdylib | + config::CrateTypeStaticlib => {} _ => { sess.fatal("lto can only be run for executables and \ static library outputs"); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 481154ba29f8c..d68998927da9f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2509,9 +2509,7 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); - let name = format!("rust_metadata_{}_{}", - cx.link_meta().crate_name, - cx.link_meta().crate_hash); + let name = cx.metadata_symbol_name(); let buf = CString::new(name).unwrap(); let llglobal = unsafe { llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf.as_ptr()) @@ -2813,18 +2811,25 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_symbols.push("main".to_string()); } - // For the purposes of LTO, we add to the reachable set all of the upstream - // reachable extern fns. These functions are all part of the public ABI of - // the final product, so LTO needs to preserve them. - if sess.lto() { - for cnum in sess.cstore.crates() { - let syms = sess.cstore.reachable_ids(cnum); - reachable_symbols.extend(syms.into_iter().filter(|did| { - sess.cstore.is_extern_item(shared_ccx.tcx(), *did) - }).map(|did| { - sess.cstore.item_symbol(did) - })); - } + if sess.crate_types.borrow().contains(&config::CrateTypeDylib) { + reachable_symbols.push(shared_ccx.metadata_symbol_name()); + } + + // For the purposes of LTO or when creating a cdylib, we add to the + // reachable set all of the upstream reachable extern fns. These functions + // are all part of the public ABI of the final product, so we need to + // preserve them. + // + // Note that this happens even if LTO isn't requested or we're not creating + // a cdylib. In those cases, though, we're not even reading the + // `reachable_symbols` list later on so it should be ok. + for cnum in sess.cstore.crates() { + let syms = sess.cstore.reachable_ids(cnum); + reachable_symbols.extend(syms.into_iter().filter(|did| { + sess.cstore.is_extern_item(shared_ccx.tcx(), *did) + }).map(|did| { + sess.cstore.item_symbol(did) + })); } if codegen_unit_count > 1 { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 60c6af84ebbb6..4d6c4cdcc6b07 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -503,6 +503,12 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { Substs::new(VecPerParamSpace::empty(), scheme.generics.regions.map(|_| ty::ReStatic))) } + + pub fn metadata_symbol_name(&self) -> String { + format!("rust_metadata_{}_{}", + self.link_meta().crate_name, + self.link_meta().crate_hash) + } } impl<'tcx> LocalCrateContext<'tcx> { diff --git a/src/test/compile-fail/auxiliary/cdylib-dep.rs b/src/test/compile-fail/auxiliary/cdylib-dep.rs new file mode 100644 index 0000000000000..a3d0222a14c97 --- /dev/null +++ b/src/test/compile-fail/auxiliary/cdylib-dep.rs @@ -0,0 +1,11 @@ +// Copyright 2016 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. + +#![crate_type = "dylib"] diff --git a/src/test/compile-fail/cdylib-deps-must-be-static.rs b/src/test/compile-fail/cdylib-deps-must-be-static.rs new file mode 100644 index 0000000000000..4b160f26e92ca --- /dev/null +++ b/src/test/compile-fail/cdylib-deps-must-be-static.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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. + +// error-pattern: dependency `cdylib_dep` not found in rlib format +// aux-build:cdylib-dep.rs +// ignore-musl + +#![crate_type = "cdylib"] + +extern crate cdylib_dep; diff --git a/src/test/run-make/cdylib/Makefile b/src/test/run-make/cdylib/Makefile new file mode 100644 index 0000000000000..ae3b82537db52 --- /dev/null +++ b/src/test/run-make/cdylib/Makefile @@ -0,0 +1,19 @@ +include ../tools.mk + +all: $(call RUN_BINFILE,foo) + $(call RUN,foo) + rm $(call DYLIB,foo) + $(RUSTC) foo.rs -C lto + $(call RUN,foo) + +ifdef IS_MSVC +$(call RUN_BINFILE,foo): $(call DYLIB,foo) + $(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.dll.lib -Fe:`cygpath -w $@` +else +$(call RUN_BINFILE,foo): $(call DYLIB,foo) + $(CC) $(CFLAGS) foo.c -lfoo -o $(call RUN_BINFILE,foo) -L $(TMPDIR) +endif + +$(call DYLIB,foo): + $(RUSTC) bar.rs + $(RUSTC) foo.rs diff --git a/src/test/run-make/cdylib/bar.rs b/src/test/run-make/cdylib/bar.rs new file mode 100644 index 0000000000000..2c97298604cbc --- /dev/null +++ b/src/test/run-make/cdylib/bar.rs @@ -0,0 +1,15 @@ +// Copyright 2016 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. + +#![crate_type = "rlib"] + +pub fn bar() { + println!("hello!"); +} diff --git a/src/test/run-make/cdylib/foo.c b/src/test/run-make/cdylib/foo.c new file mode 100644 index 0000000000000..1c950427c658b --- /dev/null +++ b/src/test/run-make/cdylib/foo.c @@ -0,0 +1,20 @@ +// Copyright 2016 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. + +#include + +extern void foo(); +extern unsigned bar(unsigned a, unsigned b); + +int main() { + foo(); + assert(bar(1, 2) == 3); + return 0; +} diff --git a/src/test/run-make/cdylib/foo.rs b/src/test/run-make/cdylib/foo.rs new file mode 100644 index 0000000000000..cdac6d1903525 --- /dev/null +++ b/src/test/run-make/cdylib/foo.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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. + +#![crate_type = "cdylib"] + +extern crate bar; + +#[no_mangle] +pub extern fn foo() { + bar::bar(); +} + +#[no_mangle] +pub extern fn bar(a: u32, b: u32) -> u32 { + a + b +}