当前位置: 首页 > news >正文

Rust跨平台编译

如果你感觉自己被困住了,焦虑并充满消极情绪,生命出现了停滞,那么治疗方法很简单:「做点什么」

大家好,我是「柒八九」。一个「专注于前端开发技术/RustAI应用知识分享」Coder

前言

之前我们不是写了一篇Rust 赋能前端-开发一款属于你的前端脚手架,从系统架构角度带大家看如何从0到1构建一个功能完备的前端脚手架。因为,内容包含很多,有些同学说有点消化不了,所以前段时间又写了几篇关于写脚手架可能会用到的技术。

  1. 如何在Rust中操作JSON
  2. Rust 写脚手架,Clap你应该知道的二三事

有动手能力强的小伙伴,就开始动手写自己的脚手架了。在他们写完功能后,他们就想要把脚手架编译成二进制文件,并且通过直接访问或者设置.bashrc等全局访问。更有甚者,他们还想让自己的朋友使用。在实际操作过程中,就会发生一个问题。

A同学用Mac构建了一个工具,但是她想让B同学在Windows环境上使用。此时就会发生问题,我们都知道WindowsMac由于系统架构的不同,在它们环境下编译的二进制文件是「不互通」的。

之前,我们处理的方式就是采用「交叉编译」也就是大家说的跨平台编译。但是呢,由于受文章内容的限制,我们就一带而过,没有过多的去解释。

alt

而有的小伙伴,想了解这方面的知识。所以,今天我们就来聊聊--Rust跨平台编译

好了,天不早了,干点正事哇。

alt

我们能所学到的知识点

  1. 跨平台编译及其在Rust中的好处
  2. Rust 目标三元组
  3. Rust原生跨平台编译
  4. 项目初始化
  5. 从Mac到Windows环境的跨平台编译
  6. 如何编写特定于平台的代码
  7. 其他跨平台解决方案

1. 跨平台编译及其在Rust中的好处

跨平台编译是指能够在一个平台上编译源代码,生成可以在其他平台上运行的可执行文件库文件。它的主要好处是可以显著提高代码的「可移植性」「复用性」

Rust 中,跨平台编译有以下主要优势:

  1. 「无需依赖虚拟机」 不同于 Java.NET 等需要虚拟机的语言,Rust 编译器「直接将代码编译为机器码」,因此可以直接在目标平台上运行,无需额外的运行时环境,提高了性能。

  2. 「静态链接」 Rust 默认静态链接所有依赖库,生成的可执行文件是独立的,无需依赖共享库即可运行,便于部署和分发。

  3. 「LLVM 支持」 Rust 使用 LLVM 作为编译器后端,LLVM 提供了强大的跨平台支持,能为多种 CPU 架构生成高质量的机器码。

  4. 「标准库的跨平台支持」 Rust 的标准库就设计为跨平台的,它利用了一些跨平台的抽象层,如跨平台系统调用接口,从而使标准库能够在不同操作系统上运行。

  5. 「编译时单元测试」 Rust 的单元测试在编译时就运行,可以确保在发布时,程序在不同平台上的行为是一致的。

需要说明的是,虽然 Rust 为跨平台编译提供了很好的支持,但由于不同平台的差异,仍然可能需要一些平台特定的代码。不过相比其他语言,Rust 的跨平台编译支持无疑更加方便和高效。


2. Rust 目标三元组

要进行跨平台编译,我们需要知道我们要构建的平台的「目标三元组」target triple)。Rust使用与LLVM[1]相同的格式。格式为<arch><sub>-<vendor>-<sys>-<env>

例如,

  • x86_64-unknown-linux-gnu代表一个64位 Linux机器
  • x86_64-pc-windows-gnu代表一个64位的 Windows机器

我们可以运行rustc --print target-list将打印出Rust支持的所有目标。这是一段又臭又长的数据信息。

确定我们关心的平台的目标三元组的两种最佳方法是:

  1. 在该平台上运行 rustc -vV,并查找以 host:开头的行——该行的其余部分将是 目标三元组
  2. 或者在 rust platform-support [2]页面中查找

下面一些比较常见的目标三元组

