blob: 0af95d3fa47db0762be1cf9453587f43b9674bd5 [file] [log] [blame] [view]
spomorski211934b2017-10-05 21:46:33 +02001---
2layout: documentation
3title: Migrating from Xcode to Bazel
4---
5
6# Migrating from Xcode to Bazel
7
8This guide describes how to build or test an Xcode project with Bazel. It
9describes the differences between Xcode and Bazel, and provides the steps for
10converting an Xcode project to a Bazel project.
11
12## Contents
13
14- [Differences between Xcode and Bazel](#differences-between-xcode-and-bazel)
15- [Before you begin](#before-you-begin)
16 - [Analyze project dependencies](#analyze-project-dependencies)
17- [Build or test an Xcode project with Bazel](#build-or-test-an-xcode-project-with-bazel)
18 - [Step 1: Create the `WORKSPACE` file](#step-1-create-the-workspace-file)
spomorski865e9ca2017-10-26 18:36:10 +020019 - [Step 2: (Experimental) Integrate CocoaPod dependencies](#step-2-experimental-integrate-cocoapods-dependencies)
spomorski94cc04f2017-10-24 19:54:45 +020020 - [Step 3: Create a `BUILD` file:](#step-3-create-a-build-file)
21 - [Step 3a: Add the application target](#step-3a-add-the-application-target)
22 - [Step 3b: (Optional) Add the test target(s)](#step-3b-optional-add-the-test-target-s)
23 - [Step 3c: Add the library target(s)](#step-3c-add-the-library-target-s)
24 - [Step 4: (Optional) Granularize the build](#step-4-optional-granularize-the-build)
25 - [Step 5: Run the build](#step-5-run-the-build)
26 - [Step 6: Generate the Xcode project with Tulsi](#step-6-generate-the-xcode-project-with-tulsi)
spomorski211934b2017-10-05 21:46:33 +020027
28## Differences between Xcode and Bazel
29
30* Bazel requires you to explicitly specify every build target and its
31 dependencies, plus the corresponding build settings via build rules.
32
33* Bazel requires all files on which the project depends to be present
34 within the workspace directory or specified as imports in the `WORKSPACE`
35 file.
36
37* When building Xcode projects with Bazel, the `BUILD` file(s) become the
38 source of truth. If you work on the project in Xcode, you must generate a
39 new version of the Xcode project that matches the `BUILD` files using
40 [Tulsi](http://tulsi.bazel.build/) whenever you update the `BUILD` files. If
41 you're not using Xcode, the `bazel build` and `bazel test` commands provide
42 build and test capabilities with certain limitations described later in this
43 guide.
44
45* Due to differences in build configuration schemas, such as directory layouts
46 or build flags, Xcode might not be fully aware of the "big picture" of the
47 build and thus some Xcode features might not work. Namely:
48
49 * Depending on the targets you select for conversion in Tulsi, Xcode might
50 not be able to properly index the project source. This affects code
51 completion and navigation in Xcode, since Xcode won't be able to see all
52 of the project's source code.
53
54 * Static analysis, address sanitizers, and thread sanitizers might not
55 work, since Bazel does not produce the outputs that Xcode expects for
56 those features.
57
58 * If you generate an Xcode project with Tulsi and use that project to run
59 tests from within Xcode, Xcode will run the tests instead of
60 Bazel. To run tests with Bazel, run the `bazel test` command manually.
61
62## Before you begin
63
64Before you begin, do the following:
65
661. [Install Bazel](https://docs.bazel.build/versions/master/install.html) if
67 you have not already done so.
68
692. If you're not familiar with Bazel and its concepts, complete the
70 [iOS app tutorial](https://docs.bazel.build/versions/master/tutorial/ios-app.html).
71 You should understand the Bazel workspace, including the `WORKSPACE` and
72 `BUILD` files, as well as the concepts of targets, build rules, and Bazel
73 packages.
74
753. Analyze and understand the project's dependencies.
76
77### Analyze project dependencies
78
79Unlike Xcode, Bazel requires you to explicitly declare all dependencies for
80every target in the `BUILD` file.
81
82For more information on external dependencies, see
83[Working with external dependencies](https://docs.bazel.build/versions/master/external.html).
84
85## Build or test an Xcode project with Bazel
86
87To build or test an Xcode project with Bazel, do the following:
88
891. [Create the `WORKSPACE` file](#step-1-create-the-workspace-file)
90
spomorski94cc04f2017-10-24 19:54:45 +0200912. [(Experimental) Integrate CocoaPods dependencies](#step-2-experimental-integrate-cocoapods-dependencies)
spomorski211934b2017-10-05 21:46:33 +020092
spomorski94cc04f2017-10-24 19:54:45 +0200933. [Create a `BUILD` file:](#step-3-create-a-build-file)
spomorski211934b2017-10-05 21:46:33 +020094
spomorski94cc04f2017-10-24 19:54:45 +020095 a. [Add the application target](#step-3a-add-the-application-target)
spomorski211934b2017-10-05 21:46:33 +020096
spomorski94cc04f2017-10-24 19:54:45 +020097 b. [(Optional) Add the test target(s)](#step-3b-optional-add-the-test-target-s)
spomorski211934b2017-10-05 21:46:33 +020098
spomorski94cc04f2017-10-24 19:54:45 +020099 c. [Add the library target(s)](#step-3c-add-the-library-target-s)
spomorski211934b2017-10-05 21:46:33 +0200100
spomorski94cc04f2017-10-24 19:54:45 +02001014. [(Optional) Granularize the build](#step-4-optional-granularize-the-build)
spomorski211934b2017-10-05 21:46:33 +0200102
spomorski94cc04f2017-10-24 19:54:45 +02001035. [Run the build](#step-5-run-the-build)
104
1056. [Generate the Xcode project with Tulsi](#step-6-generate-the-xcode-project-with-tulsi)
spomorski211934b2017-10-05 21:46:33 +0200106
107### Step 1: Create the `WORKSPACE` file
108
109Create a `WORKSPACE` file in a new directory. This directory becomes the Bazel
110workspace root. If the project uses no external dependencies, this file can be
111empty. If the project depends on files or packages that are not in one of the
112project's directories, specify these external dependencies in the `WORKSPACE`
113file.
114
115**Note:** Place the project source code within the directory tree containing the
116 `WORKSPACE` file.
117
spomorski97a51412017-10-24 20:59:48 +0200118### Step 2: (Experimental) Integrate CocoaPods dependencies
spomorski94cc04f2017-10-24 19:54:45 +0200119
120To integrate CocoaPods dependencies into the Bazel workspace, you must convert
121them into Bazel packages as described in [Converting CocoaPods dependencies](migrate-cocoapods.md).
122
spomorski97a51412017-10-24 20:59:48 +0200123**Note:** CocoaPods conversion is a manual process with many variables.
124CocoaPods integration with Bazel has not been fully verified and is not
125officially supported.
spomorski94cc04f2017-10-24 19:54:45 +0200126
127
128### Step 3: Create a `BUILD` file
spomorski211934b2017-10-05 21:46:33 +0200129
130Once you have defined the workspace and external dependencies, you need to
131create a `BUILD` file that tells Bazel how the project is structured. Create
132the `BUILD` file at the root of the Bazel workspace and configure it to do an
133initial build of the project as follows:
134
spomorski94cc04f2017-10-24 19:54:45 +0200135* [Step 3a: Add the application target](#step-3a-add-the-application-target)
136* [Step 3b: (Optional) Add the test target(s)](#step-3b-optional-add-the-test-target-s)
137* [Step 3c: Add the library target(s)](#step-3c-add-the-library-target-s)
spomorski211934b2017-10-05 21:46:33 +0200138
139**Tip:** To learn more about packages and other Bazel concepts, see
140[Bazel Terminology](https://docs.bazel.build/versions/master/build-ref.html).
141
spomorski94cc04f2017-10-24 19:54:45 +0200142#### Step 3a: Add the application target
spomorski211934b2017-10-05 21:46:33 +0200143
144Add a [`macos_application`](https://github.com/bazelbuild/rules_apple/blob/master/doc/rules-macos.md#macos_application)
spomorski975f19a2017-11-02 12:05:01 -0400145or an [`ios_application`](https://github.com/bazelbuild/rules_apple/blob/master/doc/rules-ios.md#ios_application)
spomorski211934b2017-10-05 21:46:33 +0200146rule target. This target builds a macOS or iOS application bundle, respectively.
147In the target, specify the following at the minimum:
148
149* `bundle_id` - the bundle ID (reverse-DNS path followed by app name) of the
150 binary.
151
152* `provisioning_profile` - provisioning profile from your Apple Developer
153 account (if building for an iOS device device).
154
155* `families` (iOS only) - whether to build the application for iPhone, iPad,
156 or both.
157
158* `infoplists` - list of .plist files to merge into the final Info.plist file.
159
160* `minimum_os_version` - the minimum version of macOS or iOS that the
161 application supports. This ensures Bazel builds the application with the
162 correct API levels.
163
spomorski94cc04f2017-10-24 19:54:45 +0200164#### Step 3b: (Optional) Add the test target(s)
spomorski211934b2017-10-05 21:46:33 +0200165
166Bazel's [Apple build rules](https://github.com/bazelbuild/rules_apple) support
167running library-based unit tests on iOS and macOS, as well as application-based
168tests on macOS. For application-based tests on iOS or UI tests on either
169platform, Bazel will build the test outputs but the tests must run within Xcode
170through a project generated with Tulsi. Add test targets as follows:
171
172* [`macos_unit_test`](https://github.com/bazelbuild/rules_apple/blob/master/doc/rules-macos.md#macos_unit_test)
173 to run library-based and application-based unit tests on a macOS.
174
175* [`ios_unit_test`](https://github.com/bazelbuild/rules_apple/blob/master/doc/rules-ios.md#ios_unit_test)
176 to run library-based unit tests on iOS. For tests requiring the iOS
177 simulator, Bazel will build the test outputs but not run the tests. You must
178 [generate an Xcode project with Tulsi](#step-5-generate-the-xcode-project-with-tulsi)
179 and run the tests from within Xcode.
180
181* [`ios_ui_test`](https://github.com/bazelbuild/rules_apple/blob/master/doc/rules-ios.md#ios_ui_test)
182 to build outputs required to run user interface tests in the iOS simulator
183 using Xcode. You must [generate an Xcode project with Tulsi](#step-5-generate-the-xcode-project-with-tulsi)
184 and run the tests from within Xcode. Bazel cannot natively run UI tests.
185
186At the minimum, specify a value for the `minimum_os_version` attribute. While
187other packaging attributes, such as `bundle_identifier` and `infoplists`,
188default to most commonly used values, ensure that those defaults are compatible
189with the project and adjust them as necessary. For tests that require the iOS
190simulator, also specify the `ios_application` target name as the value of the
191`test_host` attribute.
192
193
spomorski94cc04f2017-10-24 19:54:45 +0200194#### Step 3c: Add the library target(s)
spomorski211934b2017-10-05 21:46:33 +0200195
196Add an [`objc_library`](https://docs.bazel.build/versions/master/be/objective-c.html#objc_library)
197target for each Objective C library and a [`swift_library`](https://github.com/bazelbuild/rules_apple/blob/master/doc/rules-swift.md)
198target for each Swift library on which the application and/or tests depend.
199
200
201Add the library targets as follows:
202
203* Add the application library targets as dependencies to the application
204 targets.
205
206* Add the test library targets as dependencies to the test targets.
207
208* List the implementation sources in the `srcs` attribute.
209
210* List the headers in the `hdrs` attribute.
211
212**Note:** You can use the [`glob`](https://docs.bazel.build/versions/master/be/functions.html#glob)
213function to include all sources and/or headers of a certain type. Use it
214carefully as it might include files you do not want Bazel to build.
215
216For more information on build rules, see [Apple Rules for Bazel](https://github.com/bazelbuild/rules_apple).
217
218At this point, it is a good idea to test the build:
219
220`bazel build //:<application_target>`
221
spomorski94cc04f2017-10-24 19:54:45 +0200222### Step 4: (Optional) Granularize the build
spomorski211934b2017-10-05 21:46:33 +0200223
224If the project is large, or as it grows, consider chunking it into multiple
225Bazel packages. This increased granularity provides:
226
227* Increased incrementality of builds,
228
229* Increased parallelization of build tasks,
230
231* Better maintainability for future users,
232
233* Better control over source code visibility across targets and packages. This
234 prevents issues such as libraries containing implementation details leaking
235 into public APIs.
236
237Tips for granularizing the project:
238
239* Put each library in its own Bazel package. Start with those requiring the
240 fewest dependencies and work your way up the dependency tree.
241
242* As you add `BUILD` files and specify targets, add these new targets to the
243 `deps` attributes of targets that depend on them.
244
245* The `glob()` function does not cross package boundaries, so as the number
246 of packages grows the files matched by `glob()` will shrink.
247
248* When adding a `BUILD` file to a `main` directory, also add a `BUILD` file to
249 the corresponding `test` directory.
250
251* Enforce healthy visibility limits across packages.
252
253* Build the project after each major change to the `BUILD` files and fix
254 build errors as you encounter them.
255
spomorski94cc04f2017-10-24 19:54:45 +0200256### Step 5: Run the build
spomorski211934b2017-10-05 21:46:33 +0200257
258Run the fully migrated build to ensure it completes with no errors or warnings.
259Run every application and test target individually to more easily find sources
260of any errors that occur.
261
262For example:
263
264```bash
265bazel build //:my-target
266```
267
spomorski94cc04f2017-10-24 19:54:45 +0200268### Step 6: Generate the Xcode project with Tulsi
spomorski211934b2017-10-05 21:46:33 +0200269
270When building with Bazel, the `WORKSPACE` and `BUILD` files become the source
271of truth about the build. To make Xcode aware of this, you must generate a
272Bazel-compatible Xcode project using [Tulsi](http://tulsi.bazel.build/).