diff --git a/.github/workflows/cmake_tests.yml b/.github/workflows/cmake_tests.yml new file mode 100644 index 00000000..6b12e51e --- /dev/null +++ b/.github/workflows/cmake_tests.yml @@ -0,0 +1,50 @@ +name: CMake build + +on: + workflow_call: + inputs: + update_cmake_lists_config: + type: string + description: "The configuration used when updating the CMake lists." + required: true + cmake_build_target_directory: + type: string + description: "The directory to pass to `cmake build`." + default: "." + cmake_version: + type: string + description: "The version of CMake to install." + default: "" + image: + type: string + description: "The docker image to run the checks in." + default: "swift:6.0-jammy" + +jobs: + cmake-checks: + name: CMake checks + runs-on: ubuntu-latest + container: + image: ${{ inputs.image }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: true + - name: Mark the workspace as safe + # https://github.com/actions/checkout/issues/766 + run: git config --global --add safe.directory ${GITHUB_WORKSPACE} + - name: Check CMakeLists files + run: | + which curl jq || apt -q update + which curl || apt -yq install curl + which jq || apt -yq install jq + curl -s https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/update-cmake-lists.sh | CONFIG_JSON='${{ inputs.update_cmake_lists_config }}' FAIL_ON_CHANGES=true bash + - name: CMake build + run: | + which curl cmake ninja || apt -q update + which curl || apt -yq install curl + which cmake || apt -yq install cmake + which ninja || apt -yq install ninja-build + curl -s https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/cmake-build.sh | TARGET_DIRECTORY="${{ inputs.cmake_build_target_directory }}" CMAKE_VERSION="${{ inputs.cmake_version }}" bash diff --git a/.github/workflows/scripts/cmake-build.sh b/.github/workflows/scripts/cmake-build.sh new file mode 100755 index 00000000..7a0f7d75 --- /dev/null +++ b/.github/workflows/scripts/cmake-build.sh @@ -0,0 +1,39 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2025 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -uo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +target_dir="${TARGET_DIRECTORY:=""}" + +if [ -z "$target_dir" ]; then + fatal "Target directory must be specified." +fi + +CURL_BIN="${CURL_BIN:-$(which curl)}" || fatal "CURL_BIN unset and no curl on PATH" +TAR_BIN="${TAR_BIN:-$(which tar)}" || fatal "TAR_BIN unset and no tar on PATH" +CMAKE_BIN="${CMAKE_BIN:-$(which cmake)}" || fatal "CMAKE_BIN unset and no cmake on PATH" +NINJA_BIN="${NINJA_BIN:-$(which ninja)}" || fatal "NINJA_BIN unset and no ninja on PATH" +ASSEMBLY_COMPILER_BIN="${ASSEMBLY_COMPILER_BIN:-$(which clang)}" || fatal "ASSEMBLY_COMPILER_BIN unset and no clang on PATH" + +log "Building Ninja build files for target" +build_dir="${target_dir}/build" +mkdir -p "$build_dir" +cd "${build_dir}" || fatal "Could not 'cd' to ${build_dir}" +ASM="$ASSEMBLY_COMPILER_BIN" "$CMAKE_BIN" build -G Ninja -S .. + +log "Building target" +"$NINJA_BIN" diff --git a/.github/workflows/scripts/update-cmake-lists.sh b/.github/workflows/scripts/update-cmake-lists.sh new file mode 100755 index 00000000..30fecaf2 --- /dev/null +++ b/.github/workflows/scripts/update-cmake-lists.sh @@ -0,0 +1,128 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2025 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -eu + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +config="${CONFIG_JSON:=""}" +fail_on_changes="${FAIL_ON_CHANGES:="false"}" + +if [ -z "$config" ]; then + fatal "Configuration must be provided." +fi + +here=$(pwd) + +case "$(uname -s)" in + Darwin) + find=gfind # brew install findutils + ;; + *) + find='find' + ;; +esac + +function update_cmakelists_source() { + src_root="$here/Sources/$1" + + src_exts=("*.c" "*.swift" "*.cc") + num_exts=${#src_exts[@]} + log "Finding source files (" "${src_exts[@]}" ") and platform independent assembly files under $src_root" + + # Build file extensions argument for `find` + declare -a exts_arg + exts_arg+=(-name "${src_exts[0]}") + for (( i=1; i>:%P>"\n' | LC_ALL=POSIX sort) + + srcs="$srcs"$'\n'"$asm_srcs" + log "$srcs" + + # Update list of source files in CMakeLists.txt + # The first part in `BEGIN` (i.e., `undef $/;`) is for working with multi-line; + # the second is so that we can pass in a variable to replace with. + perl -pi -e 'BEGIN { undef $/; $replace = shift } s/add_library\(([^\n]+)\n([^\)]+)/add_library\($1\n$replace/' "$srcs" "$src_root/CMakeLists.txt" + log "Updated $src_root/CMakeLists.txt" +} + +function update_cmakelists_assembly() { + src_root="$here/Sources/$1" + log "Finding assembly files (.S) under $src_root" + + mac_x86_64_asms=$($find "${src_root}" -type f \( -name "*x86_64*" -or -name "*avx2*" \) -name "*apple*" -name "*.S" -printf ' %P\n' | LC_ALL=POSIX sort) + linux_x86_64_asms=$($find "${src_root}" -type f \( -name "*x86_64*" -or -name "*avx2*" \) -name "*linux*" -name "*.S" -printf ' %P\n' | LC_ALL=POSIX sort) + mac_aarch64_asms=$($find "${src_root}" -type f -name "*armv8*" -name "*apple*" -name "*.S" -printf ' %P\n' | LC_ALL=POSIX sort) + linux_aarch64_asms=$($find "${src_root}" -type f -name "*armv8*" -name "*linux*" -name "*.S" -printf ' %P\n' | LC_ALL=POSIX sort) + log "$mac_x86_64_asms" + log "$linux_x86_64_asms" + log "$mac_aarch64_asms" + log "$linux_aarch64_asms" + + # Update list of assembly files in CMakeLists.txt + # The first part in `BEGIN` (i.e., `undef $/;`) is for working with multi-line; + # the second is so that we can pass in a variable to replace with. + perl -pi -e 'BEGIN { undef $/; $replace = shift } s/Darwin([^\)]+)x86_64"\)\n target_sources\(([^\n]+)\n([^\)]+)/Darwin$1x86_64"\)\n target_sources\($2\n$replace/' "$mac_x86_64_asms" "$src_root/CMakeLists.txt" + perl -pi -e 'BEGIN { undef $/; $replace = shift } s/Linux([^\)]+)x86_64"\)\n target_sources\(([^\n]+)\n([^\)]+)/Linux$1x86_64"\)\n target_sources\($2\n$replace/' "$linux_x86_64_asms" "$src_root/CMakeLists.txt" + perl -pi -e 'BEGIN { undef $/; $replace = shift } s/Darwin([^\)]+)aarch64"\)\n target_sources\(([^\n]+)\n([^\)]+)/Darwin$1aarch64"\)\n target_sources\($2\n$replace/' "$mac_aarch64_asms" "$src_root/CMakeLists.txt" + perl -pi -e 'BEGIN { undef $/; $replace = shift } s/Linux([^\)]+)aarch64"\)\n target_sources\(([^\n]+)\n([^\)]+)/Linux$1aarch64"\)\n target_sources\($2\n$replace/' "$linux_aarch64_asms" "$src_root/CMakeLists.txt" + log "Updated $src_root/CMakeLists.txt" +} + +echo "$config" | jq -c '.targets[]' | while read -r target; do + name="$(echo "$target" | jq -r .name)" + type="$(echo "$target" | jq -r .type)" + exceptions=("$(echo "$target" | jq -r .exceptions | jq -r @sh)") + log "Updating cmake list for ${name}" + + case "$type" in + source) + update_cmakelists_source "$name" "${exceptions[@]}" + ;; + assembly) + update_cmakelists_assembly "$name" + ;; + *) + fatal "Unknown target type: $type" + ;; + esac +done + +if [[ "${fail_on_changes}" == true ]]; then + if [ -n "$(git status --untracked-files=no --porcelain)" ]; then + fatal "Changes in the cmake files detected. Please update." + else + log "✅ CMake files are up-to-date." + fi +fi