1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![feature(rustc_private)]
16 extern crate rustc_driver;
17 extern crate rustc_front;
18 extern crate rustc_lint;
19 extern crate rustc_metadata;
20 extern crate rustc_resolve;
23 use std::ffi::{CStr, CString};
24 use std::mem::transmute;
25 use std::path::PathBuf;
27 use std::thread::Builder;
29 use rustc::front::map as ast_map;
31 use rustc::middle::cstore::{CrateStore, LinkagePreference};
32 use rustc::middle::ty;
33 use rustc::session::config::{self, basic_options, build_configuration, Input, Options};
34 use rustc::session::build_session;
35 use rustc_driver::{driver, abort_on_err};
36 use rustc_front::lowering::{lower_crate, LoweringContext};
37 use rustc_resolve::MakeGlobMap;
38 use rustc_metadata::cstore::CStore;
41 use syntax::diagnostics::registry::Registry;
42 use syntax::parse::token;
45 // Currently trips an assertion on i686-msvc, presumably because the support
46 // in LLVM is a little young.
47 if cfg!(target_env = "msvc") && cfg!(target_arch = "x86") {
53 pub static TEST_STATIC: i32 = 42;
58 pub fn test_add(a: i32, b: i32) -> i32 { a + b }
61 let mut path = match std::env::args().nth(2) {
62 Some(path) => PathBuf::from(&path),
63 None => panic!("missing rustc path")
66 // Remove two segments from rustc path to get sysroot.
70 let mut ee = ExecutionEngine::new(program, path);
72 let test_static = match ee.get_global("TEST_STATIC") {
73 Some(g) => g as *const i32,
74 None => panic!("failed to get global")
77 assert_eq!(unsafe { *test_static }, 42);
79 ee.add_module(program2);
81 let test_add: fn(i32, i32) -> i32;
83 test_add = match ee.get_function("test_add") {
84 Some(f) => unsafe { transmute(f) },
85 None => panic!("failed to get function")
88 assert_eq!(test_add(1, 2), 3);
91 struct ExecutionEngine {
92 ee: llvm::ExecutionEngineRef,
93 modules: Vec<llvm::ModuleRef>,
97 impl ExecutionEngine {
98 pub fn new(program: &str, sysroot: PathBuf) -> ExecutionEngine {
99 let (llmod, deps) = compile_program(program, sysroot.clone())
100 .expect("failed to compile program");
102 let ee = unsafe { llvm::LLVMBuildExecutionEngine(llmod) };
105 panic!("Failed to create ExecutionEngine: {}", llvm_error());
108 let ee = ExecutionEngine{
110 modules: vec![llmod],
118 pub fn add_module(&mut self, program: &str) {
119 let (llmod, deps) = compile_program(program, self.sysroot.clone())
120 .expect("failed to compile program in add_module");
122 unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); }
124 self.modules.push(llmod);
125 self.load_deps(&deps);
128 /// Returns a raw pointer to the named function.
129 pub fn get_function(&mut self, name: &str) -> Option<*const c_void> {
130 let s = CString::new(name.as_bytes()).unwrap();
132 for &m in &self.modules {
133 let fv = unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) };
136 let fp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) };
138 assert!(!fp.is_null());
145 /// Returns a raw pointer to the named global item.
146 pub fn get_global(&mut self, name: &str) -> Option<*const c_void> {
147 let s = CString::new(name.as_bytes()).unwrap();
149 for &m in &self.modules {
150 let gv = unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) };
153 let gp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) };
155 assert!(!gp.is_null());
162 /// Loads all dependencies of compiled code.
163 /// Expects a series of paths to dynamic library files.
164 fn load_deps(&self, deps: &[PathBuf]) {
166 let s = match path.as_os_str().to_str() {
169 "Could not convert crate path to UTF-8 string: {:?}", path)
171 let cs = CString::new(s).unwrap();
173 let res = unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) };
176 panic!("Failed to load crate {:?}: {}",
177 path.display(), llvm_error());
183 impl Drop for ExecutionEngine {
185 unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) };
189 /// Returns last error from LLVM wrapper code.
190 fn llvm_error() -> String {
191 String::from_utf8_lossy(
192 unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() })
196 fn build_exec_options(sysroot: PathBuf) -> Options {
197 let mut opts = basic_options();
199 // librustc derives sysroot from the executable name.
200 // Since we are not rustc, we must specify it.
201 opts.maybe_sysroot = Some(sysroot);
203 // Prefer faster build time
204 opts.optimize = config::OptLevel::No;
206 // Don't require a `main` function
207 opts.crate_types = vec![config::CrateTypeDylib];
212 /// Compiles input up to phase 4, translation to LLVM.
214 /// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries
215 /// for crates used in the given input.
216 fn compile_program(input: &str, sysroot: PathBuf)
217 -> Option<(llvm::ModuleRef, Vec<PathBuf>)> {
218 let input = Input::Str(input.to_string());
219 let thread = Builder::new().name("compile_program".to_string());
221 let handle = thread.spawn(move || {
222 let opts = build_exec_options(sysroot);
223 let cstore = Rc::new(CStore::new(token::get_ident_interner()));
224 let sess = build_session(opts, None, Registry::new(&rustc::DIAGNOSTICS),
226 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
228 let cfg = build_configuration(&sess);
230 let id = "input".to_string();
232 let krate = driver::phase_1_parse_input(&sess, cfg, &input);
234 let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None)
235 .expect("phase_2 returned `None`");
237 let krate = driver::assign_node_ids(&sess, krate);
238 let lcx = LoweringContext::new(&sess, Some(&krate));
239 let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate));
240 let arenas = ty::CtxtArenas::new();
241 let ast_map = driver::make_map(&sess, &mut hir_forest);
243 abort_on_err(driver::phase_3_run_analysis_passes(
244 &sess, &cstore, ast_map, &arenas, &id,
245 MakeGlobMap::No, |tcx, mir_map, analysis| {
247 let trans = driver::phase_4_translate_to_llvm(tcx, mir_map, analysis);
249 let crates = tcx.sess.cstore.used_crates(LinkagePreference::RequireDynamic);
251 // Collect crates used in the session.
252 // Reverse order finds dependencies first.
253 let deps = crates.into_iter().rev()
254 .filter_map(|(_, p)| p).collect();
256 assert_eq!(trans.modules.len(), 1);
257 let llmod = trans.modules[0].llmod;
259 // Workaround because raw pointers do not impl Send
260 let modp = llmod as usize;
266 match handle.join() {
267 Ok((llmod, deps)) => Some((llmod as llvm::ModuleRef, deps)),