您可以指定 rustgcc
在构建依赖项时使用编译器,只要您正确安装了 rust 即可mingw
。确保您的 rust 配置正确以供mingw
使用此线程。请记住,默认情况下,Rust for windows 将被配置为 MSVC,而不是 mingw。
以下步骤最初在官方rust-sdl2 文档中提到
完成后,您需要一个构建脚本来将库链接到依赖项。但首先,您需要这些库。从官方libsdl 网站下载mingw
特定库
cargo.toml
现在您需要将这些文件按正确的顺序放在与 相同的文件夹中 -
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\i686-w64-mingw32\bin -> gnu-mingw\dll\32
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\x86_64-w64-mingw32\bin -> gnu-mingw\dll\64
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\i686-w64-mingw32\lib -> gnu-mingw\lib\32
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\x86_64-w64-mingw32\lib -> gnu-mingw\lib\64
gnu-mingw
应该是在同一目录中的文件夹cargo.toml
现在您需要构建脚本本身,创建一个名为的文件build.rs
并将其放入您[package]
的cargo.toml
构建 =“构建.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
,你需要放-
目标=“x86_64-pc-windows-gnu”
可以在货物构建文档中找到可用目标的列表
更多关于构建配置的信息可以在配置文档中找到
作为奖励,如果您想使用其他编译器(除了gcc
)。您所要做的就是确保必要的库位于同一目录中并将它们放在您的[target.TARGET_NAME]
linker = "path\\to\\c\\linker"
ar = "path\\to\\c\\ar"
用TARGET_NAME
您选择的目标三倍替换。
编辑:根据 OP 的要求,提供有关如何将 CMake 与 rust 结合使用的信息。
使用 rust 的 CMake 是可能的,但是,编译和构建第三方依赖项几乎肯定需要一个自定义构建脚本,该脚本将能够替换依赖项自己的构建脚本。
为了说明,让我们使用带有 rust 的 CMake 制作一个自定义的简单 C 静态库。
以下步骤最初是在这个代码火焰博客中提到的
首先,您需要一个 C 项目,现在除了文件之外不需要太多 .c
,您应该将.c
文件放在一个名为libfoo
(或任何您的库可能被调用的目录)的目录中。现在你可以把这个libfoo
目录和你的rust
项目放在同一个目录或任何你喜欢的地方,但一定要记住路径。
继续在.c
文件中放一个简单的“hello world”程序——
#include <stdio.h>
void testcall(float value)
{
printf("Hello, world from C! Value passed: %f\n",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!
s 在那里?
那些将必要的命令写入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 本身肯定需要大量的修补——但我希望这已经为您指明了正确的方向。