Browse Source

Share incremental builds on FreeBSD and select portable hardening flags

master
evgeny 3 days ago
parent
commit
e0ba199e20
  1. 45
      build.sh
  2. 162
      build_bsd_full.sh
  3. 19
      configure.ac

45
build.sh

@ -1,5 +1,5 @@
#!/bin/bash
# Инкрементальная сборка Linux и Windows/MSYS2; флаги задаются через configure.
#!/usr/bin/env bash
# Инкрементальная сборка Linux, FreeBSD и Windows/MSYS2; флаги задаются через configure.
set -euo pipefail
cd "$(dirname "$0")"
@ -48,9 +48,25 @@ while [[ $# -gt 0 ]]; do
done
[[ "$JOBS" =~ ^[1-9][0-9]*$ ]] || { echo "ERROR: invalid job count: $JOBS" >&2; exit 1; }
for tool in make sha256sum; do
command -v "$tool" >/dev/null || { echo "ERROR: required tool not found: $tool" >&2; exit 1; }
done
PLATFORM=$(uname -s)
MAKE_TOOL=${MAKE:-make}
if [[ "$PLATFORM" = FreeBSD ]]; then
MAKE_TOOL=${MAKE:-gmake}
export CC="${CC:-clang}"
fi
MAKE_PATH=$(command -v "$MAKE_TOOL") || { echo "ERROR: GNU make not found: $MAKE_TOOL (FreeBSD: pkg install gmake)" >&2; exit 1; }
MAKE_ID=$("$MAKE_TOOL" --version) || { echo "ERROR: GNU make is required; use MAKE=gmake on BSD" >&2; exit 1; }
[[ "$MAKE_ID" = *'GNU Make'* ]] || { echo "ERROR: GNU make is required; use MAKE=gmake on BSD" >&2; exit 1; }
export MAKE="$MAKE_TOOL"
if command -v sha256sum >/dev/null; then
HASH_COMMAND=(sha256sum)
elif command -v sha256 >/dev/null; then
HASH_COMMAND=(sha256 -r)
elif command -v shasum >/dev/null; then
HASH_COMMAND=(shasum -a 256)
else
echo "ERROR: SHA-256 utility not found: sha256sum, sha256 or shasum is required" >&2; exit 1
fi
read -r -a COMPILER <<< "${CC:-gcc}"
COMPILER_PATH=$(command -v "${COMPILER[0]}") || { echo "ERROR: compiler not found: ${CC:-gcc}" >&2; exit 1; }
COMPILER_ID=$("${COMPILER[@]}" --version) || { echo "ERROR: cannot identify compiler: ${CC:-gcc}" >&2; exit 1; }
@ -58,7 +74,7 @@ COMPILER_ID=$("${COMPILER[@]}" --version) || { echo "ERROR: cannot identify comp
# Хеши учитывают содержимое и имена файлов, включая добавление/удаление макросов.
hash_files() {
local result
result=$(sha256sum "$@" | sha256sum)
result=$({ printf '%s\0' "$@"; "${HASH_COMMAND[@]}" "$@"; } | "${HASH_COMMAND[@]}")
printf '%s\n' "${result%% *}"
}
@ -66,9 +82,8 @@ BUILD_DIRS=(lib lib/libopus src tests)
AUTOTOOLS_INPUTS=(configure.ac Makefile.am lib/Makefile.am lib/libopus/Makefile.am src/Makefile.am tests/Makefile.am)
AUTOTOOLS_OUTPUTS=(configure aclocal.m4 config.h.in Makefile.in lib/Makefile.in lib/libopus/Makefile.in src/Makefile.in tests/Makefile.in)
CONFIG_OUTPUTS=(config.status config.h Makefile lib/Makefile lib/libopus/Makefile src/Makefile tests/Makefile)
if [[ -d m4 ]]; then
while IFS= read -r -d '' macro; do AUTOTOOLS_INPUTS+=("$macro"); done < <(find m4 -type f -name '*.m4' -print0 | sort -z)
fi
shopt -s globstar nullglob
for macro in m4/**/*.m4; do AUTOTOOLS_INPUTS+=("$macro"); done
GENERATION_INPUT=$(hash_files "${AUTOTOOLS_INPUTS[@]}")
GENERATION_OUTPUT=missing
CONFIG_OUTPUT=missing
@ -91,13 +106,14 @@ if command -v pkg-config >/dev/null && pkg-config --exists "${FFMPEG_PACKAGES[@]
FFMPEG_LDFLAGS=$(pkg-config --libs-only-L "${FFMPEG_PACKAGES[@]}")
fi
request_sum=$({
printf '%s\0' "$MODE" "${OSTYPE:-}" "${MSYSTEM:-}" "${MSYSTEM_PREFIX:-}" "${CC:-gcc}" "$COMPILER_PATH" "$COMPILER_ID"
printf '%s\0' "$MODE" "$PLATFORM" "${MSYSTEM:-}" "${MSYSTEM_PREFIX:-}" "${CC:-gcc}" "$COMPILER_PATH" "$COMPILER_ID"
printf '%s\0' "$MAKE_PATH" "$MAKE_ID" "${HASH_COMMAND[@]}"
printf '%s\0' "${CFLAGS+x}" "${CFLAGS-}" "${CPPFLAGS+x}" "${CPPFLAGS-}" "${LDFLAGS+x}" "${LDFLAGS-}"
printf '%s\0' "${LIBS+x}" "${LIBS-}" "${MAKEFLAGS-}" "${DEBUG_FLAGS+x}" "${DEBUG_FLAGS-}"
printf '%s\0' "$FFMPEG_OPTION" "$FFMPEG_ID" "$FFMPEG_CFLAGS" "$FFMPEG_LDFLAGS"
printf '%s\0' "${MAKE_SETTINGS[@]}"
sha256sum build.sh
} | sha256sum)
hash_files build.sh
} | "${HASH_COMMAND[@]}")
CONFIG_REQUEST=${request_sum%% *}
OLD_GENERATION_INPUT=""; OLD_GENERATION_OUTPUT=""; OLD_CONFIG_REQUEST=""; OLD_CONFIG_OUTPUT=""
@ -130,6 +146,7 @@ if [[ "$REGENERATE" = 1 || "$CONFIG_REQUEST" != "$OLD_CONFIG_REQUEST" || "$CONFI
if [[ "$MODE" = asan ]]; then
export CFLAGS="${CFLAGS-} -g -Og -fsanitize=address -fno-omit-frame-pointer -fno-pie"
export LDFLAGS="${LDFLAGS-} -fsanitize=address -no-pie"
if [[ "$PLATFORM" = FreeBSD ]]; then export ASAN_OPTIONS="${ASAN_OPTIONS:-detect_leaks=0}"; fi
elif [[ "$MODE" = hardened ]]; then
CONFIG_ARGS+=(--enable-hardening)
fi
@ -161,7 +178,7 @@ for directory in "${BUILD_DIRS[@]}"; do
done
if [[ "$RECONFIGURE" = 1 || "$CLEAN" = 1 || "$MISSING_DEPS" = 1 ]]; then
echo "INFO: cleaning objects: reconfigured=$RECONFIGURE requested=$CLEAN missing_dependencies=$MISSING_DEPS"
make clean 2>&1 | tee build.log || { echo "ERROR: clean failed; see build.log" >&2; exit 1; }
"$MAKE_TOOL" clean 2>&1 | tee build.log || { echo "ERROR: clean failed; see build.log" >&2; exit 1; }
else
echo "INFO: configuration unchanged; incremental build (mode=$MODE)"
: > build.log
@ -172,7 +189,7 @@ if [[ "$MODE" = asan ]]; then
echo "INFO: AddressSanitizer: building lib, Opus and src; skipping tests"
MAKE_ARGS+=("SUBDIRS=lib lib/libopus src")
fi
make "-j$JOBS" "${MAKE_ARGS[@]}" 2>&1 | tee -a build.log || { echo "ERROR: build failed; see build.log" >&2; exit 1; }
"$MAKE_TOOL" "-j$JOBS" "${MAKE_ARGS[@]}" 2>&1 | tee -a build.log || { echo "ERROR: build failed; see build.log" >&2; exit 1; }
# Состояние обновляется после успешной сборки ядра; ошибка GUI не инвалидирует готовые объекты.
GENERATION_OUTPUT=$(hash_files "${AUTOTOOLS_OUTPUTS[@]}")

162
build_bsd_full.sh

@ -1,144 +1,32 @@
#!/bin/sh
# Build script for uTun on FreeBSD (full rebuild)
# Usage: ./build_bsd_full.sh [options]
# Options:
# -h, --help Show this help
# --asan Build with AddressSanitizer (clang)
# --hardened Build with compiler security hardening flags (clang)
# -j[N] Build with N parallel jobs (default: sysctl hw.ncpu)
# Полная сборка FreeBSD: зависимости и общий инкрементальный скрипт.
set -e
# Parse arguments
USE_ASAN=0
USE_HARDENED=0
JOBS=""
MAKE_ARGS=""
while [ $# -gt 0 ]; do
case "$1" in
-h|--help)
echo "Usage: ./build_bsd_full.sh [options]"
echo "Options:"
echo " -h, --help Show this help"
echo " --asan Build with AddressSanitizer"
echo " --hardened Build with compiler security hardening flags"
echo " -j[N] Build with N parallel jobs (default: sysctl hw.ncpu)"
exit 0
;;
--asan)
USE_ASAN=1
shift
;;
--hardened)
USE_HARDENED=1
shift
;;
-j*)
JOBS="$1"
shift
;;
*)
MAKE_ARGS="$MAKE_ARGS $1"
shift
;;
esac
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
case " ${*} " in
*" --help "*|*" -h "*)
echo "Usage: ./build_bsd_full.sh [--asan|--hardened] [-jN] [build.sh arguments]"
echo "Installs missing build tools and runs build.sh --full"
exit 0 ;;
esac
need_install=0
for tool in bash gmake autoreconf aclocal automake libtoolize pkg-config; do
command -v "$tool" >/dev/null 2>&1 || need_install=1
done
if [ -z "$JOBS" ]; then
if command -v nproc >/dev/null 2>&1; then
JOBS="-j$(nproc)"
else
JOBS="-j$(sysctl -n hw.ncpu)"
fi
if [ "$need_install" -eq 1 ]; then
echo "INFO: installing missing FreeBSD build dependencies (requires root)"
pkg install -y bash gmake autoconf automake libtool pkgconf openssl || {
echo "ERROR: cannot install FreeBSD build dependencies" >&2; exit 1;
}
fi
# Проверка и установка зависимостей
need_install=""
for cmd in autoreconf aclocal automake libtoolize; do
if ! command -v "$cmd" >/dev/null 2>&1; then
need_install=1
break
fi
jobs_found=0
for argument do
case "$argument" in -j*) jobs_found=1 ;; esac
done
if [ -n "$need_install" ]; then
echo "Устанавливаются необходимые пакеты (нужен root)..."
pkg update
pkg install -y autoconf automake libtool pkgconf openssl
fi
# Предпочитаем GNU make (gmake), но fallback на bmake — он собирает
# autotools-генерённые Makefile данного проекта. gmake ставится отдельно:
# pkg install gmake (нужен root)
GMAKE="$(command -v gmake || command -v make)"
echo "Используем make: $GMAKE"
mkdir -p m4
echo "=== Полная пересборка uTun ==="
# 1. Очистка
echo "[1/4] Очистка..."
$GMAKE distclean 2>/dev/null || true
rm -f config.h config.status config.log
rm -f configure.log autoreconf.log build.log
# 2. Генерация configure
echo "[2/4] Автогенерация..."
autoreconf -fi 2>&1 | tee autoreconf.log
# Проверяем, появился ли configure
if [ ! -f configure ]; then
echo "Ошибка: autoreconf не создал configure."
exit 1
fi
chmod +x configure
# 3. Конфигурация
echo "[3/4] Конфигурация..."
# FFmpeg (опционально) — автоопределение через pkg-config
FFMPEG_OPT=""
if command -v pkg-config >/dev/null 2>&1 && \
pkg-config --exists libavformat libavcodec libavutil libswscale libswresample 2>/dev/null; then
FFMPEG_OPT="--with-ffmpeg"
echo "FFmpeg detected — building with video transcoding"
else
echo "FFmpeg not found — building without video transcoding"
fi
if [ "$USE_ASAN" -eq 1 ]; then
echo "(AddressSanitizer enabled — clang, lib/ + src/ only)"
./configure --prefix=/usr/local CC=clang \
CFLAGS="-g -O1 -fsanitize=address -fno-omit-frame-pointer" \
LDFLAGS="-fsanitize=address" $FFMPEG_OPT 2>&1 | tee configure.log
elif [ "$USE_HARDENED" -eq 1 ]; then
echo "(Hardening enabled — clang-safe flags)"
./configure --prefix=/usr/local CC=clang \
CFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong -fPIE" \
LDFLAGS="-Wl,-z,relro -Wl,-z,now -pie" $FFMPEG_OPT 2>&1 | tee configure.log
else
./configure --prefix=/usr/local $FFMPEG_OPT 2>&1 | tee configure.log
fi
# 4. Сборка
echo "[4/4] Сборка..."
if [ "$USE_ASAN" -eq 1 ]; then
(cd lib && $GMAKE $JOBS $MAKE_ARGS 2>&1 | tee ../build.log)
(cd lib/libopus && $GMAKE $JOBS $MAKE_ARGS 2>&1 | tee ../../build.log)
(cd src && $GMAKE $JOBS $MAKE_ARGS 2>&1 | tee ../build.log)
else
$GMAKE $JOBS $MAKE_ARGS 2>&1 | tee build.log
fi
echo
echo "=== Готово ==="
echo "Бинарный файл: src/utun"
if [ "$USE_ASAN" -eq 1 ]; then
echo
echo "Запуск с ASAN (detect_leaks=0 обязателен на FreeBSD):"
echo " ASAN_OPTIONS=detect_leaks=0:halt_on_error=0 ./src/utun -f -p /tmp/utun.pid -l /tmp/utun.log"
if [ "$jobs_found" -eq 0 ]; then
jobs=$(sysctl -n hw.ncpu) || { echo "ERROR: cannot determine CPU count" >&2; exit 1; }
set -- "-j$jobs" "$@"
fi
echo "INFO: running shared build script for FreeBSD"
exec bash "$SCRIPT_DIR/build.sh" --full "$@"

