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)]
14 extern crate rustc_driver
;
15 extern crate rustc_lint
;
16 extern crate rustc_resolve
;
19 use std
::ffi
::{CStr, CString}
;
20 use std
::mem
::transmute
;
21 use std
::path
::PathBuf
;
22 use std
::thread
::Builder
;
26 use rustc
::metadata
::cstore
::RequireDynamic
;
27 use rustc
::middle
::ty
;
28 use rustc
::session
::config
::{self, basic_options, build_configuration, Input, Options}
;
29 use rustc
::session
::build_session
;
30 use rustc_driver
::driver
;
31 use rustc_resolve
::MakeGlobMap
;
33 use syntax
::diagnostics
::registry
::Registry
;
38 pub static TEST_STATIC: i32 = 42;
43 pub fn test_add(a: i32, b: i32) -> i32 { a + b }
46 let mut path
= match std
::env
::args().nth(2) {
47 Some(path
) => PathBuf
::from(&path
),
48 None
=> panic
!("missing rustc path")
51 // Remove two segments from rustc path to get sysroot.
55 let mut ee
= ExecutionEngine
::new(program
, path
);
57 let test_static
= match ee
.get_global("TEST_STATIC") {
58 Some(g
) => g
as *const i32,
59 None
=> panic
!("failed to get global")
62 assert_eq
!(unsafe { *test_static }
, 42);
64 ee
.add_module(program2
);
66 let test_add
: fn(i32, i32) -> i32;
68 test_add
= match ee
.get_function("test_add") {
69 Some(f
) => unsafe { transmute(f) }
,
70 None
=> panic
!("failed to get function")
73 assert_eq
!(test_add(1, 2), 3);
76 struct ExecutionEngine
{
77 ee
: llvm
::ExecutionEngineRef
,
78 modules
: Vec
<llvm
::ModuleRef
>,
82 impl ExecutionEngine
{
83 pub fn new(program
: &str, sysroot
: PathBuf
) -> ExecutionEngine
{
84 let (llmod
, deps
) = compile_program(program
, sysroot
.clone())
85 .expect("failed to compile program");
87 let ee
= unsafe { llvm::LLVMBuildExecutionEngine(llmod) }
;
90 panic
!("Failed to create ExecutionEngine: {}", llvm_error());
93 let ee
= ExecutionEngine
{
103 pub fn add_module(&mut self, program
: &str) {
104 let (llmod
, deps
) = compile_program(program
, self.sysroot
.clone())
105 .expect("failed to compile program in add_module");
107 unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); }
109 self.modules
.push(llmod
);
110 self.load_deps(&deps
);
113 /// Returns a raw pointer to the named function.
114 pub fn get_function(&mut self, name
: &str) -> Option
<*const ()> {
115 let s
= CString
::new(name
.as_bytes()).unwrap();
117 for &m
in &self.modules
{
118 let fv
= unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) }
;
121 let fp
= unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) }
;
123 assert
!(!fp
.is_null());
130 /// Returns a raw pointer to the named global item.
131 pub fn get_global(&mut self, name
: &str) -> Option
<*const ()> {
132 let s
= CString
::new(name
.as_bytes()).unwrap();
134 for &m
in &self.modules
{
135 let gv
= unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) }
;
138 let gp
= unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) }
;
140 assert
!(!gp
.is_null());
147 /// Loads all dependencies of compiled code.
148 /// Expects a series of paths to dynamic library files.
149 fn load_deps(&self, deps
: &[PathBuf
]) {
151 let s
= match path
.as_os_str().to_str() {
154 "Could not convert crate path to UTF-8 string: {:?}", path
)
156 let cs
= CString
::new(s
).unwrap();
158 let res
= unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) }
;
161 panic
!("Failed to load crate {:?}: {}",
162 path
.display(), llvm_error());
168 impl Drop
for ExecutionEngine
{
170 unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) }
;
174 /// Returns last error from LLVM wrapper code.
175 fn llvm_error() -> String
{
176 String
::from_utf8_lossy(
177 unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() }
)
181 fn build_exec_options(sysroot
: PathBuf
) -> Options
{
182 let mut opts
= basic_options();
184 // librustc derives sysroot from the executable name.
185 // Since we are not rustc, we must specify it.
186 opts
.maybe_sysroot
= Some(sysroot
);
188 // Prefer faster build time
189 opts
.optimize
= config
::No
;
191 // Don't require a `main` function
192 opts
.crate_types
= vec
![config
::CrateTypeDylib
];
197 /// Compiles input up to phase 4, translation to LLVM.
199 /// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries
200 /// for crates used in the given input.
201 fn compile_program(input
: &str, sysroot
: PathBuf
)
202 -> Option
<(llvm
::ModuleRef
, Vec
<PathBuf
>)> {
203 let input
= Input
::Str(input
.to_string());
204 let thread
= Builder
::new().name("compile_program".to_string());
206 let handle
= thread
.spawn(move || {
207 let opts
= build_exec_options(sysroot
);
208 let sess
= build_session(opts
, None
, Registry
::new(&rustc
::DIAGNOSTICS
));
209 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
211 let cfg
= build_configuration(&sess
);
213 let id
= "input".to_string();
215 let krate
= driver
::phase_1_parse_input(&sess
, cfg
, &input
);
217 let krate
= driver
::phase_2_configure_and_expand(&sess
, krate
, &id
, None
)
218 .expect("phase_2 returned `None`");
220 let mut forest
= ast_map
::Forest
::new(krate
);
221 let arenas
= ty
::CtxtArenas
::new();
222 let ast_map
= driver
::assign_node_ids_and_map(&sess
, &mut forest
);
224 driver
::phase_3_run_analysis_passes(
225 sess
, ast_map
, &arenas
, id
, MakeGlobMap
::No
, |tcx
, analysis
| {
227 let trans
= driver
::phase_4_translate_to_llvm(tcx
, analysis
);
229 let crates
= tcx
.sess
.cstore
.get_used_crates(RequireDynamic
);
231 // Collect crates used in the session.
232 // Reverse order finds dependencies first.
233 let deps
= crates
.into_iter().rev()
234 .filter_map(|(_
, p
)| p
).collect();
236 assert_eq
!(trans
.modules
.len(), 1);
237 let llmod
= trans
.modules
[0].llmod
;
239 // Workaround because raw pointers do not impl Send
240 let modp
= llmod
as usize;
246 match handle
.join() {
247 Ok((llmod
, deps
)) => Some((llmod
as llvm
::ModuleRef
, deps
)),