13.3.1. 编译并静态链接到绑定的 C 语言库

cc-badge cat-development-tools-badge

为了适应项目中需要混合 C、C++,或 asm 等语言的场景,cc crate 提供了一个简单的 API,用于将绑定的 C/C++/asm 代码编译成静态库(.a),静态库可以通过 rustc 静态链接。

下面的实例有一些绑定的 C 语言代码(src/hello.c),将从 rust 中调用它们。在编译 rust 源代码之前,Cargo.toml 中指定的“构建”文件(build.rs)预先运行。使用 cc crate,将生成一个静态库文件(本实例中为 libhello.a,请参阅 compile 文档),通过在 extern 代码块中声明外部函数签名,然后就可以从 rust 中调用该静态库。

本实例中绑定的 C 语言文件非常简单,只需要将一个源文件传递给 cc::Build。对于更复杂的构建需求,cc::Build 提供了一整套构建器方法,用于指定(包含)include路径和扩展编译器标志(flag)

Cargo.toml

[package]
name = "cc-bundled-static"
version = "0.1.0"
authors = ["zzy <ask@rusthub.org>"]
edition = "2018"

build = "build.rs"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[build-dependencies]
cc = "1.0.66"

[dependencies]
error-chain = "0.12.4"


build.rs

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("hello");   // 输出 `libhello.a`
}

src/hello.c

#include <stdio.h>


void hello() {
    printf("Hello from C!\n");
}

void greet(const char* name) {
    printf("Hello, %s!\n", name);
}

src/main.rs

use error_chain::error_chain;
use std::ffi::CString;
use std::os::raw::c_char;

error_chain! {
    foreign_links {
        NulError(::std::ffi::NulError);
        Io(::std::io::Error);
    }
}
fn prompt(s: &str) -> Result<String> {
    use std::io::Write;
    print!("{}", s);
    std::io::stdout().flush()?;
    let mut input = String::new();
    std::io::stdin().read_line(&mut input)?;
    Ok(input.trim().to_string())
}

extern {
    fn hello();
    fn greet(name: *const c_char);
}

fn main() -> Result<()> {
    unsafe { hello() }
    let name = prompt("What's your name? ")?;
    let c_name = CString::new(name)?;
    unsafe { greet(c_name.as_ptr()) }
    Ok(())
}