Skip to content

Commit 6de10f8

Browse files
authored
Merge pull request #59 from stepfunc/feature/c-static-bindings
Add C static bindings to the CI pipeline.
2 parents 7196755 + 186d220 commit 6de10f8

File tree

18 files changed

+161
-81
lines changed

18 files changed

+161
-81
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,18 +170,23 @@ jobs:
170170
with:
171171
command: run
172172
args: --release --bin foo-bindings -- --java
173-
- name: Upload compiled C bindings (Windows)
173+
- name: Upload compiled FFI modules (Windows)
174174
if: ${{ runner.os == 'Windows' }}
175175
uses: actions/upload-artifact@v2
176176
with:
177177
name: ffi-modules
178178
path: tests/bindings/c/generated/x86_64-pc-windows-msvc/lib
179-
- name: Upload compiled C bindings (Linux)
179+
- name: Upload compiled FFI modules (Linux)
180180
if: ${{ runner.os == 'Linux' }}
181181
uses: actions/upload-artifact@v2
182182
with:
183183
name: ffi-modules
184184
path: tests/bindings/c/generated/x86_64-unknown-linux-gnu/lib
185+
- name: Upload C bindings
186+
uses: actions/upload-artifact@v2
187+
with:
188+
name: c-bindings
189+
path: tests/bindings/c/generated
185190
- name: Upload compiled Java bindings
186191
uses: actions/upload-artifact@v2
187192
with:
@@ -225,11 +230,16 @@ jobs:
225230
use-cross: true
226231
command: run
227232
args: --release --target ${{ matrix.target }} --bin foo-bindings -- --c --no-tests
228-
- name: Upload compiled C bindings
233+
- name: Upload compiled FFI modules
229234
uses: actions/upload-artifact@v2
230235
with:
231236
name: ffi-modules
232237
path: tests/bindings/c/generated/${{ matrix.target }}/lib
238+
- name: Upload C bindings
239+
uses: actions/upload-artifact@v2
240+
with:
241+
name: c-bindings
242+
path: tests/bindings/c/generated
233243
# Package all the generated bindings
234244
packaging:
235245
needs: [lock, bindings, cross]
@@ -259,11 +269,6 @@ jobs:
259269
with:
260270
command: run
261271
args: --bin foo-bindings -- --package ./ffi-modules -f dependencies.txt
262-
- name: Upload C bindings
263-
uses: actions/upload-artifact@v2
264-
with:
265-
name: c-bindings
266-
path: tests/bindings/c/generated
267272
- name: Upload .NET bindings
268273
uses: actions/upload-artifact@v2
269274
with:

ci-script/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ci-script"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
authors = ["Émile Grégoire <[email protected]>"]
55
edition = "2018"
66