目标三元组名描述
x86_64-unknown-linux-gnu64位Linux(内核3.2+,glibc 2.17+)
x86_64-pc-windows-gnu64位MinGW(Windows 7+)
x86_64-pc-windows-msvc64位MSVC(Windows 7+)
x86_64-apple-darwin64位macOS(10.7+,Lion+)
aarch64-unknown-linux-gnuARM64 Linux(内核4.1,glibc 2.17+)
aarch64-apple-darwinARM64 macOS(11.0+,Big Sur+)
aarch64-apple-iosARM64 iOS
aarch64-apple-ios-simARM64上的Apple iOS模拟器
armv7-linux-androideabiARMv7a Android

3. Rust原生跨平台编译

之前,我们在处理f_cli的跨平台编译的时候,我们直接是用cargo build --target xx,这是Rust内置的方式。

但是呢,这块有一个问题。

要将源代码编译成适配特定平台,我们需要指定一个目标(target)。这告诉编译器我们的代码应该编译为哪个平台。因此,我们需要安装相应的 GCC[3]。然后,将目标添加到 Rust 工具链中。

工具链是一组工具,帮助语言生成功能性的目标代码。它们可以提供编译器链接器程序,或者额外的库中扩展功能。

下一步是添加链接器。这可以在 Cargo 配置中设置。

Rust 编译器「按顺序处理程序中的每个源代码文件」,并检查我们的代码以确保其遵循 Rust 语言的规则,并「将我们的源代码转换为称为目标文件的机器语言文件」编译器创建一个或多个目标文件之后,另一个名为链接器的程序将编译器生成的所有目标文件合并为一个「单独的可执行程序」。除了能够链接目标文件外,链接器还能够链接库文件。库文件是预编译代码的集合,已经被“打包”以供在其他程序中重用。

例如,如果我们想要在Mac环境下将程序编译成可以在Windows环境下运行的。就需要执行以下步骤

  1. 安装目标 mingw-w64

    brew install mingw-w64
  2. rustup 添加目标:

    rustup target add x86_64-pc-windows-gnu
  3. 创建 .cargo/config

    • 将以下指令添加到 .cargo/config
    [target.x86_64-pc-windows-gnu]
    linker = "x86_64-w64-mingw32-gcc"
  4. 最后运行:

      cargo build 
      --target=x86_64-pc-windows-gnu 
      --verbose

这只是其中一个平台,如果我们的程序想要在多个平台上发布,那就需要做更多的设置。这是一项功能繁杂的工程。

上面的解决方式是可以的,但是今天我们再解释一种更优雅的跨平台编译方式。--cross[4],该crate曾由Rust嵌入式工作组维护。

下面,我们就简单来启动一个小项目来讲解一下如何使用cross进行Rust的跨平台编译。


4. 项目初始化

又到了我们再熟悉不过的场景了。我们用cargo new构建一个项目

cargo new cross_compile

然后,我们将main.rs中内容替换成如下代码:

use current_platform::CURRENT_PLATFORM;

fn main() {
    println!("我用的电脑系统是{}!", CURRENT_PLATFORM);
}

我们使用current_platformcrate来探查我们的代码运行的系统信息。

alt

我们可以使用cargo run来执行对应的代码。因为我的系统是mac,所以CURRENT_PLATFORM对应的值为x86_64-apple-darwin

我们可以通过rustc -vV进行查验。

alt

如图所示,通过current_platform返回的值和rustc的值是匹配的。大家可以在自己的电脑上运行上面的代码。


5. 从Mac到Windows环境的跨平台编译

通过上文我们已经得知Windows的目标三元组是x86_64-pc-windows-gnu那么我们就来开始我们的操作 - 在Mac中将代码编译到Windows环境中。

我们使用cross crate进行操作。

第一步是运行cargo install cross。这将把Cross安装到$HOME/.cargo/bin

Cross通过使用一个带有适当工具链的镜像的容器引擎来工作。

alt

由于我们是macOS,所以我们选择使用Docker来进行处理。对于Linux,它建议使用Podman[5],这是一个流行的Docker替代品。

