Skip to content

Commit ce7a39b

Browse files
committed
ci: add musl build step
1 parent 3f6595d commit ce7a39b

File tree

7 files changed

+181
-12
lines changed

7 files changed

+181
-12
lines changed

.cargo/config.toml

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

77
[target.i686-pc-windows-msvc]
88
linker = "rust-lld"
9+
10+
[target.'cfg(target_env = "musl")']
11+
rustflags = [
12+
"-C",
13+
"target-feature=-crt-static",
14+
"-C",
15+
"link-arg=-Wl,-undefined,dynamic_lookup",
16+
]

.github/action/musl/Dockerfile

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Multi-stage Dockerfile for building ext-php-rs with musl libc
2+
# This ensures PHP and the Rust extension are both compiled against musl
3+
FROM alpine:3.20 AS php-builder
4+
5+
ARG PHP_VERSION=8.4.1
6+
ARG PHP_BRANCH=PHP-${PHP_VERSION}
7+
ARG TS=ts
8+
9+
RUN apk add --no-cache \
10+
autoconf \
11+
automake \
12+
bison \
13+
re2c \
14+
gcc \
15+
g++ \
16+
make \
17+
musl-dev \
18+
linux-headers \
19+
pkgconfig \
20+
git \
21+
libxml2-dev \
22+
sqlite-dev \
23+
openssl-dev \
24+
curl-dev
25+
26+
WORKDIR /tmp/php-src
27+
RUN git clone --depth 1 -b ${PHP_BRANCH} https://github.com/php/php-src.git .
28+
29+
RUN ./buildconf --force && \
30+
CONFIGURE_OPTS="--enable-debug --enable-embed=shared --with-openssl --with-curl --with-sqlite3 --disable-cgi" && \
31+
if [ "$TS" = "ts" ]; then CONFIGURE_OPTS="$CONFIGURE_OPTS --enable-zts"; fi && \
32+
./configure $CONFIGURE_OPTS --prefix=/usr/local && \
33+
make -j$(nproc) && \
34+
make install
35+
36+
FROM alpine:3.20 AS rust-builder
37+
38+
COPY --from=php-builder /usr/local /usr/local
39+
40+
RUN apk add --no-cache \
41+
curl \
42+
gcc \
43+
g++ \
44+
musl-dev \
45+
clang17 \
46+
clang17-libclang \
47+
clang17-dev \
48+
clang17-static \
49+
llvm17-dev \
50+
llvm17-libs \
51+
llvm17-static \
52+
make \
53+
git
54+
55+
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
56+
ENV PATH="/root/.cargo/bin:${PATH}"
57+
58+
RUN rustup target add x86_64-unknown-linux-musl
59+
60+
ENV CC=gcc
61+
ENV LIBCLANG_PATH=/usr/lib/llvm17
62+
ENV LLVM_CONFIG_PATH=/usr/bin/llvm-config
63+
ENV PHP=/usr/local/bin/php
64+
ENV PHP_CONFIG=/usr/local/bin/php-config
65+
ENV LIBCLANG_STATIC=1
66+
ENV BINDGEN_EXTRA_CLANG_ARGS="-I/usr/lib/llvm17/include"
67+
68+
WORKDIR /workspace
69+
70+
COPY . .
71+
72+
RUN cargo build --release \
73+
--features closure,anyhow,runtime \
74+
--workspace \
75+
--target x86_64-unknown-linux-musl
76+
77+
FROM alpine:3.20 AS runtime
78+
COPY --from=php-builder /usr/local /usr/local
79+
COPY --from=rust-builder /workspace/target/x86_64-unknown-linux-musl/release/cargo-php /usr/local/bin/
80+
81+
RUN apk add --no-cache \
82+
libxml2 \
83+
sqlite-libs \
84+
openssl \
85+
curl
86+
87+
WORKDIR /app
88+
89+
ENTRYPOINT ["/usr/local/bin/cargo-php"]
90+
91+
FROM rust-builder AS ci-builder
92+
93+
ENTRYPOINT ["cargo"]
94+
CMD ["build", "--release", "--features", "closure,anyhow,static", "--workspace", "--target", "x86_64-unknown-linux-musl"]

.github/workflows/build.yml

Lines changed: 47 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,50 @@ 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
231+
runs-on: ubuntu-latest
232+
strategy:
233+
matrix:
234+
php: ["8.1", "8.2", "8.3", "8.4"]
235+
phpts: [ts, nts]
236+
env:
237+
CARGO_TERM_COLOR: always
238+
steps:
239+
- name: Checkout code
240+
uses: actions/checkout@v5
241+
242+
- name: Set up Docker Buildx
243+
uses: docker/setup-buildx-action@v3
244+
245+
- name: Build Docker image with PHP ${{ matrix.php }}
246+
uses: docker/build-push-action@v6
247+
with:
248+
context: .
249+
file: .github/action/musl/Dockerfile
250+
target: ci-builder
251+
tags: ext-php-rs-musl:${{ matrix.php }}-${{ matrix.phpts }}
252+
cache-from: type=gha,scope=musl-${{ matrix.php }}-${{ matrix.phpts }}
253+
cache-to: type=gha,mode=max,scope=musl-${{ matrix.php }}-${{ matrix.phpts }}
254+
build-args: |
255+
PHP_VERSION=${{ matrix.php }}
256+
TS=${{ matrix.phpts }}
257+
load: true
258+
259+
- name: Build ext-php-rs with musl
260+
run: |
261+
docker run --rm \
262+
-e EXT_PHP_RS_TEST="" \
263+
-v ${{ github.workspace }}:/workspace \
264+
-w /workspace \
265+
ext-php-rs-musl:${{ matrix.php }}-${{ matrix.phpts }} \
266+
build --release --features closure,anyhow,static --workspace --target x86_64-unknown-linux-musl
267+
268+
- name: Test ext-php-rs with musl
269+
run: |
270+
docker run --rm \
271+
-v ${{ github.workspace }}:/workspace \
272+
-w /workspace \
273+
ext-php-rs-musl:${{ matrix.php }}-${{ matrix.phpts }} \
274+
test --release --workspace --features closure,anyhow,static --target x86_64-unknown-linux-musl --no-fail-fast

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,22 @@ 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) Requirements
130+
131+
Building for Alpine Linux (musl libc) is supported on stable Rust with the following
132+
requirements:
133+
134+
- Install musl toolchain: `sudo apt-get install musl-tools musl-dev`
135+
- Add musl target: `rustup target add x86_64-unknown-linux-musl`
136+
- Build with dynamic linking flag:
137+
```bash
138+
RUSTFLAGS="-C target-feature=-crt-static" \
139+
cargo build --target x86_64-unknown-linux-musl
140+
```
141+
142+
**Note**: Building for musl requires dynamic CRT linking (`-crt-static` flag) to produce
143+
the `cdylib` output required for PHP extensions.
144+
129145
### Windows Requirements
130146

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

tests/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
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, features = [
10+
"closure",
11+
"runtime",
12+
] }
1013

1114
[features]
1215
default = ["enum"]

tests/src/integration/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ mod test {
3636
{
3737
command.arg("--features=enum");
3838
}
39-
assert!(command
40-
.output()
41-
.expect("failed to build extension")
42-
.status
43-
.success());
39+
assert!(
40+
command
41+
.output()
42+
.expect("failed to build extension")
43+
.status
44+
.success()
45+
);
4446
});
4547
}
4648

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)