Skip to content

Instantly share code, notes, and snippets.

@imWildCat
Last active March 19, 2023 21:46
Show Gist options
  • Save imWildCat/cedef73ffc731f0e34b9be917b6dfd15 to your computer and use it in GitHub Desktop.
Save imWildCat/cedef73ffc731f0e34b9be917b6dfd15 to your computer and use it in GitHub Desktop.
GPT-4: Converting Xcodegen yaml to Bazel demo

Convert this project.yml (XcodeGen) to Bazel build files:

name: Project
include: [environments.yml, AnotherProject/project.yml]
options:
  bundleIdPrefix: com.project
  usesTabs: false
  indentWidth: 2
  tabWidth: 2
  transitivelyLinkDependencies: true
  deploymentTarget:
    watchOS: 4.0
  groupSortPosition: top
  preGenCommand: echo "This is a pre-gen command"
  postGenCommand: scripts/script.sh
  fileTypes:
    abc:
      buildPhase: none
    abcd:
      buildPhase: none
fileGroups:
  - Configs
  - FileGroup
  - SomeFile
  - Utilities
  - App_iOS/Configuration.storekit
projectReferences:
  AnotherProject:
    path: ./AnotherProject/AnotherProject.xcodeproj
configFiles:
  Test Debug: Configs/config.xcconfig
packages:
  Swinject:
    url: https://github.com/Swinject/Swinject
    version: 2.8.0
breakpoints:
  - type: File
    path: App_iOS/AppDelegate.swift
    line: 7
    condition: launchOptions == nil
    actions:
      - type: Log
        message: message
        conveyanceType: speak
  - type: File
    path: App_iOS/AppDelegate.swift
    line: 11
    column: 13
  - type: Exception
    scope: All
    stopOnStype: Catch
    actions:
      - type: DebuggerCommand
        command: po $arg1
      - type: AppleScript
        script: display alert "Exception happened!"
      - type: Sound
        sound: Blow
  - type: SwiftError
    enabled: false
  - type: OpenGLError
    ignoreCount: 2
    actions:
      - type: ShellCommand
        path: script.sh
        arguments: argument1, argument2
        waitUntilDone: true
  - type: Symbolic
    symbol: UIViewAlertForUnsatisfiableConstraints
    module: UIKitCore
    actions:
      - type: GraphicsTrace
  - type: IDEConstraintError
    continueAfterRunningActions: true
  - type: IDETestFailure
targets:
  Legacy:
    type: ""
    platform: iOS
    legacy:
      toolPath: /usr/bin/true
      passSettings: true

  App_macOS:
    type: application
    platform: macOS
    scheme: {}
    info:
      path: App_macOS/App-Info.plist
      properties:
        LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET)
        NSMainStoryboardFile: Main
        NSPrincipalClass: NSApplication
        CFBundleIconFile: ""
        CustomSetting: $CUSTOM_SETTING
    attributes:
      ProvisioningStyle: Automatic
    sources:
      - path: App_macOS
      - path: StandaloneFiles/Standalone.swift
      - path: Vendor/SomeXPCService.xpc
      - path: NonExisting
        optional: true
    dependencies:
      - target: Framework_macOS
        copy:
            destination: plugins
            subpath: "test"
      - target: XPC Service
      - target: NetworkSystemExtension
      - target: EndpointSecuritySystemExtension
      - target: DriverKitDriver
      - sdk: Contacts.framework
      - sdk: libc++.tbd
      - sdk: libz.dylib

  App_iOS:
    type: application
    platform: iOS
    attributes:
      ProvisioningStyle: Automatic
    sources:
      - StandaloneFiles/StandaloneAssets.xcassets
      - path: App_iOS
        name: App
        compilerFlags:
          - "-Werror"
        excludes:
          - "**/excluded-file"
          - "excluded-file"
          - "Model.xcmappingmodel"
          - "Configuration.storekit"
      - path: App_iOS
        name: App
        includes:
          - "Model.xcmappingmodel"
      - path: StandaloneFiles/Standalone.swift
      - FileGroup/UnderFileGroup
      - Resources/MyBundle.bundle
      - Resources/SceneKitCatalog.scnassets
      - Resources/GoogleService-Info.plist
      - path: Resources/ResourceFolder
        type: folder
      - path: Folder
        type: folder
        buildPhase: none
        group: CustomGroup
      - path: Mintfile
        type: file
        buildPhase: none
        group: CustomGroup
      - path: Group/File1.swift
        group: CustomGroup
      - path: Group2/File2.swift
        group: CustomGroup
      - path: CopyFiles
        buildPhase:
          copyFiles:
            destination: productsDirectory
            subpath: include/$(PRODUCT_NAME)
      - path: Resources/example.mp4
        buildPhase: resources
        resourceTags:
          - tag1
          - tag2
    settings:
      INFOPLIST_FILE: App_iOS/Info.plist
      PRODUCT_BUNDLE_IDENTIFIER: com.project.app
    dependencies:
      - target: Framework_iOS
        platformFilter: all
      - target: StaticLibrary_ObjC_iOS
      - carthage: Result
        platformFilter: macOS
      - carthage: SwiftyJSON
        linkType: static
        platformFilter: iOS
      - target: Framework2_iOS
        weak: true
        platformFilter: iOS
      - target: App_watchOS
      - target: iMessageApp
      - sdk: Contacts.framework
      - bundle: BundleX.bundle
      - { bundle: BundleY.bundle, codeSign: false }
      - target: AnotherProject/ExternalTarget
      - target: App_Clip
      - package: Swinject
        product: Swinject
        platformFilter: iOS
