├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── appveyor.yml ├── build.rs ├── src ├── init.rs ├── lib.rs └── path.rs └── tests └── llvm-api.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | 5 | src/llvm_gen.rs 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | cache: cargo 3 | 4 | matrix: 5 | include: 6 | - os: linux 7 | rust: nightly 8 | 9 | - os: linux 10 | rust: stable 11 | 12 | - os: osx 13 | rust: nightly 14 | 15 | - os: osx 16 | rust: stable 17 | 18 | script: 19 | - cargo check 20 | - cargo test 21 | 22 | branches: 23 | only: 24 | - master 25 | 26 | notifications: 27 | email: 28 | on_success: never 29 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustc-llvm-proxy" 3 | version = "0.2.0" 4 | authors = ["Denys Zariaiev "] 5 | license = "MIT" 6 | edition = "2018" 7 | 8 | readme = "README.md" 9 | description = "Dynamically proxy LLVM calls into Rust own shared library" 10 | repository = "https://github.com/denzp/rustc-llvm-proxy" 11 | categories = ["development-tools::build-utils", "external-ffi-bindings"] 12 | keywords = ["llvm"] 13 | 14 | [badges] 15 | appveyor = { repository = "denzp/rustc-llvm-proxy", branch = "master", service = "github" } 16 | travis-ci = { repository = "denzp/rustc-llvm-proxy", branch = "master" } 17 | maintenance = { status = "passively-maintained" } 18 | 19 | [dependencies] 20 | libloading = "0.5" 21 | lazy_static = "1.0" 22 | failure = "0.1" 23 | libc = "0.2" 24 | llvm-sys = { version = "80", features = ["no-llvm-linking", "disable-alltargets-init"] } 25 | 26 | [build-dependencies] 27 | cargo_metadata = "0.8" 28 | failure = "0.1" 29 | quote = "0.6" 30 | syn = { version = "0.15", features = ["full"] } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Denys Zariaiev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rustc LLVM Proxy 2 | 3 | [![Build Status](https://travis-ci.org/denzp/rustc-llvm-proxy.svg?branch=master)](https://travis-ci.org/denzp/rustc-llvm-proxy) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/4oxi872d3nir8ndk/branch/master?svg=true)](https://ci.appveyor.com/project/denzp/rustc-llvm-proxy) 5 | [![Current Version](https://img.shields.io/crates/v/rustc-llvm-proxy.svg)](https://crates.io/crates/rustc-llvm-proxy) 6 | [![Docs](https://docs.rs/rustc-llvm-proxy/badge.svg)](https://docs.rs/rustc-llvm-proxy) 7 | 8 | Dynamically proxy LLVM calls into Rust own shared library! 🎉 9 | 10 | ## Use cases 11 | Normally there is no much need for the crate, except a couple of exotic cases: 12 | 13 | * Your crate is some kind build process helper that leverages LLVM (e.g. [ptx-linker](https://github.com/denzp/rust-ptx-linker)), 14 | * Your crate needs to stay up to date with Rust LLVM version (again [ptx-linker](https://github.com/denzp/rust-ptx-linker)), 15 | * You would prefer not to have dependencies on host LLVM libs (as always [ptx-linker](https://github.com/denzp/rust-ptx-linker)). 16 | 17 | ## Usage 18 | First, you need to make sure no other crate links your binary against system LLVM library. 19 | In case you are using `llvm-sys`, this can be achieved with a special feature: 20 | 21 | ``` toml 22 | [dependencies.llvm-sys] 23 | version = "60" 24 | features = ["no-llvm-linking", "disable-alltargets-init"] 25 | ``` 26 | 27 | Then all you need to do is to include the crate into your project: 28 | 29 | ``` toml 30 | [dependencies] 31 | rustc-llvm-proxy = "0.2" 32 | ``` 33 | 34 | ``` rust 35 | extern crate rustc_llvm_proxy; 36 | ``` 37 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | RUST_BACKTRACE: 1 3 | 4 | matrix: 5 | - TARGET: x86_64-pc-windows-gnu 6 | - TARGET: i686-pc-windows-gnu 7 | - TARGET: x86_64-pc-windows-msvc 8 | - TARGET: i686-pc-windows-msvc 9 | 10 | install: 11 | - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 12 | - rustup-init.exe -y --default-host %TARGET% 13 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;C:\msys64\mingw64\bin 14 | - rustc -V 15 | - cargo -V 16 | 17 | build: off 18 | 19 | test_script: 20 | - cargo check 21 | - cargo test 22 | 23 | branches: 24 | only: 25 | - master 26 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | 3 | extern crate cargo_metadata; 4 | extern crate quote; 5 | extern crate syn; 6 | 7 | #[macro_use] 8 | extern crate failure; 9 | 10 | use std::env; 11 | 12 | fn main() { 13 | let out_dir = env::var("OUT_DIR").unwrap(); 14 | 15 | // Dummy declarations for RLS. 16 | if std::env::var("CARGO").unwrap_or_default().ends_with("rls") { 17 | llvm::Generator::default() 18 | .write_declarations(&format!("{}/llvm_gen.rs", out_dir)) 19 | .expect("Unable to write generated LLVM declarations"); 20 | 21 | return; 22 | } 23 | 24 | println!("cargo:rerun-if-changed=build.rs"); 25 | 26 | llvm::Generator::default() 27 | .parse_llvm_sys_crate() 28 | .expect("Unable to parse 'llvm-sys' crate") 29 | .write_declarations(&format!("{}/llvm_gen.rs", out_dir)) 30 | .expect("Unable to write generated LLVM declarations"); 31 | } 32 | 33 | #[derive(Debug)] 34 | struct Declaration { 35 | name: String, 36 | args: String, 37 | ret_ty: String, 38 | } 39 | 40 | mod llvm { 41 | use std::fs::File; 42 | use std::io::{Read, Write}; 43 | use std::path::{Path, PathBuf}; 44 | 45 | use cargo_metadata::MetadataCommand; 46 | use failure::Error; 47 | use quote::ToTokens; 48 | use syn::{parse_file, Abi, ForeignItem, Item, ItemForeignMod, ReturnType}; 49 | 50 | use super::*; 51 | 52 | const LLVM_SOURCES: &[&str] = &[ 53 | "core.rs", 54 | "linker.rs", 55 | "bit_reader.rs", 56 | "bit_writer.rs", 57 | "ir_reader.rs", 58 | "disassembler.rs", 59 | "error_handling.rs", 60 | "initialization.rs", 61 | "link_time_optimizer.rs", 62 | "lto.rs", 63 | "object.rs", 64 | "orc.rs", 65 | "support.rs", 66 | "target.rs", 67 | "target_machine.rs", 68 | "transforms/ipo.rs", 69 | "transforms/pass_manager_builder.rs", 70 | "transforms/scalar.rs", 71 | "transforms/vectorize.rs", 72 | "debuginfo.rs", 73 | "analysis.rs", 74 | "execution_engine.rs", 75 | ]; 76 | 77 | const INIT_MACROS: &[&str] = &[ 78 | "LLVM_InitializeAllTargetInfos", 79 | "LLVM_InitializeAllTargets", 80 | "LLVM_InitializeAllTargetMCs", 81 | "LLVM_InitializeAllAsmPrinters", 82 | "LLVM_InitializeAllAsmParsers", 83 | "LLVM_InitializeAllDisassemblers", 84 | "LLVM_InitializeNativeTarget", 85 | "LLVM_InitializeNativeAsmParser", 86 | "LLVM_InitializeNativeAsmPrinter", 87 | "LLVM_InitializeNativeDisassembler", 88 | ]; 89 | 90 | #[derive(Default)] 91 | pub struct Generator { 92 | declarations: Vec, 93 | } 94 | 95 | impl Generator { 96 | pub fn parse_llvm_sys_crate(mut self) -> Result { 97 | let llvm_src_path = self.get_llvm_sys_crate_path()?; 98 | 99 | for file in LLVM_SOURCES { 100 | let path = llvm_src_path.join(file); 101 | let mut declarations = self.extract_file_declarations(&path)?; 102 | 103 | self.declarations.append(&mut declarations); 104 | } 105 | 106 | Ok(self) 107 | } 108 | 109 | pub fn write_declarations(self, path: &str) -> Result<(), Error> { 110 | let mut file = File::create(path)?; 111 | 112 | for decl in self.declarations { 113 | if INIT_MACROS.contains(&decl.name.as_str()) { 114 | // Skip target initialization wrappers 115 | // (see llvm-sys/wrappers/target.c) 116 | continue; 117 | } 118 | writeln!( 119 | file, 120 | "create_proxy!({}; {}; {});", 121 | decl.name, 122 | decl.ret_ty, 123 | decl.args.trim_end_matches(",") 124 | )?; 125 | } 126 | 127 | Ok(()) 128 | } 129 | 130 | fn get_llvm_sys_crate_path(&self) -> Result { 131 | let metadata = MetadataCommand::new() 132 | .exec() 133 | .map_err(|_| format_err!("Unable to get crate metadata"))?; 134 | 135 | let llvm_dependency = metadata 136 | .packages 137 | .into_iter() 138 | .find(|item| item.name == "llvm-sys") 139 | .ok_or(format_err!( 140 | "Unable to find 'llvm-sys' in the crate metadata" 141 | ))?; 142 | 143 | let llvm_lib_rs_path = PathBuf::from( 144 | llvm_dependency 145 | .targets 146 | .into_iter() 147 | .find(|item| item.name == "llvm-sys") 148 | .ok_or(format_err!( 149 | "Unable to find lib target for 'llvm-sys' crate" 150 | ))? 151 | .src_path, 152 | ); 153 | 154 | Ok(llvm_lib_rs_path.parent().unwrap().into()) 155 | } 156 | 157 | fn extract_file_declarations(&self, path: &Path) -> Result, Error> { 158 | let mut file = File::open(path) 159 | .map_err(|_| format_err!("Unable to open file: {}", path.to_str().unwrap()))?; 160 | 161 | let mut content = String::new(); 162 | file.read_to_string(&mut content)?; 163 | 164 | let ast = parse_file(&content).map_err(|e| failure::err_msg(e.to_string()))?; 165 | 166 | Ok(ast.items.iter().fold(vec![], |mut list, item| match item { 167 | Item::ForeignMod(ref item) if item.abi.is_c() => { 168 | list.append(&mut self.extract_foreign_mod_declarations(item)); 169 | list 170 | } 171 | 172 | _ => list, 173 | })) 174 | } 175 | 176 | fn extract_foreign_mod_declarations(&self, item: &ItemForeignMod) -> Vec { 177 | item.items.iter().fold(vec![], |mut list, item| match item { 178 | ForeignItem::Fn(ref item) => { 179 | let ret_ty = match item.decl.output { 180 | ReturnType::Default => "()".into(), 181 | ReturnType::Type(_, ref ty) => ty.into_token_stream().to_string(), 182 | }; 183 | 184 | list.push(Declaration { 185 | name: item.ident.to_string(), 186 | args: item.decl.inputs.clone().into_token_stream().to_string(), 187 | ret_ty, 188 | }); 189 | 190 | list 191 | } 192 | 193 | _ => list, 194 | }) 195 | } 196 | } 197 | 198 | trait AbiExt { 199 | fn is_c(&self) -> bool; 200 | } 201 | 202 | impl AbiExt for Abi { 203 | fn is_c(&self) -> bool { 204 | let abi_name = self 205 | .name 206 | .as_ref() 207 | .map(|item| item.value()) 208 | .unwrap_or(String::new()); 209 | 210 | abi_name == "C" 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/init.rs: -------------------------------------------------------------------------------- 1 | use super::SHARED_LIB; 2 | use llvm_sys::prelude::LLVMBool; 3 | 4 | use std::io::{BufRead, BufReader, Result}; 5 | use std::process::Command; 6 | 7 | const POSSIBLE_BACKENDS: &[&str] = &[ 8 | "AArch64", "AMDGPU", "ARM", "BPF", "Hexagon", "Lanai", "Mips", "MSP430", "NVPTX", "PowerPC", 9 | "Sparc", "SystemZ", "X86", "XCore", 10 | ]; 11 | 12 | fn get_native_arch() -> Result { 13 | let output = Command::new("rustc").args(&["--print", "cfg"]).output()?; 14 | let buf = BufReader::new(output.stdout.as_slice()); 15 | for line in buf.lines() { 16 | let line = line?; 17 | if !line.starts_with("target_arch") { 18 | continue; 19 | } 20 | // line should be like: target_arch="x86_64" 21 | return Ok(line.split('"').nth(1).unwrap().into()); 22 | } 23 | unreachable!("`rustc --print cfg` result is wrong"); 24 | } 25 | 26 | fn arch2backend(arch: &str) -> String { 27 | match arch { 28 | "aarch64" => "AArch64".into(), 29 | "arm" => "ARM".into(), 30 | "mips" | "mips64" => "Mips".into(), 31 | "powerpc" | "powerpc64" => "PowerPC".into(), 32 | "sparc" | "sparc64" => "Sparc".into(), 33 | "x86" | "x86_64" => "X86".into(), 34 | _ => panic!("Unknown backend: {}", arch), 35 | } 36 | } 37 | 38 | fn get_native_backend() -> String { 39 | let arch = get_native_arch().expect("Fail to get native arch"); 40 | arch2backend(&arch) 41 | } 42 | 43 | unsafe fn init_all(postfix: &str) { 44 | for backend in POSSIBLE_BACKENDS { 45 | let name = format!("LLVMInitialize{}{}", backend, postfix); 46 | if let Ok(entrypoint) = SHARED_LIB.get::(name.as_bytes()) { 47 | entrypoint(); 48 | } 49 | } 50 | } 51 | 52 | #[no_mangle] 53 | pub unsafe extern "C" fn LLVM_InitializeAllTargetInfos() { 54 | init_all("TargetInfo"); 55 | } 56 | #[no_mangle] 57 | pub unsafe extern "C" fn LLVM_InitializeAllTargets() { 58 | init_all("Target"); 59 | } 60 | #[no_mangle] 61 | pub unsafe extern "C" fn LLVM_InitializeAllTargetMCs() { 62 | init_all("TargetMC"); 63 | } 64 | #[no_mangle] 65 | pub unsafe extern "C" fn LLVM_InitializeAllAsmParsers() { 66 | init_all("AsmParser"); 67 | } 68 | #[no_mangle] 69 | pub unsafe extern "C" fn LLVM_InitializeAllAsmPrinters() { 70 | init_all("AsmPrinter"); 71 | } 72 | 73 | unsafe fn init_native(postfix: &str) -> LLVMBool { 74 | let backend = get_native_backend(); 75 | let name = format!("LLVMInitialize{}{}", backend, postfix); 76 | if let Ok(entrypoint) = SHARED_LIB.get::(name.as_bytes()) { 77 | entrypoint(); 78 | 0 79 | } else { 80 | 1 81 | } 82 | } 83 | 84 | #[no_mangle] 85 | pub unsafe extern "C" fn LLVM_InitializeNativeTarget() -> LLVMBool { 86 | init_native("Target") 87 | } 88 | #[no_mangle] 89 | pub unsafe extern "C" fn LLVM_InitializeNativeAsmParser() -> LLVMBool { 90 | init_native("AsmParser") 91 | } 92 | #[no_mangle] 93 | pub unsafe extern "C" fn LLVM_InitializeNativeAsmPrinter() -> LLVMBool { 94 | init_native("AsmPrinter") 95 | } 96 | #[no_mangle] 97 | pub unsafe extern "C" fn LLVM_InitializeNativeDisassembler() -> LLVMBool { 98 | init_native("Disassembler") 99 | } 100 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #![allow(non_snake_case, unused_imports, unused_macros)] 3 | 4 | //! Dynamically proxy LLVM calls into Rust own shared library! 🎉 5 | //! 6 | //! ## Use cases 7 | //! Normally there is no much need for the crate, except a couple of exotic cases: 8 | //! 9 | //! * Your crate is some kind build process helper that leverages LLVM (e.g. [ptx-linker](https://github.com/denzp/rust-ptx-linker)), 10 | //! * Your crate needs to stay up to date with Rust LLVM version (again [ptx-linker](https://github.com/denzp/rust-ptx-linker)), 11 | //! * You would prefer not to have dependencies on host LLVM libs (as always [ptx-linker](https://github.com/denzp/rust-ptx-linker)). 12 | //! 13 | //! ## Usage 14 | //! First, you need to make sure no other crate links your binary against system LLVM library. 15 | //! In case you are using `llvm-sys`, this can be achieved with a special feature: 16 | //! 17 | //! ``` toml 18 | //! [dependencies.llvm-sys] 19 | //! version = "70" 20 | //! features = ["no-llvm-linking"] 21 | //! ``` 22 | //! 23 | //! Then all you need to do is to include the crate into your project: 24 | //! 25 | //! ``` toml 26 | //! [dependencies] 27 | //! rustc-llvm-proxy = "0.1" 28 | //! ``` 29 | //! 30 | //! ``` rust 31 | //! extern crate rustc_llvm_proxy; 32 | //! ``` 33 | 34 | #[macro_use] 35 | extern crate lazy_static; 36 | 37 | #[macro_use] 38 | extern crate failure; 39 | 40 | extern crate libc; 41 | extern crate libloading as lib; 42 | extern crate llvm_sys; 43 | 44 | use lib::Library; 45 | 46 | mod path; 47 | use path::find_lib_path; 48 | 49 | pub mod init; 50 | 51 | lazy_static! { 52 | static ref SHARED_LIB: Library = { 53 | let lib_path = match find_lib_path() { 54 | Ok(path) => path, 55 | 56 | Err(error) => { 57 | eprintln!("{}", error); 58 | panic!(); 59 | } 60 | }; 61 | 62 | match Library::new(lib_path) { 63 | Ok(path) => path, 64 | 65 | Err(error) => { 66 | eprintln!("Unable to open LLVM shared lib: {}", error); 67 | panic!(); 68 | } 69 | } 70 | }; 71 | } 72 | 73 | /// Commonly used LLVM CAPI symbols with dynamic resolving 74 | pub mod proxy { 75 | use super::SHARED_LIB; 76 | 77 | use llvm_sys::analysis::*; 78 | use llvm_sys::debuginfo::*; 79 | use llvm_sys::disassembler::*; 80 | use llvm_sys::error::*; 81 | use llvm_sys::error_handling::*; 82 | use llvm_sys::execution_engine::*; 83 | use llvm_sys::link_time_optimizer::*; 84 | use llvm_sys::lto::*; 85 | use llvm_sys::object::*; 86 | use llvm_sys::orc::*; 87 | use llvm_sys::prelude::*; 88 | use llvm_sys::target::*; 89 | use llvm_sys::target_machine::*; 90 | use llvm_sys::transforms::pass_manager_builder::*; 91 | use llvm_sys::*; 92 | 93 | macro_rules! create_proxy { 94 | ($name:ident ; $ret_ty:ty ; $($arg:ident : $arg_ty:ty),*) => { 95 | #[no_mangle] 96 | pub unsafe extern "C" fn $name($($arg: $arg_ty),*) -> $ret_ty { 97 | let entrypoint = { 98 | SHARED_LIB 99 | .get:: $ret_ty>(stringify!($name).as_bytes()) 100 | }; 101 | 102 | match entrypoint { 103 | Ok(entrypoint) => entrypoint($($arg),*), 104 | 105 | Err(_) => { 106 | eprintln!("Unable to find symbol '{}' in the LLVM shared lib", stringify!($name)); 107 | panic!(); 108 | } 109 | } 110 | } 111 | }; 112 | } 113 | 114 | include!(concat!(env!("OUT_DIR"), "/llvm_gen.rs")); 115 | } 116 | -------------------------------------------------------------------------------- /src/path.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::read_dir; 3 | use std::path::{Path, PathBuf}; 4 | use std::process::Command; 5 | 6 | use failure::Error; 7 | 8 | pub fn find_lib_path() -> Result { 9 | let directories = collect_possible_directories(); 10 | 11 | if directories.is_empty() { 12 | bail!("Unable to find possible LLVM shared lib locations."); 13 | } 14 | 15 | for directory in &directories { 16 | if let Some(library) = find_library_in_directory(&directory) { 17 | return Ok(library); 18 | } 19 | } 20 | 21 | bail!( 22 | "Unable to find LLVM shared lib in possible locations:\n- {}", 23 | directories 24 | .into_iter() 25 | .map(|item| item.to_str().unwrap().to_owned()) 26 | .collect::>() 27 | .join("\n- ") 28 | ); 29 | } 30 | 31 | fn collect_possible_directories() -> Vec { 32 | let mut paths = vec![]; 33 | let separator = if cfg!(windows) { ';' } else { ':' }; 34 | 35 | if let Ok(lib_paths) = env::var("LD_LIBRARY_PATH") { 36 | for item in lib_paths.split(separator) { 37 | paths.push(PathBuf::from(item)); 38 | } 39 | } 40 | 41 | if let Ok(lib_paths) = env::var("DYLD_FALLBACK_LIBRARY_PATH") { 42 | for item in lib_paths.split(separator) { 43 | paths.push(PathBuf::from(item)); 44 | } 45 | } 46 | 47 | if let Ok(bin_paths) = env::var("PATH") { 48 | for item in bin_paths.split(separator) { 49 | let mut possible_path = PathBuf::from(item); 50 | 51 | possible_path.pop(); 52 | possible_path.push("lib"); 53 | paths.push(possible_path); 54 | } 55 | } 56 | 57 | paths 58 | } 59 | 60 | fn find_library_in_directory(directory: &Path) -> Option { 61 | match read_dir(directory) { 62 | Ok(files) => files 63 | .filter_map(Result::ok) 64 | .find(|file| file.file_name().to_string_lossy().starts_with("libLLVM")) 65 | .map(|file| file.path()), 66 | 67 | Err(_) => None, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/llvm-api.rs: -------------------------------------------------------------------------------- 1 | extern crate llvm_sys; 2 | extern crate rustc_llvm_proxy; 3 | 4 | use llvm_sys::core::*; 5 | use std::ffi::{CStr, CString}; 6 | 7 | #[test] 8 | fn module_creation() { 9 | unsafe { 10 | let module_name = CString::new("test module").unwrap(); 11 | let module = LLVMModuleCreateWithName(module_name.as_ptr()); 12 | 13 | let data_layout = CString::new("e-i64:64-v16:16-v32:32-n16:32:64").unwrap(); 14 | LLVMSetDataLayout(module, data_layout.as_ptr()); 15 | 16 | let module_contents_raw = LLVMPrintModuleToString(module); 17 | let module_contents = CStr::from_ptr(module_contents_raw); 18 | 19 | assert_eq!( 20 | module_contents.to_str().unwrap(), 21 | r#"; ModuleID = 'test module' 22 | source_filename = "test module" 23 | target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64" 24 | "# 25 | ); 26 | 27 | LLVMDisposeMessage(module_contents_raw); 28 | LLVMDisposeModule(module); 29 | } 30 | } 31 | --------------------------------------------------------------------------------