c2rust使用

需要实验室内网。密码见4090群的公告。

(使用时不要开vpn,不然会影响页面打开)。

bash 复制代码
docker run -d --gpus all -p 2002:22 --name rust all-ready-devel:latest

docker exec -it rust /bin/bash

source /root/.bashrc

conda init

在主远程端口创建后,直接回到本地页面连接。

bash 复制代码
ssh -p 2002 root@10.130.151.13

已经创建rust docker完毕,可以直接使用端口 ip和密码进入。进入后,直接使用默认的base环境即可。所以实验室人员可以直接跳到编译makefile项目开始,无需安装和配置过程。


c2rust工具

配置c2rust.

bash 复制代码
apt install build-essential llvm clang libclang-dev cmake libssl-dev pkg-config python3 git

先安装cargo,再使用它安装c2rust。

cargo安装

为了安装cargo先配置rust工具链。

bash 复制代码
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

source $HOME/.cargo/env

安装c2rust

首先要设置安装镜像。

bash 复制代码
mkdir -p ~/.cargo
touch ~/.cargo/config

# 如果没安装nano,先安装
# 以 root 用户执行(你当前是 root,无需 sudo)
apt-get update && apt-get install -y nano

nano ~/.cargo/config

写入文件中如下内容。

XML 复制代码
[source.crates-io]
replace-with = 'ustc'  # 替换为国内镜像源

# 中科大镜像源(推荐)
[source.ustc]
registry = "https://mirrors.ustc.edu.cn/crates.io-index"

# (可选)如果需要 Git 仓库镜像(部分 crate 依赖 Git)
[registry."https://github.com/rust-lang/crates.io-index"]
index = "https://mirrors.ustc.edu.cn/git/crates.io-index.git"

[net]
git-fetch-with-cli = true  # 强制使用 git 命令行工具拉取,避免网络问题
bash 复制代码
apt-get install libarchive13=3.6.0-1ubuntu1.5

cargo install c2rust

环境版本如下

bash 复制代码
(base) root@5e834ba0217a:~# cmake --version
cmake version 3.22.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).
(base) root@5e834ba0217a:~# c2rust --version
C2Rust 0.20.0
(base) root@5e834ba0217a:~# clang --version
Ubuntu clang version 14.0.0-1ubuntu1.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

编译makefile项目

接下来,选择下载一个c的项目到本地。

bash 复制代码
git clone https://github.com/landley/toybox.git
cd toybox

在使用c2rust转化之前,需要先生成这个项目的json文件。

可选指令 如果目标平台是嵌入式设备(如 ARM),需设置交叉编译工具链:

bash 复制代码
export CROSS_COMPILE=arm-linux-gnueabihf-  # 示例:ARM 工具链前缀
bash 复制代码
pip install scan-build

intercept-build make defconfig  # 生成默认配置
intercept-build make -j$(nproc)  # 编译并生成编译数据库

#  有时也可能是直接输入如下指令,而不是上面那两个指令。
.configure
intercept-build make

最后,转换全部代码。

bash 复制代码
c2rust transpile compile_commands.json

查看生成的所有.rs文件。

bash 复制代码
find . -type f -name "*.rs"    

日志调试

bash 复制代码
RUST_LOG=debug c2rust transpile compile_commands.json

编译单个c文件

在toybox目录下创建一个hello.c文件。

cpp 复制代码
// hello.c
#include <stdio.h>
int main() {
    printf("Hello C2Rust!\n");
    return 0;
}

使用c2rust进行转化。

bash 复制代码
intercept-build sh -c "clang hello.c"
c2rust transpile --binary hello compile_commands.json

这个转化会覆盖之前更新项目的compile_commands.json文件的内容。

转化后的hello.rs文件如下。

rust 复制代码
#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut
)]
use ::c2rust_out::*;
extern "C" {
    fn printf(_: *const libc::c_char, _: ...) -> libc::c_int;
}
unsafe fn main_0() -> libc::c_int {
    printf(b"Hello C2Rust!\n\0" as *const u8 as *const libc::c_char);
    return 0 as libc::c_int;
}
pub fn main() {
    unsafe { ::std::process::exit(main_0() as i32) }
}

另外创建一个复杂一点的two_thread.c文件。

two_thread.c是两个线程并行运行的代码。