# https://github.com/yonaskolb/XcodeGen/issues/1232
# After GitHub Actions start supporting Xcode 14, an example for extensionKit should be added.
#      - target: ExtensionKitExtension
    onlyCopyFilesOnInstall: true
    scheme:
      testTargets:
        - App_iOS_Tests
        - App_iOS_UITests
      gatherCoverageData: true
      coverageTargets:
        - App_iOS
      disableMainThreadChecker: true
      stopOnEveryMainThreadCheckerIssue: true
      configVariants:
        - Test
        - Staging
        - Production
      commandLineArguments:
          MyEnabledArgument: true
          MyDisabledArgument: false
      storeKitConfiguration: "App_iOS/Configuration.storekit"
    postbuildScripts:
      - path: scripts/strip-frameworks.sh
        name: Strip Unused Architectures from Frameworks
        runOnlyWhenInstalling: true
        basedOnDependencyAnalysis: false
      - name: MyScript
        script: |
          echo "You ran a script!"
          touch "${DERIVED_FILE_DIR}/target.d"
        inputFileLists:
          - App_iOS/inputList.xcfilelist
        outputFileLists:
          - App_iOS/outputList.xcfilelist
        discoveredDependencyFile: $(DERIVED_FILE_DIR)/target.d

  EntitledApp:
    type: application
    platform: iOS
    entitlements:
      path: App_iOS/App.entitlements
      properties:
        com.apple.security.application-groups: group.com.app

  App_watchOS:
      type: application.watchapp2
      platform: watchOS
      deploymentTarget: 4.0
      sources:
        App_watchOS
      settings:
        PRODUCT_BUNDLE_IDENTIFIER: com.project.app.watch
      dependencies:
        - target: App_watchOS Extension
      templates: [MyTemplate]

  App_watchOS Extension:
      type: watchkit2-extension
      platform: watchOS
      sources:
        App_watchOS Extension
      settings:
        PRODUCT_BUNDLE_IDENTIFIER: com.project.app.watch.extension
      dependencies:
        - carthage: Result
          link: false

  iMessageApp:
    type: application.messages
    platform: iOS
    sources: iMessageApp
    scheme: {}
    dependencies:
      - target: iMessageExtension

  iMessageExtension:
    type: app-extension.messages
    platform: iOS
    sources: iMessageExtension
    settings:
      PRODUCT_BUNDLE_IDENTIFIER: com.project.iMessageApp.extension
    scheme: {}

  iMessageStickersExtension:
    type: app-extension.messages-sticker-pack
    platform: iOS
    sources:
      - path: iMessageStickers

  DriverKitDriver:
    platform: macOS
    type: driver-extension
    sources:
      - DriverKit Driver
    settings:
      PRODUCT_BUNDLE_IDENTIFIER: com.project.App-macOS.Driver
      CODE_SIGN_ENTITLEMENTS: DriverKit Driver/Driver.entitlements
      SDKROOT: driverkit
      DRIVERKIT_DEPLOYMENT_TARGET: 20.4
    scheme: {}
    dependencies:
      - sdk: DriverKit.framework

  NetworkSystemExtension:
    platform: macOS
    type: system-extension
    sources:
      - Network Extension
    settings:
      PRODUCT_BUNDLE_IDENTIFIER: com.project.App-macOS.NetworkExtension
      CODE_SIGN_ENTITLEMENTS: Network Extension/NetworkExtension.entitlements
    scheme: {}
    dependencies:
      - sdk: NetworkExtension.framework

  EndpointSecuritySystemExtension:
    platform: macOS
    type: system-extension
    sources:
      - EndpointSecurity Extension
    settings:
      PRODUCT_BUNDLE_IDENTIFIER: com.project.App-macOS.EndpointSecurity
      CODE_SIGN_ENTITLEMENTS: EndpointSecurity Extension/EndpointSecurity.entitlements
    scheme: {}
    dependencies:
      - sdk: libEndpointSecurity.tbd

  StaticLibrary_ObjC:
    type: library.static
    platform: [iOS, tvOS, watchOS, macOS]
    sources: StaticLibrary_ObjC

  StaticLibrary_Swift:
    type: library.static
    platform: iOS
    sources: StaticLibrary_Swift

  Framework:
    type: framework
    platform: [iOS, tvOS, watchOS, macOS]
    sources:
      - path: Framework
        excludes:
          - "*.xcodeproj"
      - path: Headers
        buildPhase: headers
        type: folder
        headerVisibility: public
    postbuildScripts:
      - name: MyScript
        path: scripts/script.sh
    dependencies:
      - carthage: Result
      - target: StaticLibrary_ObjC_${platform}
      - target: Framework2_${platform}
        platforms: [tvOS, watchOS]

  Framework2:
    type: framework
    platform: [iOS, tvOS, watchOS, macOS]
    sources:
      - path: Framework
        excludes:
          - "*.xcodeproj"
  TestFramework:
    type: framework
    platform: iOS
    sources:
      - path: Framework
        excludes:
          - "*.xcodeproj"
    depencencies:
      - sdk: Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework
        root: DEVELOPER_DIR

  CrossOverlayFramework:
    type: framework
    platform: [iOS, tvOS, watchOS, macOS]
    sources:
      - path: CrossOverlayFramework
        excludes:
          - "*.xcodeproj"

  App_iOS_Tests:
    type: bundle.unit-test
    platform: iOS
    sources: App_iOS_Tests
    dependencies:
      - target: App_iOS
      - target: TestFramework
      - carthage: swift-tagged
        linkType: static
  App_iOS_UITests:
    type: bundle.ui-testing
    platform: iOS
    sources: App_iOS_UITests
    dependencies:
      - target: App_iOS

  App_macOS_Tests:
    type: bundle.unit-test
    platform: macOS
    sources: App_macOS_Tests
    dependencies:
      - target: App_macOS

  XPC Service:
    type: xpc-service
    platform: macOS
    sources:
      - path: XPC Service

  Tool:
    type: tool
    platform: macOS
    sources: [Tool]
    scheme: {}

  App_Clip:
    type: application.on-demand-install-capable
    platform: iOS
    entitlements:
      path: App_Clip/Clip.entitlements
      properties:
        com.apple.developer.parent-application-identifiers: [$(AppIdentifierPrefix)com.project.appwithclip]
        com.apple.security.application-groups: group.com.app
    sources:
      App_Clip
    settings:
      INFOPLIST_FILE: App_Clip/Info.plist
      PRODUCT_BUNDLE_IDENTIFIER: com.project.app.clip
    dependencies:
      - target: Framework_iOS
      - target: StaticLibrary_ObjC_iOS
    scheme:
      testTargets:
        - App_Clip_Tests
        - App_Clip_UITests

  App_Clip_Tests:
    type: bundle.unit-test
    platform: iOS
    sources: App_iOS_Tests
    dependencies:
      - target: App_Clip
      - target: TestFramework
      - carthage: swift-tagged
        linkType: static

  App_Clip_UITests:
    type: bundle.ui-testing
    platform: iOS
    sources: App_Clip_UITests
    dependencies:
      - target: App_Clip
