<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="https://alexanderneben.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://alexanderneben.com/" rel="alternate" type="text/html" /><updated>2025-03-11T23:10:54+00:00</updated><id>https://alexanderneben.com/feed.xml</id><title type="html">Alexander Neben</title><subtitle>This is my blog. I write about engineering just not very much.</subtitle><author><name>Alexander Neben</name></author><entry><title type="html">Static Analysis with Bazel</title><link href="https://alexanderneben.com/2022/01/16/static-analysis-with-bazel.html" rel="alternate" type="text/html" title="Static Analysis with Bazel" /><published>2022-01-16T06:00:00+00:00</published><updated>2022-01-16T06:00:00+00:00</updated><id>https://alexanderneben.com/2022/01/16/static-analysis-with-bazel</id><content type="html" xml:base="https://alexanderneben.com/2022/01/16/static-analysis-with-bazel.html">&lt;p&gt;C++/Python Static Analysis with Bazel.&lt;/p&gt;

&lt;h1 id=&quot;static-analysis&quot;&gt;&lt;a href=&quot;#static-analysis&quot;&gt;Static Analysis&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Coming soon!&lt;/p&gt;</content><author><name>Alexander Neben</name></author><summary type="html">C++/Python Static Analysis with Bazel.</summary></entry><entry><title type="html">Continuous Integration at Ocient (Part 2)</title><link href="https://alexanderneben.com/2021/12/27/ci-at-ocient-part-2.html" rel="alternate" type="text/html" title="Continuous Integration at Ocient (Part 2)" /><published>2021-12-27T14:43:53+00:00</published><updated>2021-12-27T14:43:53+00:00</updated><id>https://alexanderneben.com/2021/12/27/ci-at-ocient-part-2</id><content type="html" xml:base="https://alexanderneben.com/2021/12/27/ci-at-ocient-part-2.html">&lt;p&gt;What are some other approaches considered and how we deal with common testing problems?&lt;/p&gt;

