RustからC/C++を使う

#目的
C/C++で書かれているコードをRustから使用するにはどうすればよいかを知る。

#方法① CのコードをRustと一緒にビルドする方法
[cc-rs](https://github.com/alexcrichton/cc-rs)を使った方法
[The Crgo Book](https://doc.rust-lang.org/cargo/reference/build-script-examples.html)に記載してある方法で実行できた。

流れ
①構成を以下のようにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/b93b1988-df2f-fc66-aab6-19d8c5622576.png)

②ccクレートを使うことをtomlファイルに記述。CファイルにHello World実装
ccクレートを使うことでcargoにリンクオプションを自動追加してくれ、Ｃコードから生成されたlib.aファイルを自動でリンクしてくれるようになる。

```Rust:Cargo.toml
[package]
name = "tmp"
version = "0.1.0"
edition = "2018"

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

[build-dependencies]
cc = "1.0"
```


```c:hello.c
#include <stdio.h>

void hello() {
    printf("Hello, World!\n");
}
```


```Rust:main.rs
extern { fn hello(); }

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

②build.rsファイルにどのＣファイルをビルドするか記述する

```Rust:Build.rs
extern crate cc;

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

③ビルド実行
ビルドを実行すると、outフォルダにhello.cから作成されたlibhello.aファイルが作成され自動でリンクしてくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/9e2d0b8a-cecf-8fd1-76f7-04bcf2538f10.png)

Hello Worldが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/a2d6ef1d-4597-69e8-9a98-5348dc75b432.png)


詰まった箇所としては[cc-rs](https://github.com/alexcrichton/cc-rs)はclang MSVCで実行されるようで、vsCodeのビルドのデフォルトをgccにしていると上手くいかなかった。clangが必要。


#方法② CのAPIを、Rustで使えるようにインターフェース定義する方法
[bindgen](https://crates.io/crates/bindgen)を使い、自動でインターフェースが生成することができる。
RustでCのどの機能を使っているか分かりやすい。

①フォルダ構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/517ab4e5-d127-f338-21a4-5f91ee36e8ed.png)
src下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/9c662dd2-cd22-221f-6adc-4897dc2df73b.png)

②Rustで使いたいインターフェースやデータ型定義を全てのCヘッダ-を1つの.hファイルに集め記載する。


```c:hello.h
void hello();
```
②実装は.cに書く

```c:hello.c
#include <stdio.h>

void hello() {
    printf("Hello, World!\n");
}
```

③tomlファイルにbindgenを追加する

```Rust:Cargo.toml
[package]
name = "tmp"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[build-dependencies]
bindgen = "0.59.1"

```

④ビルド情報を記載する。
OUTディレクトリに.hから変換されたbindings.rsが生成される

```Rust:Build.rs
extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
     let bindings = bindgen::Builder::default()
        .header("src/hello.h")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

        bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

}

```
```Rust:main.rs
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));


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

```

⑤cargo buildでビルドするとoutフォルダ下にbuilding.rsが生成されている。Build.rsは自動生成されたbindings.rsをインクルードしてコンパイルされる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/87becb86-3edc-17b5-4a02-3a37a1065c02.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/7429e426-8178-03ae-b7dc-3199b3d9ba76.png)



環境構築で少しはまった。
LLVM clangがないと上手くいかない。以下のようなエラーメッセージが出る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/47107b9b-eb8b-a6ee-43f0-c9d928b6f4a5.png)
[bindgen](https://crates.io/crates/bindgen)にはLLVMとclangが必要とあったのでLLVMと[clang](https://qiita.com/tomota-tar-gz/items/74ed1e473829eddbee8a)をインストール。