Skip to content

Commit ce6cf28

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

File tree

7 files changed

+183
-12
lines changed

7 files changed

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

.github/workflows/build.yml

Lines changed: 46 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,49 @@ 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+
load: true
257+
258+
- name: Build ext-php-rs with musl
259+
run: |
260+
docker run --rm \
261+
-e EXT_PHP_RS_TEST="" \
262+
-v ${{ github.workspace }}:/workspace \
263+
-w /workspace \
264+
ext-php-rs-musl:${{ matrix.php }}-${{ matrix.phpts }} \
265+
build --release --features closure,anyhow,static --workspace --target x86_64-unknown-linux-musl
266+
267+
- name: Test ext-php-rs with musl
268+
run: |
269+
docker run --rm \
270+
-v ${{ github.workspace }}:/workspace \
271+
-w /workspace \
272+
ext-php-rs-musl:${{ matrix.php }}-${{ matrix.phpts }} \
273+
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)