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