# https://github.com/yonaskolb/XcodeGen/issues/1232
# After GitHub Actions start supporting Xcode 14, an example for extensionKit should be added.
#  ExtensionKitExtension:
#    type: extensionkit-extension
#    platform: iOS
#    sources: ExtensionKit Extension

schemes:
  Framework:
    build:
      parallelizeBuild: false
      buildImplicitDependencies: false
      targets:
        Framework_iOS: all
      preActions:
        - script: echo Starting Framework Build
          settingsTarget: Framework_iOS
      runPostActionsOnFailure: true
    run:
      commandLineArguments:
        argument: YES
        argument.with.dot: YES
    test:
      gatherCoverageData: true
      language: ja
      region: en
  App_Scheme:
    build:
      targets:
        App_iOS: all
    run:
      simulateLocation:
        allow: true
        defaultLocation: Honolulu, HI, USA
      customLLDBInit: ${SRCROOT}/.lldbinit
      enableGPUFrameCaptureMode: "disabled"
      storeKitConfiguration: "App_iOS/Configuration.storekit"
      macroExpansion: App_iOS 
    test:
      gatherCoverageData: true
      targets:
        - App_iOS_UITests
        - name: App_iOS_Tests
          parallelizable: true
          randomExecutionOrder: true
          location: New York, NY, USA
      customLLDBInit: ${SRCROOT}/.lldbinit
      testPlans:
        - path: App_iOS/App_iOS.xctestplan
