Skip to content

Commit f3da890

Browse files
authored
Merge pull request #41 from stepfunc/feature/ci-musl
Add musl generator in the CI
2 parents 6598930 + efc79ec commit f3da890

File tree

8 files changed

+144
-39
lines changed

8 files changed

+144
-39
lines changed

.cargo/config-linux-musl.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build]
2+
target = "x86_64-unknown-linux-musl"
3+
rustflags = ["-C", "target-feature=+crt-static"]

.github/workflows/ci.yml

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,43 @@ jobs:
1616
- stable
1717
- beta
1818
- nightly
19+
toolchain:
20+
- default
21+
- musl
22+
exclude:
23+
- os: windows-latest
24+
toolchain: musl
1925
runs-on: ${{ matrix.os }}
2026
steps:
2127
- name: Checkout
2228
uses: actions/checkout@v1
2329
- name: Install Rust ${{ matrix.rust }}
30+
if: ${{ matrix.toolchain != 'musl' }}
2431
uses: actions-rs/toolchain@v1
2532
with:
2633
profile: minimal
2734
toolchain: ${{ matrix.rust }}
2835
override: true
36+
- name: Install Rust ${{ matrix.rust }} (musl)
37+
if: ${{ matrix.toolchain == 'musl' }}
38+
uses: actions-rs/toolchain@v1
39+
with:
40+
profile: minimal
41+
toolchain: ${{ matrix.rust }}
42+
target: x86_64-unknown-linux-musl
43+
override: true
2944
- name: Copy Windows config
3045
if: ${{ runner.os == 'Windows' }}
3146
shell: pwsh
3247
run: Copy-Item -Path .cargo/config-windows.toml -Destination .cargo/config.toml
3348
- name: Copy Linux config
34-
if: ${{ runner.os == 'Linux' }}
49+
if: ${{ runner.os == 'Linux' && matrix.toolchain == 'default' }}
3550
shell: pwsh
3651
run: Copy-Item -Path .cargo/config-linux.toml -Destination .cargo/config.toml
52+
- name: Copy Linux musl config
53+
if: ${{ runner.os == 'Linux' && matrix.toolchain == 'musl' }}
54+
shell: pwsh
55+
run: Copy-Item -Path .cargo/config-linux-musl.toml -Destination .cargo/config.toml
3756
- name: Run Rust unit tests
3857
uses: actions-rs/cargo@v1
3958
with:
@@ -44,11 +63,13 @@ jobs:
4463
command: run
4564
args: --release --bin foo-bindings -- --c
4665
- name: .NET bindings
66+
if: ${{ matrix.toolchain != 'musl' }}
4767
uses: actions-rs/cargo@v1
4868
with:
4969
command: run
5070
args: --release --bin foo-bindings -- --dotnet
5171
- name: Java bindings
72+
if: ${{ matrix.toolchain != 'musl' }}
5273
uses: actions-rs/cargo@v1
5374
with:
5475
command: run
@@ -60,7 +81,7 @@ jobs:
6081
name: ffi-modules
6182
path: tests/bindings/c/generated/lib
6283
- name: Upload compiled Java bindings
63-
if: ${{ matrix.rust == 'stable' }}
84+
if: ${{ matrix.rust == 'stable' && matrix.toolchain != 'musl' }}
6485
uses: actions/upload-artifact@v2
6586
with:
6687
name: ffi-modules