使用cross进行交叉编译和cargo类似。也是需要指定需要编译的target

cross run --target x86_64-pc-windows-gnu

第一次运行时会花费一些时间,因为需要下载并启动适当的容器。

alt

一旦完成,我们就会看到对应的代码输出。(正如上面图中的最后一行)。我们看到cross_compile.exe正在Windows环境上运行!

从上面的输出中可以看到,编译后的.exe文件位于target/x86_64-pc-windows-gnu/debug。我们可以将其复制到Windows机器上运行,会显示预期的输出。

执行完上述工作后,我们就可以在Docker中查看对应的镜像信息。 alt

Cross甚至支持在其他平台上运行测试!让我们在main.rs文件中添加一个测试:

mod tests {
    use current_platform::{COMPILED_ON, CURRENT_PLATFORM};

    #[test]
    fn test_compiled_on_equals_current_platform() {
        assert_eq!(COMPILED_ON, CURRENT_PLATFORM);
    }
}

请注意,这是一个我们期望在Mac上运行时通过的测试,但当我们跨编译到Windows并在那里运行时将会失败。

我们在Mac上运行cargo test,会得到这样的输出:

alt

要在Windows上运行测试,语法与运行可执行文件非常相似:

cross test --target x86_64-pc-windows-gnu

大约一分钟后,我们会得到输出:

alt

很遗憾,测试失败了!

测试不是在所有平台上都受支持。此外,由于线程问题,测试是顺序运行的,这可能比在本机运行测试要慢得多。


6. 如何编写特定于平台的代码

通常,我们可能希望编写仅在一个平台上运行的代码。Rust通过cfg属性[6]使这变得简单。

让我们修改我们的程序,添加一个仅在Windows上打印的消息。事实上,我们甚至不会在非Windows平台上编译此代码:

use current_platform::CURRENT_PLATFORM;

#[cfg(target_os="windows")]
fn windows_only() {
    println!("该方法只在windows环境被触发");
}

fn main() {
    println!("我用的电脑系统是{}!", CURRENT_PLATFORM);
    #[cfg(target_os="windows")]
    {
        windows_only();
    }
}

在这里,我们将cfg属性应用于windows_only()函数,以便它不会在非Windows平台上编译。但这意味着我们只能在Windows上调用它,因此我们将相同的cfg属性应用于调用该函数的代码块。

实际上,我们还可以将属性应用于其他位置,如enumstruct和匹配表达式!

Mac上运行cargo run会得到以下输出:

alt

如我们所见,上面的输出没有Windows特定的消息。但使用cross run --target x86_64-pc-windows-gnu会得到以下输出:

alt

由于编码的原因,有些汉字没显示全,但是这不是主要的核心点,我们就不做处理了。

Rust还提供了一种根据平台信息按需应用属性的简单方法

alt

7. 其他跨平台解决方案

上面我们介绍了两种跨平台编译的的方式

  1. 内置方式 cargo run --target xxx
  2. cross run --target xx

可以说,上面的方式属于是N vs N的。也就是可以在多个平台进行互相编译。

其实还有很多解决的方案。只不过有些解决方案是1 vs N 或者是N vs 1的。 下面我们就简单的列举几个。

  1. cargo-xwin [7]:将 Cargo 项目交叉编译为 Windows msvc 目标
  2. cargo-zigbuild [8]:使用 zig 作为链接器编译 Cargo 项目。

后记

「分享是一种态度」

「全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。」

alt

Reference

[1]

LLVM: https://llvm.org/

[2]

rust platform-support : https://doc.rust-lang.org/nightly/rustc/platform-support.html

[3]

GCC: https://gcc.gnu.org/

[4]

cross: https://crates.io/crates/cross

[5]

Podman: https://podman.io/

[6]

cfg属性: https://doc.rust-lang.org/rust-by-example/attribute/cfg.html

[7]

cargo-xwin: https://github.com/rust-cross/cargo-xwin

[8]

cargo-zigbuild: https://github.com/rust-cross/cargo-zigbuild

本文由 mdnice 多平台发布

相关文章:

Rust跨平台编译

