You have decided to integrate Swift source code formatting into your project using
rules_swiftformat
. Now, the question is what is the best way to do so.
This is pretty straightforward. Either manually or using
Buildozer, you can add the
swiftformat_pkg
macro to the Bazel packages
that contain Swift source files. This is the technique that is described in the
quickstart and the simple example.
However, this option has one downside. There is no easy way to ensure that swiftformat_pkg
is
added to any new Bazel packages that are created in the future.
Wouldn't it be great if we could combine the build and format declarations into one declaration? Yes, it would. Luckily, Bazel supports user-defined macros. They allow us to combine multiple declarations into a convenient and tidy declaration.
After implementing rules_swiftformat
, we began rolling it out to our other projects. We
immediately realized that we wanted to make it very simple to define a Swift build target and
formatting target. We assumed that other folks would want to do the same. So, we implemented
swiftformat_library
,
swiftformat_binary
, and
swiftformat_test
. These macros define
the corresponding swift_XXX
declaration and the appropriate swiftformat_pkg
declaration. This
technique is demonstrated in our rules_swift_helpers example.
In short, the swiftformat_XXX
macros take all of the same attributes as their swift_XXX
counterparts. In addition, they have two other attributes:
swiftformat_config
and
a swiftformat_name
.
These can be used to customize the formatting for the package if desired.
The following shows a BUILD.bazel
file that uses the
swiftformat_library
macro.
load(
"@rules_swift_tidy//swiftformat:defs.bzl",
"swiftformat_library",
)
swiftformat_library(
name = "Foo",
srcs = glob(["*.swift"]),
module_name = "Foo",
visibility = ["//:__subpackages__"],
)
Perhaps the idea of combining the build and formatting declarations sounds great to you. However,
you don't like the idea of introducing an unfamiliar declaration like swiftformat_XXX
. Or, perhaps
you just want to consolidate your build declarations with some project-specific defaults. Well, you
may want to define your own swift_library
, swift_binary
, and swift_test
macros. We
use this technique in our Swift Toolbox repository.
Create the build/swift
directories at the root of your workspace and add a BUILD.bazel
file.
$ mkdir -p build/swift
$ echo "# Intentionally blank" >> build/swift/BUILD.bazel
Now, create a swift_library.bzl
file with the following contents:
load(
"@rules_swift_tidy//swiftformat:defs.bzl",
"swiftformat_library",
)
def swift_library(name, srcs = None, **kwargs):
if srcs == None:
srcs = native.glob(["*.swift"])
swiftformat_library(
name = name,
srcs = srcs,
**kwargs
)
Next, create a swift_test.bzl
file and a swift_binary.bzl
file using the same template as above.
Be sure to change _library
to the appropriate suffix.
Lastly, update the load statements for all of the Bazel build files that contain swift_XXX
declarations so that they load your macro instead of the original rule. Change
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_XXX")
to
load("//build/swift:swift_library.bzl", "swift_XXX")
.
Here is an example of an updated BUILD.bazel
file.
load("//build/swift:swift_library.bzl", "swift_library")
swift_library(
name = "DateUtils",
module_name = "DateUtils",
visibility = ["//visibility:public"],
)
As we have seen, there are several ways to integrate rules_swiftformat
into your Bazel project.
All of them are valid. However, we would recommend using either Option #2 or Option #3 if you are
implementing this for a large repository or a repository that has multiple contributors. It is less
likely that new Bazel packages will be implemented without the desired formatting capabilities.