1 unstable release

Uses new Rust 2024

new 0.0.1 Feb 17, 2026

#6 in #ecma-335

MIT license

67KB
1.5K SLoC

bnd-winmd

C header → ECMA-335 .winmd metadata generator.

Parses C headers via libclang, extracts functions, structs, enums, typedefs, constants, and callback signatures, then emits a .winmd file using the windows-metadata writer. The resulting .winmd can be fed to windows-bindgen to produce Rust FFI bindings.

Pipeline

C Headers ──→ libclang (extract) ──→ Intermediate Model ──→ ECMA-335 (emit) ──→ .winmd
Module Role
config TOML configuration loading (partitions, headers, traverse paths)
extract libclang AST → intermediate model (CType, FunctionDef, StructDef, …)
model Type-safe intermediate representation of C declarations
emit Model → ECMA-335 WinMD bytes via windows-metadata writer

Library usage

Generate a .winmd file from a config (suitable for build.rs):

use std::path::Path;

bnd_winmd::run(Path::new("bnd-winmd.toml"), None).unwrap();

Or get the raw bytes without writing to disk:

use std::path::Path;

let winmd_bytes = bnd_winmd::generate(Path::new("bnd-winmd.toml")).unwrap();

CLI

bnd-winmd [OPTIONS] [CONFIG]

Arguments:
  [CONFIG]  Path to bnd-winmd.toml [default: bnd-winmd.toml]

Options:
  -o, --output <PATH>  Output file path (overrides config)

Configuration

[output]
name = "MyLib"
file = "mylib.winmd"

# Optional: extra include search paths
# include_paths = ["/usr/include/x86_64-linux-gnu"]

[[partition]]
namespace = "MyLib"
library = "mylib"
headers = ["mylib.h"]
traverse = ["mylib.h"]

Each [[partition]] maps a set of headers to a WinMD namespace and shared library name. The traverse list controls which headers' declarations are extracted (included headers outside this list provide types but not function exports).

Prerequisites

  • libclangapt install libclang-dev (or equivalent)

Example bindings built with bnd-winmd

  • bnd-posix — 15 POSIX modules from glibc system headers
  • bnd-openssl — 8 OpenSSL 3.x partitions across libssl + libcrypto

Dependencies

~10–14MB
~183K SLoC