【问题标题】:Hide private fields of a Rust lib when generating its C header生成 C 标头时隐藏 Rust 库的私有字段
【发布时间】:2019-12-05 19:56:42
【问题描述】:

我正在制作一个包含以下代码的 Rust 库:

pub mod my_module{

    use std::os::raw::{c_int, c_double};
    use std::collections::HashMap;

    struct MyPrivateClass {
        my_parameter:c_int
    }

    (...)

    #[repr(C)]
    pub struct MyPublicClass {
        my_private_parameter:HashMap<String,MyPrivateClass>,
        pub my_public_parameter:c_int,
        pub my_other_public_parameter:c_double
    }

    (...)

}

我想使用 Objective-C 中的那个库。所以我使用 cbindgen 来生成一个 C 头文件。 在我的 Objective-C 项目中,我只需要访问 MyPublicClass 的公共字段。 但是生成的 C 标头包含我的公共结构的所有字段,包括私有字段。

这是生成的 C 标头的样子:

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct HashMap_String__MyPrivateClass HashMap_String__MyPrivateClass;

typedef struct {
  HashMap_String__MyPrivateClass my_private_parameter;
  int my_public_parameter;
  double my_other_public_parameter;
} MyPublicClass;

在这种特殊情况下,HashMap 类型没有直接的 C 等效项,所以我不能使用这个 C 标头。

我只需要在我的 Rust 库中使用这个 HashMap。我不需要在 Objective-C 中使用它。

我怎样才能生成一个不暴露它而不破坏任何东西的 C 头文件?

【问题讨论】:

  • C 结构中不能有HashMap。 C 不知道它的 ABI,C 也不知道它不能按位复制它。 C不知道它必须放弃它。我的猜测是,您实际上根本不希望 C 知道 MyPublicClass,而只希望在 C 中指向它。在这种情况下,您只需声明 typedef struct MyPublicClass MyPublicClass;
  • C 和 C++ 不能忽略私有成员,因为它们需要知道类型的 大小。解决这个问题的唯一方法是使用指针成员,如前向声明的结构或 void*。

标签: c rust shared-libraries static-libraries c-header


【解决方案1】:

我最终遵循了 mcarton 的回答,不再需要将 MyPublicClass 暴露给我的 C 标头。

因此,我依靠函数来访问参数,而不是直接将它们作为实例参数进行访问。 当从 Xcode 运行我的 Objective-C 项目时,它的缺点是无法从调试器检查 MyPublicClass 字段的值,但至少它可以按预期编译和工作。

我的 Rust 代码:

// This struct is no longer exposed to C:
pub struct MyPublicClass {
    my_private_parameter:HashMap<String,MyPrivateClass>,
    pub my_public_parameter:c_int,
    pub my_other_public_parameter:c_double
}


impl MyPublicClass {
    pub fn new() -> Self {
        (…)
        MyPublicClass {
            my_private_parameter: … ,
            my_public_parameter: … ,
            my_other_public_parameter: … ,
        }
    }

    // Necessary to access my_public_parameter outside of Rust:
    pub fn get_my_public_parameter_value(&self) -> c_int {
        return self.my_public_parameter;
    }
}

// Exposed to C:
#[no_mangle]
pub unsafe extern fn my_public_class_new() -> *mut MyPublicClass {
    Box::into_raw(Box::new(MyPublicClass::new()))
}

// Exposed to C and necessary to access my_public_parameter outside of Rust:
#[no_mangle]
pub unsafe extern fn my_public_class_get_my_public_parameter_value(ptr: *mut MyPublicClass) -> c_int {
    let mpc = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };
    mpc.get_my_public_parameter_value()
}

C 头文件:

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct MyPublicClass MyPublicClass;
MyPublicClass *my_public_class_new();
int my_public_class_get_my_public_parameter_value(MyPublicClass *ptr);

【讨论】:

    猜你喜欢
    • 2013-07-07
    • 1970-01-01
    • 2010-09-17
    • 2011-12-11
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    相关资源
    最近更新 更多