]>
Commit | Line | Data |
---|---|---|
62682a34 SL |
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. | |
4 | // | |
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. | |
10 | ||
11 | #![feature(rustc_private)] | |
c1a9b12d | 12 | #![feature(libc)] |
62682a34 | 13 | |
c1a9b12d | 14 | extern crate libc; |
62682a34 SL |
15 | extern crate rustc; |
16 | extern crate rustc_driver; | |
17 | extern crate rustc_lint; | |
54a0048b | 18 | extern crate rustc_llvm as llvm; |
92a42be0 | 19 | extern crate rustc_metadata; |
62682a34 | 20 | extern crate rustc_resolve; |
3157f602 XL |
21 | extern crate rustc_errors; |
22 | extern crate rustc_errors as errors; | |
54a0048b | 23 | #[macro_use] extern crate syntax; |
62682a34 SL |
24 | |
25 | use std::ffi::{CStr, CString}; | |
26 | use std::mem::transmute; | |
27 | use std::path::PathBuf; | |
92a42be0 | 28 | use std::rc::Rc; |
62682a34 SL |
29 | use std::thread::Builder; |
30 | ||
7453a54e | 31 | use rustc::dep_graph::DepGraph; |
54a0048b | 32 | use rustc::hir::map as ast_map; |
92a42be0 | 33 | use rustc::middle::cstore::{CrateStore, LinkagePreference}; |
54a0048b | 34 | use rustc::ty; |
62682a34 SL |
35 | use rustc::session::config::{self, basic_options, build_configuration, Input, Options}; |
36 | use rustc::session::build_session; | |
7453a54e | 37 | use rustc_driver::{driver, abort_on_err}; |
62682a34 | 38 | use rustc_resolve::MakeGlobMap; |
a7813a04 | 39 | use rustc_metadata::creader::read_local_crates; |
92a42be0 | 40 | use rustc_metadata::cstore::CStore; |
c1a9b12d | 41 | use libc::c_void; |
62682a34 | 42 | |
3157f602 | 43 | use rustc_errors::registry::Registry; |
92a42be0 | 44 | use syntax::parse::token; |
62682a34 SL |
45 | |
46 | fn main() { | |
7453a54e SL |
47 | // Currently trips an assertion on i686-msvc, presumably because the support |
48 | // in LLVM is a little young. | |
49 | if cfg!(target_env = "msvc") && cfg!(target_arch = "x86") { | |
50 | return | |
51 | } | |
52 | ||
62682a34 SL |
53 | let program = r#" |
54 | #[no_mangle] | |
55 | pub static TEST_STATIC: i32 = 42; | |
56 | "#; | |
57 | ||
58 | let program2 = r#" | |
59 | #[no_mangle] | |
60 | pub fn test_add(a: i32, b: i32) -> i32 { a + b } | |
61 | "#; | |
62 | ||
63 | let mut path = match std::env::args().nth(2) { | |
64 | Some(path) => PathBuf::from(&path), | |
65 | None => panic!("missing rustc path") | |
66 | }; | |
67 | ||
68 | // Remove two segments from rustc path to get sysroot. | |
69 | path.pop(); | |
70 | path.pop(); | |
71 | ||
72 | let mut ee = ExecutionEngine::new(program, path); | |
73 | ||
74 | let test_static = match ee.get_global("TEST_STATIC") { | |
75 | Some(g) => g as *const i32, | |
76 | None => panic!("failed to get global") | |
77 | }; | |
78 | ||
79 | assert_eq!(unsafe { *test_static }, 42); | |
80 | ||
81 | ee.add_module(program2); | |
82 | ||
83 | let test_add: fn(i32, i32) -> i32; | |
84 | ||
85 | test_add = match ee.get_function("test_add") { | |
86 | Some(f) => unsafe { transmute(f) }, | |
87 | None => panic!("failed to get function") | |
88 | }; | |
89 | ||
90 | assert_eq!(test_add(1, 2), 3); | |
91 | } | |
92 | ||
93 | struct ExecutionEngine { | |
94 | ee: llvm::ExecutionEngineRef, | |
95 | modules: Vec<llvm::ModuleRef>, | |
96 | sysroot: PathBuf, | |
97 | } | |
98 | ||
99 | impl ExecutionEngine { | |
100 | pub fn new(program: &str, sysroot: PathBuf) -> ExecutionEngine { | |
101 | let (llmod, deps) = compile_program(program, sysroot.clone()) | |
102 | .expect("failed to compile program"); | |
103 | ||
104 | let ee = unsafe { llvm::LLVMBuildExecutionEngine(llmod) }; | |
105 | ||
106 | if ee.is_null() { | |
107 | panic!("Failed to create ExecutionEngine: {}", llvm_error()); | |
108 | } | |
109 | ||
110 | let ee = ExecutionEngine{ | |
111 | ee: ee, | |
112 | modules: vec![llmod], | |
113 | sysroot: sysroot, | |
114 | }; | |
115 | ||
116 | ee.load_deps(&deps); | |
117 | ee | |
118 | } | |
119 | ||
120 | pub fn add_module(&mut self, program: &str) { | |
121 | let (llmod, deps) = compile_program(program, self.sysroot.clone()) | |
122 | .expect("failed to compile program in add_module"); | |
123 | ||
124 | unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); } | |
125 | ||
126 | self.modules.push(llmod); | |
127 | self.load_deps(&deps); | |
128 | } | |
129 | ||
130 | /// Returns a raw pointer to the named function. | |
c1a9b12d | 131 | pub fn get_function(&mut self, name: &str) -> Option<*const c_void> { |
62682a34 SL |
132 | let s = CString::new(name.as_bytes()).unwrap(); |
133 | ||
134 | for &m in &self.modules { | |
135 | let fv = unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) }; | |
136 | ||
137 | if !fv.is_null() { | |
138 | let fp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) }; | |
139 | ||
140 | assert!(!fp.is_null()); | |
141 | return Some(fp); | |
142 | } | |
143 | } | |
144 | None | |
145 | } | |
146 | ||
147 | /// Returns a raw pointer to the named global item. | |
c1a9b12d | 148 | pub fn get_global(&mut self, name: &str) -> Option<*const c_void> { |
62682a34 SL |
149 | let s = CString::new(name.as_bytes()).unwrap(); |
150 | ||
151 | for &m in &self.modules { | |
152 | let gv = unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) }; | |
153 | ||
154 | if !gv.is_null() { | |
155 | let gp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) }; | |
156 | ||
157 | assert!(!gp.is_null()); | |
158 | return Some(gp); | |
159 | } | |
160 | } | |
161 | None | |
162 | } | |
163 | ||
164 | /// Loads all dependencies of compiled code. | |
165 | /// Expects a series of paths to dynamic library files. | |
166 | fn load_deps(&self, deps: &[PathBuf]) { | |
167 | for path in deps { | |
168 | let s = match path.as_os_str().to_str() { | |
169 | Some(s) => s, | |
170 | None => panic!( | |
171 | "Could not convert crate path to UTF-8 string: {:?}", path) | |
172 | }; | |
173 | let cs = CString::new(s).unwrap(); | |
174 | ||
175 | let res = unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) }; | |
176 | ||
177 | if res == 0 { | |
178 | panic!("Failed to load crate {:?}: {}", | |
179 | path.display(), llvm_error()); | |
180 | } | |
181 | } | |
182 | } | |
183 | } | |
184 | ||
185 | impl Drop for ExecutionEngine { | |
186 | fn drop(&mut self) { | |
187 | unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) }; | |
188 | } | |
189 | } | |
190 | ||
191 | /// Returns last error from LLVM wrapper code. | |
192 | fn llvm_error() -> String { | |
193 | String::from_utf8_lossy( | |
194 | unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() }) | |
195 | .into_owned() | |
196 | } | |
197 | ||
198 | fn build_exec_options(sysroot: PathBuf) -> Options { | |
199 | let mut opts = basic_options(); | |
200 | ||
201 | // librustc derives sysroot from the executable name. | |
202 | // Since we are not rustc, we must specify it. | |
203 | opts.maybe_sysroot = Some(sysroot); | |
204 | ||
205 | // Prefer faster build time | |
9cc50fc6 | 206 | opts.optimize = config::OptLevel::No; |
62682a34 SL |
207 | |
208 | // Don't require a `main` function | |
209 | opts.crate_types = vec![config::CrateTypeDylib]; | |
210 | ||
211 | opts | |
212 | } | |
213 | ||
214 | /// Compiles input up to phase 4, translation to LLVM. | |
215 | /// | |
216 | /// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries | |
217 | /// for crates used in the given input. | |
218 | fn compile_program(input: &str, sysroot: PathBuf) | |
219 | -> Option<(llvm::ModuleRef, Vec<PathBuf>)> { | |
54a0048b SL |
220 | let input = Input::Str { |
221 | name: driver::anon_src(), | |
222 | input: input.to_string(), | |
223 | }; | |
62682a34 SL |
224 | let thread = Builder::new().name("compile_program".to_string()); |
225 | ||
226 | let handle = thread.spawn(move || { | |
227 | let opts = build_exec_options(sysroot); | |
a7813a04 XL |
228 | let dep_graph = DepGraph::new(opts.build_dep_graph()); |
229 | let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); | |
230 | let sess = build_session(opts, | |
231 | &dep_graph, | |
232 | None, | |
233 | Registry::new(&rustc::DIAGNOSTICS), | |
9cc50fc6 | 234 | cstore.clone()); |
62682a34 SL |
235 | rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); |
236 | ||
237 | let cfg = build_configuration(&sess); | |
238 | ||
239 | let id = "input".to_string(); | |
240 | ||
54a0048b | 241 | let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); |
62682a34 | 242 | |
3157f602 XL |
243 | let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = { |
244 | driver::phase_2_configure_and_expand( | |
245 | &sess, &cstore, krate, &id, None, MakeGlobMap::No, |_| Ok(()), | |
246 | ).expect("phase_2 returned `None`") | |
a7813a04 XL |
247 | }; |
248 | ||
62682a34 | 249 | let arenas = ty::CtxtArenas::new(); |
a7813a04 | 250 | let ast_map = ast_map::map_crate(&mut hir_forest, defs); |
62682a34 | 251 | |
7453a54e | 252 | abort_on_err(driver::phase_3_run_analysis_passes( |
a7813a04 XL |
253 | &sess, ast_map, analysis, resolutions, &arenas, &id, |
254 | |tcx, mir_map, analysis, _| { | |
62682a34 | 255 | |
7453a54e | 256 | let trans = driver::phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis); |
62682a34 | 257 | |
92a42be0 | 258 | let crates = tcx.sess.cstore.used_crates(LinkagePreference::RequireDynamic); |
62682a34 SL |
259 | |
260 | // Collect crates used in the session. | |
261 | // Reverse order finds dependencies first. | |
262 | let deps = crates.into_iter().rev() | |
263 | .filter_map(|(_, p)| p).collect(); | |
264 | ||
265 | assert_eq!(trans.modules.len(), 1); | |
266 | let llmod = trans.modules[0].llmod; | |
267 | ||
268 | // Workaround because raw pointers do not impl Send | |
269 | let modp = llmod as usize; | |
270 | ||
271 | (modp, deps) | |
7453a54e | 272 | }), &sess) |
62682a34 SL |
273 | }).unwrap(); |
274 | ||
275 | match handle.join() { | |
276 | Ok((llmod, deps)) => Some((llmod as llvm::ModuleRef, deps)), | |
277 | Err(_) => None | |
278 | } | |
279 | } |