Skip to content

Commit a664a76

Browse files
committed
ci: add musl build step
1 parent d5022a1 commit a664a76

File tree

8 files changed

+150
-21
lines changed

8 files changed

+150
-21
lines changed

.cargo/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ linker = "rust-lld"
66

77
[target.i686-pc-windows-msvc]
88
linker = "rust-lld"
9+
10+
[target.'cfg(target_env = "musl")']
11+
rustflags = ["-C", "target-feature=-crt-static"]

.github/action/musl/Dockerfile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
ARG PHP_VERSION=8.4
2+
ARG TS=-zts
3+
4+
FROM php:${PHP_VERSION}${TS}-alpine
5+
6+
RUN apk add --no-cache \
7+
llvm17 \
8+
llvm17-dev \
9+
llvm17-libs \
10+
llvm17-static \
11+
clang17 \
12+
clang17-dev \
13+
clang17-static \
14+
curl
15+
16+
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
17+
ENV PATH="/root/.cargo/bin:${PATH}"
18+
19+
RUN rustup target add x86_64-unknown-linux-musl
20+
RUN cargo install cargo-expand --locked
21+
22+
ENV PHP=/usr/local/bin/php
23+
ENV PHP_CONFIG=/usr/local/bin/php-config
24+
25+
ENV LLVM_CONFIG_PATH=/usr/lib/llvm17/bin/llvm-config
26+
ENV LIBCLANG_PATH=/usr/lib/llvm17/lib
27+
ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/lib
28+
ENV RUSTFLAGS="-C target-feature=-crt-static -C link-arg=-Wl,-rpath,/usr/local/lib -L /usr/local/lib"
29+
30+
WORKDIR /workspace
31+
32+
COPY . .
33+
34+
ENTRYPOINT ["cargo"]
35+
CMD ["build", "--release", "--no-default-features", "--features", "closure,anyhow,runtime,enum", "--workspace", "--target", "x86_64-unknown-linux-musl"]

.github/workflows/build.yml

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ jobs:
168168
# Macos fails on unstable rust. We skip the inline examples test for now.
169169
if: "!(contains(matrix.os, 'macos') && matrix.rust == 'nightly')"
170170
run: cargo test --release --workspace --features closure,anyhow,runtime --no-fail-fast
171-
172171
test-embed:
173172
name: Test with embed
174173
runs-on: ubuntu-latest
@@ -226,3 +225,45 @@ jobs:
226225
227226
- name: Test with embed feature
228227
run: cargo test --workspace --release --features closure,embed,anyhow --no-fail-fast
228+
229+
build-musl:
230+
name: musl / ${{ matrix.php }} / ${{ matrix.phpts[1] }}
231+
runs-on: ubuntu-latest
232+
strategy:
233+
matrix:
234+
php: ["8.1", "8.2", "8.3", "8.4"]
235+
phpts: [["-zts", "TS"], ["", "NTS"]]
236+
env:
237+
CARGO_TERM_COLOR: always
238+
steps:
239+
- name: Checkout code
240+
uses: actions/checkout@v5
241+
- name: Setup DockerX
242+
uses: docker/setup-buildx-action@v3
243+
- name: Build
244+
uses: docker/build-push-action@v6
245+
with:
246+
context: .github/action/musl
247+
file: .github/action/musl/Dockerfile
248+
tags: |
249+
extphprs/ext-php-rs:musl-${{ matrix.php }}-${{ matrix.phpts[1] }}
250+
push: false
251+
load: true
252+
platforms: linux/amd64
253+
build-args: |
254+
PHP_VERSION=${{ matrix.php }}
255+
TS=${{ matrix.phpts[0] }}
256+
- name: Build
257+
run: |
258+
docker run \
259+
-v $(pwd):/workspace \
260+
-w /workspace \
261+
extphprs/ext-php-rs:musl-${{ matrix.php }}-${{ matrix.phpts[1] }} \
262+
build --release --features closure,anyhow,runtime --workspace
263+
- name: Run tests
264+
run: |
265+
docker run \
266+
-v $(pwd):/workspace \
267+
-w /workspace \
268+
extphprs/ext-php-rs:musl-${{ matrix.php }}-${{ matrix.phpts[1] }} \
269+
test --workspace --release --features closure,anyhow,runtime --no-fail-fast

Dockerfile

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,20 @@ apt update -y
88
apt install -y \
99
libclang-dev \
1010
bison \
11-
re2c
11+
re2c \
12+
curl \
13+
jq
14+
15+
# Download and extract PHP
16+
FULL_VERSION=$(curl -fsSL "https://www.php.net/releases/index.php?json&version=${PHP_VERSION}" | jq -r '.version')
17+
echo "Downloading PHP ${FULL_VERSION}..."
18+
curl -fsSL "https://www.php.net/distributions/php-${FULL_VERSION}.tar.gz" -o php.tar.gz
19+
tar -xzf php.tar.gz
20+
rm php.tar.gz
21+
mv "php-${FULL_VERSION}" php-src
1222