❝ 如果你感觉自己被困住了&#xff0c;焦虑并充满消极情绪&#xff0c;生命出现了停滞&#xff0c;那么治疗方法很简单&#xff1a;「做点什么」。 ❞ 大家好&#xff0c;我是「柒八九」。一个「专注于前端开发技术/Rust及AI应用知识分享」的Coder 前言 之前我们不是写了一篇R…...

php其他反序列化知识学习

简单总结一下最近学习的&#xff0c;php其他的一些反序列化知识 phar soap session 其他 __wakeup绕过gc绕过异常非公有属性&#xff0c;类名大小写不敏感正则匹配&#xff0c;十六进制绕过关键字检测原生类的利用 phar 基础知识 在 之前学习的反序列化利用中&#xff0…...

浏览器工作原理与实践--HTTP/1:HTTP性能优化

谈及浏览器中的网络&#xff0c;就避不开HTTP。我们知道HTTP是浏览器中最重要且使用最多的协议&#xff0c;是浏览器和服务器之间的通信语言&#xff0c;也是互联网的基石。而随着浏览器的发展&#xff0c;HTTP为了能适应新的形式也在持续进化&#xff0c;我认为学习HTTP的最佳…...

idea 使用springboot helper 创建springboot项目

Spring Boot Helper 是一个在 IntelliJ IDEA 中用于快速创建 Spring Boot 项目的插件。通过这个插件&#xff0c;开发者可以简化 Spring Boot 项目的创建过程&#xff0c;并快速生成所需的依赖和配置文件。以下是使用 Spring Boot Helper 插件创建 Spring Boot 项目的详细步骤&…...

关于 Amazon DynamoDB 的学习和使用

文章主要针对于博主自己的技术栈&#xff0c;从Unity的角度出发&#xff0c;对于 DynamoDB 的使用。 绿色通道&#xff1a; WS SDK for .NET Version 3 API Reference - AmazonDynamoDBClient Amazon DynamoDB Amazon DynamoDB is a fast, highly scalable, highly available,…...

【fastapi】搭建第一个fastapi后端项目

本篇文章介绍一下fastapi后端项目的搭建。其实没有什么好说的&#xff0c;按照官方教程来即可&#xff1a;https://fastapi.tiangolo.com/zh/ 安装依赖 这也是我觉得python项目的槽点之一。所有依赖都安装在本地&#xff0c;一旦在别人电脑上编写项目就又要安装一遍。很扯淡。…...

Qt/QML编程之路:图片进度条的实现(50)

要实现进度条,而进度条是通过一个图片来展示的,比如逐渐增大的音量,或者逐步增大的车速,通过图片显示的效果肯定更好一些。最直接的想法是通过一个透明的rectagle,把不想让看到的遮住,实际上这种方法不可行。 import QtQuick 2.5 import QtQuick.Window 2.2 import QtGra…...

OOCT WPF_D3D项目报错无法加载依赖项

运行示例项目报错缺少dll&#xff0c;发现运用了这个大老李&#xff0c;通过添加PATH路径也无法解决&#xff0c;看到debug文件夹下面没有其他的依赖项。 通过depneds工具可以看到 OCCTProxy_D3D.dll 缺少依赖项&#xff0c;图中的缺项都是OCCT生成的模块dll所以讲这些dll从..…...

模板方法模式:定义算法骨架的设计策略

在软件开发中&#xff0c;模板方法模式是一种行为型设计模式&#xff0c;它在父类中定义一个操作的算法框架&#xff0c;允许子类在不改变算法结构的情况下重定义算法的某些步骤。这种模式是基于继承的基本原则&#xff0c;通过抽象类达到代码复用的目的。本文将详细介绍模板方…...

es6对于变量的解构赋值(数组解构,对象解构,字符串解构,函数解构等)解析(2024-04-12)

1、数组的解构赋值 [ ] 1.1 数组解构的基本用法 ES6 允许按照一定模式&#xff0c;从数组和对象中提取值&#xff0c;对变量进行赋值&#xff0c;这被称为解构&#xff08;Destructuring&#xff09;。本质上叫模型匹配&#xff0c;等号两边的模型相同就可以对应上。 //以前…...

