diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8623863a..9c905a6b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,3 +52,11 @@ jobs: sudo apt-get install -y qemu-system-x86 bash tests/test_redir_qemu.sh build/shared/bin/ timeout-minutes: 8 + + - name: Debian package build test + if: runner.os == 'Linux' + run: | + sudo apt-get install -y --no-install-recommends \ + build-essential debhelper dpkg-dev fakeroot asciidoc-base xmlto pkg-config + bash tests/test_deb_build.sh + timeout-minutes: 10 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a04623c..3616039b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,16 +137,10 @@ else () set(LIBCORK_SOURCE ${LIBCORK_SOURCE} libcork/src/libcork/posix/mingw.c) endif () -if (WITH_STATIC) add_library(cork STATIC ${LIBCORK_SOURCE}) target_compile_definitions(cork PUBLIC -DCORK_API=CORK_LOCAL) -endif () - -add_library(cork-shared SHARED ${LIBCORK_SOURCE}) -target_compile_definitions(cork-shared PUBLIC -DCORK_API=CORK_EXPORT) -set_target_properties(cork-shared PROPERTIES OUTPUT_NAME cork) if (MINGW) -target_link_libraries(cork-shared ws2_32) +target_link_libraries(cork ws2_32) endif () set(LIBIPSET_SOURCE @@ -171,28 +165,17 @@ set(LIBIPSET_SOURCE libipset/src/libipset/set/storage.c ) -if (WITH_STATIC) add_library(ipset STATIC ${LIBIPSET_SOURCE}) -endif () - -add_library(ipset-shared SHARED ${LIBIPSET_SOURCE}) -set_target_properties(ipset-shared PROPERTIES OUTPUT_NAME ipset) set(LIBBLOOM_SOURCE libbloom/bloom.c libbloom/murmur2/MurmurHash2.c ) -if (WITH_STATIC) add_library(bloom STATIC ${LIBBLOOM_SOURCE}) target_link_libraries(ipset cork bloom) endif () -add_library(bloom-shared SHARED ${LIBBLOOM_SOURCE}) -target_link_libraries(ipset-shared cork-shared bloom-shared) -set_target_properties(bloom-shared PROPERTIES OUTPUT_NAME bloom) -endif () - add_subdirectory(src) add_subdirectory(doc) diff --git a/debian/rules b/debian/rules index 5d8dae81..2121df06 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ override_dh_auto_install: dh_auto_install override_dh_auto_configure: - dh_auto_configure + dh_auto_configure -- -DWITH_STATIC=OFF override_dh_installchangelogs: dh_installchangelogs -XChanges diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18ae7ba0..80503cb2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -138,9 +138,9 @@ find_library(LIBPCRE2_SHARED pcre2-8) if (WITH_EMBEDDED_SRC) list(APPEND DEPS_SHARED m - bloom-shared - cork-shared - ipset-shared + bloom + cork + ipset ${LIBEV_SHARED} ${LIBUDNS_SHARED} ${LIBPCRE2_SHARED} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b27effaf..436dc99a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -43,7 +43,7 @@ set(TEST_NETUTILS_LIBS ${LIBUDNS_SHARED} ) if(WITH_EMBEDDED_SRC) - list(APPEND TEST_NETUTILS_LIBS cork-shared) + list(APPEND TEST_NETUTILS_LIBS cork) else() list(APPEND TEST_NETUTILS_LIBS ${LIBCORK_SHARED}) endif() @@ -59,7 +59,7 @@ ss_add_test(test_cache # test_ppbloom - needs bloom set(TEST_PPBLOOM_LIBS "") if(WITH_EMBEDDED_SRC) - list(APPEND TEST_PPBLOOM_LIBS bloom-shared) + list(APPEND TEST_PPBLOOM_LIBS bloom) else() list(APPEND TEST_PPBLOOM_LIBS ${LIBBLOOM_SHARED}) endif() @@ -73,7 +73,7 @@ set(TEST_RULE_LIBS ${LIBSODIUM_SHARED} ) if(WITH_EMBEDDED_SRC) - list(APPEND TEST_RULE_LIBS cork-shared) + list(APPEND TEST_RULE_LIBS cork) else() list(APPEND TEST_RULE_LIBS ${LIBCORK_SHARED}) endif() @@ -88,7 +88,7 @@ set(TEST_JCONF_LIBS ${LIBUDNS_SHARED} ) if(WITH_EMBEDDED_SRC) - list(APPEND TEST_JCONF_LIBS cork-shared) + list(APPEND TEST_JCONF_LIBS cork) else() list(APPEND TEST_JCONF_LIBS ${LIBCORK_SHARED}) endif() @@ -109,7 +109,7 @@ set(TEST_CRYPTO_LIBS ${LIBEV_SHARED} ) if(WITH_EMBEDDED_SRC) - list(APPEND TEST_CRYPTO_LIBS bloom-shared) + list(APPEND TEST_CRYPTO_LIBS bloom) else() list(APPEND TEST_CRYPTO_LIBS ${LIBBLOOM_SHARED}) endif() diff --git a/tests/test_deb_build.sh b/tests/test_deb_build.sh new file mode 100644 index 00000000..7dbca66d --- /dev/null +++ b/tests/test_deb_build.sh @@ -0,0 +1,190 @@ +#!/bin/bash +# +# Test that Debian packages build, contain expected files, install, and work. +# +# Usage: bash tests/test_deb_build.sh +# +# Requirements (Linux only): +# - dpkg-buildpackage, debhelper, fakeroot +# - Build dependencies listed in debian/control +# - sudo (for install phase) +# + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +# --- helpers ---------------------------------------------------------------- + +PASS_COUNT=0 +FAIL_COUNT=0 +FAILURES="" + +log() { + echo "=== [test_deb_build] $* ===" +} + +check_pass() { + PASS_COUNT=$((PASS_COUNT + 1)) + echo " PASS: $*" +} + +check_fail() { + FAIL_COUNT=$((FAIL_COUNT + 1)) + FAILURES="${FAILURES} FAIL: $*"$'\n' + echo " FAIL: $*" +} + +# check_file_in_deb DEB_FILE PATTERN DESCRIPTION +# Verifies that at least one file matching PATTERN exists in the .deb +check_file_in_deb() { + local deb="$1" pattern="$2" desc="$3" + # Avoid grep -q: with pipefail, early grep exit causes SIGPIPE on dpkg-deb + if dpkg-deb -c "$deb" | grep -E "$pattern" >/dev/null; then + check_pass "$desc" + else + check_fail "$desc" + fi +} + +# check_command CMD DESCRIPTION +# Verifies that a command runs successfully (exit 0) +check_command() { + local desc="$2" + if eval "$1" >/dev/null 2>&1; then + check_pass "$desc" + else + check_fail "$desc" + fi +} + +summary() { + echo "" + log "Results: $PASS_COUNT passed, $FAIL_COUNT failed" + if [ "$FAIL_COUNT" -gt 0 ]; then + echo "" + echo "Failures:" + printf '%s' "$FAILURES" + exit 1 + fi +} + +# --- phase 1: build -------------------------------------------------------- + +log "Phase 1: Build Debian packages" + +cd "$PROJECT_DIR" + +# dpkg-buildpackage -b builds binary-only packages (no .orig.tar.gz needed) +dpkg-buildpackage -b -us -uc -j"$(nproc)" + +# .deb files are placed in the parent directory +PARENT_DIR="$(dirname "$PROJECT_DIR")" + +DEB_MAIN="" +DEB_LIB="" +DEB_DEV="" +for f in "$PARENT_DIR"/shadowsocks-libev_*.deb; do + [ -f "$f" ] && DEB_MAIN="$f" && break +done +for f in "$PARENT_DIR"/libshadowsocks-libev2_*.deb; do + [ -f "$f" ] && DEB_LIB="$f" && break +done +for f in "$PARENT_DIR"/libshadowsocks-libev-dev_*.deb; do + [ -f "$f" ] && DEB_DEV="$f" && break +done + +# --- phase 2: verify contents ---------------------------------------------- + +log "Phase 2: Verify package contents" + +# Check all three .deb files exist +if [ -n "$DEB_MAIN" ] && [ -f "$DEB_MAIN" ]; then + check_pass "shadowsocks-libev .deb exists: $(basename "$DEB_MAIN")" +else + check_fail "shadowsocks-libev .deb not found" +fi + +if [ -n "$DEB_LIB" ] && [ -f "$DEB_LIB" ]; then + check_pass "libshadowsocks-libev2 .deb exists: $(basename "$DEB_LIB")" +else + check_fail "libshadowsocks-libev2 .deb not found" +fi + +if [ -n "$DEB_DEV" ] && [ -f "$DEB_DEV" ]; then + check_pass "libshadowsocks-libev-dev .deb exists: $(basename "$DEB_DEV")" +else + check_fail "libshadowsocks-libev-dev .deb not found" +fi + +# Bail early if any .deb is missing - remaining checks would all fail +if [ "$FAIL_COUNT" -gt 0 ]; then + summary +fi + +# Main package: binaries +for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do + check_file_in_deb "$DEB_MAIN" "usr/bin/${bin}" "$bin binary in main package" +done + +# Main package: man pages +for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do + check_file_in_deb "$DEB_MAIN" "usr/share/man/man1/$bin\\.1" "$bin man page in main package" +done + +# Shared library package +check_file_in_deb "$DEB_LIB" "usr/lib/.*/libshadowsocks-libev\\.so\\." "shared library in lib package" + +# Dev package: header +check_file_in_deb "$DEB_DEV" "usr/include/shadowsocks\\.h" "shadowsocks.h header in dev package" + +# Dev package: pkg-config +check_file_in_deb "$DEB_DEV" "usr/lib/.*/pkgconfig/shadowsocks-libev\\.pc" "pkg-config file in dev package" + +# Dev package: unversioned .so symlink +check_file_in_deb "$DEB_DEV" "usr/lib/.*/libshadowsocks-libev\\.so[^.]" "unversioned .so symlink in dev package" + +# --- phase 3: install ------------------------------------------------------- + +log "Phase 3: Install packages" + +sudo dpkg -i "$DEB_LIB" "$DEB_DEV" "$DEB_MAIN" || true +sudo apt-get -f install -y + +# Verify dpkg thinks they are installed +for pkg in shadowsocks-libev libshadowsocks-libev2 libshadowsocks-libev-dev; do + if dpkg -s "$pkg" >/dev/null 2>&1; then + check_pass "$pkg installed" + else + check_fail "$pkg not installed" + fi +done + +# --- phase 4: smoke-test ---------------------------------------------------- + +log "Phase 4: Smoke-test installed binaries" + +# Each binary should respond to --help +for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do + check_command "$bin --help" "$bin --help runs" +done + +# Shared library should be findable by ldconfig +sudo ldconfig +if ldconfig -p | grep -q libshadowsocks-libev; then + check_pass "libshadowsocks-libev found by ldconfig" +else + check_fail "libshadowsocks-libev not found by ldconfig" +fi + +# Header should be in the include path +if [ -f /usr/include/shadowsocks.h ]; then + check_pass "shadowsocks.h installed in /usr/include" +else + check_fail "shadowsocks.h not installed in /usr/include" +fi + +# --- summary ---------------------------------------------------------------- + +summary