我如何弄清楚为什么在使用 llvm-sys 调用时对 LLVMTargetMachineEmitToFile 的调用失败?

How can I figure out why a call to LLVMTargetMachineEmitToFile fails when called using llvm-sys?

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[=10=]".as_ptr() as *const i8;
        let feature = "[=10=]".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[=10=]".as_ptr() as *mut i8, file_type, ["Cannot generate file.[=10=]".as_ptr()].as_mut_ptr() as *mut *mut i8);
    }
}

我正在写一个玩具编译器,我想生成目标文件,但是 LLVM 输出的文件是空的。

我发现LLVMTargetMachineEmitToFile returns 1,这意味着我做的事情是错误的,但是我做错了什么?

如果能知道怎么知道哪里出了问题就更好了。有什么办法可以得到一些错误信息吗?我在 C/C++ 方面没有任何经验。

正如评论者已经说过的那样,要完成您想做的事情(使用 LLVM 编写编译器),您将需要至少能够阅读(并且可能会编写)C 语言甚至 C++。

即使您正在使用 Rust 编译器编译代码,您还没有真正编写任何 Rust。您的 整个 程序被包裹在 unsafe 块中,因为您正在调用 LLVM(用 C++ 编写)公开的 C 函数。这可能就是为什么一些评​​论者问您是否已经让您的代码首先在 C 中工作。

, you are still calling the LLVM methods incorrectly. In this case, review the documentation for LLVMTargetMachineEmitToFile

LLVMBool LLVMTargetMachineEmitToFile(LLVMTargetMachineRef T,
                                     LLVMModuleRef M,
                                     char *Filename,
                                     LLVMCodeGenFileType codegen,
                                     char **ErrorMessage)

Returns any error in ErrorMessage. Use LLVMDisposeMessage to dispose the message.

方法本身会告诉你哪里出了问题,但你必须给它一个地方来存储错误信息。您应该 向它提供错误字符串。我很确定当前代码在尝试写入字符串文字时可能会产生一些令人兴奋的内存错误。

如果我重写你的代码使用错误信息:

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[=11=]".as_ptr() as *const i8);
        emit(module);
    }
}

TargetMachine can't emit a file of this type

那是你的问题。

Rust-wise,您可能想要结束处理愚蠢 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");