diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 75abc440a..ba36f8995 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -108,3 +108,160 @@ jobs: ${{ runner.temp }}/${{ env.BASELINE_FILE }} ${{ runner.temp }}/${{ env.COMPARE_FILE }} ${{ runner.temp }}/${{ env.COMPARE_OUT_FILE }} + crossrepo: + name: Cross-Repo Validation + runs-on: ubuntu-latest + container: + image: swift:6.3-jammy + steps: + - name: Checkout repo + uses: actions/checkout@v7 + - name: Install apt dependencies + run: apt-get -qq update && apt-get -qq -y install curl ninja-build + - name: Install CMake 3.30.2 + run: | + ARCH=`uname -m` + curl -sL https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-$ARCH.tar.gz -O + tar xzf cmake-3.30.2-linux-$ARCH.tar.gz + export PATH="`pwd`/cmake-3.30.2-linux-$ARCH/bin:$PATH" + echo "PATH=$PATH" >> $GITHUB_ENV + cmake --version + - name: Compare CMakeLists.txt against swiftlang/swift/Runtimes/Supplemental + id: compare + env: + UPSTREAM_DIR: https://raw.githubusercontent.com/swiftlang/swift/refs/heads/main/Runtimes/Supplemental/StringProcessing + MODULES: _StringProcessing _RegexParser + shell: bash + run: | + set -u + + # `-f` so a file moving upstream reports a fetch error rather than + # diffing against a 404 page. + for module in $MODULES; do + if ! curl -fsSL "$UPSTREAM_DIR/$module/CMakeLists.txt" \ + -o "upstream-$module-CMakeLists.txt"; then + echo "result=fetch-failed" >> "$GITHUB_OUTPUT" + echo "Could not fetch $module/CMakeLists.txt from swiftlang/swift." + exit 1 + fi + done + + : > "$RUNNER_TEMP/cmake-diff.txt" + status=0 + for module in $MODULES; do + if ! diff -u \ + --label "swiftlang/swift: Runtimes/Supplemental/StringProcessing/$module/CMakeLists.txt" \ + --label "this repo: Sources/$module/CMakeLists.txt" \ + "upstream-$module-CMakeLists.txt" \ + "Sources/$module/CMakeLists.txt" \ + >> "$RUNNER_TEMP/cmake-diff.txt"; then + status=1 + fi + done + + if [ "$status" -eq 0 ]; then + echo "result=match" >> "$GITHUB_OUTPUT" + echo "Both CMakeLists.txt files match swiftlang/swift." + else + echo "result=differs" >> "$GITHUB_OUTPUT" + cat "$RUNNER_TEMP/cmake-diff.txt" + fi + exit "$status" + - name: Configure CMake + id: configure + if: ${{ !cancelled() }} + run: cmake -G Ninja -S Sources -B build -DCMAKE_BUILD_TYPE=Release + - name: Build + id: build + if: ${{ !cancelled() }} + run: cmake --build build + - name: Verdict + if: ${{ always() }} + env: + COMPARE_OUTCOME: ${{ steps.compare.outcome }} + COMPARE_RESULT: ${{ steps.compare.outputs.result }} + CONFIGURE_OUTCOME: ${{ steps.configure.outcome }} + BUILD_OUTCOME: ${{ steps.build.outcome }} + shell: bash + run: | + set -u + + # Report to the step log and to the job summary page. + emit() { printf '%s\n' "$@" | tee -a "$GITHUB_STEP_SUMMARY"; } + + failed=0 + + # --- the CMake build --- + if [ "$CONFIGURE_OUTCOME" = failure ] || [ "$BUILD_OUTCOME" = failure ]; then + failed=1 + if [ "$CONFIGURE_OUTCOME" = failure ]; then + stage='CMake configuration' + else + stage='CMake build' + fi + emit \ + "## :x: $stage failed" \ + '' \ + 'The CMake build of `_RegexParser` and `_StringProcessing` is broken.' \ + "See the \"$stage\" step above for the output." \ + '' + fi + + # --- the comparison against swiftlang/swift --- + case "${COMPARE_RESULT:-}" in + match) + ;; + differs) + failed=1 + emit \ + '## :warning: `CMakeLists.txt` differs from swiftlang/swift' \ + '' \ + '
Diff to apply upstream' \ + '' \ + '```diff' + tee -a "$GITHUB_STEP_SUMMARY" < "$RUNNER_TEMP/cmake-diff.txt" + emit '```' '' '
' '' + ;; + fetch-failed) + failed=1 + emit \ + '## :x: Could not fetch the upstream `CMakeLists.txt` files' + ;; + *) + failed=1 + emit \ + "## :x: Comparison did not complete (outcome: ${COMPARE_OUTCOME:-unknown})" + ;; + esac + + # --- all clear --- + if [ "$failed" -eq 0 ]; then + emit \ + '## :white_check_mark: Cross-repo validation passed' + fi + + exit "$failed" + required: + name: Required + runs-on: ubuntu-latest + needs: + - tests + - soundness + - bench + if: always() # Runs even if previous jobs fail so it can evaluate them + steps: + - name: Install required tools + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends coreutils jq + - name: Check upstream job statuses + env: + NEEDS_JSON: ${{ toJSON(needs) }} + run: | + failed=$(printf '%s' "$NEEDS_JSON" | jq -r 'to_entries | map(select(.value.result != "success")) | .[] | "\(.key): \(.value.result)"') + if [ -n "$failed" ]; then + echo "The following required jobs did not succeed:" + printf '%s\n' "$failed" + exit 1 + fi + echo "All required jobs succeeded." diff --git a/Package.swift b/Package.swift index 1ca2a7400..97186bc61 100644 --- a/Package.swift +++ b/Package.swift @@ -1,6 +1,4 @@ // swift-tools-version:6.0 -// The swift-tools-version declares the minimum version of Swift required to build this package. - import PackageDescription let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([ @@ -46,7 +44,6 @@ let publicStdlibSettings: [PackageDescription.SwiftSetting] = [ let package = Package( name: "swift-experimental-string-processing", products: [ - // Products define the executables and libraries produced by a package, and make them visible to other packages. .library( name: "_StringProcessing", targets: ["_StringProcessing"]), @@ -69,11 +66,10 @@ let package = Package( .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "_RegexParser", dependencies: [], + exclude: ["CMakeLists.txt"], packageAccess: false, swiftSettings: privateStdlibSettings), .testTarget( @@ -90,6 +86,7 @@ let package = Package( "_RegexParser", "_CUnicode", ], + exclude: ["CMakeLists.txt", "_CUnicode"], packageAccess: false, swiftSettings: publicStdlibSettings), .target( diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt new file mode 100644 index 000000000..03199afb0 --- /dev/null +++ b/Sources/CMakeLists.txt @@ -0,0 +1,92 @@ +#===-----------------------------------------------------------------------===# +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2026 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 +# +#===-----------------------------------------------------------------------===# + +# NOTE: This build configuration is only to validate that the settings +# match between the swiftlang/swift project and this one, not for +# producing installable libraries. + +cmake_minimum_required(VERSION 3.26) + +project(SwiftStringProcessing + VERSION 1.0.0 + LANGUAGES C Swift) + +include(GNUInstallDirs) + +set(CMAKE_Swift_LANGUAGE_VERSION 5) +set(CMAKE_C_STANDARD 99) + +option(BUILD_SHARED_LIBS "Build shared libraries" YES) + +set(SwiftStringProcessing_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/swift" + CACHE STRING "Destination for the built libraries") + +#===-----------------------------------------------------------------------===# +# Compiler flags +#===-----------------------------------------------------------------------===# + +add_compile_options( + "$<$:SHELL:-Xfrontend -disable-implicit-concurrency-module-import>" + "$<$:SHELL:-Xfrontend -disable-implicit-string-processing-module-import>") + +foreach(definition + "SwiftStdlib 5.7:macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0" + "SwiftStdlib 5.8:macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4" + "SwiftStdlib 5.9:macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0" + "SwiftStdlib 6.0:macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0" + "SwiftStdlib 6.1:macOS 15.4, iOS 18.4, watchOS 11.4, tvOS 18.4, visionOS 2.4" + "SwiftStdlib 6.2:macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0" + "SwiftStdlib 6.3:macOS 26.4, iOS 26.4, watchOS 26.4, tvOS 26.4, visionOS 26.4" + "SwiftStdlib 6.4:macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0" + "SwiftStdlib 6.5:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999") + add_compile_options( + "$<$:SHELL:-Xfrontend -define-availability -Xfrontend \"${definition}\">") +endforeach() + +add_compile_options( + "$<$:SHELL:-enable-upcoming-feature MemberImportVisibility>") + +#===-----------------------------------------------------------------------===# +# Shims for the runtime build +#===-----------------------------------------------------------------------===# +# +# The module files call into helpers that only exist in the Swift runtime's +# build. Define just enough here for them to resolve. Each shim below is a no-op, +# so this configuration builds and links the two modules but does *not* produce +# an installable stdlib component. + +# In the runtime build `swiftCore` is a real target. Standalone, the stdlib +# comes from the toolchain and needs no explicit link. +if(NOT TARGET swiftCore) + add_library(swiftCore INTERFACE) +endif() + +# Library evolution and `.swiftinterface` emission. +function(emit_swift_interface target) +endfunction() + +function(install_swift_interface target) +endfunction() + +# Darwin packaging metadata, irrelevant to a standalone build. +function(generate_plist name version target) +endfunction() + +function(embed_manifest target) +endfunction() + +#===-----------------------------------------------------------------------===# +# Modules +#===-----------------------------------------------------------------------===# + +# Order matters: _StringProcessing links _RegexParser. +add_subdirectory(_RegexParser) +add_subdirectory(_StringProcessing) diff --git a/Sources/_RegexParser/CMakeLists.txt b/Sources/_RegexParser/CMakeLists.txt new file mode 100644 index 000000000..a3bad7850 --- /dev/null +++ b/Sources/_RegexParser/CMakeLists.txt @@ -0,0 +1,49 @@ +add_library(swift_RegexParser + Regex/TreeProtocols.swift + Regex/Parse/DelimiterLexing.swift + Regex/Parse/Source.swift + Regex/Parse/CharacterPropertyClassification.swift + Regex/Parse/LexicalAnalysis.swift + Regex/Parse/SyntaxOptions.swift + Regex/Parse/CaptureList.swift + Regex/Parse/CompilerInterface.swift + Regex/Parse/CaptureStructure.swift + Regex/Parse/Parse.swift + Regex/Parse/SourceLocation.swift + Regex/Parse/Diagnostics.swift + Regex/Parse/Sema.swift + Regex/Printing/RenderRanges.swift + Regex/Printing/PrettyPrinter.swift + Regex/Printing/PrintAsCanonical.swift + Regex/Printing/DumpAST.swift + Regex/AST/ASTAction.swift + Regex/AST/AST.swift + Regex/AST/CustomCharClass.swift + Regex/AST/Quantification.swift + Regex/AST/Conditional.swift + Regex/AST/MatchingOptions.swift + Regex/AST/ASTProtocols.swift + Regex/AST/Group.swift + Regex/AST/Atom.swift + Utility/TypeConstruction.swift + Utility/Misc.swift + Utility/AllScalars.swift + Utility/Errors.swift + Utility/MissingUnicode.swift) + +target_link_libraries(swift_RegexParser PRIVATE + swiftCore + $<$:swiftSwiftDirectRuntime>) + +set_target_properties(swift_RegexParser PROPERTIES + Swift_MODULE_NAME _RegexParser) + +install(TARGETS swift_RegexParser + ARCHIVE DESTINATION "${SwiftStringProcessing_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${SwiftStringProcessing_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") +emit_swift_interface(swift_RegexParser) +install_swift_interface(swift_RegexParser) + +generate_plist(swiftRegexParser "${CMAKE_PROJECT_VERSION}" swift_RegexParser) +embed_manifest(swift_RegexParser) diff --git a/Sources/_StringProcessing/CMakeLists.txt b/Sources/_StringProcessing/CMakeLists.txt new file mode 100644 index 000000000..56914d90b --- /dev/null +++ b/Sources/_StringProcessing/CMakeLists.txt @@ -0,0 +1,96 @@ +add_library(swift_StringProcessing + _CUnicode/UnicodeData.c + _CUnicode/UnicodeScalarProps.c + _CharacterClassModel.swift + Executor.swift + Capture.swift + Unicode/NumberParsing.swift + Unicode/ASCII.swift + Unicode/CharacterProps.swift + Unicode/Transcoding.swift + Unicode/ScalarProps.swift + Unicode/Comparison.swift + Unicode/NecessaryEvils.swift + Unicode/Validation.swift + Unicode/UCD.swift + Unicode/NFC.swift + Unicode/Encodings.swift + Unicode/Formatting.swift + Unicode/WordBreaking.swift + Unicode/Decoding.swift + Unicode/CaseConversion.swift + Algorithms/Matching/FirstMatch.swift + Algorithms/Matching/MatchingCollectionSearcher.swift + Algorithms/Matching/MatchResult.swift + Algorithms/Matching/MatchReplace.swift + Algorithms/Matching/Matches.swift + Algorithms/Algorithms/FirstRange.swift + Algorithms/Algorithms/Contains.swift + Algorithms/Algorithms/Split.swift + Algorithms/Algorithms/Trim.swift + Algorithms/Algorithms/Ranges.swift + Algorithms/Algorithms/StartsWith.swift + Algorithms/Algorithms/Replace.swift + Algorithms/Algorithms/SubstringSearcher.swift + Algorithms/Searchers/CollectionSearcher.swift + Algorithms/Searchers/ZSearcher.swift + Algorithms/Consumers/CollectionConsumer.swift + Algorithms/Consumers/FixedPatternConsumer.swift + Regex/Options.swift + Regex/Match.swift + Regex/CustomComponents.swift + Regex/Core.swift + Regex/ASTConversion.swift + Regex/DSLTree.swift + Regex/DSLList.swift + Regex/AnyRegexOutput.swift + LiteralPrinter.swift + MatchingOptions.swift + Compiler.swift + ConsumerInterface.swift + PrintAsPattern.swift + Engine/MEBuiltins.swift + Engine/Processor.swift + Engine/MEProgram.swift + Engine/MEQuantify.swift + Engine/InstPayload.swift + Engine/Backtracking.swift + Engine/Instruction.swift + Engine/Registers.swift + Engine/MEBuilder.swift + Engine/Structuralize.swift + Engine/Tracing.swift + Engine/Metrics.swift + Engine/MECapture.swift + ByteCodeGen.swift + ByteCodeGen+DSLList.swift + Optimizations/AutoPossessification.swift + Utility/AsciiBitset.swift + Utility/AtomicCounter.swift + Utility/Traced.swift + Utility/TypedIndex.swift + Utility/Misc.swift + Utility/TypedInt.swift + Utility/Protocols.swift + Utility/TypeVerification.swift + Utility/RegexFactory.swift + Utility/UndoableArray.swift + Utility/ASTBuilder.swift) + +set_target_properties(swift_StringProcessing PROPERTIES + Swift_MODULE_NAME _StringProcessing) + +target_link_libraries(swift_StringProcessing PRIVATE + swift_RegexParser + swiftCore + $<$:swiftSwiftDirectRuntime>) + +install(TARGETS swift_StringProcessing + ARCHIVE DESTINATION "${SwiftStringProcessing_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${SwiftStringProcessing_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") +emit_swift_interface(swift_StringProcessing) +install_swift_interface(swift_StringProcessing) + +generate_plist(swiftStringProcessing "${CMAKE_PROJECT_VERSION}" swift_StringProcessing) +embed_manifest(swift_StringProcessing) diff --git a/Sources/_StringProcessing/_CUnicode b/Sources/_StringProcessing/_CUnicode new file mode 120000 index 000000000..efcc8b167 --- /dev/null +++ b/Sources/_StringProcessing/_CUnicode @@ -0,0 +1 @@ +../_CUnicode \ No newline at end of file