Skip to content

Commit 037cd7a

Browse files
yedayakcpu
authored andcommitted
cbindgen: Add version defines
This will allow users to check the version of rustls-ffi without resorting to checking if functions are defined. Also add make rustls_version_match verify that defines are the correct. In addition to RUSTLS_VERSION_{MAJOR,MINOR,PATCH}, also define RUSTLS_VERSION_NUMBER, which includes each version part in it, bit shifted to the left. This is inspired by openssl[0], c-ares[1]. There are other options for this, for example zstd multiplies each part by a power of 100[2]. We might want to also have the entire version string here, which could help tools that need to parse the header file itself. [0] https://github.com/openssl/openssl/blob/cdd01b5e0734b0324251b32a8edd97f42ba90429/include/openssl/opensslv.h.in#L92-L102 [1] https://github.com/c-ares/c-ares/blob/42ddbc14ec008e738fa44aa2c16e74cad93742c2/include/ares_version.h#L43-L45 [2] https://github.com/facebook/zstd/blob/3c3b8274c517727952927c705940eb90c10c736f/lib/zstd.h#L115 Fixes #557
1 parent 7bb0c00 commit 037cd7a

File tree

6 files changed

+123
-0
lines changed

6 files changed

+123
-0
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

librustls/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[package]
22
name = "rustls-ffi"
3+
# Keep in sync with defines in cbindgen.toml
34
version = "0.15.0"
45
license = "Apache-2.0 OR ISC OR MIT"
56
readme = "../README-crates.io.md"

librustls/cbindgen.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
include_guard = "RUSTLS_H"
22
language = "C"
3+
# Keep in sync with "package.version" in Cargo.toml
34
after_includes = """
5+
6+
#define RUSTLS_VERSION_MAJOR 0
7+
#define RUSTLS_VERSION_MINOR 15
8+
#define RUSTLS_VERSION_PATCH 0
9+
10+
/**
11+
* This gives each version part 8 bits, and leaves the 8 least significant bits
12+
* empty for future additions, for example pre-release versions.
13+
*/
14+
#define RUSTLS_VERSION_NUMBER ((RUSTLS_VERSION_MAJOR << 24) \\
15+
|(RUSTLS_VERSION_MINOR << 16) \\
16+
|(RUSTLS_VERSION_MINOR << 8))
17+
418
#if defined(__clang__) || defined(__GNUC__)
519
# define DEPRECATED_FUNC(why) __attribute__((deprecated(why)))
620
#elif defined(_MSC_VER)

librustls/src/rustls.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@
66
#include <stddef.h>
77
#include <stdint.h>
88
#include <stdlib.h>
9+
10+
#define RUSTLS_VERSION_MAJOR 0
11+
#define RUSTLS_VERSION_MINOR 15
12+
#define RUSTLS_VERSION_PATCH 0
13+
14+
/**
15+
* This gives each version part 8 bits, and leaves the 8 least significant bits
16+
* empty for future additions, for example pre-release versions.
17+
*/
18+
#define RUSTLS_VERSION_NUMBER ((RUSTLS_VERSION_MAJOR << 24) \
19+
|(RUSTLS_VERSION_MINOR << 16) \
20+
|(RUSTLS_VERSION_MINOR << 8))
21+
922
#if defined(__clang__) || defined(__GNUC__)
1023
# define DEPRECATED_FUNC(why) __attribute__((deprecated(why)))
1124
#elif defined(_MSC_VER)

tools/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ publish = false
66

77
[dependencies]
88
rustls = { workspace = true }
9+
rustls-ffi = { path = "../librustls" }
910
hickory-resolver = { workspace = true }
1011
tokio = { workspace = true }
12+
toml = { workspace = true }
1113
serde = { workspace = true }
1214
serde_json = { workspace = true }
1315
tree-sitter = { workspace = true }

tools/tests/rustls_header_version.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use std::fs::File;
2+
use std::fs::read_to_string;
3+
use std::io::Read;
4+
use std::path::PathBuf;
5+
6+
use toml::Table;
7+
use tree_sitter::{Parser, Query, QueryCursor};
8+
9+
/// Ensure that the correct version part defines are in src/rustls.h
10+
///
11+
/// If this test starts to fail, you probably forgot to update cbindgen.toml with new version
12+
/// parts, or need to rerun cbindgen after updating it.
13+
///
14+
/// This test is in the tools crate because it requires an msrv of 1.76 and the librustls crate
15+
/// currently has an msrv of 1.73.
16+
#[test]
17+
fn rustls_header_versions_match() {
18+
// Parse Cargo.toml as a generic TOML Table.
19+
let mut metadata_file =
20+
File::open(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../librustls/Cargo.toml"))
21+
.expect("failed to open Cargo.toml");
22+
let mut metadata_content = String::new();
23+
metadata_file
24+
.read_to_string(&mut metadata_content)
25+
.expect("failed to read Cargo.toml");
26+
let metadata = metadata_content.parse::<Table>().unwrap();
27+
28+
// Find the crate version specified in Cargo.toml
29+
let package_metadata = metadata["package"]
30+
.as_table()
31+
.expect("missing package metadata");
32+
let crate_version = package_metadata["version"]
33+
.as_str()
34+
.expect("missing crate version");
35+
36+
let version_in_header = version_in_header();
37+
assert_eq!(
38+
crate_version, version_in_header,
39+
"Version in header (.h file) doesn't match version in Cargo.toml"
40+
);
41+
}
42+
43+
fn version_in_header() -> String {
44+
// Create a C parser.
45+
let mut parser = Parser::new();
46+
let language = tree_sitter_c::LANGUAGE;
47+
parser.set_language(&language.into()).unwrap();
48+
49+
// Parse the .h into an AST.
50+
let header_file =
51+
read_to_string("../librustls/src/rustls.h").expect("Couldn't read header file");
52+
53+
let header_file_bytes = header_file.as_bytes();
54+
let tree = parser
55+
.parse(&header_file, None)
56+
.ok_or("no tree parsed from input")
57+
.unwrap();
58+
let query = r#"
59+
(preproc_def name: (identifier) @define.name
60+
(#match? @define.name "^RUSTLS_VERSION_[MAJOR|MINOR|PATCH]")
61+
)"#;
62+
let query = Query::new(&language.into(), query).unwrap();
63+
let mut cursor = QueryCursor::new();
64+
let matches = cursor.matches(&query, tree.root_node(), header_file_bytes);
65+
let mut version_parts: [&str; 3] = Default::default();
66+
for query_match in matches {
67+
for preproc in query_match.nodes_for_capture_index(0) {
68+
let Some(value_node) = preproc.parent().unwrap().child_by_field_name("value") else {
69+
continue;
70+
};
71+
let key = preproc.utf8_text(header_file_bytes).unwrap();
72+
let value = value_node.utf8_text(header_file_bytes).unwrap();
73+
match key {
74+
"RUSTLS_VERSION_MAJOR" => {
75+
version_parts[0] = value;
76+
}
77+
"RUSTLS_VERSION_MINOR" => {
78+
version_parts[1] = value;
79+
}
80+
"RUSTLS_VERSION_PATCH" => {
81+
version_parts[2] = value;
82+
}
83+
_ => (),
84+
}
85+
}
86+
}
87+
format!(
88+
"{0}.{1}.{2}",
89+
version_parts[0], version_parts[1], version_parts[2]
90+
)
91+
}

0 commit comments

Comments
 (0)