1323
# Build PHP
14-
git clone --depth 1 -b PHP-${PHP_VERSION} https://github.com/php/php-src.git
1524
cd php-src
16-
# by default you will be on the master branch, which is the current
17-
# development version. You can check out a stable branch instead:
18-
./buildconf
1925
./configure \
2026
--enable-debug \
2127
--disable-all --disable-cgi

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ best resource at the moment. This can be viewed at [docs.rs].
126126
1.57 at the time of writing.
127127
- Clang 5.0 or later.
128128

129+
### Alpine Linux (musl)
130+
131+
Building for Alpine Linux (musl libc) is supported on stable Rust with dynamic linking
132+
thanks to `runtime` feature flag from `bindgen`.
133+
134+
**Note**: Building for musl requires dynamic CRT linking (`-crt-static` flag) to produce
135+
the `cdylib` output required for PHP extensions.
136+
If you want to build statically, you'll need full LLVM + Clang toolchain.
137+
Please read: <https://github.com/KyleMayes/clang-sys#static>
138+
129139
### Windows Requirements
130140

131141
- Extensions can only be compiled for PHP installations sourced from

tests/Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
[package]
22
name = "tests"
33
version = "0.0.0"
4-
edition = "2021"
4+
edition = "2024"
55
publish = false
66
license = "MIT OR Apache-2.0"
77

88
[dependencies]
9-
ext-php-rs = { path = "../", default-features = false, features = ["closure", "runtime"] }
9+
ext-php-rs = { path = "../", default-features = false }
1010

1111
[features]
12-
default = ["enum"]
12+
default = ["enum", "runtime", "closure"]
1313
enum = ["ext-php-rs/enum"]
14+
anyhow = ["ext-php-rs/anyhow"]
15+
runtime = ["ext-php-rs/runtime"]
16+
closure = ["ext-php-rs/closure"]
17+
static = ["ext-php-rs/static"]
1418

1519
[lib]
1620
crate-type = ["cdylib"]

tests/src/integration/mod.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,41 @@ mod test {
3131
fn setup() {
3232
BUILD.call_once(|| {
3333
let mut command = Command::new("cargo");
34-
command.arg("build").arg("--no-default-features");
35-
#[cfg(feature = "enum")]
34+
command.arg("build");
35+
36+
#[cfg(not(debug_assertions))]
37+
command.arg("--release");
38+
39+
// Build features list dynamically based on compiled features
40+
// Note: Using vec_init_then_push pattern here is intentional due to conditional compilation
41+
#[allow(clippy::vec_init_then_push)]
3642
{
37-
command.arg("--features=enum");
43+
let mut features = vec![];
44+
#[cfg(feature = "enum")]
45+
features.push("enum");
46+
#[cfg(feature = "closure")]
47+
features.push("closure");
48+
#[cfg(feature = "anyhow")]
49+
features.push("anyhow");
50+
#[cfg(feature = "runtime")]
51+
features.push("runtime");
52+
#[cfg(feature = "static")]
53+
features.push("static");
54+
55+
if !features.is_empty() {
56+
command.arg("--no-default-features");
57+
command.arg("--features").arg(features.join(","));
58+
}
3859
}
39-
assert!(command
40-
.output()
41-
.expect("failed to build extension")
42-
.status
43-
.success());
60+
61+
let result = command.output().expect("failed to execute cargo build");
62+
63+
assert!(
64+
result.status.success(),
65+
"Extension build failed:\nstdout: {}\nstderr: {}",
66+
String::from_utf8_lossy(&result.stdout),
67+
String::from_utf8_lossy(&result.stderr)
68+
);
4469
});
4570
}
4671

@@ -99,7 +124,12 @@ mod test {
99124
let mut path = env::current_dir().expect("Could not get cwd");
100125
path.pop();
101126
path.push("target");
127+
128+
#[cfg(not(debug_assertions))]
129+
path.push("release");
130+
#[cfg(debug_assertions)]
102131
path.push("debug");
132+
103133
path.push(if std::env::consts::DLL_EXTENSION == "dll" {
104134
"tests"
105135
} else {

tests/src/integration/variadic_args/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ pub fn test_variadic_first_last(items: &[&Zval]) -> Vec<Zval> {
7979
if let Some(first) = items.first() {
8080
result.push(first.shallow_clone());
8181
}
82-
if let Some(last) = items.last() {
83-
if items.len() > 1 {
84-
result.push(last.shallow_clone());
85-
}
82+
if let Some(last) = items.last()
83+
&& items.len() > 1
84+
{
85+
result.push(last.shallow_clone());
8686
}
8787
result
8888
}

0 commit comments

Comments
 (0)