diff --git a/tools/linux/build.sh b/tools/linux/build.sh new file mode 100644 index 0000000..c65ab64 --- /dev/null +++ b/tools/linux/build.sh @@ -0,0 +1,258 @@ +#!/bin/bash +set -e + +# Default values +JOBS=0 +GENERATOR="ninja" +BUILD_TYPE="Release" +PRESERVE_BUILD=0 +LINK_STATIC_GCC=OFF +LINK_STATIC_STDCPP=OFF +OPTIMIZE_NATIVE=OFF +ADDITIONAL_CMAKE_ARGS="" + +# Display help message +show_help() { + cat << EOF +Usage: tools/linux/build.sh [options] + +Options: + -h, --help + Show this help message and exit. + + -b, --build-type + Set the build type (Debug, Release, RelWithDebInfo) (default: Release). + + -c, --compiler + Specify the compiler to use (gcc or clang) (default: auto-detected). + + -j, --jobs + Number of parallel jobs for the build (default: number of CPU cores). + + -k, --keep-build + Preserve the build directory; does not delete it before building. + + -o, --optimize + Enable optimizations for the current CPU (equivalent to compiler flag -march=native). + + -s, --static-runtime + Enable static linking of runtime libraries (e.g., libgcc, libstdc++). + + -- + Pass remaining arguments directly to CMake. + +Examples: + tools/linux/build.sh + Automatically detect the compiler and build with default settings. + + tools/linux/build.sh -c gcc -b debug + Build using the GCC compiler with the Debug build type. + + tools/linux/build.sh --compiler clang --optimize + Build using the Clang compiler with optimizations enabled for the current CPU. + + tools/linux/build.sh -- -DENABLE_SPEEX_VORBIS_PSY=ON + Automatically detect the compiler and pass additional options to CMake. +EOF +} + +# Parse command-line arguments +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + show_help + exit 0 + ;; + -b|--build-type) + BUILD_TYPE="$2" + shift 2 + ;; + -c|--compiler) + COMPILER="$2" + shift 2 + ;; + -j|--jobs) + JOBS="$2" + shift 2 + ;; + -k|--keep-build) + PRESERVE_BUILD=1 + shift + ;; + -o|--optimize) + OPTIMIZE_NATIVE=ON + shift + ;; + -s|--static-runtime) + LINK_STATIC_GCC=ON + LINK_STATIC_STDCPP=ON + shift + ;; + --) + shift + ADDITIONAL_CMAKE_ARGS="$*" + break + ;; + *) + echo "Unknown option: $1" + show_help + exit 1 + ;; + esac +done + +# Check availability of Ninja build system +check_ninja() { + if ! command -v ninja &> /dev/null; then + echo "Error: Ninja build system not found. Please install Ninja build." + exit 1 + fi + + echo "-- Found Ninja $(ninja --version)" +} + +# Check CMake availability and minimum version +check_cmake() { + local required_major=3 + local required_minor=21 + + if ! command -v cmake &> /dev/null; then + echo "Error: CMake not found. Please install CMake." + exit 1 + fi + + local cmake_version + cmake_version=$(cmake --version | head -n1 | sed 's/cmake version //') + echo "-- Found CMake version $cmake_version" + + local cmake_major cmake_minor + cmake_major=$(echo "$cmake_version" | cut -d. -f1) + cmake_minor=$(echo "$cmake_version" | cut -d. -f2) + + if (( cmake_major < required_major || (cmake_major == required_major && cmake_minor < required_minor) )); then + echo "Error: CMake version $required_major.$required_minor or higher is required. Please update CMake." + exit 1 + fi +} + +# Select a compiler to use +select_compiler() { + if [[ -z "$COMPILER" ]]; then + if command -v gcc &> /dev/null; then + COMPILER="gcc" + elif command -v clang &> /dev/null; then + COMPILER="clang" + else + echo "Error: No suitable compiler found. Please install GCC or Clang." + exit 1 + fi + fi +} + +# Select toolchain based on compiler +select_toolchain() { + case "$COMPILER" in + gcc) + if ! command -v gcc &> /dev/null; then + echo "Error: GCC not found." + exit 1 + fi + TOOLCHAIN="gcc-linux" + ;; + clang) + if ! command -v clang &> /dev/null; then + echo "Error: Clang not found." + exit 1 + fi + TOOLCHAIN="clang-linux" + ;; + *) + echo "Error: Unsupported compiler '$COMPILER'. Use gcc or clang." + exit 1 + ;; + esac +} + +# Select a CMake preset based on build type +select_preset() { + CONFIGURE_PRESET="$GENERATOR-$TOOLCHAIN" + + local build_type_lower + build_type_lower=$(echo "$BUILD_TYPE" | tr '[:upper:]' '[:lower:]') + + case "$build_type_lower" in + debug) + BUILD_PRESET="$CONFIGURE_PRESET-debug" + ;; + release) + BUILD_PRESET="$CONFIGURE_PRESET-release" + ;; + relwithdebinfo) + BUILD_PRESET="$CONFIGURE_PRESET-reldebinfo" + ;; + *) + echo "Error: Unsupported build type: $BUILD_TYPE" + exit 1 + ;; + esac + + echo "-- CMake build preset: $BUILD_PRESET" +} + +# Remove build directories if necessary +perform_cleanup() { + if [ "$PRESERVE_BUILD" -eq 0 ]; then + if [ -d "build" ]; then + echo "-- Removing build directory" + rm -rf build + fi + else + echo "-- Preserving build directory" + fi +} + +# Configure the build with CMake +configure_build() { + echo "" + cmake \ + --preset "$CONFIGURE_PRESET" \ + -DLINK_STATIC_GCC="$LINK_STATIC_GCC" \ + -DLINK_STATIC_STDCPP="$LINK_STATIC_STDCPP" \ + -DOPTIMIZE_FOR_CURRENT_CPU="$OPTIMIZE_NATIVE" \ + ${ADDITIONAL_CMAKE_ARGS:+"$ADDITIONAL_CMAKE_ARGS"} +} + +# Build the project using CMake +build_project() { + local args=( + --build + --preset "$BUILD_PRESET" + ) + + if [ "$JOBS" -ne 0 ]; then + args+=(--parallel "$JOBS") + fi + + if [ "$PRESERVE_BUILD" -ne 0 ]; then + args+=(--clean-first) + fi + + cmake "${args[@]}" +} + +echo "" + +# Build process +check_ninja +check_cmake +select_compiler +select_toolchain +select_preset +perform_cleanup +configure_build +build_project + +echo "" +echo "Build completed successfully!" +echo "Artifacts can be found in the \"bin\" directory." +echo "" diff --git a/tools/windows/build.ps1 b/tools/windows/build.ps1 new file mode 100644 index 0000000..b0cc45c --- /dev/null +++ b/tools/windows/build.ps1 @@ -0,0 +1,311 @@ +# Stop on first error +$ErrorActionPreference = "Stop" + +# Default values +$JOBS = 0 +$BUILD_TYPE = "Release" +$PRESERVE_BUILD = 0 +$LINK_STATIC_MSVC_RT = "OFF" +$OPTIMIZE_NATIVE = "OFF" +$ADDITIONAL_CMAKE_ARGS = @() + +# Display help message +function Show-Help { + Write-Host @" +Usage: tools\windows\build.ps1 [options] + +Options: + -h, --help + Show this help message and exit. + + -b, --build-type + Set the build type (Debug, Release, RelWithDebInfo) (default: Release). + + -c, --compiler + Specify the compiler to use (msvc or clang) (default: auto-detected). + + -g, --generator + Specify the build system generator (ninja or vs2022) (default: auto-detected). + + -j, --jobs + Number of parallel jobs for the build (default: number of CPU cores). + + -k, --keep-build + Preserve the build directory; does not delete it before building. + + -o, --optimize + Enable optimizations for the current CPU + (equivalent to compiler flag -march=native) (clang only). + + -s, --static-runtime + Enable static linking of runtime libraries (e.g., msvcrt). + + -- + Pass remaining arguments directly to CMake. + +Examples: + tools\windows\build.ps1 + Automatically detect the compiler and build with default settings. + + tools\windows\build.ps1 -c msvc -b debug + Build using the MSVC compiler with the Debug build type. + + tools\windows\build.ps1 --compiler clang --optimize + Build using the Clang compiler with optimizations enabled for the current CPU. + + tools\windows\build.ps1 -- -DENABLE_SPEEX_VORBIS_PSY=ON + Automatically detect the compiler and pass additional options to CMake. +"@ +} + +# Parse command-line arguments +$i = 0 +while ($i -lt $args.Count) { + switch ($args[$i]) { + {$_ -in "-h", "--help"} { + Show-Help; + exit 0 + } + {$_ -in "-b", "--build-type"} { + $BUILD_TYPE = $args[$i + 1] + $i += 2 + } + {$_ -in "-c", "--compiler"} { + $COMPILER = $args[$i + 1].ToLower() + $i += 2 + } + {$_ -in "-g", "--generator"} { + $GENERATOR = $args[$i + 1].ToLower() + $i += 2 + } + {$_ -in "-j", "--jobs"} { + $JOBS = $args[$i + 1] + $i += 2 + } + {$_ -in "-k", "--keep-build"} { + $PRESERVE_BUILD = 1 + $i += 1 + } + {$_ -in "-o", "--optimize"} { + $OPTIMIZE_NATIVE = "ON" + $i += 1 + } + {$_ -in "-s", "--static-runtime"} { + $LINK_STATIC_MSVC_RT = "ON" + $i += 1 + } + default { + $ADDITIONAL_CMAKE_ARGS += $args[$i] + $i += 1 + } + } +} + +# Initialize Visual Studio development environment +function Initialize-VsEnvironment { + $vsToolsPaths = @( + "C:\Program Files\Microsoft Visual Studio\*\*\*\Tools\Launch-VsDevShell.ps1" + "C:\Program Files (x86)\Microsoft Visual Studio\*\*\*\Tools\Launch-VsDevShell.ps1" + ) + + $launchVsDevShell = $vsToolsPaths | ForEach-Object { + Get-Item $_ -ErrorAction SilentlyContinue + } | Select-Object -First 1 -ExpandProperty FullName + + if (Test-Path $launchVsDevShell) { + & "$launchVsDevShell" -Arch x86 -HostArch amd64 -SkipAutomaticLocation + + if ($LASTEXITCODE -ne 0) { + throw "Failed to initialize Visual Studio environment, exit code: $LASTEXITCODE" + } + } +} + +# Check availability of Ninja build system +function Check-Ninja { + if (Get-Command ninja -ErrorAction SilentlyContinue) { + $ninjaVersion = ninja --version + Write-Host "-- Found Ninja $ninjaVersion" + } +} + +# Check CMake availability and minimum version +function Check-CMake { + $requiredMajor = 3 + $requiredMinor = 21 + $cmakeCommand = Get-Command cmake -ErrorAction SilentlyContinue + + if (-not $cmakeCommand) { + Write-Host "Error: CMake not found. Please install CMake." + exit 1 + } + + $cmakeVersionOutput = cmake --version + $cmakeVersion = ($cmakeVersionOutput -split "\n")[0] -replace "cmake version ", "" + Write-Host "-- Found CMake version $cmakeVersion" + + $versionParts = $cmakeVersion -split "\." + $cmakeMajor = [int]$versionParts[0] + $cmakeMinor = [int]$versionParts[1] + + if (($cmakeMajor -lt $requiredMajor) -or (($cmakeMajor -eq $requiredMajor) -and ($cmakeMinor -lt $requiredMinor))) { + Write-Host "Error: CMake version $requiredMajor.$requiredMinor or higher is required. Please update CMake." + exit 1 + } +} + +# Select build system generator +function Select-Generator { + if ($GENERATOR) { + return + } + + if (Get-Command ninja -ErrorAction SilentlyContinue) { + $script:GENERATOR = "ninja" + } + else { + $script:GENERATOR = "vs2022" + } +} + +# Select a compiler to use +function Select-Compiler { + if ($GENERATOR -eq "vs2022") { + if (-not $COMPILER) { + $script:COMPILER = "msvc" + } + } + else { + Initialize-VsEnvironment + $presetList = cmake --list-presets + $isClangPresetAvailable = [bool]($presetList | Where-Object { $_ -match '"[^"]*ninja-clang-[^"]*"' }) + + if (-not $COMPILER) { + if (($isClangPresetAvailable) -and (Get-Command clang -ErrorAction SilentlyContinue)) { + $script:COMPILER = "clang" + } + elseif (Get-Command cl -ErrorAction SilentlyContinue) { + $script:COMPILER = "msvc" + } + else { + Write-Host "Error: No suitable compiler found. Please install MSVC or Clang." + exit 1 + } + } + } +} + +# Select toolchain based on compiler +function Select-Toolchain { + switch ($COMPILER) { + "msvc" { + $script:TOOLCHAIN = "msvc-windows" + } + "clang" { + $script:TOOLCHAIN = "clang-windows" + } + default { + Write-Host "Error: Unsupported compiler '$COMPILER'. Use msvc or clang." + exit 1 + } + } +} + +# Select a CMake preset based on build type +function Select-Preset { + $script:CONFIGURE_PRESET = "$GENERATOR-$TOOLCHAIN" + + switch ($BUILD_TYPE.ToLower()) { + "debug" { + $script:BUILD_PRESET = "$CONFIGURE_PRESET-debug" + } + "release" { + $script:BUILD_PRESET = "$CONFIGURE_PRESET-release" + } + "relwithdebinfo" { + $script:BUILD_PRESET = "$CONFIGURE_PRESET-reldebinfo" + } + default { + Write-Host "Error: Unsupported build type: $BUILD_TYPE" + exit 1 + } + } + + Write-Host "-- CMake build preset: $BUILD_PRESET" +} + +# Remove build directories if necessary +function Perform-Cleanup { + if ($PRESERVE_BUILD -eq 0) { + if (Test-Path "build") { + Write-Host "-- Removing build directory" + Start-Process -FilePath "powershell.exe" ` + -ArgumentList "-Command", "Remove-Item -Recurse -Force 'build'" ` + -NoNewWindow -Wait + } + } + else { + Write-Host "-- Preserving build directory" + } +} + +# Configure the build with CMake +function Configure-Build { + Write-Host "" + + $cmakeArgs = @( + "--preset", "$CONFIGURE_PRESET", + "-DLINK_STATIC_MSVC_RT=$LINK_STATIC_MSVC_RT", + "-DOPTIMIZE_FOR_CURRENT_CPU=$OPTIMIZE_NATIVE" + ) + + if ($ADDITIONAL_CMAKE_ARGS) { + $cmakeArgs += $ADDITIONAL_CMAKE_ARGS + } + + & cmake $cmakeArgs + + if ($LASTEXITCODE -ne 0) { + throw "CMake configuration failed with exit code: $LASTEXITCODE" + } +} + +# Build the project using CMake +function Build-Project { + $buildArgs = @( + "--build", + "--preset", "$BUILD_PRESET" + ) + + if ($JOBS -ne 0) { + $buildArgs += "--parallel", "$JOBS" + } + + if ($PRESERVE_BUILD -ne 0) { + $buildArgs += "--clean-first" + } + + & cmake $buildArgs + + if ($LASTEXITCODE -ne 0) { + throw "CMake build failed with exit code: $LASTEXITCODE" + } +} + +Write-Host "" + +# Build process +Check-Ninja +Check-CMake +Select-Generator +Select-Compiler +Select-Toolchain +Select-Preset +Perform-Cleanup +Configure-Build +Build-Project + +Write-Host "" +Write-Host "Build completed successfully!" +Write-Host "Artifacts can be found in the 'bin' directory." +Write-Host ""