ci-script/src/lib.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,25 +80,25 @@ fn run_builder<'a, B: BindingBuilder<'a>>(
8080
) -> B {
8181
let mut platforms = PlatformLocations::new();
8282
if let Some(package_src) = package_src {
83-
let platform_path = [package_src, Platform::Linux.to_string()]
83+
let platform_path = [package_src, Platform::Win64.to_string()]
8484
.iter()
8585
.collect::<PathBuf>();
8686
if platform_path.is_dir() {
87-
platforms.add(Platform::Linux, platform_path);
87+
platforms.add(Platform::Win64, platform_path);
8888
}
8989

90-
let platform_path = [package_src, Platform::Win64.to_string()]
90+
let platform_path = [package_src, Platform::Linux.to_string()]
9191
.iter()
9292
.collect::<PathBuf>();
9393
if platform_path.is_dir() {
94-
platforms.add(Platform::Win64, platform_path);
94+
platforms.add(Platform::Linux, platform_path);
9595
}
9696

97-
let platform_path = [package_src, Platform::Win32.to_string()]
97+
let platform_path = [package_src, Platform::LinuxMusl.to_string()]
9898
.iter()
9999
.collect::<PathBuf>();
100100
if platform_path.is_dir() {
101-
platforms.add(Platform::Win32, platform_path);
101+
platforms.add(Platform::LinuxMusl, platform_path);
102102
}
103103
} else {
104104
platforms.add(Platform::current(), ffi_path());
@@ -108,7 +108,18 @@ fn run_builder<'a, B: BindingBuilder<'a>>(
108108
panic!("No platforms found!");
109109
}
110110

111+
let has_dynamic_libs = platforms.has_dynamic_lib();
112+
111113
let mut builder = B::new(settings, platforms);
114+
115+
if B::requires_dynamic_lib() && !has_dynamic_libs {
116+
println!(
117+
"Skipping {} because it requires dynamic libraries",
118+
B::name()
119+
);
120+
return builder;
121+
}
122+
112123
builder.generate(package_src.is_some());
113124

114125
if package_src.is_none() {
@@ -132,6 +143,8 @@ pub struct BindingBuilderSettings<'a> {
132143
}
133144

134145
trait BindingBuilder<'a> {
146+
fn name() -> &'static str;
147+
fn requires_dynamic_lib() -> bool;
135148
fn new(settings: &'a BindingBuilderSettings<'a>, platforms: PlatformLocations) -> Self;
136149
fn generate(&mut self, is_packaging: bool);
137150
fn build(&mut self);
@@ -175,6 +188,14 @@ impl<'a> CBindingBuilder<'a> {
175188
}
176189

177190
impl<'a> BindingBuilder<'a> for CBindingBuilder<'a> {
191+
fn name() -> &'static str {
192+
"c"
193+
}
194+
195+
fn requires_dynamic_lib() -> bool {
196+
false
197+
}
198+
178199
fn new(settings: &'a BindingBuilderSettings<'a>, platforms: PlatformLocations) -> Self {
179200
Self {
180201
settings,
@@ -256,6 +277,14 @@ impl<'a> DotnetBindingBuilder<'a> {
256277
}
257278

258279
impl<'a> BindingBuilder<'a> for DotnetBindingBuilder<'a> {
280+
fn name() -> &'static str {
281+
"dotnet"
282+
}
283+
284+
fn requires_dynamic_lib() -> bool {
285+
true
286+
}
287+
259288
fn new(settings: &'a BindingBuilderSettings<'a>, platforms: PlatformLocations) -> Self {
260289
Self {
261290
settings,
@@ -359,6 +388,14 @@ impl<'a> JavaBindingBuilder<'a> {
359388
}
360389

361390
impl<'a> BindingBuilder<'a> for JavaBindingBuilder<'a> {
391+
fn name() -> &'static str {
392+
"java"
393+
}
394+
395+
fn requires_dynamic_lib() -> bool {
396+
true
397+
}
398+
362399
fn new(settings: &'a BindingBuilderSettings<'a>, platforms: PlatformLocations) -> Self {
363400
Self {
364401
settings,

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

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -785,11 +785,44 @@ fn generate_cmake_config(lib: &Library, config: &CBindgenConfig) -> FormattingRe
785785

786786
// Write each platform variation
787787
let mut is_first_if = true;
788+
789+
// Add a config value if we have two linux versions
790+
let has_static_choice =
791+
if config.platforms.linux.is_some() && config.platforms.linux_musl.is_some() {
792+
f.writeln(&format!(
793+
"set({}_STATIC_MUSL OFF CACHE BOOL \"Use statically built musl lib on Linux for {}\")",
794+
lib.name.to_shouty_snake_case(),
795+
lib.name
796+
))?;
797+
f.newline()?;
798+
true
799+
} else {
800+
false
801+
};
802+
788803
for p in config.platforms.iter() {
789804
let platform_check = match p.platform {
790-
Platform::Win64 => "WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8",
791-
Platform::Win32 => "WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4",
792-
Platform::Linux => "UNIX AND CMAKE_SIZEOF_VOID_P EQUAL 8",
805+
Platform::Win64 => "WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8".to_string(),
806+
Platform::Linux => {
807+
if !has_static_choice {
808+
"UNIX AND CMAKE_SIZEOF_VOID_P EQUAL 8".to_string()
809+
} else {
810+
format!(
811+
"UNIX AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT $CACHE{{{}_STATIC_MUSL}}",
812+
lib.name.to_shouty_snake_case()
813+
)
814+
}
815+
}
816+
Platform::LinuxMusl => {
817+
if !has_static_choice {
818+
"UNIX AND CMAKE_SIZEOF_VOID_P EQUAL 8".to_string()
819+
} else {
820+
format!(
821+
"UNIX AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND $CACHE{{{}_STATIC_MUSL}}",
822+
lib.name.to_shouty_snake_case()
823+
)
824+
}
825+
}
793826
};
794827

795828
if is_first_if {

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ fn generate_csproj(lib: &Library, config: &DotnetBindgenConfig) -> FormattingRes
110110
f.newline()?;
111111
f.writeln(" <ItemGroup>")?;
112112

113-
for p in config.platforms.iter() {
113+
for p in config
114+
.platforms
115+
.iter()
116+
.filter(|x| x.platform != Platform::LinuxMusl)
117+
{
114118
let filename = p.bin_filename(&config.ffi_name);
115119
let filepath = dunce::canonicalize(p.location.join(&filename))?;
116120
f.writeln(&format!(" <Content Include=\"{}\" Link=\"{}\" Pack=\"true\" PackagePath=\"runtimes/{}/native\" CopyToOutputDirectory=\"PreserveNewest\" />", filepath.to_string_lossy(), filename, p.platform.to_string()))?;

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

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ pub fn generate_java_bindings(lib: &Library, config: &JavaBindgenConfig) -> Form
2929
// Copy the compiled libraries to the resource folder
3030
let mut ffi_name = config.ffi_name.clone();
3131
ffi_name.push_str("_java");
32-
for platform in config.platforms.iter() {
32+
for platform in config
33+
.platforms
34+
.iter()
35+
.filter(|x| x.platform != Platform::LinuxMusl)
36+
{
3337
let mut target_dir = config.java_resource_dir();
3438
target_dir.push(platform.platform.to_string());
3539
fs::create_dir_all(&target_dir)?;
@@ -127,16 +131,6 @@ fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> Form
127131
))
128132
})?;
129133
}
130-
Platform::Win32 => {
131-
f.writeln("if(org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS && org.apache.commons.lang3.ArchUtils.getProcessor().is32Bit())")?;
132-
blocked(f, |f| {
133-
f.writeln(&format!(
134-
"loadLibrary(\"{}\", \"{}\", \"dll\");",
135-
platform.platform.to_string(),
136-
libname
137-
))
138-
})?;
139-
}
140134
Platform::Linux => {
141135
f.writeln("if(org.apache.commons.lang3.SystemUtils.IS_OS_LINUX && org.apache.commons.lang3.ArchUtils.getProcessor().is64Bit())")?;
142136
blocked(f, |f| {
@@ -147,6 +141,7 @@ fn generate_native_func_class(lib: &Library, config: &JavaBindgenConfig) -> Form
147141
))
148142
})?;
149143
}
144+
Platform::LinuxMusl => (), // We do not generate Java bindings for Linux musl
150145
}
151146
}
152147
Ok(())

oo-bindgen/src/platforms.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,36 @@ use std::path::PathBuf;
33
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
44
pub enum Platform {
55
Win64,
6-
Win32,
76
Linux,
7+
LinuxMusl,
88
}
99

1010
impl Platform {
1111
pub fn current() -> Self {
12-
if cfg!(target_os = "windows") && cfg!(target_pointer_width = "32") {
13-
return Self::Win32;
14-
}
1512
if cfg!(target_os = "windows") && cfg!(target_pointer_width = "64") {
1613
return Self::Win64;
1714
}
18-
if cfg!(target_os = "linux") && cfg!(target_pointer_width = "64") {
15+
if cfg!(target_os = "linux")
16+
&& cfg!(target_pointer_width = "64")
17+
&& !cfg!(target_env = "musl")
18+
{
1919
return Self::Linux;
2020
}
21+
if cfg!(target_os = "linux")
22+
&& cfg!(target_pointer_width = "64")
23+
&& cfg!(target_env = "musl")
24+
{
25+
return Self::LinuxMusl;
26+
}
2127

2228
unimplemented!("Current platform is not supported")
2329
}
2430

2531
pub fn to_string(&self) -> &'static str {
2632
match self {
2733
Self::Win64 => "win-x64",
28-
Self::Win32 => "win-x32",
2934
Self::Linux => "linux",
35+
Self::LinuxMusl => "linux-musl",
3036
}
3137
}
3238
}
@@ -43,40 +49,42 @@ impl PlatformLocation {
4349

4450
pub fn lib_filename<T: AsRef<str>>(&self, libname: T) -> String {
4551
match self.platform {
46-
Platform::Win64 | Platform::Win32 => format!("{}.dll.lib", libname.as_ref()),
52+
Platform::Win64 => format!("{}.dll.lib", libname.as_ref()),
4753
Platform::Linux => format!("lib{}.so", libname.as_ref()),
54+
Platform::LinuxMusl => format!("lib{}.a", libname.as_ref()),
4855
}
4956
}
5057

5158
pub fn bin_filename<T: AsRef<str>>(&self, libname: T) -> String {
5259
match self.platform {
53-
Platform::Win64 | Platform::Win32 => format!("{}.dll", libname.as_ref()),
60+
Platform::Win64 => format!("{}.dll", libname.as_ref()),
5461
Platform::Linux => format!("lib{}.so", libname.as_ref()),
62+
Platform::LinuxMusl => format!("lib{}.a", libname.as_ref()),
5563
}
5664
}
5765
}
5866

5967
#[derive(Clone)]
6068
pub struct PlatformLocations {
6169
pub win64: Option<PathBuf>,
62-
pub win32: Option<PathBuf>,
6370
pub linux: Option<PathBuf>,
71+
pub linux_musl: Option<PathBuf>,
6472
}
6573

6674
impl PlatformLocations {
6775
pub fn new() -> Self {
6876
PlatformLocations {
6977
win64: None,
70-
win32: None,
7178
linux: None,
79+
linux_musl: None,
7280
}
7381
}
7482

7583
pub fn add(&mut self, platform: Platform, location: PathBuf) {
7684
match platform {
7785
Platform::Win64 => self.win64 = Some(location),
78-
Platform::Win32 => self.win32 = Some(location),
7986
Platform::Linux => self.linux = Some(location),
87+
Platform::LinuxMusl => self.linux_musl = Some(location),
8088
}
8189
}
8290

@@ -85,17 +93,21 @@ impl PlatformLocations {
8593
if let Some(loc) = &self.win64 {
8694
vec.push(PlatformLocation::new(Platform::Win64, loc.clone()))
8795
}
88-
if let Some(loc) = &self.win32 {
89-
vec.push(PlatformLocation::new(Platform::Win32, loc.clone()))
90-
}
9196
if let Some(loc) = &self.linux {
9297
vec.push(PlatformLocation::new(Platform::Linux, loc.clone()))
9398
}
99+
if let Some(loc) = &self.linux_musl {
100+
vec.push(PlatformLocation::new(Platform::LinuxMusl, loc.clone()))
101+
}
94102
vec.into_iter()
95103
}
96104

97105
pub fn is_empty(&self) -> bool {
98-
self.win64.is_none() && self.win32.is_none() && self.linux.is_none()
106+
self.win64.is_none() && self.linux.is_none() && self.linux_musl.is_none()
107+
}
108+
109+
pub fn has_dynamic_lib(&self) -> bool {
110+
self.win64.is_some() || self.linux.is_some()
99111
}
100112
}
101113

0 commit comments

Comments
 (0)