├── .bazelrc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── BUILD ├── LICENSE ├── README.md ├── SwiftSyntax.BUILD ├── WORKSPACE ├── deps.bzl └── test ├── BUILD ├── macos-binary-test.sh ├── macos_test_library.swift ├── main.swift ├── swift-binary-test.sh └── swift_test.swift /.bazelrc: -------------------------------------------------------------------------------- 1 | build --test_output=errors 2 | 3 | # TODO: Remove once https://github.com/bazelbuild/rules_swift/issues/775 is fixed 4 | build --swiftcopt=-wmo --host_swiftcopt=-wmo 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Bazel Build 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | macos-test: 7 | name: macOS test 8 | runs-on: macos-11 9 | steps: 10 | - uses: actions/checkout@v1 11 | - name: Select Xcode 12 | run: sudo xcode-select -s /Applications/Xcode_13.2.app 13 | - name: test 14 | run: bazelisk test //... 15 | linux-test: 16 | name: Linux test 17 | runs-on: ubuntu-20.04 18 | steps: 19 | - uses: actions/checkout@v1 20 | - uses: fwal/setup-swift@194625b58a582570f61cc707c3b558086c26b723 21 | with: 22 | swift-version: "5.7.1" 23 | - name: Get swift version 24 | run: swift --version 25 | - name: test 26 | run: CC=clang bazelisk test --build_tests_only //test:swift_binary_test //test:swift_test 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keith/swift-syntax-bazel/e653b97cd0058352ca576537a334bf3829db38f7/BUILD -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Keith Smiley (http://keith.so) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the 'Software'), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swift-syntax-bazel 2 | 3 | This repo provides a bazel target for 4 | [`SwiftSyntax`](https://github.com/apple/swift-syntax). Most importantly 5 | it handles vendoring `lib_InternalSwiftSyntaxParser` as a static library 6 | so your tool doesn't depend on a specific Xcode.app path or version. 7 | 8 | ## Usage 9 | 10 | 1. Make sure you've setup 11 | [`rules_apple`](https://github.com/bazelbuild/rules_apple) 12 | 2. Go to the [releases 13 | page](https://github.com/keith/swift-syntax-bazel/releases) to grab 14 | the WORKSPACE snippet for the Xcode version you're using 15 | 3. Add this target to your `deps`: 16 | 17 | ```bzl 18 | deps = [ 19 | "@com_github_keith_swift_syntax//:SwiftSyntax", 20 | ] 21 | ``` 22 | 23 | ## Details 24 | 25 | Previously if you built `SwiftSyntax` in your bazel build, the final 26 | binary would end up with a `rpath` like this: 27 | 28 | ``` 29 | /Applications/Xcode-12.4.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx 30 | ``` 31 | 32 | This meant if you used a remote bazel cache in your builds, everyone's 33 | Xcode path would have to match for this to work correctly. This repo 34 | links [a static 35 | binary](https://github.com/keith/StaticInternalSwiftSyntaxParser) for 36 | `lib_InternalSwiftSyntaxParser` instead. 37 | -------------------------------------------------------------------------------- /SwiftSyntax.BUILD: -------------------------------------------------------------------------------- 1 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") 2 | 3 | cc_library( 4 | name = "_CSwiftSyntax", 5 | srcs = glob(["Sources/_CSwiftSyntax/src/*.c"]), 6 | hdrs = glob(["Sources/_CSwiftSyntax/include/*.h"]), 7 | copts = ["-Iexternal/com_github_keith_swift_syntax/Sources/_CSwiftSyntax/include"], 8 | linkstatic = True, 9 | tags = ["swift_module"], 10 | ) 11 | 12 | swift_library( 13 | name = "SwiftSyntax", 14 | srcs = glob(["Sources/SwiftSyntax/**/*.swift"]), 15 | module_name = "SwiftSyntax", 16 | private_deps = ["_CSwiftSyntax"] + select({ 17 | "@platforms//os:macos": [ 18 | "@StaticInternalSwiftSyntaxParser//:lib_InternalSwiftSyntaxParser", 19 | ], 20 | "//conditions:default": [], 21 | }), 22 | visibility = ["//visibility:public"], 23 | ) 24 | 25 | swift_library( 26 | name = "SwiftSyntaxParser", 27 | srcs = glob(["Sources/SwiftSyntaxParser/**/*.swift"]), 28 | module_name = "SwiftSyntaxParser", 29 | private_deps = select({ 30 | "@platforms//os:macos": [ 31 | "@StaticInternalSwiftSyntaxParser//:lib_InternalSwiftSyntaxParser", 32 | ], 33 | "//conditions:default": [], 34 | }), 35 | visibility = ["//visibility:public"], 36 | deps = [":SwiftSyntax"], 37 | ) 38 | 39 | swift_library( 40 | name = "SwiftSyntaxBuilder", 41 | srcs = glob(["Sources/SwiftSyntaxBuilder/**/*.swift"]), 42 | module_name = "SwiftSyntaxBuilder", 43 | visibility = ["//visibility:public"], 44 | deps = [":SwiftSyntax"], 45 | ) 46 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "com_github_keith_swift_syntax_bazel") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 4 | 5 | http_archive( 6 | name = "build_bazel_rules_apple", 7 | sha256 = "36072d4f3614d309d6a703da0dfe48684ec4c65a89611aeb9590b45af7a3e592", 8 | url = "https://github.com/bazelbuild/rules_apple/releases/download/1.0.1/rules_apple.1.0.1.tar.gz", 9 | ) 10 | 11 | load( 12 | "@build_bazel_rules_apple//apple:repositories.bzl", 13 | "apple_rules_dependencies", 14 | ) 15 | 16 | apple_rules_dependencies() 17 | 18 | load( 19 | "@build_bazel_rules_swift//swift:repositories.bzl", 20 | "swift_rules_dependencies", 21 | ) 22 | 23 | swift_rules_dependencies() 24 | 25 | load( 26 | "@build_bazel_rules_swift//swift:extras.bzl", 27 | "swift_rules_extra_dependencies", 28 | ) 29 | 30 | swift_rules_extra_dependencies() 31 | 32 | load( 33 | "@build_bazel_apple_support//lib:repositories.bzl", 34 | "apple_support_dependencies", 35 | ) 36 | 37 | apple_support_dependencies() 38 | 39 | load("//:deps.bzl", "swift_syntax_deps") 40 | 41 | swift_syntax_deps() 42 | -------------------------------------------------------------------------------- /deps.bzl: -------------------------------------------------------------------------------- 1 | # buildozer: disable=module-docstring 2 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 3 | 4 | def swift_syntax_deps(): 5 | """Fetches dependencies of SwiftSyntax""" 6 | if not native.existing_rule("build_bazel_rules_apple"): 7 | fail("error: this depends on rules_apple but that wasn't setup") 8 | 9 | if not native.existing_rule("build_bazel_rules_swift"): 10 | fail("error: this depends on rules_swift but that wasn't setup") 11 | 12 | if not native.existing_rule("build_bazel_rules_apple"): 13 | fail("error: this depends on rules_apple but that wasn't setup") 14 | 15 | http_archive( 16 | name = "StaticInternalSwiftSyntaxParser", 17 | url = "https://github.com/keith/StaticInternalSwiftSyntaxParser/releases/download/5.7.1/lib_InternalSwiftSyntaxParser.xcframework.zip", 18 | sha256 = "feb332ba0a027812b1ee7f552321d6069a46207e5cd0f64fa9bb78e2a261b366", 19 | build_file_content = """ 20 | load("@build_bazel_rules_apple//apple:apple.bzl", "apple_static_framework_import") 21 | 22 | apple_static_framework_import( 23 | name = "lib_InternalSwiftSyntaxParser", 24 | framework_imports = glob( 25 | ["lib_InternalSwiftSyntaxParser.xcframework/macos-arm64_x86_64/lib_InternalSwiftSyntaxParser.framework/**"], 26 | allow_empty = False, 27 | ), 28 | visibility = ["//visibility:public"], 29 | ) 30 | """, 31 | ) 32 | 33 | http_archive( 34 | name = "com_github_keith_swift_syntax", 35 | build_file = "@com_github_keith_swift_syntax_bazel//:SwiftSyntax.BUILD", 36 | sha256 = "ea96dcd129ed4a05ea0efd7dbe39d929d47c55b1b5b8c2c7a8fce5c7de0bc4d8", 37 | strip_prefix = "swift-syntax-0.50700.1", 38 | url = "https://github.com/apple/swift-syntax/archive/refs/tags/0.50700.1.tar.gz", 39 | ) 40 | -------------------------------------------------------------------------------- /test/BUILD: -------------------------------------------------------------------------------- 1 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_binary", "swift_library", "swift_test") 2 | load("@build_bazel_rules_apple//apple:macos.bzl", "macos_command_line_application", "macos_unit_test") 3 | 4 | swift_test( 5 | name = "swift_test", 6 | size = "small", 7 | srcs = ["swift_test.swift"], 8 | deps = ["@com_github_keith_swift_syntax//:SwiftSyntaxParser"], 9 | ) 10 | 11 | swift_binary( 12 | name = "swift_binary", 13 | srcs = ["main.swift"], 14 | visibility = ["//visibility:public"], 15 | deps = ["@com_github_keith_swift_syntax//:SwiftSyntaxParser"], 16 | ) 17 | 18 | sh_test( 19 | name = "swift_binary_test", 20 | size = "small", 21 | srcs = ["swift-binary-test.sh"], 22 | data = ["swift_binary"], 23 | ) 24 | 25 | swift_library( 26 | name = "macos_test_library", 27 | srcs = ["macos_test_library.swift"], 28 | tags = ["manual"], 29 | deps = ["@com_github_keith_swift_syntax//:SwiftSyntaxParser"], 30 | ) 31 | 32 | macos_unit_test( 33 | name = "macos_unit_test", 34 | minimum_os_version = "10.15", 35 | target_compatible_with = ["@platforms//os:macos"], 36 | deps = ["macos_test_library"], 37 | ) 38 | 39 | swift_library( 40 | name = "macos_binary_main", 41 | srcs = ["main.swift"], 42 | tags = ["manual"], 43 | deps = ["@com_github_keith_swift_syntax//:SwiftSyntaxParser"], 44 | ) 45 | 46 | macos_command_line_application( 47 | name = "macos_binary", 48 | minimum_os_version = "10.15", 49 | deps = ["macos_binary_main"], 50 | ) 51 | 52 | sh_test( 53 | name = "macos_binary_test", 54 | size = "small", 55 | srcs = ["macos-binary-test.sh"], 56 | data = ["macos_binary"], 57 | target_compatible_with = ["@platforms//os:macos"], 58 | ) 59 | -------------------------------------------------------------------------------- /test/macos-binary-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | ./test/macos_binary 6 | 7 | if otool -L ./test/macos_binary | grep -q lib_InternalSwiftSyntaxParser; then 8 | echo "lib_InternalSwiftSyntaxParser is dynamically linked to the binary" 9 | exit 1 10 | fi 11 | -------------------------------------------------------------------------------- /test/macos_test_library.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import SwiftSyntaxParser 3 | 4 | final class TestLoad: XCTestCase { 5 | func testNoThrows() { 6 | _ = try! SyntaxParser.parse(source: "/dev/null") 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/main.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntaxParser 2 | 3 | _ = try! SyntaxParser.parse(source: "/dev/null") 4 | -------------------------------------------------------------------------------- /test/swift-binary-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | ./test/swift_binary 6 | 7 | if otool -L ./test/swift_binary | grep -q lib_InternalSwiftSyntaxParser; then 8 | echo "lib_InternalSwiftSyntaxParser is dynamically linked to the binary" 9 | exit 1 10 | fi 11 | -------------------------------------------------------------------------------- /test/swift_test.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import SwiftSyntaxParser 3 | 4 | final class TestLoad: XCTestCase { 5 | func testNoThrows() { 6 | _ = try! SyntaxParser.parse(source: "/dev/null") 7 | } 8 | } 9 | 10 | #if os(Linux) 11 | XCTMain([ 12 | testCase([("testNoThrows", TestLoad.testNoThrows)]) 13 | ]) 14 | #endif 15 | --------------------------------------------------------------------------------