Flutter学习13 - Widget

1、Flutter中常用 Widget 2、StatelessWidget 和 StateFulWidget Flutter 中的 widget 有很多&#xff0c;但主要分两种&#xff1a; StatelessWidget无状态的 widget如果一个 widget 是最终的或不可变的&#xff0c;那么它就是无状态的StatefulWidget有状态的 widget如果一个…...

Django开发一个学生选课系统

在这个选课系统中&#xff0c;分为管理员和学生两种角色。 学生登录系统以后&#xff0c;只能看到选课信息。管理员登录以后&#xff0c;可以看到选课信息和其他的管理系统。 选课界面如下&#xff1a; 学生管理界面如下&#xff1a; 数据分析界面如下&#xff1a; 数据…...

Vue3项目搭建及文件结构

一. Vue3项目搭建 # 安装Vue CLI npm install -g vue/cli# 通过Vue CLI创建项目&#xff1a; vue create my-vue3-project# 当问到你想要使用哪个版本的Vue时&#xff0c;选择Vue3 # 完成配置后&#xff0c;CLI会自动安装依赖并创建项目 # 最后&#xff0c;启动你的Vue3项目cd…...

【机器学习】Logistic与Softmax回归详解

在深入探讨机器学习的核心概念之前&#xff0c;我们首先需要理解机器学习在当今世界的作用。机器学习&#xff0c;作为人工智能的一个重要分支&#xff0c;已经渗透到我们生活的方方面面&#xff0c;从智能推荐系统到自动驾驶汽车&#xff0c;再到医学影像的分析。它能够从大量…...

MATLAB Simulink仿真搭建及代码生成技术—01自定义新建模型模板

MATLAB Simulink仿真搭建及代码生成技术 目录 01-自定义新建模型模板点击运行&#xff1a;显示效果&#xff1a;查看模型设置&#xff1a; 01-自定义新建模型模板 新建模型代码如下&#xff1a; function new_model(modelname) %建立一个名为SmartAss的新的模型并打开 open_…...

【Java8新特性】二、函数式接口

这里写自定义目录标题 一、什么是函数式接口二、自定义函数式接口三、作为参数传递 Lambda 表达式四、四大内置核心函数式接口1、消费形接口2、供给形接口3、函数型接口4、断言形接口 一、什么是函数式接口 只包含一个抽象方法的接口&#xff0c;称为函数式接口。你可以通过 L…...

供应RTC5606H 芯片现货

长期供应各品牌芯片现货&#xff1a; NVP2443I NVP6324 RTC5606H NZ3802-A IRF100B201 IMX290LQR-G STM32F103C8T6TR STM32F103C8T6TR STM32F103CBT7TR TPS3823-33DBVR IMX326 TPS3823-33DBVR LPC55S69**D100 OCP2184QAD DT3001S23E1-30 EMP8734-33…...

洛谷-P1596 [USACO10OCT] Lake Counting S

P1596 [USACO10OCT] Lake Counting S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> using namespace std; const int N110; int m,n; char g[N][N]; bool st[N][N]; //走/没走 int dx[] {-1,-1,-1,0,0,1,1,1}; //八联通 int dy[] {-1,0,1,1,-1,1…...

基于双向长短期神经网络BILSTM的发生概率预测,基于GRU神经网络的发生概率预

目录 背影 摘要 LSTM的基本定义 LSTM实现的步骤 BILSTM神经网络 基于双向长短期神经网络BILSTM的发生概率预测,基于GRU神经网络的发生概率预 完整代码:基于双向长短期神经网络BILSTM的发生概率预测,基于GRU神经网络的发生概率预测资源-CSDN文库 https://download.csdn.net/d…...

对OceanBase中的配置项与系统变量,合法性检查实践

在“OceanBase 配置项&系统变量实现及应用详解”的系列文章中&#xff0c;我们已经对配置项和系统变量的源码进行了解析。当涉及到新增配置项或系统变量时&#xff0c;通常会为其指定一个明确的取值范围或定义一个专门的合法性检查函数。本文将详细阐述在不同情境下&#x…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...