Setting up Bazel for Vulkan projects
Bazel for Vulkan projects
In this blog post, we will see how to set up an environment for Vulkan projects built with Bazel. Then, in the second part, we are going to see how Bazel can build GLSL shaders for Vulkan.
Vulkan — is an open standard for 3D graphics and computing that enables cross-platform access to GPUs. It targets high-performance real-time 3D graphics applications, such as video games and interactive media. You can learn more about Vulkan from its official page.
Bazel — is an open-source build system with advanced local and distributed caching, optimized dependency analysis, and parallel execution. It supports a wide variety of languages including C++. You can learn more about Bazel from its official page.
We will stick closely to Vulkan’s official environment setup guide but build everything with Bazel. To do this, we are going to use the rules_vulkan project.
In addition, we will set up tools that are usually used along with Vulkan such as:
- GLM — a library for linear algebra operations.
- GLFW — a cross-platform API for creating windows.
You can find a complete source code from this blog post on GitHub using the link below.
Prerequisites
Installing Bazel
This blog post assumes you have a Bazel (or its wrapper, Bazelisk) installed on your machine. Visit the official documentation to learn how to do it.
Downloading Vulkan SDK
Before doing any Bazel setup, we must download and install Vulkan SDK to our machine. This step would be exactly the same as you would follow the official Vulkan documentation.
- macOS. Follow only the Vulkan SDK section from the official Vulkan tutorial for macOS.
- Linux. Follow only the Vulkan Package section from the official Vulkan tutorial for Linux.
- Windows. Follow only the Vulkan SDK section from the official Vulkan tutorial for Windows.
Setting up the project
As usually with Bazel projects, we must initialize the project workspace. To do this, in the root directory of the project (let’s call it vulkan-bazel-samples
) we need to create a file named WORKSPACE
.
vulkan-bazel-samples
└── WORKSPACE
Configuring Bazel for Vulkan
First, we need to add Vulkan support to our Bazel project. We are going to use the rules_vulkan repo for this. Open WORKSPACE
file and fill it with the code below.
Here we are fetching rules_vulkan as a git_repository
and configuring it in the project using vulkan_repositories
macro.
We will see how to use it later in the blog post. However, before that, we need to configure additional third-party libraries that are usually used in Vulkan projects.
Configuring GLM
GLM — is a library for linear algebra operations.
First, we need to make it available in our project. To do this, we will use a http_archive
build rule which will download the sources from a GitHub archive.
This way we are fetching the library sources in our project and we need to configure a BUILD
file that will tell Bazel how to build it. We pass the path to this file as build_file
parameter above. This file would be placed in the root directory of the fetched library.
Obviously, we would need to create this BUILD
file. We will need to place it under the third_party/glm
folder and call it glm.BUILD
. Below are its contents.
Nothing fancy here, as we’re just telling Bazel where to get source files for the library.
After the actions above, the GLM library will be available as an external workspace @glm
. For easier usage, we can create a simple alias for it. To do this, create a third_party/glm/BUILD
file and populate it with the contents below.
Below is the file structure of the project so far.
vulkan-bazel-samples
├── third_party
│ └── glm
│ ├── glm.BUILD
│ └── BUILD
│
└── WORKSPACE
Next, we will include a GLFW library in the project.
Configuring GLFW
GLFW — is a cross-platform API for creating windows.
The algorithm for adding it to the project is similar to GLM. However, we would need to perform a bit more sophisticated configuration. Append the following code to the WORKSPACE
file.
Similar to GLM, we need to specify a BUILD
file for the GLFW library. To do this, under the third_party/glfw
directory create a file named glfw.BUILD
. Next, we will need to populate it with the contents.
First, for each of the supported operating systems, we need to pick the right set of implementation source files, define
statements, and linker flags. For the sake of saving space, the below snippet defines the corresponding variables but omits their values. However, the full code for this file could be found on GitHub.
Next, we need to define a cc_library
target that will build those sources either for Linux or Windows operating systems.
Similarly, to build the GLFW sources for macOS, we need to define an objc_library
target.
Finally, we are defining a public Bazel target that links GLFW API headers with the implementations we defined before.
In addition, create a third_party/glfw/BUILD
file that defines simple alias for the external @glfw
repository.
Here is the updated file structure we have so far.
vulkan-bazel-samples
├── third_party
│ ├── glm
│ │
│ └── glfw
│ ├── glfw.BUILD
│ └── BUILD
│
└── WORKSPACE
Writing and building Vulkan code
Now, we are ready to add some C++ code that uses Vulkan API. It won’t do anything fancy, just show an empty window and print the list of Vulkan extensions. This is sufficient to demonstrate that the project was configured correctly.
Create a main.cpp
file under the env_setup
directory. Fill it with the code below, which is taken from the official Vulkan tutorial.
Next, we need to add a BUILD
file for our source code under the env_setup
directory.
We are defining an env_setup
binary target that uses both glfw
and glm
libraries we configured before. In addition, it depends on vulkan_cc_library
from the @rules_vulkan
external workspace. This is how we enable Vulkan support for this target.
Below you can find the updated project structure.
vulkan-bazel-samples
├── env_setup
│ ├── main.cpp
│ └── BUILD
│
├── third_party
└── WORKSPACE
Running the code
Finally, we are ready to build and run the project with Bazel. To do so, run the following command in the terminal.
bazel run //env_setup
If all is done correctly, you should see an empty window and a bunch of Vulkan extensions printed in the console.
Conclusion
That’s it! In this blog post, we have seen how to set up a project that uses Vulkan graphics API and build it with Bazel using rules_vulkan repo. In addition, we have seen how to add GLM and GLFW libraries to such a project that serve as integral companions when working with graphics APIs.
In part 2 we will see how to build GLSL shaders with Bazel and apply this knowledge to run a project that draws a triangle.
All the source code from this blog post could be found on GitHub.
References
- rules_vulkan — a repository that enables Bazel support for Vulkan projects, created by Juan David Adarve.