19
configure.ac

@ -62,11 +62,24 @@ AC_ARG_ENABLE([hardening],
[enable_hardening=no])
if test "x$enable_hardening" = "xyes"; then
HARDEN_CFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong -fstack-clash-protection -Wformat=2 -Wformat-overflow=2 -fPIE"
HARDEN_LDFLAGS="-Wl,-z,relro -Wl,-z,now -pie"
HARDEN_CFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong -Wformat=2"
compiler_version=$($CC --version 2>&1) || AC_MSG_ERROR([Cannot identify compiler for hardening])
case "$compiler_version" in
*clang*) ;;
*) HARDEN_CFLAGS="$HARDEN_CFLAGS -fstack-clash-protection -Wformat-overflow=2" ;;
esac
case "$host" in
*mingw* | *msys* | *cygwin*)
HARDEN_LDFLAGS="-Wl,--dynamicbase,--nxcompat,--high-entropy-va"
;;
*)
HARDEN_CFLAGS="$HARDEN_CFLAGS -fPIE"
HARDEN_LDFLAGS="-Wl,-z,relro -Wl,-z,now -pie"
;;
esac
CFLAGS="$CFLAGS $HARDEN_CFLAGS"
LDFLAGS="$LDFLAGS $HARDEN_LDFLAGS"
AC_MSG_NOTICE([Hardening flags enabled: $HARDEN_CFLAGS])
AC_MSG_NOTICE([Hardening flags enabled: CFLAGS=$HARDEN_CFLAGS LDFLAGS=$HARDEN_LDFLAGS])
fi
# ==================== НАДЁЖНЫЙ ДЕТЕКТ WINDOWS ====================

Loading…
Cancel
Save