Skip to content

Commit 27e5a31

Browse files
authored
Merge pull request #75 from stepfunc/feature/version-check
Better C# copying and version check
2 parents 5e95cf0 + 0ce77c2 commit 27e5a31

File tree

9 files changed

+132
-45
lines changed

9 files changed

+132
-45
lines changed

deps-config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"ignore": ["oo-bindgen"],
3-
"allowed_licenses": ["Apache-2.0 OR MIT", "MIT OR Unlicense"],
3+
"allowed_licenses": ["MIT"],
44
"crates": {}
55
}

generators/c-oo-bindgen/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ pub fn generate_doxygen(lib: &Library, config: &CBindgenConfig) -> FormattingRes
232232
.write_all(&format!("PROJECT_NAME = {}\n", lib.name).into_bytes())
233233
.unwrap();
234234
stdin
235-
.write_all(&format!("PROJECT_NUMBER = {}\n", lib.version.to_string()).into_bytes())
235+
.write_all(&format!("PROJECT_NUMBER = {}\n", lib.version).into_bytes())
236236
.unwrap();
237237
stdin.write_all(b"HTML_OUTPUT = doc\n").unwrap();
238238
stdin.write_all(b"GENERATE_LATEX = NO\n").unwrap();
@@ -292,8 +292,7 @@ fn generate_c_header<P: AsRef<Path>>(lib: &Library, path: P) -> FormattingResult
292292
))?;
293293
f.writeln(&format!(
294294
"#define {}_VERSION_STRING \"{}\"",
295-
uppercase_name,
296-
lib.version.to_string()
295+
uppercase_name, lib.version
297296
))?;
298297
f.newline()?;
299298

