Как я могу выяснить, почему происходит сбой вызова LLVMTargetMachineEmitToFile при вызове с использованием 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\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++.

1 ответ

Решение

Как уже сказали комментаторы, чтобы делать то, что вы хотите (написать компилятор с использованием LLVM), вам нужно уметь читать (и, вероятно, писать) как минимум на C и, возможно, на C++.

Даже если вы компилируете код с помощью компилятора Rust, вы еще не пишете Rust. Вся ваша программа обернута в unsafe блокирует, потому что вы вызываете функции C, предоставляемые LLVM (который написан на C++). Это может быть причиной того, что некоторые комментаторы спрашивают, получили ли вы свой код для работы в Си.

Как и в вашем другом вопросе, вы все еще неправильно вызываете методы LLVM. В этом случае просмотрите документацию для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");
Другие вопросы по тегам