extern crate llvm_sys;
use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::core::*;
pub fn emit(module: LLVMModuleRef) {
unsafe {
use llvm_sys::target::*;
use llvm_sys::target_machine::*;
let triple = LLVMGetDefaultTargetTriple();
LLVM_InitializeNativeTarget();
let target = LLVMGetFirstTarget();
let cpu = "x86-64\0".as_ptr() as *const i8;
let feature = "\0".as_ptr() as *const i8;
let opt_level = LLVMCodeGenOptLevel::LLVMCodeGenLevelNone;
let reloc_mode = LLVMRelocMode::LLVMRelocDefault;
let code_model = LLVMCodeModel::LLVMCodeModelDefault;
let target_machine = LLVMCreateTargetMachine(target, triple, cpu, feature, opt_level, reloc_mode, code_model);
let file_type = LLVMCodeGenFileType::LLVMObjectFile;
LLVMTargetMachineEmitToFile(target_machine, module, "/Users/andyshiue/Desktop/main.o\0".as_ptr() as *mut i8, file_type, ["Cannot generate file.\0".as_ptr()].as_mut_ptr() as *mut *mut i8);
}
}
我正在编写一个玩具编译器,我想生成对象文件,但文件LLVM输出是空的。
我发现
LLVMTargetMachineEmitToFile
返回1,这意味着我做错了什么,但我做错了什么?如果我能知道我怎么知道是怎么回事就更好了。有什么方法可以让我得到一些错误信息吗?我没有C/C++的经验。
最佳答案
正如评论家已经说过的,要做你想做的事(用LLVM编写编译器),你就需要能够在至少C和C++中读(并且可能写)。
即使您使用Rust编译器编译代码,实际上您还没有编写任何Rust。您的整个程序被封装在unsafe
块中,因为您正在调用由LVVM(用C++编写)所公开的C函数。这可能就是为什么有些评论者会问你是否已经让你的代码先在C中工作了。
在your other question中,您仍然错误地调用LLVM方法。在这种情况下,请查看the documentation for LLVMTargetMachineEmitToFile
:
LLVMBool LLVMTargetMachineEmitToFile(LLVMTargetMachineRef T,
LLVMModuleRef M,
char *Filename,
LLVMCodeGenFileType codegen,
char **ErrorMessage)
返回ErrorMessage中的任何错误。使用LLVMDisposeMessage来处理消息。
方法本身会告诉您什么是错误的,但是您必须给它一个存储错误消息的位置。不应为其提供错误字符串。我敢肯定,当当前代码试图写入字符串文字时,可能会产生一些令人兴奋的内存错误。
如果我重写您的代码以使用错误消息:
extern crate llvm_sys;
use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::core::*;
use std::ptr;
use std::ffi::{CStr, CString};
pub fn emit(module: LLVMModuleRef) {
let cpu = CString::new("x86-64").expect("invalid cpu");
let feature = CString::new("").expect("invalid feature");
let output_file = CString::new("/tmp/output.o").expect("invalid file");
unsafe {
use llvm_sys::target::*;
use llvm_sys::target_machine::*;
let triple = LLVMGetDefaultTargetTriple();
LLVM_InitializeNativeTarget();
let target = LLVMGetFirstTarget();
let opt_level = LLVMCodeGenOptLevel::LLVMCodeGenLevelNone;
let reloc_mode = LLVMRelocMode::LLVMRelocDefault;
let code_model = LLVMCodeModel::LLVMCodeModelDefault;
let target_machine = LLVMCreateTargetMachine(target, triple, cpu.as_ptr(), feature.as_ptr(), opt_level, reloc_mode, code_model);
let file_type = LLVMCodeGenFileType::LLVMObjectFile;
let mut error_str = ptr::null_mut();
let res = LLVMTargetMachineEmitToFile(target_machine, module, output_file.as_ptr() as *mut i8, file_type, &mut error_str);
if res == 1 {
let x = CStr::from_ptr(error_str);
panic!("It failed! {:?}", x);
// TODO: Use LLVMDisposeMessage here
}
}
}
fn main() {
unsafe {
let module = LLVMModuleCreateWithName("Main\0".as_ptr() as *const i8);
emit(module);
}
}
TargetMachine无法发出此类型的文件
所以这就是你的问题。
在防锈方面,您可能需要完成处理愚蠢的
LLVMBool
所需的工作,以便可以重用它。一种方法是:fn llvm_bool<F>(f: F) -> Result<(), String>
where F: FnOnce(&mut *mut i8) -> i32
{
let mut error_str = ptr::null_mut();
let res = f(&mut error_str);
if res == 1 {
let err = unsafe { CStr::from_ptr(error_str) };
Err(err.to_string_lossy().into_owned())
//LLVMDisposeMessage(error_str);
} else {
Ok(())
}
}
// later
llvm_bool(|error_str| LLVMTargetMachineEmitToFile(target_machine, module, output_file.as_ptr() as *mut i8, file_type, error_str)).expect("Couldn't output");
关于rust - 如何确定为什么使用llvm-sys调用LLVMTargetMachineEmitToFile时失败?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37267769/