&lt;p&gt;If you have not read it yet &lt;a href=&quot;/2021/11/10/ci-at-ocient-part-1.html&quot;&gt;part 1&lt;/a&gt; gives some good background to this to this post.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Obligatory: the views expressed in this blog are my own and do not constitute those of my employer (&lt;a href=&quot;https://ocient.com&quot;&gt;Ocient&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;alternate-approaches&quot;&gt;&lt;a href=&quot;#alternate-approaches&quot;&gt;Alternate Approaches&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Note: this is not exhaustive of all other ways to successfully implement CI.&lt;/p&gt;

&lt;h3 id=&quot;problems&quot;&gt;&lt;a href=&quot;#problems&quot;&gt;Problems&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;There are two main issues with the approach described in my &lt;a href=&quot;/2021/11/10/ci-at-ocient-part-1.html&quot;&gt;last post&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;You have to wait for however long CI takes before you can merge.&lt;/li&gt;
  &lt;li&gt;Two conflicting changes can merge at the same time that each work by themselves but once merged together they fail. See diagram below.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ci-at-ocient-part-2-content/conflict.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While these conflicts do happen from time to time it is rare and caught fast so we have not put a lot of effort into solving this problem. However, as Ocient grows we expect to see more of this problem in the future and we might eventually move to a merge-trains like approach.&lt;/p&gt;

&lt;h3 id=&quot;merge-first-ask-questions-later&quot;&gt;&lt;a href=&quot;#merge-first-ask-questions-later&quot;&gt;Merge First Ask Questions Later&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While I am sure there is a more official name for this. In this model every dev can merge to main pending some reviews and an extremely slim CI run. Once merged, CI is run and if there are problems the merge is automatically reverted (or if the test is found to be buggy then the test is disabled instead).&lt;/p&gt;

&lt;p&gt;While this approach has its merits (and there are a lot of good blogs about this) this causes problems for us since our long pole test time is about 1hr (and that is when there is no queuing). This leaves a big gap when broken code could be pushed and when it could be reverted. Another dev can come along and rebase on the broken code during that time.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This can be fixed by using merge trains (see below).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another issue is that at Ocient often a developer will push up code to confirm their work is correct with no intention to merge the code just to get a CI run on it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This can be fixed by allowing a developer to deploy tests to Nomad (just like CI). While this is possible most devs find this annoying since it ties up an terminal window and a repo while being run (again something that could be fixed).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;merge-trains&quot;&gt;&lt;a href=&quot;#merge-trains&quot;&gt;Merge Trains&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are similar to merge first ask questions later except they solve the problem of ever having broken code in main. &lt;a href=&quot;https://docs.gitlab.com/ee/ci/pipelines/merge_trains.html&quot;&gt;Here&lt;/a&gt; is a pretty good explanation of the idea. Note this is a gitlab specific implementation and the same thing can be accomplished without using gitlab.&lt;/p&gt;

&lt;h3 id=&quot;flaky-tests&quot;&gt;&lt;a href=&quot;#flaky-tests&quot;&gt;Flaky Tests&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another problem that plagues CI systems and testing in general is flaky tests. We reduce test flakiness with nomad. We take all our existing tests and run them 100 times each. We can measure their flakiness by how often they fail. Due to limited hardware stop just short of automating this process. However, if we suspect a test is flaky we use this tool to determine how flaky it is.&lt;/p&gt;

&lt;p&gt;If a test is determined to be too flakey we disable it until the owner can fix the test.&lt;/p&gt;

&lt;p&gt;This is something we have just started doing and I will update this post as we find the most effective ways to deal with the problem.&lt;/p&gt;

&lt;h3 id=&quot;ocient-is-hiring&quot;&gt;&lt;a href=&quot;#ocient-is-hiring&quot;&gt;Ocient is Hiring&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ocient is hiring for all sorts of roles across development. If you are interested in working on build systems or any other aspect of distributed database &lt;a href=&quot;https://www.ocient.com/careers&quot;&gt;apply&lt;/a&gt; and &lt;strong&gt;drop me an email to let me know you applied&lt;/strong&gt;.&lt;/p&gt;</content><author><name>Alexander Neben</name></author><summary type="html">What are some other approaches considered and how we deal with common testing problems?</summary></entry><entry><title type="html">Continuous Integration at Ocient (Part 1)</title><link href="https://alexanderneben.com/2021/11/10/ci-at-ocient-part-1.html" rel="alternate" type="text/html" title="Continuous Integration at Ocient (Part 1)" /><published>2021-11-10T15:42:16+00:00</published><updated>2021-11-10T15:42:16+00:00</updated><id>https://alexanderneben.com/2021/11/10/ci-at-ocient-part-1</id><content type="html" xml:base="https://alexanderneben.com/2021/11/10/ci-at-ocient-part-1.html">&lt;p&gt;How do we enable developers to write correct code fast?
Unlike my last post this is going to go over a high level of what works for us and why it does rather that focus on how we implemented it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Obligatory: the views expressed in this blog are my own and do not constitute those of my employer (&lt;a href=&quot;https://ocient.com&quot;&gt;Ocient&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;background&quot;&gt;&lt;a href=&quot;#background&quot;&gt;Background&lt;/a&gt;&lt;/h1&gt;

&lt;h3 id=&quot;what-does-our-ci-need-to-accomplish&quot;&gt;&lt;a href=&quot;#why-is-our-ci-different&quot;&gt;What does our CI need to accomplish?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Traditionally I think of CI as “if something passes this then it is correct”. However, proving a pull request is bug free and has no negative performance implications is an near impossible task (especially turning that around quickly). What we are aiming for at Ocient is “if it passes CI then it is good enough for another developer to use”. The distinction is key because it allows us to virtualize our database rather than run it on real hardware and make other tradeoffs in the name of speed. We give the “our product is correct” badge after QA has a chance to run a much larger suite of tests on real hardware.&lt;/p&gt;

&lt;p&gt;In order to confirm correctness, we run automated tests which fall into a few categories.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Language Specific Tests
    &lt;ul&gt;
      &lt;li&gt;Unit Tests&lt;/li&gt;
      &lt;li&gt;Integration Tests&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Virtualized System Tests&lt;/li&gt;
  &lt;li&gt;System Tests&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;language-specific-tests&quot;&gt;&lt;a href=&quot;#language-specific-tests&quot;&gt;Language Specific Tests&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are C++ and Python based tests that do not need any external programs on setup to run. You can just type something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./run_test_a&lt;/code&gt; and it will return an exit code of zero on success and non-zero code on failure. For C++ we use &lt;a href=&quot;https://google.github.io/googletest/&quot;&gt;GoogleTest&lt;/a&gt; and for Python we use &lt;a href=&quot;https://docs.pytest.org/&quot;&gt;pytest&lt;/a&gt; to help us write these tests.&lt;/p&gt;

&lt;p&gt;While there is no hard line between what I am calling unit and integration tests we have a massive variation in duration and resource requirements for language specific tests. The longest running tests usually happen to be the most cpu and memory intensive tests as well. I am going to call these larger tests “integration tests” since they usually spin up large parts of the system and test them integrating together.&lt;/p&gt;

&lt;h3 id=&quot;virtualized-system-tests&quot;&gt;&lt;a href=&quot;#virtualized-system-tests&quot;&gt;Virtualized System Tests&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are Python based tests that test anywhere from 1-8 Ocient nodes running locally. The goal of these is to ensure our system as a whole works. In these tests the developer can load data from a various source, run SQL queries, kill a node, read monitoring data, and many more things. These are designed to be able to simulate real world scenarios (like a node crashing).&lt;/p&gt;

&lt;p&gt;These tests require a massive amount of resources and are incredibly variable in duration and memory usage.&lt;/p&gt;

&lt;h3 id=&quot;system-tests&quot;&gt;&lt;a href=&quot;#system-tests&quot;&gt;System Tests&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are the real deal, we run these on real clusters and can scale up to as many nodes as we have hardware for. Theses can be programmed using the same interface for virtualized system tests.&lt;/p&gt;

&lt;p&gt;These require entire Ocient scale nodes to run.&lt;/p&gt;

&lt;h1 id=&quot;developer-workflow&quot;&gt;&lt;a href=&quot;#developer-workflow&quot;&gt;Developer Workflow&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Lets say a developer has been working on a bugfix for a bug that QA found. The developer is confident they have fixed the bug. They added a unit test to cover the fix and push up their code. What happens next?&lt;/p&gt;

&lt;p&gt;Phase 1:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;We run some static analysis on all the code in the codebase. Much of this is cached since we use Bazel for caching the results of these tests and odds are the developer did not change too much code. We use &lt;a href=&quot;https://clang.llvm.org/extra/clang-tidy/&quot;&gt;clang-tidy&lt;/a&gt;, &lt;a href=&quot;https://clang-analyzer.llvm.org/&quot;&gt;clang static analyzer&lt;/a&gt;, &lt;a href=&quot;https://clang.llvm.org/docs/ClangFormat.html&quot;&gt;ClangFormat&lt;/a&gt;, and &lt;a href=&quot;http://mypy-lang.org/&quot;&gt;mypy&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;At the same time static analysis is running we build all things required for the types of testing described above.&lt;/li&gt;
  &lt;li&gt;[Optional] If code is changed that can affect our release docs, we build and push up our release docs to review. This is usually not important for most PRs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Phase 2:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;We run a client side program that decides what tests need to be run based on the level we are testing (PR means fewer tests, nighties mean all tests). The client will submit all jobs to our nomad server and wait for them to run. After all of them have run the client program will collect the results and report back.&lt;/li&gt;
  &lt;li&gt;[Optional] If code changed that can affect our release docs, we create Ocient packaging&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;duration&quot;&gt;&lt;a href=&quot;#duration&quot;&gt;Duration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If we ran our tests serially they would take well over 24 hours to complete. It is a requirement to run these tests as parallel as possible since we want the turnaround for developers between submitting a PR and merging it to be as fast as possible. In a perfect world if there is enough hardware running all tests should take as long as the longest running test (the long poll). The graphs below show our testes ordered by memory usage and runtime.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ci-at-ocient-part-1-content/test_times_bar.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;These are our top 20 longest running tests. About half are integration tests and half are virtualized system tests. You can see some variability in the duration. Units are in seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ci-at-ocient-part-1-content/test_memory_bar.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;These are our top 20 tests by memory usage in KB. The test on the far left had a bug we recently fixed that causes the memory usage on that test to drop to around 2GB. The next largest test is a unit test that uses 100GB of memory!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;nomad&quot;&gt;&lt;a href=&quot;#nomad&quot;&gt;Nomad&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For those of you familiar with the “running distributed tasks problem” some popular workload orchestration tools might come to mind &lt;a href=&quot;https://www.nomadproject.io/&quot;&gt;Nomad&lt;/a&gt;/&lt;a href=&quot;https://kubernetes.io/&quot;&gt;Kubernetes&lt;/a&gt;/&lt;a href=&quot;https://docs.docker.com/engine/swarm/&quot;&gt;Docker Swarm&lt;/a&gt;. As the header states, we decided on Nomad. This is our crown jewel of CI. This allows us to run all tests in parallel if we have enough hardware sitting idle.&lt;/p&gt;

&lt;p&gt;We use three tiers of workers for CI on Nomad&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Non-meta top level jobs: these are CI jobs where the computation is part of the CI job. For example, when we check that the code is formatted we run ClangFormat as part of the jobs.&lt;/li&gt;
  &lt;li&gt;Meta top level jobs: these are lightweight jobs that create and poll other jobs. For example, this job is used when we run Virtualized System Tests and rather than spin all the tests up locally the work this job does is to submit all the jobs to Nomad. It will then collect the results along with testing artifacts.&lt;/li&gt;
  &lt;li&gt;Leaf jobs: these are heavy jobs that are the actual tests (unit and virtualized system).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ci-at-ocient-part-1-content/ci-workflow.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We determine the allocation required for these jobs by looking at the last invocations of the jobs and seeing how much cpu and memory they used. This way the devs do not need to fiddle too much with guessing how much memory and cpu their tests will use. Our team will occasionally look at these numbers to see if there are any tests that use far too much memory/cpu and then work with the teams that own these tests to slim them down.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;ocient-is-hiring&quot;&gt;&lt;a href=&quot;#ocient-is-hiring&quot;&gt;Ocient is Hiring&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ocient is hiring for all sorts of roles across development. If you are interested in working on build systems or any other aspect of distributed database &lt;a href=&quot;https://www.ocient.com/careers&quot;&gt;apply&lt;/a&gt; and &lt;strong&gt;drop me an email to let me know you applied&lt;/strong&gt;.&lt;/p&gt;</content><author><name>Alexander Neben</name></author><summary type="html">How do we enable developers to write correct code fast? Unlike my last post this is going to go over a high level of what works for us and why it does rather that focus on how we implemented it.</summary></entry><entry><title type="html">Bazel for a Complex C++ Build System (Part 1)</title><link href="https://alexanderneben.com/2021/10/05/bazel-part-1.html" rel="alternate" type="text/html" title="Bazel for a Complex C++ Build System (Part 1)" /><published>2021-10-05T14:22:51+00:00</published><updated>2021-10-05T14:22:51+00:00</updated><id>https://alexanderneben.com/2021/10/05/bazel-part-1</id><content type="html" xml:base="https://alexanderneben.com/2021/10/05/bazel-part-1.html">&lt;p&gt;This is the first part of a multi-part series which is a deep dive into Ocient’s &lt;a href=&quot;https://bazel.build/&quot;&gt;Bazel-based&lt;/a&gt; build system. This post covers the motivation behind transitioning to Bazel and how we manage external dependencies.&lt;/p&gt;

&lt;p&gt;This post assumes a working knowledge of &lt;a href=&quot;https://bazel.build/&quot;&gt;Bazel&lt;/a&gt;. If you are new to Bazel, the Bazel &lt;a href=&quot;https://bazel.build/&quot;&gt;website&lt;/a&gt; will be a better place to start.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Obligatory: the views expressed in this blog are my own and do not constitute those of my employer (&lt;a href=&quot;https://ocient.com&quot;&gt;Ocient&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;background&quot;&gt;&lt;a href=&quot;#background&quot;&gt;Background&lt;/a&gt;&lt;/h1&gt;

&lt;h3 id=&quot;motivation-for-blog-series-about-bazel&quot;&gt;&lt;a href=&quot;#motivation-for-blog-series-about-bazel&quot;&gt;Motivation for Blog Series About Bazel&lt;/a&gt;?&lt;/h3&gt;
&lt;p&gt;During this project I read a ton of blogs about Bazel. It seemed like it was the cure to all ailments. Hermetic and faster builds? Sign me up! Everything anyone needed to know about Bazel was already out there. What can I add?&lt;/p&gt;

&lt;p&gt;What I quickly found is that many people who had written these blogs used contrived examples to show “how cool Bazel was” by building a hello world like program. It was either that or they worked at an organization that had strict C++ standards on compilation time and didn’t push the C++ compilation to the limit (more on this later). Ocient was in race mode when significant portions of our codebase was written which means we have some… how do I put this gently… “legacy code”. We needed a flexible build system that could scale well and would handle some of our very specific build requirements (see more on this later).&lt;/p&gt;

&lt;p&gt;My goal of writing this series is to talk about a “real-life” switch to Bazel with a project that has many external dependencies, extremely nuanced build system, and very custom solutions to building C++ code. I hope to speak fairly technically about work we did to make everything build so you can use these design patterns and ideas to facilitate your switch to Bazel, speed up your Bazel builds, or just to get inspiration.&lt;/p&gt;

&lt;p&gt;Here are some stats about the Ocient codebase.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Over &lt;strong&gt;3,000,000 lines&lt;/strong&gt; of C++ code&lt;br /&gt;
Just under &lt;strong&gt;100,000 lines&lt;/strong&gt; of Python code&lt;br /&gt;
Over &lt;strong&gt;70,000 commits&lt;/strong&gt; authored by more than &lt;strong&gt;100 people&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;!-- | Tables        | Are           | Cool  |
| ------------- |:-------------:| -----:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 | --&gt;
&lt;!-- *** --&gt;
&lt;h3 id=&quot;existing-build-system&quot;&gt;&lt;a href=&quot;#existing-build-system&quot;&gt;Existing Build System&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before this project was started our build infrastructure was &lt;a href=&quot;https://www.gnu.org/software/make/&quot;&gt;Make&lt;/a&gt; based with a &lt;a href=&quot;https://distcc.github.io/&quot;&gt;distcc&lt;/a&gt; backend. A developer would run a command like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make all -j 100&lt;/code&gt; which meant “build everything and do 100 compilations actions at the same time (and do them remotely if slots remain)”.&lt;/p&gt;

&lt;div class=&quot;info&quot;&gt;
If 100 simultaneous actions sounds like a lot it is because it is! Our build servers are not homogeneous but most have around 128 cores and 500GB of RAM. Each one cost on the order of $10,000 and we had around 8 of them when this project started, we are now up to 17. Post-Bazel we now run with 1000 concurrent actions as the default.
&lt;/div&gt;

&lt;p&gt;Our project was divided into 20+ libraries where each library contained related code and unit tests. The dependencies of the main binary target (“rolehostd”) are shown below. Do not worry too much about the names of the libraries. The point of this graph is to illustrate we have a reasonable list of internal dependencies.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/bazel-part-1-content/xgsrc-deps-min.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;build-types&quot;&gt;&lt;a href=&quot;#build-types&quot;&gt;Build Types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We had three poorly named build types as well as a variety of subtypes.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;RELEASE&lt;/em&gt;&lt;/strong&gt; builds are the most aptly named. They have all the optimizations (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O2&lt;/code&gt; and others) we support and all the asserts are compiled out. To get a sense of how many optimizations we have I have attached a list of some of our largest object files. Our top three object files sizes in this mode 1264MB, 1177MB, and 1173MB. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-j36&lt;/code&gt; it took &lt;strong&gt;over 3 hours&lt;/strong&gt; to build.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;TEST_RELEASE&lt;/em&gt;&lt;/strong&gt; are the same as release builds with asserts turned on and a few of our egregious inlining optimizations turned off. These are the builds we use for most of CI since they provide a good tradeoff between program execution speed, compile time, and correctness.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;DEBUG&lt;/em&gt;&lt;/strong&gt; are builds without any optimizations (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O0&lt;/code&gt; (note we are investigating the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-Og&lt;/code&gt; vs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O0&lt;/code&gt; &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html&quot;&gt;docs&lt;/a&gt;)). In addition these builds use &lt;strong&gt;shared objects&lt;/strong&gt; for each library for faster linking. More on this later. These builds also include an address sanitizer and a memory sanitizer. This is the default build type.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some examples of a few subtypes of builds as well. I am not including all of them for brevity.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;NO_SHARED&lt;/em&gt;&lt;/strong&gt; is only used with &lt;strong&gt;&lt;em&gt;DEBUG&lt;/em&gt;&lt;/strong&gt; builds and it signifies to build without the address sanitizer, memory sanitizer and statically link all libraries rather than building shared objects. Great naming!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;NO_DISTCC&lt;/em&gt;&lt;/strong&gt; means do not use our distributed build system, instead run locally.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;DEBUG_CONTAINERS&lt;/em&gt;&lt;/strong&gt; means to build with &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/libstdC++/manual/debug_mode_using.html#debug_mode.using.mode&quot;&gt;debug containers&lt;/a&gt; that have asserts in them to check for proper usage. This found extremely serious bugs in our code and I would highly recommend you use this in your organization.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Putting this altogether a sample command might look like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make all DEBUG_CONTAINERS=y&lt;/code&gt; which means “make all with &lt;strong&gt;&lt;em&gt;DEBUG_CONTAINERS&lt;/em&gt;&lt;/strong&gt; and use a &lt;strong&gt;&lt;em&gt;DEBUG&lt;/em&gt;&lt;/strong&gt; build”&lt;/p&gt;

&lt;h3 id=&quot;build-targets&quot;&gt;&lt;a href=&quot;#build-targets&quot;&gt;Build Targets&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For those familiar with Make you might be wondering why I am specifying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;all&lt;/code&gt; rather than a specific target (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binary-target&lt;/code&gt;). Without going into too much detail, it is because the impacts of other things included in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;all&lt;/code&gt; are negligible. The main thing we are building we call “rolehostd” but for the purposes of this post I am just going to call it our “binary target”. In addition, each library also produces a &lt;a href=&quot;https://github.com/google/googletest&quot;&gt;gtest&lt;/a&gt; binary that runs all the unit tests in that library.&lt;/p&gt;

&lt;h3 id=&quot;specific-build-requirements&quot;&gt;&lt;a href=&quot;#specific-build-requirements&quot;&gt;Specific Build Requirements&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’m sure people are going to read this and say “why don’t you do X instead of Y”. However, for each one of these changes the scope can creep and the criteria to call this project done grows and grows. It was important to have as minimal impacts outside of the build system as possible. Many of these hard requirements crept up on Ocient. For example, we would never test building with a different version of gcc. Lo and behold when we are no longer continuously testing we eventually lose compatibility.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Stripping debug symbols from many object files because our binary was so large that it would fail to link. Sections need to be within 2GB of each other since there were only 32 bit offsets. This is worthy of a post by itself.&lt;/li&gt;
  &lt;li&gt;We use linker scripts to move sections around in the binary since these addresses can conflict with the memory regions the address sanitizer reserves.&lt;/li&gt;
  &lt;li&gt;We build with &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html&quot;&gt;-mcmodel=large&lt;/a&gt;. This is also worthy of a post by itself.&lt;/li&gt;
  &lt;li&gt;We require gcc 8.2 with a patch. We are using features in &lt;a href=&quot;https://en.cppreference.com/w/cpp/20&quot;&gt;C++20&lt;/a&gt;. Downgrading or upgrading gcc would be a non-trivial amount of work.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;DEBUG&lt;/em&gt;&lt;/strong&gt; builds required creating a shared object for each library.&lt;/li&gt;
  &lt;li&gt;We use gdb 10.&lt;/li&gt;
  &lt;li&gt;Our developer containers run Ubuntu 16.04.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;problems-with-the-existing-build-system&quot;&gt;&lt;a href=&quot;#problems-with-the-existing-build-system&quot;&gt;Problems with the Existing Build System&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So hopefully by now you have some background. Now lets talk about why there were problems. At the time this project started we had about 44 employees in development roles (not counting interns). By the time the project was finished we had about 55 employees (an increase of 20%). We were already starting to see the age of the build system. Frequently, during times of high demand, we would see compile actions time out on remote nodes and then have to be run locally. Since our hardware is shared this had a hugely negative impact on our CI nodes as well as developer containers. For example, if a developer built when our distcc build farm was saturated, the other people on the shared machine would notice a significant slowdown and a significant increase in memory usage. To minimize saturating the distcc build farm, we lowered the concurrency of builds in CI and it was not unheard of for CI to take longer than 8 hours.&lt;/p&gt;

&lt;p&gt;Other than slowness, there were a other problems with Make/distcc.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Distcc offered no support for &lt;a href=&quot;https://gcc.gnu.org/wiki/DebugFission&quot;&gt;debug symbol fissioning&lt;/a&gt;. This was the primary driver to upgrade. We needed support for this because we needed a way to keep our massive amounts of debugging information.&lt;/li&gt;
  &lt;li&gt;No caching of artifacts could be shared between developers. When we tried with &lt;a href=&quot;https://ccache.dev/&quot;&gt;ccache&lt;/a&gt;, we found bugs at scale.&lt;/li&gt;
  &lt;li&gt;Little in the way of elasticity which implied often resources were underused.&lt;/li&gt;
  &lt;li&gt;Semi-frequent build errors that were due to a stale build artifact sitting around. Often we would have to tell people to blow away all their build artifacts and like magic it would just start to work but waste a lot of their time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With all that being said it was time to find a new solution.&lt;/p&gt;

&lt;h1 id=&quot;bazel-transition&quot;&gt;&lt;a href=&quot;#bazel-transition&quot;&gt;Bazel Transition&lt;/a&gt;&lt;/h1&gt;

&lt;h3 id=&quot;bazel-perks&quot;&gt;&lt;a href=&quot;#bazel-perks&quot;&gt;Bazel Perks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Besides solving the problems with Make/distcc Bazel comes with some other goodies.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Support for &lt;a href=&quot;https://gcc.gnu.org/wiki/DebugFission&quot;&gt;debug symbol fissioning&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.bazel.build/versions/main/remote-execution.html&quot;&gt;Remote execution and cache&lt;/a&gt; (for compilation and test actions)&lt;/li&gt;
  &lt;li&gt;Better resource utilization (will get into this in a later post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.bazel.build/versions/main/sandboxing.html&quot;&gt;Build sandbox&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Excellent built in &lt;a href=&quot;https://docs.bazel.build/versions/main/skylark/performance.html#profile-information&quot;&gt;profiling&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Potential for auto-scaling based on demand&lt;/li&gt;
  &lt;li&gt;Linking could be done on the build farm&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;moving-our-toolchain-to-bazel&quot;&gt;&lt;a href=&quot;#moving-our-toolchain-to-bazel&quot;&gt;Moving our Toolchain to Bazel&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In our Make based system there was a bootstrapping step when building. First, a new developer would have to build our toolchain a 2-3 hour process that they had to go though on their first day (boring!). Then once the toolchain was built then they could use the tools built in the toolchain to actually build our system. The real toolchain pain came when something in the toolchain was updated. Every single developer would have to remake their toolchain. Depending on the change a developer might have to blow away all existing object files and archives. Many many times developers would skip that step and have nightmarish linker bugs since a stale object was being linked with an incompatible different object. Our toolchain consisted of two things, the tools to build Ocient, think g++, and some external dependencies of which some were linked and some where not (think curl and gdb). These external dependencies were versioned by git sha and stored on our internal servers. Secondly, there were additional external dependencies were kept outside of toolchain locked to a specific commit hash (you know… to keep everything simple /s). Before we made any progress on Bazel we had to port our toolchain and external dependencies to Bazel.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/bazel-part-1-content/developer-toolchain-workflow-before.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;info&quot;&gt;
Something I briefly looking into while building this was a cross-compiler toolchain. I am in no way claiming I fully understand this topic. This is something that is hard to do but allows for different GCCs for different targets (32 bit vs 64 bit gcc for example).
&lt;/div&gt;

&lt;h3 id=&quot;our-first-approach&quot;&gt;&lt;a href=&quot;#our-first-approach&quot;&gt;Our First Approach&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We noted that every developer was building the same set of tools. We could build this once and have every developer clone this down. The building of toolchain can be an automated job whenever our toolchain changes. We used Make since this allowed us to reuse some of the existing toolchain code. We spent the time to migrate all our toolchain and ext dependencies to our Bazel toolchain. The new process was to just run a &lt;a href=&quot;https://rclone.org/&quot;&gt;rclone&lt;/a&gt; command and a new developer was ready to go.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/bazel-part-1-content/developer-toolchain-workflow-phase1.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This worked well until it didn’t. We found we were frequently updating our external dependencies and each time we did we would have to deploy a new toolchain while supporting the old one until no one used it anymore. By itself this is just horrible for us (and great for the rest of the development organization), we would have anywhere from 10 minute to 8 hour iteration times for toolchain changes. In the worst case we would need to rebuild toolchain and our binary only to discover there was something that needed to be changed in the toolchain. This leads us to the second approach.&lt;/p&gt;

&lt;h3 id=&quot;bazels-recommended-approach&quot;&gt;&lt;a href=&quot;#bazels-recommended-approach&quot;&gt;Bazel’s Recommended Approach&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was the first point where I was disappointed with Bazel docs and the literature on the subject of external dependencies. It appeared to me, that the &lt;a href=&quot;https://docs.bazel.build/versions/main/external.html#depending-on-non-Bazel-projects&quot;&gt;suggested&lt;/a&gt; way of dealing with external deps was to replace the project’s build system with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUILD.bazel&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WORKSPACE&lt;/code&gt; file. I assume this works great for organizations the size of Google since you can afford to spend the development effort on things like this. However, for Ocient, every second I spent working on rewriting a build system for an open source piece of software was a second not spent adding features to Ocient. This was made even more frustrating since these projects &lt;strong&gt;already have a working build system&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We have &lt;strong&gt;47 external C++ dependencies&lt;/strong&gt; (60+ including tools built) &lt;br /&gt;
Of those &lt;strong&gt;7 are header-only&lt;/strong&gt; (require no building) &lt;br /&gt;
In Bazel’s default approach we need to maintain a build system for &lt;strong&gt;40 external dependencies&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;our-second-approach&quot;&gt;&lt;a href=&quot;#our-second-approach&quot;&gt;Our Second Approach&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What if we could build most of our external dependencies in Bazel and leave only a select few things in our toolchain while utilizing the external project’s existing build system? This avoids the problem of frequent toolchain upgrades while still getting caching and hermetic builds. There is another good blog post detailing this &lt;a href=&quot;https://blog.envoyproxy.io/external-c-dependency-management-in-Bazel-dd37477422f5&quot;&gt;here&lt;/a&gt; (scroll to the very bottom of the article). The solution uses &lt;a href=&quot;https://github.com/Bazelbuild/rules_foreign_cc&quot;&gt;rules_foreign_cc&lt;/a&gt; to wrap non Bazel build system in Bazel by listing the artifacts we are expecting. For headers output by libraries you only need to specify a folder rather than every file in the folder (which is huge). This is the approach we are still using today and I would recommend you use.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/bazel-part-1-content/developer-toolchain-workflow-phase2.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’m not claiming we have the most complicated dependency system but I do think it is more complicated than the average Bazel blog post which is why I am going to share the code for some our our dependencies.&lt;/p&gt;

&lt;p&gt;Lets start simple. This is a fairly popular C++ library known as &lt;a href=&quot;http://tclap.sourceforge.net/&quot;&gt;TCLAP&lt;/a&gt;. This is very simple because it is a header only library.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# WORKSPACE
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http_archive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;tclap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Hold on, I thought you said we don't want to replace any existing build systems?
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Yes, that is true but it is easier to just rip out the header files than it is to get TCLAP to build using its own build system.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# By just creating a cc_library with only the header files we can #include them later in our program (since this library does not produce any archive or shared object files)
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;build_file_content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
cc_library(
  name = &quot;tclap&quot;,
  # Find all the header files for the library. See the bazel docs on cc_library for more info.
  hdrs = glob([&quot;include/**/*.h&quot;]),
  # This is the magic line right here.
  # Without this when we would #include any TCLAP header we would need to preface it with &quot;include/&quot;
  # However, maybe that is your style but it still would not work.
  # TCLAP headers can include other TCLAP headers and those #includes do not start with an &quot;include/&quot;
  # We need to strip the include prefix.
  strip_include_prefix = &quot;include/&quot;,
  # Make this visible to everyone
  visibility = [&quot;//visibility:public&quot;],
)
    &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# The sha to use for this library. If the sha does not match the download this will fail.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;sha256&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;9f9f0fe3719e8a89d79b6ca30cf2d16620fba3db5b9610f9b51dd2cd033deebb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# After unzipping we want to cd into the folder to run our commands.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;strip_prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;tclap-1.2.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# The locations to download the files from.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ext_location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;tclap-1.2.1.tar.gz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# WORKSPACE file for this dependency. Usually can be left blank.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# This is used more often if this library is a Bazel dependency.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;workspace_file_content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Lets knock it up one notch. This is another a real life example for &lt;a href=&quot;https://github.com/open-source-parsers/jsoncpp&quot;&gt;jsoncpp&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#WORKSPACE
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@Bazel_tools//tools/build_defs/repo:http.bzl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http_archive&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Select all files and to use those as the input to the cmake rule
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all_content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;filegroup(name = &quot;all&quot;, srcs = glob([&quot;**&quot;]), visibility = [&quot;//visibility:public&quot;])&quot;&quot;&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;ext_location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http://external-packages-location/&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Standard Bazel practice to declare the package an http_archive to be downloaded before the analysis phase
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http_archive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;jsoncpp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# &quot;Select all files&quot;
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;build_file_content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all_content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# About 50% of our external dependencies need at least one patch to work.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# This is due to the flags we use when compiling, general bugs, and static analysis problems.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# We often found patching to be relatively easy.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;patch_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-p0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;patches&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;//toolchain/patches:jsoncpp-clang-fix.patch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# The sha to use for this library. If the sha does not match the download this will fail.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;sha256&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;90618516abaed488d23f7b7e358341075073cbdce3d1ed0329bb23cdaaa66183&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# After unzipping we want to cd into the folder to run our commands.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;strip_prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;jsoncpp-1.7.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# The locations to download the files from.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ext_location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;jsoncpp-1.7.2.zip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# WORKSPACE file for this dependency. Usually can be left blank.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# This is used more often if this library is a Bazel dependency.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;workspace_file_content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#BUILD.Bazel
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@rules_foreign_cc//foreign_cc:defs.bzl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;cmake&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cmake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;jsoncpp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Understanding this requires some knowledge of cmake.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# The build command is run with these defined.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# To understand what these mean you need to read the cmake documentation as well as the documentation of the project.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# In this case, each line is pretty self explanatory with what it does.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# A good hint to see these configuration options is to run `cmake -LA`
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;cache_entries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;CMAKE_BUILD_TYPE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Release&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;BUILD_STATIC_LIBS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;BUILD_SHARED_LIBS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;JSONCPP_WITH_WARNING_AS_ERROR&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;off&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;JSONCPP_WITH_STRICT_ISO&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;off&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Issue all the warnings demanded by strict ISO C and ISO C++ - found in the source code of this library
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# I think going deep into this is worth of its own post.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# This enables -mcmodel=large so that we can statically link our binary
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# This also allows us to switch on the build type.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# For debug containers, we have to enable debug containers here.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# By putting everything behind the &quot;EXTERNAL_FEATURES&quot; variable we can change this is the future and make sure all the changes happen to every external dependency.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXTERNAL_FEATURES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Reference to the source files this is &quot;all_content&quot;
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lib_source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;@jsoncpp//:all&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# comment out out_shared_libs and uncomment out_static_libs to statically link
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# out_static_libs = [&quot;libjsoncpp.a&quot;],
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Prefer to use shared libs here.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# We used to use the static archive and we left it here for illustration.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;out_shared_libs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;libjsoncpp.so&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;libjsoncpp.so.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;libjsoncpp.so.1.7.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Everything should be able to reference this dependency.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;visibility&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//visibility:public&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Another example. This is for &lt;a href=&quot;https://github.com/DPDK/dpdk&quot;&gt;DPDK&lt;/a&gt;. I skipped the changes to the WORKSPACE file since they are similar (except we have more patches for DPDK). Warning, it gets grosser!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#BUILD.Bazel
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@rules_foreign_cc//foreign_cc:defs.bzl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;make&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;dpdk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# See above
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXTERNAL_FEATURES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# See above
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lib_source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;@dpdk//:all&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# YUCK! Now we need to make changes to this library if we change some gcc flags.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# However, this avoids the problem of rewriting DPDK's build system.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# We are passing CFLAGS and other various arguments to the meson build system that mirror the arguments we build with.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Note $EXT_BUILD_DEPS and $INSTALLDIR.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# These variables are provided by rules_foreign_cc for scripting.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Later we will see how to get a list of such variables.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# DPDK uses ninja/meson. These are the commands used to run ninja/meson.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;make_commands&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;CFLAGS=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-march=broadwell -mcmodel=large -fPIC&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; $EXT_BUILD_DEPS/bin/meson.py -Dprefix=$INSTALLDIR -Ddisable_drivers=* -Dmachine=broadwell --buildtype=release --libdir=lib --default-library=shared build&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;cd build&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;ninja&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;ninja install&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Yuck, more grossness...
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# We need to know all outputs so Bazel can build its dependency graph.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# We found these by running the DPDK install and copying all the libraries output.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;static_libraries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_acl.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bbdev.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bitratestats.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bpf.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bus_dpaa.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bus_fslmc.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bus_ifpga.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bus_pci.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_bus_vdev.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_cfgfile.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_cmdline.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_common_octeontx.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_compressdev.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_cryptodev.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_distributor.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_eal.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_efd.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_ethdev.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_eventdev.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_flow_classify.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_gro.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_gso.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_hash.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_ip_frag.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_jobstats.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_kni.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_kvargs.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_latencystats.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_lpm.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mbuf.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_member.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mempool.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mempool_bucket.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mempool_dpaa2.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mempool_dpaa.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mempool_octeontx.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mempool_ring.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_mempool_stack.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_meter.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_metrics.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_net.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_pci.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_pdump.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_pipeline.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_port.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_power.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_rawdev.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_reorder.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_ring.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_sched.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_security.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_table.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_timer.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_vhost.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;librte_telemetry.a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Requires meson
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;tools_deps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@meson//:meson&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Anyone can see this
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;visibility&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//visibility:public&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;end-of-part-1&quot;&gt;&lt;a href=&quot;#end-of-part-1&quot;&gt;End of Part 1&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;That is it for part 1! If you have any feedback or see any mistakes please drop me a line. The upcoming posts will cover the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUILD.bazel&lt;/code&gt; files we use to actually build our code, how we deal with protobuf dependencies, how we do remote execution, and any other topics people are interested in.&lt;/p&gt;

&lt;h3 id=&quot;ocient-is-hiring&quot;&gt;&lt;a href=&quot;#ocient-is-hiring&quot;&gt;Ocient is Hiring&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ocient is hiring for all sorts of roles across development. If you are interested in working on build systems or any other aspect of distributed database &lt;a href=&quot;https://www.ocient.com/careers&quot;&gt;apply&lt;/a&gt; and &lt;strong&gt;drop me an email to let me know you applied&lt;/strong&gt;.&lt;/p&gt;</content><author><name>Alexander Neben</name></author><summary type="html">This is the first part of a multi-part series which is a deep dive into Ocient’s Bazel-based build system. This post covers the motivation behind transitioning to Bazel and how we manage external dependencies.</summary></entry></feed>