ci-script/src/lib.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ fn run_builder<'a, B: BindingBuilder<'a>>(
107107
let mut platforms = PlatformLocations::new();
108108
if let Some(package_src) = package_src {
109109
let mut check_platform = |platform: Platform| {
110-
let platform_path = [package_src, platform.to_string()]
110+
let platform_path = [package_src, platform.as_string()]
111111
.iter()
112112
.collect::<PathBuf>();
113113
if platform_path.is_dir() {
@@ -158,10 +158,17 @@ fn run_builder<'a, B: BindingBuilder<'a>>(
158158
}
159159

160160
pub struct BindingBuilderSettings<'a> {
161+
/// FFI target name (as specified in with `cargo build -p <...>`)
162+
pub ffi_target_name: &'a str,
163+
/// Compiled FFI name (usually the same as `ffi_target_name`, but with hyphens replaced by underscores)
161164
pub ffi_name: &'a str,
165+
/// Path to the FFI target
162166
pub ffi_path: &'a Path,
167+
/// Name of the Java group (e.g. `io.stepfunc`)
163168
pub java_group_id: &'a str,
169+
/// Destination path
164170
pub destination_path: &'a Path,
171+
/// Library to build
165172
pub library: &'a Library,
166173
}
167174

@@ -189,9 +196,11 @@ impl<'a> CBindingBuilder<'a> {
189196
fn build_doxygen(&self) {
190197
let config = c_oo_bindgen::CBindgenConfig {
191198
output_dir: self.output_dir(),
199+
ffi_target_name: self.settings.ffi_target_name.to_owned(),
192200
ffi_name: self.settings.ffi_name.to_owned(),
201+
is_release: env!("PROFILE") == "release",
193202
extra_files: Vec::new(),
194-
platforms: self.platforms.clone(),
203+
platform_location: self.platforms.iter().next().unwrap(),
195204
};
196205

197206
c_oo_bindgen::generate_doxygen(&self.settings.library, &config)
@@ -235,15 +244,19 @@ impl<'a> BindingBuilder<'a> for CBindingBuilder<'a> {
235244
}
236245

237246
fn generate(&mut self, _is_packaging: bool) {
238-
let config = c_oo_bindgen::CBindgenConfig {
239-
output_dir: self.output_dir(),
240-
ffi_name: self.settings.ffi_name.to_owned(),
241-
extra_files: self.extra_files.clone(),
242-
platforms: self.platforms.clone(),
243-
};
244-
245-
c_oo_bindgen::generate_c_package(&self.settings.library, &config)
246-
.expect("failed to package C lib");
247+
for platform in self.platforms.iter() {
248+
let config = c_oo_bindgen::CBindgenConfig {
249+
output_dir: self.output_dir(),
250+
ffi_target_name: self.settings.ffi_target_name.to_owned(),
251+
ffi_name: self.settings.ffi_name.to_owned(),
252+
is_release: env!("PROFILE") == "release",
253+
extra_files: self.extra_files.clone(),
254+
platform_location: platform.clone(),
255+
};
256+
257+
c_oo_bindgen::generate_c_package(&self.settings.library, &config)
258+
.expect("failed to package C lib");
259+
}
247260
}
248261

249262
fn build(&mut self) {
@@ -265,7 +278,7 @@ impl<'a> BindingBuilder<'a> for CBindingBuilder<'a> {
265278
// CMake build
266279
let result = Command::new("cmake")
267280
.current_dir(&build_dir)
268-
.args(&["--build", "."])
281+
.args(&["--build", ".", "--config", "Debug"])
269282
.status()
270283
.unwrap();
271284
assert!(result.success());

generators/c-oo-bindgen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "c-oo-bindgen"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
authors = ["Émile Grégoire <[email protected]>"]
55
edition = "2018"
66

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

Lines changed: 94 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ clippy::all
3939
#![forbid(
4040
unsafe_code,
4141
// intra_doc_link_resolution_failure, broken_intra_doc_links
42-
safe_packed_borrows,
42+
unaligned_references,
4343
while_true,
4444
bare_trait_objects
4545
)]
@@ -159,51 +159,49 @@ impl CFormatting for ReturnType {
159159

160160
pub struct CBindgenConfig {
161161
pub output_dir: PathBuf,
162+
pub ffi_target_name: String,
162163
pub ffi_name: String,
164+
pub is_release: bool,
163165
pub extra_files: Vec<PathBuf>,
164-
pub platforms: PlatformLocations,
166+
pub platform_location: PlatformLocation,
165167
}
166168

167169
pub fn generate_c_package(lib: &Library, config: &CBindgenConfig) -> FormattingResult<()> {
168-
for platform in config.platforms.iter() {
169-
generate_single_package(lib, config, &platform)?;
170-
}
171-
172-
Ok(())
173-
}
174-
175-
fn generate_single_package(
176-
lib: &Library,
177-
config: &CBindgenConfig,
178-
platform_location: &PlatformLocation,
179-
) -> FormattingResult<()> {
180170
let output_dir = config
181171
.output_dir
182-
.join(platform_location.platform.to_string());
172+
.join(config.platform_location.platform.as_string());
183173

184174
// Create header file
185175
let include_path = output_dir.join("include");
186176
generate_c_header(lib, include_path)?;
187177

188178
// Generate CMake config file
189-
generate_cmake_config(lib, config, &platform_location)?;
179+
generate_cmake_config(lib, config, &config.platform_location)?;
190180

191181
// Copy lib files (lib and DLL on Windows, .so on Linux)
192182
let lib_path = output_dir
193183
.join("lib")
194-
.join(platform_location.platform.to_string());
184+
.join(config.platform_location.platform.as_string());
195185
fs::create_dir_all(&lib_path)?;
196186

197-
let lib_filename = platform_location.lib_filename(&config.ffi_name);
187+
let lib_filename = config
188+
.platform_location
189+
.static_lib_filename(&config.ffi_name);
198190
fs::copy(
199-
platform_location.location.join(&lib_filename),
191+
config.platform_location.location.join(&lib_filename),
192+
lib_path.join(&lib_filename),
193+
)?;
194+
195+
let lib_filename = config.platform_location.dyn_lib_filename(&config.ffi_name);
196+
fs::copy(
197+
config.platform_location.location.join(&lib_filename),
200198
lib_path.join(&lib_filename),
201199
)?;
202200

203201
// Copy DLL on Windows
204-
let bin_filename = platform_location.bin_filename(&config.ffi_name);
202+
let bin_filename = config.platform_location.bin_filename(&config.ffi_name);
205203
fs::copy(
206-
platform_location.location.join(&bin_filename),
204+
config.platform_location.location.join(&bin_filename),
207205
lib_path.join(&bin_filename),
208206
)?;
209207

@@ -243,7 +241,7 @@ pub fn generate_doxygen(lib: &Library, config: &CBindgenConfig) -> FormattingRes
243241
.write_all(
244242
&format!(
245243
"INPUT = {}/include\n",
246-
config.platforms.iter().next().unwrap().platform.to_string()
244+
config.platform_location.platform.as_string()
247245
)
248246
.into_bytes(),
249247
)
@@ -1002,30 +1000,100 @@ fn generate_cmake_config(
10021000
// Create file
10031001
let cmake_path = config
10041002
.output_dir
1005-
.join(platform_location.platform.to_string())
1003+
.join(platform_location.platform.as_string())
10061004
.join("cmake");
10071005
fs::create_dir_all(&cmake_path)?;
10081006
let filename = cmake_path.join(format!("{}-config.cmake", lib.name));
10091007
let mut f = FilePrinter::new(filename)?;
10101008

1009+
let link_deps = get_link_dependencies(config);
1010+
10111011
// Prefix used everywhere else
10121012
f.writeln("set(prefix \"${CMAKE_CURRENT_LIST_DIR}/../\")")?;
10131013
f.newline()?;
10141014

1015+
// Write dynamic library version
10151016
f.writeln(&format!("add_library({} SHARED IMPORTED GLOBAL)", lib.name))?;
10161017
f.writeln(&format!("set_target_properties({} PROPERTIES", lib.name))?;
10171018
indented(&mut f, |f| {
10181019
f.writeln(&format!(
10191020
"IMPORTED_LOCATION \"${{prefix}}/lib/{}/{}\"",
1020-
platform_location.platform.to_string(),
1021+
platform_location.platform.as_string(),
10211022
platform_location.bin_filename(&config.ffi_name)
10221023
))?;
10231024
f.writeln(&format!(
10241025
"IMPORTED_IMPLIB \"${{prefix}}/lib/{}/{}\"",
1025-
platform_location.platform.to_string(),
1026-
platform_location.lib_filename(&config.ffi_name)
1026+
platform_location.platform.as_string(),
1027+
platform_location.dyn_lib_filename(&config.ffi_name)
10271028
))?;
10281029
f.writeln("INTERFACE_INCLUDE_DIRECTORIES \"${prefix}/include\"")
10291030
})?;
1031+
f.writeln(")")?;
1032+
1033+
f.newline()?;
1034+
1035+
// Write static library
1036+
f.writeln(&format!(
1037+
"add_library({}_static STATIC IMPORTED GLOBAL)",
1038+
lib.name
1039+
))?;
1040+
f.writeln(&format!(
1041+
"set_target_properties({}_static PROPERTIES",
1042+
lib.name
1043+
))?;
1044+
indented(&mut f, |f| {
1045+
f.writeln(&format!(
1046+
"IMPORTED_LOCATION \"${{prefix}}/lib/{}/{}\"",
1047+
platform_location.platform.as_string(),
1048+
platform_location.static_lib_filename(&config.ffi_name)
1049+
))?;
1050+
f.writeln("INTERFACE_INCLUDE_DIRECTORIES \"${prefix}/include\"")?;
1051+
f.writeln(&format!(
1052+
"INTERFACE_LINK_LIBRARIES \"{}\"",
1053+
link_deps.join(";")
1054+
))
1055+
})?;
10301056
f.writeln(")")
10311057
}
1058+
1059+
fn get_link_dependencies(config: &CBindgenConfig) -> Vec<String> {
1060+
let mut args = Vec::from(["rustc", "-p", &config.ffi_target_name]);
1061+
1062+
if config.is_release {
1063+
args.push("--release");
1064+
}
1065+
1066+
args.extend(&["--", "--print", "native-static-libs"]);
1067+
1068+
let output = Command::new("cargo")
1069+
.args(&args)
1070+
.output()
1071+
.expect("failed to run cargo");
1072+
1073+
if !output.status.success() {
1074+
panic!("failed to get the link dependencies");
1075+
}
1076+
1077+
// It prints to stderr for some reason
1078+
let result = String::from_utf8_lossy(&output.stderr);
1079+
1080+
// Find where the libs are written
1081+
const PATTERN: &str = "native-static-libs: ";
1082+
let pattern_idx = result
1083+
.find(PATTERN)
1084+
.expect("failed to parse link dependencies");
1085+
let deps = &result[pattern_idx + PATTERN.len()..result.len()];
1086+
let endline = deps.find('\n').expect("failed to parse link dependencies");
1087+
let deps = &deps[0..endline];
1088+
1089+
// Extract the libs
1090+
let mut result = deps
1091+
.split_whitespace()
1092+
.map(|x| x.to_owned())
1093+
.collect::<Vec<_>>();
1094+
1095+
// Remove duplicates
1096+
result.dedup();
1097+
1098+
result
1099+
}

generators/dotnet-oo-bindgen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "dotnet-oo-bindgen"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
authors = ["Émile Grégoire <[email protected]>"]
55
edition = "2018"
66

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ clippy::all
3939
#![forbid(
4040
unsafe_code,
4141
//intra_doc_link_resolution_failure, broken_intra_doc_links
42-
safe_packed_borrows,
42+
unaligned_references,
4343
while_true,
4444
bare_trait_objects
4545
)]

generators/java-oo-bindgen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "java-oo-bindgen"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
authors = ["Émile Grégoire <[email protected]>"]
55
edition = "2018"
66

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub fn generate_java_bindings(lib: &Library, config: &JavaBindgenConfig) -> Form
3737
.filter(|x| SUPPORTED_PLATFORMS.iter().any(|y| *y == x.platform))
3838
{
3939
let mut target_dir = config.java_resource_dir();
40-
target_dir.push(platform.platform.to_string());
40+
target_dir.push(platform.platform.as_string());
4141
fs::create_dir_all(&target_dir)?;
4242

4343
let mut source_file = platform.location.clone();
@@ -234,7 +234,7 @@ fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> Form
234234
blocked(f, |f| {
235235
f.writeln(&format!(
236236
"loadLibrary(\"{}\", \"{}\", \"dll\");",
237-
platform.platform.to_string(),
237+
platform.platform.as_string(),
238238
libname
239239
))
240240
})?;
@@ -244,7 +244,7 @@ fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> Form
244244
blocked(f, |f| {
245245
f.writeln(&format!(
246246
"loadLibrary(\"{}\", \"lib{}\", \"so\");",
247-
platform.platform.to_string(),
247+
platform.platform.as_string(),
248248
libname
249249
))
250250
})?;

0 commit comments

Comments
 (0)