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

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-使用this thread.记住,默认情况下,Rust for windows将配置为MSVC,而不是mingw.

The following steps were originally mentioned in the official 100

完成后,需要一个构建脚本将库链接到依赖项.但首先,你需要图书馆.从官方网站libsdl website下载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的文件,并将其放入cargo.toml中的[package]

build="build.rs"

有关构建脚本的更多信息,请参见here

这是 playbook -

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");
                }
            }
        }
    }
}

Note:这故意省略了MSVC特定的内容.

现在在你的构建配置aka [build] inside cargo.toml中,你需要-

target="x86_64-pc-windows-gnu"

可用目标的列表可以在cargo build docs中找到

更多关于构建配置的信息可以在config docs页中找到

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

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

用你 Select 的目标值替换TARGET_NAME.

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

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

为了举例说明,让我们使用CMake with rust创建一个定制的简单C静态库.

The following steps were originally mentioned in 100

首先,你需要一个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);
}

(Note:函数应该是not,因为我们正在构建一个静态库)

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

cmake_minimum_required(VERSION 3.0)
project(LibFoo C)

add_library(foo STATIC foo.c)

install(TARGETS foo DESTINATION .)

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

所以现在,文件 struct 可能看起来像-

.
├── 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就可以搜索库并链接它.This is where the name and destination of your c library comes into play

现在,您只需执行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 本身,这当然需要很多修改——但我希望这为您指明了正确的方向.

Rust相关问答推荐

移植带有可变borrow 的C代码-卸载期间错误(nappgui示例)

在actix—web中使用Redirect或NamedFile响应

从Rust调用C++虚拟方法即使在成功执行之后也会引发Access违规错误

在UdpSocket上使用sendto时的隐式套接字绑定

为什么基于高山Linux的Docker镜像不能在绝对路径下找到要执行的命令?

为什么';t std::cell::ref使用引用而不是非空?

正则表达式中的重叠匹配?(铁 rust 正则式发动机)

我无法理解Rust范围的定义(Rust Programming Language,第二版克拉布尼克和尼科尔斯)

我如何使用AWS SDK for Rust获取我承担的角色的凭据?

如何初始化选项<;T>;数组Rust 了?

为什么HashMap::get和HashMap::entry使用不同类型的密钥?

为什么 GAT、生命周期和异步的这种组合需要 `T: 'static`?

try 实现线程安全的缓存

可以在旋转循环中调用try_recv()吗?

注释闭包参数强调使用高阶排定特征界限

切片不能被 `usize` 索引?

当我在 struct 中存储异步函数时,为什么它需要生命周期

Rust,我如何正确释放堆分配的内存?

相交着色器从 SSBO 中读取零

返回引用的返回函数