mirror of
https://github.com/dlang/dmd.git
synced 2025-04-25 20:50:41 +03:00
GHA main: Add Alpine Linux job, to CI-test musl libc (#20741)
* GHA main: Add Alpine Linux job, to CI-test musl libc Incl. some test fixes. * [refactor common isDlcoseNoop logic and prepare for Darwin support]
This commit is contained in:
parent
94714307ec
commit
130e6aa1d4
9 changed files with 115 additions and 50 deletions
18
.github/workflows/main.yml
vendored
18
.github/workflows/main.yml
vendored
|
@ -49,6 +49,10 @@ jobs:
|
||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
host_dmd: gdmd-9
|
host_dmd: gdmd-9
|
||||||
disable_debug_for_dmd_unittests: true # no `-debug` - host frontend too old
|
disable_debug_for_dmd_unittests: true # no `-debug` - host frontend too old
|
||||||
|
- job_name: Alpine 3.21 x64, LDC
|
||||||
|
os: ubuntu-latest
|
||||||
|
container_image: alpine:3.21
|
||||||
|
host_dmd: ldmd2
|
||||||
# macOS
|
# macOS
|
||||||
- job_name: macOS 13 x64, DMD (latest)
|
- job_name: macOS 13 x64, DMD (latest)
|
||||||
os: macos-13
|
os: macos-13
|
||||||
|
@ -74,6 +78,7 @@ jobs:
|
||||||
model: 32
|
model: 32
|
||||||
name: ${{ matrix.job_name }}
|
name: ${{ matrix.job_name }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
container: ${{ matrix.container_image }}
|
||||||
timeout-minutes: 40
|
timeout-minutes: 40
|
||||||
env:
|
env:
|
||||||
# for ci/run.sh:
|
# for ci/run.sh:
|
||||||
|
@ -90,6 +95,11 @@ jobs:
|
||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
steps:
|
steps:
|
||||||
|
- name: 'Alpine container: Pre-install bash, git and sudo'
|
||||||
|
if: startsWith(matrix.container_image, 'alpine')
|
||||||
|
shell: sh
|
||||||
|
run: apk add bash git sudo
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 50
|
fetch-depth: 50
|
||||||
|
@ -149,20 +159,20 @@ jobs:
|
||||||
- name: Test dmd
|
- name: Test dmd
|
||||||
run: ci/run.sh test_dmd
|
run: ci/run.sh test_dmd
|
||||||
- name: Test druntime
|
- name: Test druntime
|
||||||
if: '!matrix.coverage'
|
if: '!matrix.coverage && (success() || failure())'
|
||||||
run: ci/run.sh test_druntime
|
run: ci/run.sh test_druntime
|
||||||
- name: 'Windows x86: Add 32-bit libcurl.dll to PATH (required for Phobos unittests)'
|
- name: 'Windows x86: Add 32-bit libcurl.dll to PATH (required for Phobos unittests)'
|
||||||
if: runner.os == 'Windows' && env.MODEL == '32' && !matrix.coverage
|
if: runner.os == 'Windows' && env.MODEL == '32' && !matrix.coverage && (success() || failure())
|
||||||
run: |
|
run: |
|
||||||
# LDC
|
# LDC
|
||||||
echo "$(dirname "$(which $DC)")/../lib32" >> $GITHUB_PATH
|
echo "$(dirname "$(which $DC)")/../lib32" >> $GITHUB_PATH
|
||||||
# DMD
|
# DMD
|
||||||
echo "$(dirname "$(which $DC)")/../bin" >> $GITHUB_PATH
|
echo "$(dirname "$(which $DC)")/../bin" >> $GITHUB_PATH
|
||||||
- name: Test phobos
|
- name: Test phobos
|
||||||
if: '!matrix.coverage'
|
if: '!matrix.coverage && (success() || failure())'
|
||||||
run: ci/run.sh test_phobos
|
run: ci/run.sh test_phobos
|
||||||
- name: Test self-compile
|
- name: Test self-compile
|
||||||
if: '!matrix.coverage' # already re-built with enabled coverage
|
if: '!matrix.coverage && (success() || failure())' # already re-built with enabled coverage
|
||||||
run: ENABLE_RELEASE=0 ci/run.sh rebuild
|
run: ENABLE_RELEASE=0 ci/run.sh rebuild
|
||||||
- name: Upload coverage report
|
- name: Upload coverage report
|
||||||
if: matrix.coverage
|
if: matrix.coverage
|
||||||
|
|
|
@ -15,18 +15,24 @@ if [ ! -z ${HOST_DC+x} ] ; then HOST_DMD=${HOST_DC}; fi
|
||||||
if [ -z ${HOST_DMD+x} ] ; then echo "Variable 'HOST_DMD' needs to be set."; exit 1; fi
|
if [ -z ${HOST_DMD+x} ] ; then echo "Variable 'HOST_DMD' needs to be set."; exit 1; fi
|
||||||
|
|
||||||
if [ "$OS_NAME" == "linux" ]; then
|
if [ "$OS_NAME" == "linux" ]; then
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
if type -P apk &>/dev/null; then
|
||||||
packages="git-core make g++ gdb gnupg curl libcurl4 tzdata zip unzip xz-utils llvm valgrind libc6-dbg"
|
# Alpine
|
||||||
if [ "$MODEL" == "32" ]; then
|
apk add git make g++ ldc \
|
||||||
dpkg --add-architecture i386
|
bash grep coreutils diffutils curl gdb linux-headers dub
|
||||||
packages="$packages g++-multilib libcurl4:i386 libc6-dbg:i386"
|
else
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
packages="git-core make g++ gdb gnupg curl libcurl4 tzdata zip unzip xz-utils llvm valgrind libc6-dbg"
|
||||||
|
if [ "$MODEL" == "32" ]; then
|
||||||
|
dpkg --add-architecture i386
|
||||||
|
packages="$packages g++-multilib libcurl4:i386 libc6-dbg:i386"
|
||||||
|
fi
|
||||||
|
if [ "${HOST_DMD:0:4}" == "gdmd" ]; then
|
||||||
|
# ci/run.sh uses `sudo add-apt-repository ...` to add a PPA repo
|
||||||
|
packages="$packages sudo software-properties-common"
|
||||||
|
fi
|
||||||
|
apt-get -q update
|
||||||
|
apt-get install -yq $packages
|
||||||
fi
|
fi
|
||||||
if [ "${HOST_DMD:0:4}" == "gdmd" ]; then
|
|
||||||
# ci/run.sh uses `sudo add-apt-repository ...` to add a PPA repo
|
|
||||||
packages="$packages sudo software-properties-common"
|
|
||||||
fi
|
|
||||||
apt-get -q update
|
|
||||||
apt-get install -yq $packages
|
|
||||||
elif [ "$OS_NAME" == "osx" ]; then
|
elif [ "$OS_NAME" == "osx" ]; then
|
||||||
# upgrade GNU make
|
# upgrade GNU make
|
||||||
brew install make
|
brew install make
|
||||||
|
|
10
ci/run.sh
10
ci/run.sh
|
@ -123,6 +123,11 @@ test_dmd() {
|
||||||
local args=(ARGS="-O -inline -release")
|
local args=(ARGS="-O -inline -release")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if type -P apk &>/dev/null; then
|
||||||
|
# Alpine: no TLS variables support with gdb, https://gitlab.alpinelinux.org/alpine/aports/-/issues/11154
|
||||||
|
rm compiler/test/runnable/gdb4181.d
|
||||||
|
fi
|
||||||
|
|
||||||
$build_path/dmd -g -i -Icompiler/test -release compiler/test/run.d -ofgenerated/run
|
$build_path/dmd -g -i -Icompiler/test -release compiler/test/run.d -ofgenerated/run
|
||||||
generated/run -j$N --environment MODEL=$MODEL HOST_DMD=$build_path/dmd "${args[@]}"
|
generated/run -j$N --environment MODEL=$MODEL HOST_DMD=$build_path/dmd "${args[@]}"
|
||||||
}
|
}
|
||||||
|
@ -262,6 +267,11 @@ install_host_compiler() {
|
||||||
echo "export DMD=gdmd-$gdc_version" > ~/dlang/gdc-$gdc_version/activate
|
echo "export DMD=gdmd-$gdc_version" > ~/dlang/gdc-$gdc_version/activate
|
||||||
echo "deactivate(){ echo;}" >> ~/dlang/gdc-$gdc_version/activate
|
echo "deactivate(){ echo;}" >> ~/dlang/gdc-$gdc_version/activate
|
||||||
fi
|
fi
|
||||||
|
elif type -P apk &>/dev/null; then
|
||||||
|
# fake install script and create a fake 'activate' script
|
||||||
|
mkdir -p ~/dlang/$HOST_DMD
|
||||||
|
echo "export DMD=$HOST_DMD" > ~/dlang/$HOST_DMD/activate
|
||||||
|
echo "deactivate(){ echo;}" >> ~/dlang/$HOST_DMD/activate
|
||||||
else
|
else
|
||||||
local install_sh="install.sh"
|
local install_sh="install.sh"
|
||||||
download_install_sh "$install_sh"
|
download_install_sh "$install_sh"
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
TESTS=stderr_msg unittest_assert invalid_memory_operation unknown_gc static_dtor \
|
ifeq ($(OS),linux)
|
||||||
|
# FIXME: detect musl libc robustly; just checking Alpine Linux' apk tool for now
|
||||||
|
ifeq (1,$(shell which apk &>/dev/null && echo 1))
|
||||||
|
IS_MUSL:=1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
TESTS=stderr_msg unittest_assert invalid_memory_operation static_dtor \
|
||||||
future_message refcounted rt_trap_exceptions_drt catch_in_finally \
|
future_message refcounted rt_trap_exceptions_drt catch_in_finally \
|
||||||
message_with_null
|
message_with_null
|
||||||
|
|
||||||
|
# FIXME: segfaults with musl libc
|
||||||
|
ifneq ($(IS_MUSL),1)
|
||||||
|
TESTS += unknown_gc
|
||||||
|
endif
|
||||||
|
|
||||||
# fails on 32 bit linux
|
# fails on 32 bit linux
|
||||||
ifneq ($(OS),linux)
|
ifneq ($(OS),linux)
|
||||||
TESTS += assert_fail
|
TESTS += assert_fail
|
||||||
|
@ -12,8 +24,11 @@ SED:=sed
|
||||||
GDB:=gdb
|
GDB:=gdb
|
||||||
|
|
||||||
ifeq ($(OS),linux)
|
ifeq ($(OS),linux)
|
||||||
TESTS+=line_trace line_trace_21656 long_backtrace_trunc rt_trap_exceptions cpp_demangle \
|
TESTS+=line_trace line_trace_21656 long_backtrace_trunc rt_trap_exceptions cpp_demangle
|
||||||
memoryerror_null_read memoryerror_null_write memoryerror_null_call memoryerror_stackoverflow
|
# registerMemoryAssertHandler requires glibc
|
||||||
|
ifneq ($(IS_MUSL),1)
|
||||||
|
TESTS+=memoryerror_null_read memoryerror_null_write memoryerror_null_call memoryerror_stackoverflow
|
||||||
|
endif
|
||||||
line_trace_dflags:=-L--export-dynamic
|
line_trace_dflags:=-L--export-dynamic
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
TESTS := importc_compare
|
TESTS := importc_compare
|
||||||
|
|
||||||
|
# FIXME: fails on Alpine v3.21 with conflicting struct declarations in the C headers:
|
||||||
|
# /usr/include/asm-generic/fcntl.h(195): Error: struct `importc_includes.flock` conflicts with struct `importc_includes.flock` at /usr/include/fcntl.h(24)
|
||||||
|
ifeq ($(OS),linux)
|
||||||
|
ifeq (1,$(shell which apk &>/dev/null && echo 1))
|
||||||
|
TESTS :=
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
||||||
extra_dflags += -d
|
extra_dflags += -d
|
||||||
|
|
|
@ -32,7 +32,7 @@ extern (C) alias SetFinalizeCounter = void function(shared(size_t*));
|
||||||
|
|
||||||
void main(string[] args)
|
void main(string[] args)
|
||||||
{
|
{
|
||||||
import utils : dllExt, loadSym;
|
import utils : dllExt, isDlcloseNoop, loadSym;
|
||||||
|
|
||||||
auto name = args[0] ~ '\0';
|
auto name = args[0] ~ '\0';
|
||||||
const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
|
const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
|
||||||
|
@ -44,7 +44,7 @@ void main(string[] args)
|
||||||
auto nf1 = new NoFinalize;
|
auto nf1 = new NoFinalize;
|
||||||
auto nf2 = new NoFinalizeBig;
|
auto nf2 = new NoFinalizeBig;
|
||||||
|
|
||||||
shared size_t finalizeCounter;
|
static shared size_t finalizeCounter;
|
||||||
SetFinalizeCounter setFinalizeCounter;
|
SetFinalizeCounter setFinalizeCounter;
|
||||||
loadSym(h, setFinalizeCounter, "setFinalizeCounter");
|
loadSym(h, setFinalizeCounter, "setFinalizeCounter");
|
||||||
setFinalizeCounter(&finalizeCounter);
|
setFinalizeCounter(&finalizeCounter);
|
||||||
|
@ -57,8 +57,11 @@ void main(string[] args)
|
||||||
auto r = Runtime.unloadLibrary(h);
|
auto r = Runtime.unloadLibrary(h);
|
||||||
if (!r)
|
if (!r)
|
||||||
assert(0);
|
assert(0);
|
||||||
if (finalizeCounter != 4)
|
static if (!isDlcloseNoop)
|
||||||
assert(0);
|
{
|
||||||
|
if (finalizeCounter != 4)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
if (nf1._finalizeCounter)
|
if (nf1._finalizeCounter)
|
||||||
assert(0);
|
assert(0);
|
||||||
if (nf2._finalizeCounter)
|
if (nf2._finalizeCounter)
|
||||||
|
|
|
@ -130,26 +130,29 @@ void main(string[] args)
|
||||||
{
|
{
|
||||||
auto name = args[0] ~ '\0';
|
auto name = args[0] ~ '\0';
|
||||||
const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
|
const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
|
||||||
import utils : dllExt;
|
import utils : dllExt, isDlcloseNoop;
|
||||||
name = name[0 .. pathlen] ~ "lib." ~ dllExt;
|
name = name[0 .. pathlen] ~ "lib." ~ dllExt;
|
||||||
|
|
||||||
runTests(name);
|
runTests(name);
|
||||||
|
|
||||||
// lib is no longer resident
|
static if (!isDlcloseNoop)
|
||||||
name ~= '\0';
|
|
||||||
version (Windows)
|
|
||||||
{
|
{
|
||||||
import core.sys.windows.winbase;
|
// lib is no longer resident
|
||||||
assert(!GetModuleHandleA(name.ptr));
|
name ~= '\0';
|
||||||
}
|
version (Windows)
|
||||||
else
|
{
|
||||||
{
|
import core.sys.windows.winbase;
|
||||||
import core.sys.posix.dlfcn : dlopen, RTLD_LAZY;
|
assert(!GetModuleHandleA(name.ptr));
|
||||||
assert(dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null);
|
}
|
||||||
}
|
else
|
||||||
name = name[0 .. $-1];
|
{
|
||||||
|
import core.sys.posix.dlfcn : dlopen, RTLD_LAZY;
|
||||||
|
assert(dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null);
|
||||||
|
}
|
||||||
|
name = name[0 .. $-1];
|
||||||
|
|
||||||
auto thr = new Thread({runTests(name);});
|
auto thr = new Thread({runTests(name);});
|
||||||
thr.start();
|
thr.start();
|
||||||
thr.join();
|
thr.join();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ void runTest(string name)
|
||||||
auto h = Runtime.loadLibrary(name);
|
auto h = Runtime.loadLibrary(name);
|
||||||
assert(h !is null);
|
assert(h !is null);
|
||||||
|
|
||||||
import utils : loadSym;
|
import utils : isDlcloseNoop, loadSym;
|
||||||
void function()* pLibStaticDtorHook, pLibSharedStaticDtorHook;
|
void function()* pLibStaticDtorHook, pLibSharedStaticDtorHook;
|
||||||
loadSym(h, pLibStaticDtorHook, "_D9lib_1341414staticDtorHookOPFZv");
|
loadSym(h, pLibStaticDtorHook, "_D9lib_1341414staticDtorHookOPFZv");
|
||||||
loadSym(h, pLibSharedStaticDtorHook, "_D9lib_1341420sharedStaticDtorHookOPFZv");
|
loadSym(h, pLibSharedStaticDtorHook, "_D9lib_1341420sharedStaticDtorHookOPFZv");
|
||||||
|
@ -20,19 +20,12 @@ void runTest(string name)
|
||||||
*pLibSharedStaticDtorHook = &sharedStaticDtorHook;
|
*pLibSharedStaticDtorHook = &sharedStaticDtorHook;
|
||||||
|
|
||||||
const unloaded = Runtime.unloadLibrary(h);
|
const unloaded = Runtime.unloadLibrary(h);
|
||||||
version (CRuntime_Musl)
|
assert(unloaded);
|
||||||
{
|
assert(tlsDtor == 1);
|
||||||
// On Musl, unloadLibrary is a no-op because dlclose is a no-op
|
static if (isDlcloseNoop)
|
||||||
assert(!unloaded);
|
|
||||||
assert(tlsDtor == 0);
|
|
||||||
assert(dtor == 0);
|
assert(dtor == 0);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
assert(unloaded);
|
|
||||||
assert(tlsDtor == 1);
|
|
||||||
assert(dtor == 1);
|
assert(dtor == 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(string[] args)
|
void main(string[] args)
|
||||||
|
|
|
@ -1,12 +1,29 @@
|
||||||
module utils;
|
module utils;
|
||||||
|
|
||||||
|
version (OSX)
|
||||||
|
version = Darwin;
|
||||||
|
else version (iOS)
|
||||||
|
version = Darwin;
|
||||||
|
else version (TVOS)
|
||||||
|
version = Darwin;
|
||||||
|
else version (WatchOS)
|
||||||
|
version = Darwin;
|
||||||
|
|
||||||
version (Windows)
|
version (Windows)
|
||||||
enum dllExt = "dll";
|
enum dllExt = "dll";
|
||||||
else version (darwin)
|
else version (Darwin)
|
||||||
enum dllExt = "dylib";
|
enum dllExt = "dylib";
|
||||||
else
|
else
|
||||||
enum dllExt = "so";
|
enum dllExt = "so";
|
||||||
|
|
||||||
|
// on some platforms, dlclose() is a no-op
|
||||||
|
version (Darwin)
|
||||||
|
enum isDlcloseNoop = true; // since macOS ~10.12.6 if shared lib uses TLS: https://github.com/rust-lang/rust/issues/28794#issuecomment-368693049
|
||||||
|
else version (CRuntime_Musl)
|
||||||
|
enum isDlcloseNoop = true; // https://wiki.musl-libc.org/functional-differences-from-glibc.html
|
||||||
|
else
|
||||||
|
enum isDlcloseNoop = false;
|
||||||
|
|
||||||
void loadSym(T)(void* handle, ref T val, const char* mangle)
|
void loadSym(T)(void* handle, ref T val, const char* mangle)
|
||||||
{
|
{
|
||||||
version (Windows)
|
version (Windows)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue