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.
-
Create a
WORKSPACE
file in your project's root directory. This file will contain the external dependencies and other configurations. -
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.
-
Create a
BUILD
file in the root directory of your project. This file will contain the build rules for your project's targets. -
Define the
App_macOS
target in theBUILD
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
- Define the
App_iOS
target in theBUILD
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"],
)
-
Define other targets, such as
App_watchOS
,App_watchOS_Extension
, andiMessageApp
, in theBUILD
file using similar rules as shown above forApp_macOS
andApp_iOS
. -
Define test targets, such as
App_iOS_Tests
andApp_iOS_UITests
, in theBUILD
file usingswift_test
orobjc_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.
-
For handling deployment targets, you can use the
minimum_os_version
attribute in your Bazel rules, as shown in the examples above forApp_macOS
andApp_iOS
. -
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 useglob(["**/*.abc"], exclude=["**/*.abcd"])
to include all.abc
files and exclude all.abcd
files. -
To handle target dependencies, you can use the
deps
attribute in your Bazel rules, as shown in the examples above forApp_macOS
andApp_iOS
. -
For handling breakpoints, you'll need to configure your IDE or debugger separately, as Bazel does not have built-in support for breakpoints.
-
To handle project references, you can use the
local_repository
rule in yourWORKSPACE
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"],
)
- Aggregate targets can be handled using Bazel's
alias
rule or custom macros to group multiple targets together. For example, you can create analias
that depends on multiple targets:
alias(