Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/cmake_tests.yml
Original file line number Diff line number Diff line change
@@ -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
39 changes: 39 additions & 0 deletions .github/workflows/scripts/cmake-build.sh
Original file line number Diff line number Diff line change
@@ -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"
128 changes: 128 additions & 0 deletions .github/workflows/scripts/update-cmake-lists.sh
Original file line number Diff line number Diff line change
@@ -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<num_exts; i++ ));
do
exts_arg+=(-o -name "${src_exts[$i]}")
done

# Build an array with the rest of the arguments
shift
exceptions=("$@")
# Add path exceptions for `find`
if (( ${#exceptions[@]} )); then
log "Excluding source paths (" "${exceptions[@]}" ") under $src_root"
num_exceptions=${#exceptions[@]}
for (( i=0; i<num_exceptions; i++ ));
do
exts_arg+=(! -path "${exceptions[$i]}")
done
fi

# Wrap quotes around each filename since it might contain spaces
srcs=$($find -L "${src_root}" -type f \( "${exts_arg[@]}" \) -printf ' "%P"\n' | LC_ALL=POSIX sort)
asm_srcs=$($find -L "${src_root}" -type f \( \( -name "*.S" -a ! -name "*x86_64*" -a ! -name "*arm*" -a ! -name "*apple*" -a ! -name "*linux*" \) \) -printf ' "$<$<NOT:$<PLATFORM_ID:Windows>>:%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
Loading