2个版本

0.1.1 2023年8月6日
0.1.0 2023年8月5日

#392 in 过程宏


nucomcore中使用

MIT许可

82KB
2K SLoC

nuidl

nuidl是Nucom的IDL编译器。它既可作为命令行工具,也可作为Rust宏crate提供。

有关Nucom的更多信息,请参阅Nucom 仓库或nucomcore crate (lib.rs crates.io)。

命令行界面

与Nix一起使用

运行 nix shell git +https://git.dblsaiko.net/nucom 以进入带有nuidl的shell。

与Cargo一起使用

运行 cargo install nuidl 以进行安装。

语法

IDL source generator

Usage: nuidl [OPTIONS] <--header|--c-guid|--rust> <FILE>...

Arguments:
  <FILE>...  Specify input IDL files

Options:
  -I, --include <DIR>  Add to include path
  -c, --header         Generate C/C++ header files
  -g, --c-guid         Generate C GUID source for interfaces
  -r, --rust           Generate Rust module
  -o, --output <DIR>   Specify output directory [default: .]
  -w, --win32          Generate headers compatible with the Win32 C/C++ API instead of nucom
  -h, --help           Print help
  -V, --version        Print version

注释

  • 生成的文件依赖于Rust和C/C++的nucomcore库。
  • 目前未实现--win32选项。

宏crate

nuidl还可以使用过程宏直接从IDL文件生成Rust模块,而无需首先将生成的代码保存到文件中。

nuidlnucomcore添加到您的项目中。

[build-dependencies]
nuidl = "0.1.0"

[dependencies]
nucomcore = "0.1.0"
nuidl = "0.1.0"

由于IDL编译器需要访问您在IDL中导入的IDL文件,如iunknown.idl,因此它需要知道包含路径列表以找到这些文件。在Cargo编译时,这可以自动发现,您只需在build.rs中运行此代码即可。将以下代码添加到文件中

fn main() {
    nuidl::cargo::use_cargo_deps();
}

最后,使用println!("cargo:rustc-env=NUIDL_INCLUDE_PATH={}", paths);将包含路径传递给nuidl,因此如果您愿意,也可以手动传递这些路径(在这种情况下,您不需要将nuidl作为构建依赖项)。

之后,将您的IDL文件放入crate根目录下的include目录中(建议将其放在子目录中以避免路径冲突,例如Nucom IDLs位于include/nucom)。您可以通过在Cargo.toml中使用package.metadata.nucom.include键来更改crate的include路径。此处指定的路径相对于crate根目录。

[package.metadata.nucom]
include = ["other/path"]

在您的crate中创建一个包含以下内容的idl模块

use nuidl::idl_mod;

// Import everything from each crate's idl module that you want to use. idl_mod!
// generated code will use these.
// You'll probably want nucomcore at the very least.

#[allow(unused_imports)]
use nucomcore::idl::*;

// List your crate's IDL files here, relative to the include directory.
// If your include path is unchanged, this will look in
// include/path/to/foo.idl.

idl_mod!(pub mod "path/to/foo.idl");
idl_mod!(pub mod "path/to/bar.idl");

// If your IDLs have any include statements (not import) referring to C headers,
// they must also be provided as Rust code. For example, a C header baz.h with
// the following contents,
//
//     #include <nucom/iunknown.h>
//     
//     extern IUnknown *make_baz(void);
//
// might be represented as the following module:

pub mod baz {
    // The scope module helps to emulate C #include behavior, where including
    // a file also brings all the type that file itself includes into scope.
    // This is an ugly hack and I might replace it with something else in the
    // future. Ideally, everything should be written as IDL definitions anyway,
    // so once the IDL compiler is sufficiently done maybe this can go away.
    //
    // Any declarations visible from the C header (here, IUnknown and make_baz)
    // must also be publicly accessible through the scope module.
    #[doc(hidden)]
    pub mod scope {
        // NB: this does not re-export private items from super, like ComPtr.
        pub use super::*;
        pub use nucomcore::IUnknown;
    }
    
    use nucomcore::{ComPtr, IUnknown};
    
    extern "C" {
        // ComPtr<T> has the same representation as a T* pointer in C.
        pub fn make_baz() -> ComPtr<IUnknown>;
    }
}

依赖项

~5–15MB
~176K SLoC