generators/dotnet-oo-bindgen/src/lib.rs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub fn generate_dotnet_bindings(
8989
fs::create_dir_all(&config.output_dir)?;
9090

9191
generate_csproj(lib, config)?;
92+
generate_targets_scripts(lib, config)?;
9293
generate_native_functions(lib, config)?;
9394
generate_constants(lib, config)?;
9495
generate_structs(lib, config)?;
@@ -118,7 +119,7 @@ fn generate_helpers(lib: &Library, config: &DotnetBindgenConfig) -> FormattingRe
118119
fn generate_csproj(lib: &Library, config: &DotnetBindgenConfig) -> FormattingResult<()> {
119120
// Open file
120121
let mut filename = config.output_dir.clone();
121-
filename.push(lib.name.clone());
122+
filename.push(&lib.name);
122123
filename.set_extension("csproj");
123124
let mut f = FilePrinter::new(filename)?;
124125

@@ -128,13 +129,10 @@ fn generate_csproj(lib: &Library, config: &DotnetBindgenConfig) -> FormattingRes
128129
f.writeln(" <GenerateDocumentationFile>true</GenerateDocumentationFile>")?;
129130
f.writeln(" <IncludeSymbols>true</IncludeSymbols>")?; // Include symbols
130131
f.writeln(" <SymbolPackageFormat>snupkg</SymbolPackageFormat>")?; // Use new file format
131-
f.writeln(&format!(
132-
" <PackageId>{}</PackageId>",
133-
lib.name.to_string()
134-
))?;
132+
f.writeln(&format!(" <PackageId>{}</PackageId>", lib.name))?;
135133
f.writeln(&format!(
136134
" <PackageVersion>{}</PackageVersion>",
137-
lib.version.to_string()
135+
lib.version
138136
))?;
139137
f.writeln(&format!(
140138
" <Description>{}</Description>",
@@ -168,6 +166,11 @@ fn generate_csproj(lib: &Library, config: &DotnetBindgenConfig) -> FormattingRes
168166
f.writeln(&format!(" <Content Include=\"{}\" Link=\"{}\" Pack=\"true\" PackagePath=\"runtimes/{}/native\" CopyToOutputDirectory=\"PreserveNewest\" />", filepath.to_string_lossy(), filename, dotnet_platform_string(p.platform)))?;
169167
}
170168

169+
// Include the target files to force the copying of DLLs of NuGet packages on .NET Framework
170+
// See https://github.com/stepfunc/dnp3/issues/147
171+
f.writeln(&format!(" <Content Include=\"build/net45/{}.targets\" Pack=\"true\" PackagePath=\"build/net45/\" />", lib.name))?;
172+
f.writeln(&format!(" <Content Include=\"buildTransitive/net45/{}.targets\" Pack=\"true\" PackagePath=\"buildTransitive/net45/\" />", lib.name))?;
173+
171174
f.writeln(" </ItemGroup>")?;
172175

173176
// Dependencies and files to include
@@ -190,6 +193,66 @@ fn generate_csproj(lib: &Library, config: &DotnetBindgenConfig) -> FormattingRes
190193
f.writeln("</Project>")
191194
}
192195

196+
fn generate_targets_scripts(lib: &Library, config: &DotnetBindgenConfig) -> FormattingResult<()> {
197+
// The target file is used to automatically copy the DLL to the build directory when using
198+
// .NET Framework (Windows only). In .NET Core or .NET 5/6, the DLLs are automatically
199+
// loaded from the appropriate runtime/*/native directory.
200+
// This solution is based on gRPC library.
201+
// We only support x64 Platform and .NET Framework 4.5 or higher.
202+
// See https://github.com/stepfunc/dnp3/issues/147
203+
204+
// Main target file
205+
{
206+
let mut filename = config.output_dir.clone();
207+
filename.push("build");
208+
filename.push("net45");
209+
210+
fs::create_dir_all(&filename)?;
211+
212+
filename.push(&lib.name);
213+
filename.set_extension("targets");
214+
let mut f = FilePrinter::new(filename)?;
215+
216+
f.writeln("<?xml version=\"1.0\" encoding=\"utf-8\"?>")?;
217+
f.writeln("<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">")?;
218+
f.writeln(" <ItemGroup>")?;
219+
220+
for p in config
221+
.platforms
222+
.iter()
223+
.filter(|x| x.platform == Platform::WinX64Msvc)
224+
{
225+
f.writeln(&format!(" <Content Include=\"$(MSBuildThisFileDirectory)../../runtimes/{}/native/{}\" Link=\"{}\" CopyToOutputDirectory=\"Always\" Visible=\"false\" NuGetPackageId=\"{}\" />", dotnet_platform_string(p.platform), p.bin_filename(&config.ffi_name), p.bin_filename(&config.ffi_name), lib.name))?;
226+
}
227+
228+
f.writeln(" </ItemGroup>")?;
229+
f.writeln("</Project>")?;
230+
}
231+
232+
// Transistive target file (simply points to the main one)
233+
{
234+
let mut filename = config.output_dir.clone();
235+
filename.push("buildTransitive");
236+
filename.push("net45");
237+
238+
fs::create_dir_all(&filename)?;
239+
240+
filename.push(&lib.name);
241+
filename.set_extension("targets");
242+
let mut f = FilePrinter::new(filename)?;
243+
244+
f.writeln("<?xml version=\"1.0\" encoding=\"utf-8\"?>")?;
245+
f.writeln("<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">")?;
246+
f.writeln(&format!(
247+
" <Import Project=\"$(MSBuildThisFileDirectory)../../build/net45/{}.targets\" />",
248+
lib.name
249+
))?;
250+
f.writeln("</Project>")?;
251+
}
252+
253+
Ok(())
254+
}
255+
193256
fn generate_native_functions(lib: &Library, config: &DotnetBindgenConfig) -> FormattingResult<()> {
194257
let mut filename = config.output_dir.clone();
195258
filename.push(NATIVE_FUNCTIONS_CLASSNAME);

generators/dotnet-oo-bindgen/src/wrappers.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,25 @@ pub(crate) fn generate_native_functions_class(
1818
namespaced(f, &lib.name, |f| {
1919
f.writeln(&format!("internal class {}", NATIVE_FUNCTIONS_CLASSNAME))?;
2020
blocked(f, |f| {
21+
f.writeln(&format!("const string VERSION = \"{}\";", lib.version))?;
22+
23+
// Static constructor used to verify the version
24+
f.writeln(&format!("static {}()", NATIVE_FUNCTIONS_CLASSNAME))?;
25+
blocked(f, |f| {
26+
f.writeln("var loadedVersion = Helpers.RustString.FromNative(version());")?;
27+
f.writeln("if (loadedVersion != VERSION)")?;
28+
blocked(f, |f| {
29+
f.writeln(&format!("throw new Exception(\"{} module version mismatch. Expected \" + VERSION + \" but loaded \" + loadedVersion);", lib.name))
30+
})
31+
})?;
32+
33+
f.newline()?;
34+
2135
for func in lib.native_functions() {
2236
f.newline()?;
2337
write_conversion_wrapper(f, func, &lib.c_ffi_prefix)?;
2438
}
39+
2540
Ok(())
2641
})?;
2742

generators/java-oo-bindgen/src/java/mod.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ fn generate_pom(lib: &Library, config: &JavaBindgenConfig) -> FormattingResult<(
100100
"<artifactId>{}</artifactId>",
101101
lib.name.to_kebab_case()
102102
))?;
103-
f.writeln(&format!("<version>{}</version>", lib.version.to_string()))?;
103+
f.writeln(&format!("<version>{}</version>", lib.version))?;
104104

105105
f.newline()?;
106106

@@ -219,8 +219,17 @@ fn generate_pom(lib: &Library, config: &JavaBindgenConfig) -> FormattingResult<(
219219
fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> FormattingResult<()> {
220220
let mut f = create_file(NATIVE_FUNCTIONS_CLASSNAME, config, lib)?;
221221

222+
f.newline()?;
223+
222224
f.writeln(&format!("class {}", NATIVE_FUNCTIONS_CLASSNAME))?;
223225
blocked(&mut f, |f| {
226+
f.writeln(&format!(
227+
"static final String VERSION = \"{}\";",
228+
lib.version
229+
))?;
230+
231+
f.newline()?;
232+
224233
// Load the library
225234
f.writeln("static")?;
226235
blocked(f, |f| {
@@ -278,6 +287,15 @@ fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> Form
278287
f.writeln("if(!loaded)")?;
279288
blocked(f, |f| {
280289
f.writeln("throw new Exception(\"Unable to load any of the included native library\");")
290+
})?;
291+
292+
f.newline()?;
293+
294+
// Check the loaded binary version
295+
f.writeln("String loadedVersion = version();")?;
296+
f.writeln("if (!loadedVersion.equals(VERSION))")?;
297+
blocked(f, |f| {
298+
f.writeln(&format!("throw new Exception(\"{} module version mismatch. Expected \" + VERSION + \" but loaded \" + loadedVersion);", lib.name))
281299
})
282300
})
283301
})?;

generators/java-oo-bindgen/src/rust/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ fn generate_toml(lib: &Library, config: &JavaBindgenConfig) -> FormattingResult<
7272

7373
f.writeln("[package]")?;
7474
f.writeln(&format!("name = \"{}\"", config.java_ffi_name()))?;
75-
f.writeln(&format!("version = \"{}\"", lib.version.to_string()))?;
75+
f.writeln(&format!("version = \"{}\"", lib.version))?;
7676
f.writeln("edition = \"2018\"")?;
7777
f.newline()?;
7878
f.writeln("[lib]")?;

oo-bindgen/src/doc.rs

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -440,17 +440,13 @@ fn validate_reference_with_params(
440440
if handle.find_method(method_name).is_none() {
441441
return Err(BindingError::DocInvalidReference {
442442
symbol_name: symbol_name.to_string(),
443-
ref_name: format!(
444-
"{}.{}()",
445-
class_name.to_string(),
446-
method_name.to_string()
447-
),
443+
ref_name: format!("{}.{}()", class_name, method_name),
448444
});
449445
}
450446
} else {
451447
return Err(BindingError::DocInvalidReference {
452448
symbol_name: symbol_name.to_string(),
453-
ref_name: format!("{}.{}()", class_name.to_string(), method_name.to_string()),
449+
ref_name: format!("{}.{}()", class_name, method_name),
454450
});
455451
}
456452
}
@@ -459,7 +455,7 @@ fn validate_reference_with_params(
459455
if handle.constructor.is_none() {
460456
return Err(BindingError::DocInvalidReference {
461457
symbol_name: symbol_name.to_string(),
462-
ref_name: format!("{}.[constructor]", class_name.to_string(),),
458+
ref_name: format!("{}.[constructor]", class_name),
463459
});
464460
}
465461
}
@@ -469,7 +465,7 @@ fn validate_reference_with_params(
469465
if handle.destructor.is_none() {
470466
return Err(BindingError::DocInvalidReference {
471467
symbol_name: symbol_name.to_string(),
472-
ref_name: format!("{}.[destructor]", class_name.to_string(),),
468+
ref_name: format!("{}.[destructor]", class_name),
473469
});
474470
}
475471
}
@@ -487,17 +483,13 @@ fn validate_reference_with_params(
487483
if handle.find_element(method_name).is_none() {
488484
return Err(BindingError::DocInvalidReference {
489485
symbol_name: symbol_name.to_string(),
490-
ref_name: format!(
491-
"{}.{}",
492-
struct_name.to_string(),
493-
method_name.to_string()
494-
),
486+
ref_name: format!("{}.{}", struct_name, method_name),
495487
});
496488
}
497489
} else {
498490
return Err(BindingError::DocInvalidReference {
499491
symbol_name: symbol_name.to_string(),
500-
ref_name: format!("{}.{}", struct_name.to_string(), method_name.to_string()),
492+
ref_name: format!("{}.{}", struct_name, method_name),
501493
});
502494
}
503495
}
@@ -506,17 +498,13 @@ fn validate_reference_with_params(
506498
if handle.find_method(element_name).is_none() {
507499
return Err(BindingError::DocInvalidReference {
508500
symbol_name: symbol_name.to_string(),
509-
ref_name: format!(
510-
"{}.{}()",
511-
struct_name.to_string(),
512-
element_name.to_string()
513-
),
501+
ref_name: format!("{}.{}()", struct_name, element_name),
514502
});
515503
}
516504
} else {
517505
return Err(BindingError::DocInvalidReference {
518506
symbol_name: symbol_name.to_string(),
519-
ref_name: format!("{}.{}()", struct_name.to_string(), element_name.to_string()),
507+
ref_name: format!("{}.{}()", struct_name, element_name),
520508
});
521509
}
522510
}
@@ -533,13 +521,13 @@ fn validate_reference_with_params(
533521
if handle.find_variant_by_name(variant_name).is_none() {
534522
return Err(BindingError::DocInvalidReference {
535523
symbol_name: symbol_name.to_string(),
536-
ref_name: format!("{}.{}", enum_name.to_string(), variant_name.to_string()),
524+
ref_name: format!("{}.{}", enum_name, variant_name),
537525
});
538526
}
539527
} else {
540528
return Err(BindingError::DocInvalidReference {
541529
symbol_name: symbol_name.to_string(),
542-
ref_name: format!("{}.{}", enum_name.to_string(), variant_name.to_string()),
530+
ref_name: format!("{}.{}", enum_name, variant_name),
543531
});
544532
}
545533
}
@@ -556,21 +544,13 @@ fn validate_reference_with_params(
556544
if handle.find_callback(method_name).is_none() {
557545
return Err(BindingError::DocInvalidReference {
558546
symbol_name: symbol_name.to_string(),
559-
ref_name: format!(
560-
"{}.{}()",
561-
interface_name.to_string(),
562-
method_name.to_string()
563-
),
547+
ref_name: format!("{}.{}()", interface_name, method_name),
564548
});
565549
}
566550
} else {
567551
return Err(BindingError::DocInvalidReference {
568552
symbol_name: symbol_name.to_string(),
569-
ref_name: format!(
570-
"{}.{}()",
571-
interface_name.to_string(),
572-
method_name.to_string()
573-
),
553+
ref_name: format!("{}.{}()", interface_name, method_name),
574554
});
575555
}
576556
}

oo-bindgen/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,13 @@ impl LibraryBuilder {
648648
}
649649
}
650650

651-
pub fn build(self) -> Result<Library> {
651+
pub fn build(mut self) -> Result<Library> {
652+
// Add the version function
653+
self.declare_native_function("version")?
654+
.return_type(ReturnType::new(Type::String, "Version number"))?
655+
.doc("Get the version of the library as a string")?
656+
.build()?;
657+
652658
// Update all native structs to full structs
653659
let mut structs = HashMap::with_capacity(self.defined_structs.len());
654660
for structure in self.defined_structs.values() {

tests/foo-ffi/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,9 @@ pub use strings::*;
2727
pub(crate) use structure::*;
2828

2929
pub mod ffi;
30+
31+
static VERSION: &str = concat!("1.2.3", "\0");
32+
33+
fn version() -> &'static std::ffi::CStr {
34+
unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(VERSION.as_bytes()) }
35+
}

0 commit comments

Comments
 (0)