targetTemplates:
  MyTemplate:
    scheme: {}
aggregateTargets:
  SuperTarget:
    attributes:
      CUSTOM: value
    targets:
      - App_iOS
      - Framework_iOS
    settings:
      MY_SETTING: hello
    buildScripts:
      - name: MyScript
        script: echo "do the thing"

Converting the entire project.yml file to Bazel BUILD files is beyond the scope of a concise answer. However, I can provide you with guidance on how to convert some important parts of the XcodeGen configuration to Bazel BUILD files.

  1. Create a WORKSPACE file in your project's root directory. This file will contain the external dependencies and other configurations.

  2. Add the Swinject package to your WORKSPACE file:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "Swinject",
    urls = ["https://github.com/Swinject/Swinject/archive/refs/tags/2.8.0.tar.gz"],
    sha256 = "<SHA256_HASH>",
    strip_prefix = "Swinject-2.8.0",
)

Replace <SHA256_HASH> with the actual hash of the downloaded archive.

  1. Create a BUILD file in the root directory of your project. This file will contain the build rules for your project's targets.

  2. Define the App_macOS target in the BUILD file:

objc_binary(
    name = "App_macOS",
    srcs = glob([
        "App_macOS/**/*.m",
        "StandaloneFiles/Standalone.swift",
        "Vendor/SomeXPCService.xpc/**/*.m",
    ]),
    hdrs = glob(["App_macOS/**/*.h"]),
    includes = ["App_macOS"],
    deps = [
        ":Framework_macOS",
        ":XPC_Service",
        ":NetworkSystemExtension",
        ":EndpointSecuritySystemExtension",
        ":DriverKitDriver",
        "@platforms//ios:Contacts",
        "@platforms//ios:libc++",
        "@platforms//ios:libz",
    ],
    infoplists = ["App_macOS/App-Info.plist"],
    minimum_os_version = "10.9",
)

objc_library(
    name = "Framework_macOS",
    srcs = glob(["Framework_macOS/**/*.m"]),
    hdrs = glob(["Framework_macOS/**/*.h"]),
    includes = ["Framework_macOS"],
)

# Add other target rules for XPC_Service, NetworkSystemExtension, EndpointSecuritySystemExtension, and DriverKitDriver
  1. Define the App_iOS target in the BUILD file:
swift_library(
    name = "App_iOS",
    srcs = glob([
        "StandaloneFiles/StandaloneAssets.xcassets/**/*.swift",
        "App_iOS/**/*.swift",
        "StandaloneFiles/Standalone.swift",
        "FileGroup/UnderFileGroup/**/*.swift",
        "Resources/MyBundle.bundle/**/*.swift",
        "Resources/SceneKitCatalog.scnassets/**/*.swift",
        "Resources/GoogleService-Info.plist/**/*.swift",
        "Resources/ResourceFolder/**/*.swift",
       ]),
    copts = ["-Werror"],
    resources = glob([
        "Resources/example.mp4",
    ]),
    resource_tags = ["tag1", "tag2"],
    deps = [
        ":Framework_iOS",
        ":StaticLibrary_ObjC_iOS",
        "@Swinject//:Swinject",
    ],
    infoplists = ["App_iOS/Info.plist"],
    minimum_os_version = "10.0",
)

swift_library(
    name = "Framework_iOS",
    srcs = glob(["Framework_iOS/**/*.swift"]),
    deps = [
        "@Swinject//:Swinject",
    ],
)

objc_library(
    name = "StaticLibrary_ObjC_iOS",
    srcs = glob(["StaticLibrary_ObjC_iOS/**/*.m"]),
    hdrs = glob(["StaticLibrary_ObjC_iOS/**/*.h"]),
    includes = ["StaticLibrary_ObjC_iOS"],
)
  1. Define other targets, such as App_watchOS, App_watchOS_Extension, and iMessageApp, in the BUILD file using similar rules as shown above for App_macOS and App_iOS.

  2. Define test targets, such as App_iOS_Tests and App_iOS_UITests, in the BUILD file using swift_test or objc_test rules, depending on the language used in the test sources.

Keep in mind that this is just a starting point for your Bazel build configuration. You might need to adjust and customize the BUILD files and rules based on your project's specific requirements. Additionally, you may need to handle other parts of the project.yml file, such as build settings, schemes, and post-build scripts, which may require custom rules or additional Bazel configuration.8. Handle build settings, schemes, and post-build scripts by creating custom Bazel rules or using Bazel's built-in features. For example, you could use Bazel's objc_binary or swift_binary rules for handling build settings, and define custom Skylark rules for post-build scripts. 9. Define the schemes in your Bazel BUILD files using the testonly attribute for test targets, and by creating custom rules or macros to group targets together. For example, you could create a custom rule that takes a list of targets as an input and builds them together.

  1. For handling deployment targets, you can use the minimum_os_version attribute in your Bazel rules, as shown in the examples above for App_macOS and App_iOS.

  2. To handle file groups and file types, you can use Bazel's glob function to include or exclude specific file patterns in your targets. For example, you can use glob(["**/*.abc"], exclude=["**/*.abcd"]) to include all .abc files and exclude all .abcd files.

  3. To handle target dependencies, you can use the deps attribute in your Bazel rules, as shown in the examples above for App_macOS and App_iOS.

  4. For handling breakpoints, you'll need to configure your IDE or debugger separately, as Bazel does not have built-in support for breakpoints.

  5. To handle project references, you can use the local_repository rule in your WORKSPACE file to include another local project:

local_repository(
    name = "AnotherProject",
    path = "AnotherProject",
)

Then, in your BUILD file, you can reference targets from the other project using the @AnotherProject//path/to/target:target_name syntax.

Remember that converting a project.yml file to Bazel BUILD files is a complex task,and the provided guidance only covers some important parts of the conversion process. You may need to further customize your Bazel configuration to fully match your project's requirements. Bazel's documentation and community resources can help you navigate through the conversion process and address any specific needs for your project.15. For handling target templates, you can create custom macros in Bazel to define reusable target configurations. For example, you can create a my_template.bzl file with the following content:

def my_template(name, srcs, deps, **kwargs):
    swift_library(
        name = name,
        srcs = srcs,
        deps = deps,
        **kwargs
    )

Then, in your BUILD file, load and use the custom macro:

load("//:my_template.bzl", "my_template")

my_template(
    name = "App_watchOS",
    srcs = glob(["App_watchOS/**/*.swift"]),
    deps = [":App_watchOS_Extension"],
)
  1. Aggregate targets can be handled using Bazel's alias rule or custom macros to group multiple targets together. For example, you can create an alias that depends on multiple targets:
alias(
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment