Совместная компиляция кода Rust и C/C++

Последнее обновление: 01.08.2024

Если у нас есть исходный код библиотеки на другом языке, то мы можем скомпилировать его совместно с кодом Rust и подключить его в программу. Рассмотрим на примере простенькой функции на языке C. Пусть у нас есть проект со следующей структурой:

├── Cargo.toml
├── build.rs
└── src
    ├── hello.c
    └── main.rs

В папке src есть файл hello.c с простенькой функцией на языке C:

#include <stdio.h>

void hello(void){
    puts("Hello METANIT.COM ");
}

Пусть файл main.rs использует эту функцию:

extern "C" {
    pub fn hello();
}

fn main() {
    unsafe { hello();};
}

Тогда в файле build.rs определим следующий код для построения приложения:

use std::process::Command;
use std::env;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap(); // каталог со сгенерированными файлами

    Command::new("gcc").args(&["src/hello.c", "-c", "-fPIC", "-o"])
                       .arg(&format!("{}/hello.o", out_dir))
                       .status().unwrap();
    Command::new("ar").args(&["crus", "libhello.a", "hello.o"])
                      .current_dir(&Path::new(&out_dir))
                      .status().unwrap();

    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=static=hello");
}

В данном случае с помощью функций Command::new() создаются две команды. Первая команда представляет команду gcc (то есть компилятор GCC), которая компилирует файл с объектным кодом "hello.o". Вторая команда - ar из hello.o формирует файл библиотеки "libhello.o". Два последних вызова макроса println устанавливают каталог для поиска библиотеки и имя используемой библиотеки.

Запустим проект с помощью команды cargo run, и приложение на Rust выполнит функцию hello из библиотеки на C:

eugene@Eugene:/workspace/rust/ffi_app$ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s
     Running `target/debug/ffi_app`
Hello METANIT.COM 
eugene@Eugene:/workspace/rust/ffi_app$ 

Компиляция с помощью крейта cc

Выше приведенный подход имеет недостаток - этот способ привязан к GCC. Например, если мы на Windows, мы можем захотеть использовать компилятор Visual C++, а не GCC. И чтобы упростить компиляцию библиотек C/C++, можно использовать крейт cc. Данный крейт сам выбирает необходимый компилятор и параметры компиляции.

Прежде всего добавим данный крейт в секцию build-dependencies в файле Cargo.toml:

[package]
name = "ffi_app"
version = "0.1.0"
edition = "2021"

[build-dependencies]
cc = "1.0"

[dependencies]

Затем изменим скрипт построения build.rs

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("hello");
    println!("cargo::rerun-if-changed=src/hello.c");
}

Код в hello.c и main.rs остается тем же. И также запустим проект с помощью команды cargo run

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850