An easy way to build CocoaPods with Bazel - it integrates pods end to end with an easy to use macro.
In the root directory, add
rules_pods to the Bazel
http_archive( name = "rules_pods", urls = ["https://github.com/pinterest/PodToBUILD/releases/download/0.18.0-95fd009/PodToBUILD.zip"], )
Pods are defined in the
WORKSPACE file with the macro,
# Load the new_pod_repository macro - needed for `WORKSPACE` usage load("@rules_pods//BazelExtensions:workspace.bzl", "new_pod_repository") new_pod_repository( name = "PINOperation", url = "https://github.com/pinterest/PINOperation/archive/1.0.3.zip", )
PINOperation and the associated
PINOperation, is available for use within Bazel. The package and target name
are combined to form the label
Thats all! Bazel will automatically setup pods along with the build.
See the examples for end to end usage.
Vendoring Pods via Pods.WORKSPACE
rules_pods supports Bazel's conventional dependency management
system via the
However, loading external files as part of the build may have implications on stability, Xcode usage, network bandwidth, and build times. e.g. downloading dependencies from an external service ties build time and reliability to that service.
As a solution, it supports
vendoring aka out of band, in tree dependency
installation. Similar to
CocoaPods, it can download and initialize Pods
relative to the project, in the
bin/update_pods, installs Pods into
notion is similar to
Create the file
Pods.WORKSPACE and add
new_pod_repositorys' there -
http_archive remains declared in the
Pods.WORKSPACE is changed,
update_pods must be ran to ensure all
pods are updated.
# src_root is the root workspace directory bazel run @rules_pods//:update_pods -- --src_root $PWD
In addition to out of band updating, labels are formed via the convention
//Vendor:__POD_NAME__:__TARGET__. Otherwise, the API of
is identical across
Pods.WORKSPACE, the only difference is
load statement isn't required in
See the Texture example for a comprehensive example.
This macro is the main point of integration for pod dependencies.
Each pod is integrated as a repository and each repository is self contained.
By declaring a
new_pod_repository, the dependency is available to all Bazel
In Bazel a label is a build target identifier. Pod labels are all formed using
the same logic. The remainder of this document uses the
The first part of the label is the package name, followed by the name of the
The top level target is determined by the root subspec.
For example, in
PINCache, the root target's label is
Subspecs targets have the same name as the subspec. For example, the label of the
Dependencies on Pods
Transitive dependencies must be declared in the
Dependencies between targets are resolved through an idiomatic naming convention.
PINCache depends on
the dependency on
//Vendor/PINOperation:PINOperation is generated. The
needs to declare both
Local dependencies in
new_pod_repository are supported in addition to remote
Instead of using a
url that points to the remote repository, use a
points to the local repository.
For example, if we wanted to depend on a local version of
new_pod_repository( name = "PINOperation", url = "/Path/To/PINOperation", )
Upon updating pods, the local files are sym-linked into the pod directory.
This can aid in local development of Pod dependencies, and was originally designed for such a use case.
Resolving issues with dependencies
Many dependencies will work with
new_pod_repository without any special
considerations: just add the
Some dependencies may not. The
install_script attribute is a way to resolve
issues with such dependencies.
For example, in
PINRemoteImage source files are in folders that have spaces in
the name. This is not supported in Bazel. Please see the Known
complications section for more info.
Customizing rule attributes
It may be desirable or required to change the way that a target is built. The compiler supports customizing attributes of generated targets.
For example, to add a custom
PINOperation we could turn on pedantic
warnings just for
new_pod_repository( name = "PINOperation", url = "https://github.com/pinterest/PINOperation/archive/1.0.3.zip", user_options = ["PINOperation.copts += -pedantic"], )
objc_library, the following fields are supported:
Acknowledgements Plist and Settings.bundle
Acknowledgments metadata from a Pod is supported.
A target containing acknowledgment metadata for a given target is automatically
generated. Acknowledgment targets have the label of the form
Merge all of the dependencies into
load("@rules_pods//BazelExtensions:extensions.bzl", "acknowledgments_plist") # Example `Settings`.bundle target objc_bundle_library( name = "Settings", resources = ["Root.plist", "acknowledgements"], visibility = ['//visibility:public'], ) ALL_POD_DEPS = ["//Vendor/PINOperation:PINOperation", "//Vendor/PINCache:PINCache"] acknowledgments_plist( name = "acknowledgements", deps = [d + "_acknowledgement" for d in ALL_POD_DEPS], merger = "//Vendor/rules_pods/BazelExtensions:acknowledgement_merger" )
new_pod_repository API reference
name: the name of this repo
url: the url of this repo
podspec_url: the podspec url. By default, we will look in the root of the
repository, and read a .podspec file. This requires having CocoaPods installed
on build nodes. If a JSON podspec is provided here, then it is not required to
strip_prefix: a directory prefix to strip from the extracted files. Many
archives contain a top-level directory that contains all of the useful files in
For most sources, this is typically not needed.
user_options: an array of key value operators that act on code
Supported operators: PlusEquals ( += ). Add an item to an array
objc_library. Supported fields:
Example usage: add a custom define to the target, Texture's
user_options = [ "Texture.copts += -DTEXTURE_DEBUG " ]
install_script: a script used for installation.
__INIT_REPO__ indicates at which point the BUILD file is
generated, if any.
repo_tools may be provided as a label. The names provided in
substituted out for the respective tools.
note that the script is ran directly after the repository has been fetched.
repo_tools: a mapping of executables in Bazel to command names. If we are
running something like "mv" or "sed" these binaries are already on path, so
there is no need to add an entry for them.
inhibit_warnings: whether compiler warnings should be inhibited.
trace: dump out useful debug info for a given repo.
generate_module_map: whether a module map should be generated.
enable_modules: set generated rules
header_visibility: DEPRECATED: This is replaced by headermaps: https://github.com/Bazelbuild/Bazel/pull/3712
Incompatible file paths
Apple File systems support different characters than Linux ones do. Bazel uses
the least common denominator, the Linux convention. For now, use an
install_script to resolve differences.
Some code, like Texture, uses
__has_include to conditionally include code.
In Bazel, if that include is not explicitly added, then this feature will not
work. In this case, use a
user_option to add dependencies available on the
Incompatible Target Names
Some targets may contain characters that are not valid Bazel targets.
The target should be renamed to a compatible name. The easiest way to achieve
this is to declare the dependency with a valid name. All references should be
replaced in the podspec file before the
BUILD file is generated.
SPUserResizableView+Pion exbibits this issue.
new_pod_repository( name = "SPUserResizableView_Pion", url = "https://github.com/keleixu/SPUserResizableView/archive/b263fc4e8101c6c5ac352806fb5c31aa69e32025.zip", user_options = ["SPUserResizableView_Pion.sdk_frameworks += UIKit, CoreGraphics, Foundation"], inhibit_warnings = True, install_script = """ /usr/bin/sed -i "" 's,SPUserResizableView+Pion,SPUserResizableView_Pion,g' 'SPUserResizableView+Pion.podspec' mv 'SPUserResizableView+Pion.podspec' 'SPUserResizableView_Pion.podspec' __INIT_REPO__ """, generate_module_map = False )
Now, in Bazel, the target is accessible via
This should eventually be handled by default.
How many pods are supported?
Most ObjC/C++/C Pods should work out of the box and the goal is support all CocoaPods. Please do file issues and PRs for pods that don't work.
Does it work with Swift?
The short answer is yes, but probably not. Swift support in
rules_swift ) is still under development.
Should I do source builds of rules_pods?
The short answer is probably not. Consider that building
rules_pods along with
an iOS application ties the build environment of
rules_pods to that of the iOS
application. This includes the Bazel rules version and swift version. In
addition to coupling the environment, it may be slow overall.
update_pods automatically does source builds of
Bazel if it is checked out as such. Simply use
git_repository instead of
http_archive as mentioned in the quickstart guide.
building with Bazel isn't
well supported in
repository_rules, and isn't supported at the moment.
How do I update rules_pods?
See the quickstart instructions.
How can I generate an Xcode project for Bazel built pods?
Please find info in the Bazel documentation.
How can I build an iOS applicaiton with Bazel with CocoaPod dependencies?
The documentation of building an iOS application resides in the Bazel documentation. This README and examples are intended to cover the rest.
How can I develop rules_pods?
make is the canonical build system of
rules_pods - see the
Makefile for up
to date development workflows.
The examples are intended to be tested, minimal, end to end, use cases of
rules_pods. The examples do a source build of
rules_pods, and setup pods.
Simply cd into an example, and run
For developing the
BUILD file compiler, use
make run EXAMPLE=_some pod_
Additionally, Xcode development is supported via Swift Package Manager. To generate an Xcode project, run:
swift package generate-xcodeproj
PRs welcome :)!