Rust cargo.toml 指定 C 链接器和编译器的自定义路径



由于我对货物设置的无知和大量的文档,我遇到了一些问题。

cargo.toml 文件是当前的:

[package]
name = "hello"
version = "0.1.0"
authors = ["PC4\Author"]
[dependencies]
sdl2 = { version = "0.34.1", features = ["bundled", "static-link"] }

SDL2 依赖项已编译,但它实际上是使用 Visual Studio。我真正想做的是在编译 crate 依赖项时使用另一个文件夹中的自定义编译器。

您可以在构建依赖项时指定 rust 以使用gcc编译器,只要您为mingw正确安装了 rust 即可。要确保您的 rust 已正确配置为mingw- 使用此线程。请记住,默认情况下,Windows 的 Rust 将针对 MSVC 进行配置,而不是 mingw。

以下步骤最初在官方 rust-sdl2 文档中提到

完成此操作后,需要一个生成脚本将库链接到依赖项。但首先,您需要库。从 libsdl 官方网站下载mingw特定的库

现在您需要将这些文件放在与cargo.toml相同的文件夹中,顺序正确-

SDL2-devel-2.0.x-mingw.tar.gzSDL2-2.0.xi686-w64-mingw32bin       ->  gnu-mingwdll32
SDL2-devel-2.0.x-mingw.tar.gzSDL2-2.0.xx86_64-w64-mingw32bin     ->  gnu-mingwdll64
SDL2-devel-2.0.x-mingw.tar.gzSDL2-2.0.xi686-w64-mingw32lib       ->  gnu-mingwlib32
SDL2-devel-2.0.x-mingw.tar.gzSDL2-2.0.xx86_64-w64-mingw32lib     ->  gnu-mingwlib64

gnu-mingw应该是与cargo.toml位于同一目录中的文件夹

现在你需要构建脚本本身,制作一个名为build.rs的文件并将其放入您的[package]cargo.toml

build ="build.rs">

有关构建脚本的更多信息,请参阅此处

这是脚本——

use std::env;
use std::path::PathBuf;
fn main() {
let target = env::var("TARGET").unwrap();
if target.contains("pc-windows") {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let mut lib_dir = manifest_dir.clone();
let mut dll_dir = manifest_dir.clone();
lib_dir.push("gnu-mingw");
dll_dir.push("gnu-mingw");
lib_dir.push("lib");
dll_dir.push("dll");
if target.contains("x86_64") {
lib_dir.push("64");
dll_dir.push("64");
}
else {
lib_dir.push("32");
dll_dir.push("32");
}
println!("cargo:rustc-link-search=all={}", lib_dir.display());
for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir")  {
let entry_path = entry.expect("Invalid fs entry").path();
let file_name_result = entry_path.file_name();
let mut new_file_path = manifest_dir.clone();
if let Some(file_name) = file_name_result {
let file_name = file_name.to_str().unwrap();
if file_name.ends_with(".dll") {
new_file_path.push(file_name);
std::fs::copy(&entry_path, new_file_path.as_path()).expect("Can't copy from DLL dir");
}
}
}
}
}

注意:这有意省略了 MSVC 特定内容。

现在在你的构建配置中,也就是[build]里面cargo.toml,你需要把-

target = "x86_64-PC-Windows-GNU">

可用目标的列表可以在货物构建文档中找到

有关构建配置的更多信息,请参阅配置文档

作为奖励,如果您想使用其他编译器(gcc除外(。您所要做的就是确保必要的库位于同一目录中,并将它们放在您的[target.TARGET_NAME]

linker = "path\to\c\linker"
ar = "path\to\c\ar"

TARGET_NAME替换为您的选择目标三重。

编辑:根据OP的要求,提供有关如何将CMake与rust相结合的信息。

将 CMake 与 rust 一起使用是可能的,不过,编译和构建第三方依赖项几乎肯定需要一个自定义构建脚本,该脚本将能够替换依赖项自己的构建脚本。

为了说明这一点,让我们使用 CMake 和 rust 创建一个自定义的、简单的 C 静态库。

以下步骤最初在此代码火焰博客中提到

首先,你需要一个 C 项目,除了现在.c文件之外不需要太多,你应该把.c文件放在一个名为libfoo的目录中(或者你的库可能被称为什么(。现在,您可以将此libfoo目录放在与rust项目相同的目录中或任何您喜欢的目录中,但请记住路径。

继续在.c文件中放置一个简单的"hello world"程序-

#include <stdio.h>
void testcall(float value)
{
printf("Hello, world from C! Value passed: %fn",value);
}

(注意:函数不应该是主要的,因为我们正在构建一个静态库(

现在我们需要在同一目录中CMakelists.txt-

cmake_minimum_required(VERSION 3.0)
project(LibFoo C)
add_library(foo STATIC foo.c)
install(TARGETS foo DESTINATION .)

这是一个非常简单的脚本,尽管最后一行很重要 - 它确保库的目的地是.- 我们稍后必须从 rust 中找到这个库。

所以现在,文件结构可能看起来像——

.
├── Cargo.lock
├── Cargo.toml
├── libfoo
│   ├── CMakeLists.txt
│   └── foo.c
└── src
└── main.rs

现在对于 rust 部分,您需要一个构建脚本和项目的构建依赖项cmake

将构建脚本添加到cargo.toml-

[package]
build="build.rs"

而依赖——

[build-dependencies]
cmake = "0.1.31"

现在在你的build.rs中,你必须调用cmake-

extern crate cmake;
use cmake::Config;
fn main()
{
let dst = Config::new("libfoo").build();       
println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static=foo");    
}

.build()部分很简单,但为什么这些println!在那里?

那些编写必要的命令来stdout,以便cargo可以搜索库并链接它。这就是 c 库的名称和目的地发挥作用的地方

现在你可以简单地执行cargo run,它将构建C库以及你的rust项目!

您也可以在详细模式(-vv(下运行它,以查看C库构建的详细输出。

现在您所要做的就是从您的main.rs调用库 -

#[link(name="foo", kind="static")]
extern { 
// this is rustified prototype of the function from our C library
fn testcall(v: f32); 
}
fn main() {
println!("Hello, world from Rust!");
// calling the function from foo library
unsafe { 
testcall(3.14159); 
};
}

非常简单,但是博客的作者为extern函数留下了注释-

请注意,这个原型需要从 C 原型到 Rust 原型进行一些手动转换。对于对基元值类型进行操作的简单函数来说,这很简单,但当涉及更复杂的数据类型时,可能更难制作。

这让我们回到了 SDL2 crate,编译它所需的 C 库,链接它们,然后构建 crate 本身肯定需要大量的修补 - 但我希望这为你指明了正确的方向。

最新更新