cpp 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 线程1的任务函数
void* thread1_task(void* arg) {
    for (int i = 0; i < 5; i++) {
        printf("Thread 1: count %d\n", i);
        sleep(1); // 模拟工作
    }
    return NULL;
}

// 线程2的任务函数
void* thread2_task(void* arg) {
    for (int i = 0; i < 5; i++) {
        printf("Thread 2: count %d\n", i);
        sleep(1); // 模拟工作
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    
    // 创建线程1
    if (pthread_create(&thread1, NULL, thread1_task, NULL) != 0) {
        perror("Failed to create thread1");
        return 1;
    }
    
    // 创建线程2
    if (pthread_create(&thread2, NULL, thread2_task, NULL) != 0) {
        perror("Failed to create thread2");
        return 1;
    }
    
    // 等待线程结束
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    
    printf("All threads completed!\n");
    return 0;
}

C语言的运行效果如下。

bash 复制代码
(base) root@5e834ba0217a:~/toybox# gcc -pthread two_thread.c -o parallel
(base) root@5e834ba0217a:~/toybox# ./parallel
Thread 1: count 0
Thread 2: count 0
Thread 1: count 1
Thread 2: count 1
Thread 1: count 2
Thread 2: count 2
Thread 1: count 3
Thread 2: count 3
Thread 1: count 4
Thread 2: count 4
All threads completed!

将two_thread.c转化为rust语言。

bash 复制代码
(base) root@5e834ba0217a:~/toybox# intercept-build sh -c "clang two_thread.c"
(base) root@5e834ba0217a:~/toybox# c2rust transpile --binary hello compile_commands.json

转化后的rust代码如下

rust 复制代码
use ::libc;
extern "C" {
    fn printf(_: *const libc::c_char, _: ...) -> libc::c_int;
    fn perror(__s: *const libc::c_char);
    fn pthread_create(
        __newthread: *mut pthread_t,
        __attr: *const pthread_attr_t,
        __start_routine: Option::<
            unsafe extern "C" fn(*mut libc::c_void) -> *mut libc::c_void,
        >,
        __arg: *mut libc::c_void,
    ) -> libc::c_int;
    fn pthread_join(
        __th: pthread_t,
        __thread_return: *mut *mut libc::c_void,
    ) -> libc::c_int;
    fn sleep(__seconds: libc::c_uint) -> libc::c_uint;
}
pub type pthread_t = libc::c_ulong;
#[derive(Copy, Clone)]
#[repr(C)]
pub union pthread_attr_t {
    pub __size: [libc::c_char; 56],
    pub __align: libc::c_long,
}
#[no_mangle]
pub unsafe extern "C" fn thread1_task(mut arg: *mut libc::c_void) -> *mut libc::c_void {
    let mut i: libc::c_int = 0 as libc::c_int;
    while i < 5 as libc::c_int {
        printf(b"Thread 1: count %d\n\0" as *const u8 as *const libc::c_char, i);
        sleep(1 as libc::c_int as libc::c_uint);
        i += 1;
        i;
    }
    return 0 as *mut libc::c_void;
}
#[no_mangle]
pub unsafe extern "C" fn thread2_task(mut arg: *mut libc::c_void) -> *mut libc::c_void {
    let mut i: libc::c_int = 0 as libc::c_int;
    while i < 5 as libc::c_int {
        printf(b"Thread 2: count %d\n\0" as *const u8 as *const libc::c_char, i);
        sleep(1 as libc::c_int as libc::c_uint);
        i += 1;
        i;
    }
    return 0 as *mut libc::c_void;
}
unsafe fn main_0() -> libc::c_int {
    let mut thread1: pthread_t = 0;
    let mut thread2: pthread_t = 0;
    if pthread_create(
        &mut thread1,
        0 as *const pthread_attr_t,
        Some(
            thread1_task as unsafe extern "C" fn(*mut libc::c_void) -> *mut libc::c_void,
        ),
        0 as *mut libc::c_void,
    ) != 0 as libc::c_int
    {
        perror(b"Failed to create thread1\0" as *const u8 as *const libc::c_char);
        return 1 as libc::c_int;
    }
    if pthread_create(
        &mut thread2,
        0 as *const pthread_attr_t,
        Some(
            thread2_task as unsafe extern "C" fn(*mut libc::c_void) -> *mut libc::c_void,
        ),
        0 as *mut libc::c_void,
    ) != 0 as libc::c_int
    {
        perror(b"Failed to create thread2\0" as *const u8 as *const libc::c_char);
        return 1 as libc::c_int;
    }
    pthread_join(thread1, 0 as *mut *mut libc::c_void);
    pthread_join(thread2, 0 as *mut *mut libc::c_void);
    printf(b"All threads completed!\n\0" as *const u8 as *const libc::c_char);
    return 0 as libc::c_int;
}
pub fn main() {
    unsafe { ::std::process::exit(main_0() as i32) }
}

运行rust文件

cargo编译运行文件

使用cargo创建新项目

bash 复制代码
cargo new --bin thread_demo
cd thread_demo

添加 libc 到 thread_demo/ Cargo.toml

XML 复制代码
[dependencies]
libc = "0.2"

将你的代码复制到 src/main.rs

bash 复制代码
cp ../two_thread.rs src/main.rs

在编译前,先在父目录toybox的cargo.toml中进行一点修改,让cargo意识到现在到底要编译的是什么。

打开父目录的 Cargo.toml

bash 复制代码
[workspace]
members = [
    "thread_demo"  # 添加这行
]

回到项目目录编译:

bash 复制代码
cd /root/toybox/thread_demo
cargo build

最后运行。

bash 复制代码
cargo run

转化得到的c2rust代码具有明显的问题。

1. 过度依赖unsafe

  • 问题 :整个线程实现都在unsafe块中

  • 风险:失去了Rust的内存安全保证

  • 改进方向

rust 复制代码
use std::thread;
thread::spawn(|| { /* 安全代码 */ });  // 使用Rust原生线程

2. 直接使用C风格指针

  • 问题*mut libc::c_void 是原始指针

  • 风险:可能引发空指针或数据竞争

  • 改进方向

rust 复制代码
Arc<Mutex<T>>  // 线程安全的数据共享

3. 手动字符串转换

rust 复制代码
b"Thread 1: count %d\n\0" as *const u8 as *const libc::c_char
  • 问题:易出错且不直观

  • 改进方向

rust 复制代码
CString::new("Thread 1: count").unwrap().as_ptr()

此外,在编译的过程中,编译器出现了一些警告。

bash 复制代码
warning: variable does not need to be mutable
  --> thread_demo/src/main.rs:27:39
   |
27 | pub unsafe extern "C" fn thread1_task(mut arg: *mut libc::c_void) -> *mut libc::c_void {
   |                                       ----^^^
   |                                       |
   |                                       help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

warning: variable does not need to be mutable
  --> thread_demo/src/main.rs:38:39
   |
38 | pub unsafe extern "C" fn thread2_task(mut arg: *mut libc::c_void) -> *mut libc::c_void {
   |                                       ----^^^
   |                                       |
   |                                       help: remove this `mut`


warning: path statement with no effect
  --> thread_demo/src/main.rs:44:9
   |
44 |         i;
   |         ^^

可见出现了一些无意义的变量和语句,这些可以直接删除。

LLM生成代码

如下是LLM生成的rust版本的two_thread.rs代码。

rust 复制代码
use std::thread;
use std::time::Duration;

fn main() {
    let thread1 = thread::spawn(|| {
        for i in 0..5 {
            println!("Thread 1: count {}", i);
            thread::sleep(Duration::from_secs(1));
        }
    });

    let thread2 = thread::spawn(|| {
        for i in 0..5 {
            println!("Thread 2: count {}", i);
            thread::sleep(Duration::from_secs(1));
        }
    });

    thread1.join().unwrap();
    thread2.join().unwrap();
    println!("All threads completed!");
}

这个代码可以直接运行,并且编译没有出现任何警告。

生成usb驱动

配置libusb代码仓库的环境

bash 复制代码
git clone https://github.com/libusb/libusb.git
cd libusb

## 然后我发先上面下载的代码好像和我的环境有些问题。
# 于是下载了最新的代码


# 下载源码
wget https://github.com/libusb/libusb/archive/refs/tags/v1.0.26.tar.gz
tar -xvf v1.0.26.tar.gz
cd libusb-1.0.26/


# 配置环境
sudo apt-get update
sudo apt-get install -y libudev-dev

# 配置和编译 libusb
./autogen.sh
./configure
make
sudo make install
sudo ldconfig

# 编译example文件
gcc -o listdevs examples/listdevs.c -I/usr/local/include/libusb-1.0 -L/usr/local/lib -lusb-1.0

运行其中一个文件

运行example/listdev的结果

它会列出当前设备上的所有usb设备。

bash 复制代码
(base) root@5e834ba0217a:~/libusb/libusb-1.0.26# gcc -o listdevs examples/listdevs.c -I/usr/local/include/libusb-1.0 -L/usr/local/lib -lusb-1.0
(base) root@5e834ba0217a:~/libusb/libusb-1.0.26# ./listdevs
1d6b:0003 (bus 2, device 1)
0b1f:03ee (bus 1, device 4) path: 7.2
0557:9241 (bus 1, device 3) path: 7.1
1d6b:0107 (bus 1, device 2) path: 7
1d6b:0002 (bus 1, device 1)
(base) root@5e834ba0217a:~/libusb/libusb-1.0.26# 

c2rust转换listdev

接下来使用c2rust转化这个驱动。

bash 复制代码
# 先清除之前编译的文件等中间变量
make clean
# 重新生成配置
./autogen.sh  # 重新生成 configure 脚本(如果之前运行过)
./configure   # 重新生成 Makefile
# 生成编译数据库
intercept-build make

此时compile_commands.json文件已经有了很多内容。可以使用它进行c2rust的转换了。

在转化的时候报了个错误

bash 复制代码
c2rust transpile compile_commands.json
......
warning: Missing type 110138661456080 for node: AstNode { tag: TagTypedefDecl, children: [], loc: SrcSpan { fileid: 45, begin_line: 104, begin_column: 1, end_line: 104, end_column: 37 }, type_id: Some(110138661456080), rvalue: LValue, macro_expansions: [], macro_expansion_text: Some("__ATOMIC_SEQ_CST"), extras: [Text("atomic_uint_least16_t"), Bool(false)] }
Exported Clang AST was invalid. Check warnings above for unimplemented features.
--> /usr/lib/llvm-14/lib/clang/14.0.0/include/stdatomic.h:104:1
 [-Wclang-ast]

thread 'main' panicked at /root/.cargo/registry/src/mirrors.ustc.edu.cn-5857e57f01837ef8/c2rust-transpile-0.20.0/src/c_ast/mod.rs:269:30:
Could not find CTypeId(3326) in TypedAstContext
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
(base) root@5e834ba0217a:~/libusb/libusb-1.0.26#

直接输入常用指令会报错。

bash 复制代码
c2rust transpile compile_commands.json

🛠️ 错误原因分析

  1. ​C11 原子类型未正确映射​

    stdatomic.h中的原子类型(如 atomic_int)依赖于编译器扩展或特定标准库实现。C2Rust 的 Clang 前端可能无法正确解析这些类型,导致类型检查失败。

  2. ​编译命令配置问题​

    如果 compile_commands.json中未正确传递 -std=c11-D_GNU_SOURCE等编译选项,C2Rust 可能无法识别原子类型相关的宏和类型定义。

  3. ​C2Rust 版本限制​

    旧版本的 C2Rust 对现代 C 特性(如 _Atomic修饰符)支持有限。需要确认你使用的 C2Rust 版本是否 >= 0.22.x。

思考

c2rust存在一些缺陷,对于一些C的库没有覆盖,尤其是对于驱动这部分。

C11 `_Generic` is not supported · Issue #760 · immunant/c2rust

相关推荐
2zcode1 小时前
基于Matlab的深度学习智能行人检测与统计系统
人工智能·深度学习·目标跟踪
weixin_464078071 小时前
机器学习sklearn:过滤
人工智能·机器学习·sklearn
weixin_464078071 小时前
机器学习sklearn:降维
人工智能·机器学习·sklearn
数据与人工智能律师2 小时前
智能合约漏洞导致的损失,法律责任应如何分配
大数据·网络·人工智能·算法·区块链
张艾拉 Fun AI Everyday2 小时前
小宿科技:AI Agent 的卖铲人
人工智能·aigc·创业创新·ai-native
zhongqu_3dnest2 小时前
三维火灾调查重建:科技赋能,探寻真相
人工智能
飞哥数智坊2 小时前
AI编程实战:写作助手进化,Trae+Kimi-K2两小时搞定“带样式复制”
人工智能·trae
Nayuta2 小时前
【论文导读】OS-Genesis 基于自动探索构建 GUI 数据
人工智能·机器学习
Zhang.jialei2 小时前
HiveMQ 2024.9 设计与开发文档
hive·物联网·activemq