Build programs with Bazel (2023)

Report an issueopen_in_new View sourceopen_in_new

This page covers how to build a program with Bazel, build command syntax, andtarget pattern syntax.

Quickstart

To run Bazel, go to your base workspace directoryor any of its subdirectories and type bazel. See build if youneed to make a new workspace.

bazel help [Bazel release bazel version]Usage: bazel command options ...

Available commands

  • analyze-profile: Analyzes build profile data.
  • aquery: Executes a query on the post-analysis action graph.
  • build: Builds the specified targets.
  • canonicalize-flags: Canonicalize Bazel flags.
  • clean: Removes output files and optionally stops the server.
  • cquery: Executes a post-analysis dependency graph query.
  • dump: Dumps the internal state of the Bazel server process.
  • help: Prints help for commands, or the index.
  • info: Displays runtime info about the bazel server.
  • fetch: Fetches all external dependencies of a target.
  • mobile-install: Installs apps on mobile devices.
  • query: Executes a dependency graph query.
  • run: Runs the specified target.
  • shutdown: Stops the Bazel server.
  • test: Builds and runs the specified test targets.
  • version: Prints version information for Bazel.

Getting help

  • bazel help command: Prints help and options forcommand.
  • bazel helpstartup_options: Options for the JVM hosting Bazel.
  • bazel helptarget-syntax: Explains the syntax for specifying targets.
  • bazel help info-keys: Displays a list of keys used by the info command.

The bazel tool performs many functions, called commands. The most commonlyused ones are bazel build and bazel test. You can browse the online helpmessages using bazel help.

Building one target

Before you can start a build, you need a workspace. A workspace is adirectory tree that contains all the source files needed to build yourapplication. Bazel allows you to perform a build from a completely read-onlyvolume.

To build a program with Bazel, type bazel build followed by thetarget you want to build.

bazel build //foo

After issuing the command to build //foo, you'll see output similar to this:

INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).INFO: Found 1 target...Target //foo:foo up-to-date: bazel-bin/foo/fooINFO: Elapsed time: 9.905s, Critical Path: 3.25sINFO: Build completed successfully, 6 total actions

First, Bazel loads all packages in your target's dependency graph. Thisincludes declared dependencies, files listed directly in the target's BUILDfile, and transitive dependencies, files listed in the BUILD files of yourtarget's dependencies. After identifying all dependencies, Bazel analyzesthem for correctness and creates the build actions. Last, Bazel executesthe compilers and other tools of the build.

During the build's execution phase, Bazel prints progress messages. The progressmessages include the current build step (such as, compiler or linker) as itstarts, and the number completed over the total number of build actions. As thebuild starts, the number of total actions often increases as Bazel discoversthe entire action graph, but the number stabilizes within a few seconds.

At the end of the build, Bazel prints which targets were requested, whether ornot they were successfully built, and if so, where the output files can befound. Scripts that run builds can reliably parse this output; see--show_result for more details.

If you type the same command again, the build finishes much faster.

bazel build //fooINFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).INFO: Found 1 target...Target //foo:foo up-to-date: bazel-bin/foo/fooINFO: Elapsed time: 0.144s, Critical Path: 0.00sINFO: Build completed successfully, 1 total action

This is a null build. Because nothing changed, there are no packages to reloadand no build steps to execute. If something changed in 'foo' or itsdependencies, Bazel would re-execute some build actions, or complete anincremental build.

Building multiple targets

Bazel allows a number of ways to specify the targets to be built. Collectively,these are known as target patterns. This syntax is used in commands likebuild, test, or query.

Whereas labels are used to specify individualtargets, such as for declaring dependencies in BUILD files, Bazel's targetpatterns specify multiple targets. Target patterns are a generalization of thelabel syntax for sets of targets, using wildcards. In the simplest case, anyvalid label is also a valid target pattern, identifying a set of exactly onetarget.

All target patterns starting with // are resolved relative to the currentworkspace.

(Video) Bazel Tutorial: (Part 1) Getting Started, Bazelisk & our First Build Targets

//foo/bar:wiz Just the single target //foo/bar:wiz.
//foo/bar Equivalent to //foo/bar:bar.
//foo/bar:all All rule targets in the package foo/bar.
//foo/... All rule targets in all packages beneath the directory foo.
//foo/...:all All rule targets in all packages beneath the directory foo.
//foo/...:* All targets (rules and files) in all packages beneath the directory foo.
//foo/...:all-targets All targets (rules and files) in all packages beneath the directory foo.
//... All targets in packages in the workspace. This does not include targets from external repositories.
//:all All targets in the top-level package, if there is a `BUILD` file at the root of the workspace.

Target patterns that do not begin with // are resolved relative to thecurrent working directory. These examples assume a working directory of foo:

:foo Equivalent to //foo:foo.
bar:wiz Equivalent to //foo/bar:wiz.
bar/wiz Equivalent to:
  • //foo/bar/wiz:wiz if foo/bar/wiz is a package
  • //foo/bar:wiz if foo/bar is a package
  • //foo:bar/wiz otherwise
bar:all Equivalent to //foo/bar:all.
:all Equivalent to //foo:all.
...:all Equivalent to //foo/...:all.
... Equivalent to //foo/...:all.
bar/...:all Equivalent to //foo/bar/...:all.

By default, directory symlinks are followed for recursive target patterns,except those that point to under the output base, such as the conveniencesymlinks that are created in the root directory of the workspace.

In addition, Bazel does not follow symlinks when evaluating recursive targetpatterns in any directory that contains a file named as follows:DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/... is a wildcard over packages, indicating all packages recursivelybeneath directory foo (for all roots of the package path). :all is awildcard over targets, matching all rules within a package. These two may becombined, as in foo/...:all, and when both wildcards are used, this may beabbreviated to foo/....

In addition, :* (or :all-targets) is a wildcard that matches every targetin the matched packages, including files that aren't normally built by any rule,such as _deploy.jar files associated with java_binary rules.

This implies that :* denotes a superset of :all; while potentiallyconfusing, this syntax does allow the familiar :all wildcard to be used fortypical builds, where building targets like the _deploy.jar is not desired.

In addition, Bazel allows a slash to be used instead of the colon required bythe label syntax; this is often convenient when using Bash filename expansion.For example, foo/bar/wiz is equivalent to //foo/bar:wiz (if there is apackage foo/bar) or to //foo:bar/wiz (if there is a package foo).

Many Bazel commands accept a list of target patterns as arguments, and they allhonor the prefix negation operator -. This can be used to subtract a set oftargets from the set specified by the preceding arguments. Note that this meansorder matters. For example,

bazel build foo/... bar/...

means "build all targets beneath foo and all targets beneath bar", whereas

bazel build -- foo/... -foo/bar/...

means "build all targets beneath foo except those beneath foo/bar". (The-- argument is required to prevent the subsequent arguments starting with -from being interpreted as additional options.)

It's important to point out though that subtracting targets this way will notguarantee that they are not built, since they may be dependencies of targetsthat weren't subtracted. For example, if there were a target //foo:all-apisthat among others depended on //foo/bar:api, then the latter would be built aspart of building the former.

Targets with tags = ["manual"] are not included in wildcard target patterns(..., :*, :all, etc.) when specified in commands likebazel build and bazel test; you should specify suchtest targets with explicit target patterns on the command line if you want Bazelto build/test them. In contrast, bazel query doesn't perform anysuch filtering automatically (that would defeat the purpose ofbazel query).

Fetching external dependencies

By default, Bazel will download and symlink external dependencies during thebuild. However, this can be undesirable, either because you'd like to knowwhen new external dependencies are added or because you'd like to"prefetch" dependencies (say, before a flight where you'll be offline). If youwould like to prevent new dependencies from being added during builds, youcan specify the --fetch=false flag. Note that this flag onlyapplies to repository rules that do not point to a directory in the localfile system. Changes, for example, to local_repository,new_local_repository and Android SDK and NDK repository ruleswill always take effect regardless of the value --fetch .

If you disallow fetching during builds and Bazel finds new externaldependencies, your build will fail.

You can manually fetch dependencies by running bazel fetch. Ifyou disallow during-build fetching, you'll need to run bazel fetch:

(Video) Building Software at Google Scale: Bazel

  • Before you build for the first time.
  • After you add a new external dependency.

Once it has been run, you should not need to run it again until the WORKSPACEfile changes.

fetch takes a list of targets to fetch dependencies for. Forexample, this would fetch dependencies needed to build //foo:barand //bar:baz:

bazel fetch //foo:bar //bar:baz

To fetch all external dependencies for a workspace, run:

bazel fetch //...

You do not need to run bazel fetch at all if you have all of the tools you areusing (from library jars to the JDK itself) under your workspace root.However, if you're using anything outside of the workspace directory then Bazelwill automatically run bazel fetch before runningbazel build.

The repository cache

Bazel tries to avoid fetching the same file several times, even if the samefile is needed in different workspaces, or if the definition of an externalrepository changed but it still needs the same file to download. To do so,bazel caches all files downloaded in the repository cache which, by default,is located at ~/.cache/bazel/_bazel_$USER/cache/repos/v1/. Thelocation can be changed by the --repository_cache option. Thecache is shared between all workspaces and installed versions of bazel.An entry is taken from the cache ifBazel knows for sure that it has a copy of the correct file, that is, if thedownload request has a SHA256 sum of the file specified and a file with thathash is in the cache. So specifying a hash for each external file isnot only a good idea from a security perspective; it also helps avoidingunnecessary downloads.

Upon each cache hit, the modification time of the file in the cache isupdated. In this way, the last use of a file in the cache directory can easilybe determined, for example to manually clean up the cache. The cache is nevercleaned up automatically, as it might contain a copy of a file that is nolonger available upstream.

Distribution files directories

The distribution directory is another Bazel mechanism to avoid unnecessarydownloads. Bazel searches distribution directories before the repository cache.The primary difference is that the distribution directory requires manualpreparation.

Using the--distdir=/path/to-directoryoption, you can specify additional read-only directories to look for filesinstead of fetching them. A file is taken from such a directory if the file nameis equal to the base name of the URL and additionally the hash of the file isequal to the one specified in the download request. This only works if thefile hash is specified in the WORKSPACE declaration.

While the condition on the file name is not necessary for correctness, itreduces the number of candidate files to one per specified directory. In thisway, specifying distribution files directories remains efficient, even if thenumber of files in such a directory grows large.

Running Bazel in an airgapped environment

To keep Bazel's binary size small, Bazel's implicit dependencies are fetchedover the network while running for the first time. These implicit dependenciescontain toolchains and rules that may not be necessary for everyone. Forexample, Android tools are unbundled and fetched only when building Androidprojects.

However, these implicit dependencies may cause problems when runningBazel in an airgapped environment, even if you have vendored all of yourWORKSPACE dependencies. To solve that, you can prepare a distribution directorycontaining these dependencies on a machine with network access, and thentransfer them to the airgapped environment with an offline approach.

To prepare the distribution directory, use the--distdirflag. You will need to do this once for every new Bazel binary version, sincethe implicit dependencies can be different for every release.

To build these dependencies outside of your airgapped environment, firstcheckout the Bazel source tree at the right version:

git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"cd "$BAZEL_DIR"git checkout "$BAZEL_VERSION"

Then, build the tarball containing the implicit runtime dependencies for thatspecific Bazel version:

bazel build @additional_distfiles//:archives.tar

Export this tarball to a directory that can be copied into your airgappedenvironment. Note the --strip-components flag, because --distdir can bequite finicky with the directory nesting level:

(Video) Bazel Tutorial for C++ in 30 Minutes

tar xvf bazel-bin/external/additional_distfiles/archives.tar \ -C "$NEW_DIRECTORY" --strip-components=3

Finally, when you use Bazel in your airgapped environment, pass the --distdirflag pointing to the directory. For convenience, you can add it as an .bazelrcentry:

build --distdir=path/to/directory

Build configurations and cross-compilation

All the inputs that specify the behavior and result of a given build can bedivided into two distinct categories. The first kind is the intrinsicinformation stored in the BUILD files of your project: the build rule, thevalues of its attributes, and the complete set of its transitive dependencies.The second kind is the external or environmental data, supplied by the user orby the build tool: the choice of target architecture, compilation and linkingoptions, and other toolchain configuration options. We refer to a complete setof environmental data as a configuration.

In any given build, there may be more than one configuration. Consider across-compile, in which you build a //foo:bin executable for a 64-bitarchitecture, but your workstation is a 32-bit machine. Clearly, the build willrequire building //foo:bin using a toolchain capable of creating 64-bitexecutables, but the build system must also build various tools used during thebuild itself—for example tools that are built from source, then subsequentlyused in, say, a genrule—and these must be built to run on your workstation. Thuswe can identify two configurations: the exec configuration, which is usedfor building tools that run during the build, and the target configuration(or request configuration, but we say "target configuration" more often eventhough that word already has many meanings), which is used for building thebinary you ultimately requested.

Typically, there are many libraries that are prerequisites of both the requestedbuild target (//foo:bin) and one or more of the exec tools, for example somebase libraries. Such libraries must be built twice, once for the execconfiguration, and once for the target configuration. Bazel takes care ofensuring that both variants are built, and that the derived files are keptseparate to avoid interference; usually such targets can be built concurrently,since they are independent of each other. If you see progress messagesindicating that a given target is being built twice, this is most likely theexplanation.

The exec configuration is derived from the target configuration as follows:

  • Use the same version of Crosstool (--crosstool_top) as specified in therequest configuration, unless --host_crosstool_top is specified.
  • Use the value of --host_cpu for --cpu (default: k8).
  • Use the same values of these options as specified in the requestconfiguration: --compiler, --use_ijars, and if --host_crosstool_top isused, then the value of --host_cpu is used to look up adefault_toolchain in the Crosstool (ignoring --compiler) for the execconfiguration.
  • Use the value of --host_javabase for --javabase
  • Use the value of --host_java_toolchain for --java_toolchain
  • Use optimized builds for C++ code (-c opt).
  • Generate no debugging information (--copt=-g0).
  • Strip debug information from executables and shared libraries(--strip=always).
  • Place all derived files in a special location, distinct from that used byany possible request configuration.
  • Suppress stamping of binaries with build data (see --embed_* options).
  • All other values remain at their defaults.

There are many reasons why it might be preferable to select a distinct execconfiguration from the request configuration. Most importantly:

Firstly, by using stripped, optimized binaries, you reduce the time spentlinking and executing the tools, the disk space occupied by the tools, and thenetwork I/O time in distributed builds.

Secondly, by decoupling the exec and request configurations in all builds, youavoid very expensive rebuilds that would result from minor changes to therequest configuration (such as changing a linker options does), as describedearlier.

Correct incremental rebuilds

One of the primary goals of the Bazel project is to ensure correct incrementalrebuilds. Previous build tools, especially those based on Make, make severalunsound assumptions in their implementation of incremental builds.

Firstly, that timestamps of files increase monotonically. While this is thetypical case, it is very easy to fall afoul of this assumption; syncing to anearlier revision of a file causes that file's modification time to decrease;Make-based systems will not rebuild.

More generally, while Make detects changes to files, it does not detect changesto commands. If you alter the options passed to the compiler in a given buildstep, Make will not re-run the compiler, and it is necessary to manually discardthe invalid outputs of the previous build using make clean.

Also, Make is not robust against the unsuccessful termination of one of itssubprocesses after that subprocess has started writing to its output file. Whilethe current execution of Make will fail, the subsequent invocation of Make willblindly assume that the truncated output file is valid (because it is newer thanits inputs), and it will not be rebuilt. Similarly, if the Make process iskilled, a similar situation can occur.

Bazel avoids these assumptions, and others. Bazel maintains a database of allwork previously done, and will only omit a build step if it finds that the setof input files (and their timestamps) to that build step, and the compilationcommand for that build step, exactly match one in the database, and, that theset of output files (and their timestamps) for the database entry exactly matchthe timestamps of the files on disk. Any change to the input files or outputfiles, or to the command itself, will cause re-execution of the build step.

The benefit to users of correct incremental builds is: less time wasted due toconfusion. (Also, less time spent waiting for rebuilds caused by use of makeclean, whether necessary or pre-emptive.)

Build consistency and incremental builds

Formally, we define the state of a build as consistent when all the expectedoutput files exist, and their contents are correct, as specified by the steps orrules required to create them. When you edit a source file, the state of thebuild is said to be inconsistent, and remains inconsistent until you next runthe build tool to successful completion. We describe this situation as unstableinconsistency, because it is only temporary, and consistency is restored byrunning the build tool.

(Video) Bazel Tutorial - Ultimate Beginner Guide

There is another kind of inconsistency that is pernicious: stableinconsistency. If the build reaches a stable inconsistent state, then repeatedsuccessful invocation of the build tool does not restore consistency: the buildhas gotten "stuck", and the outputs remain incorrect. Stable inconsistent statesare the main reason why users of Make (and other build tools) type make clean.Discovering that the build tool has failed in this manner (and then recoveringfrom it) can be time consuming and very frustrating.

Conceptually, the simplest way to achieve a consistent build is to throw awayall the previous build outputs and start again: make every build a clean build.This approach is obviously too time-consuming to be practical (except perhapsfor release engineers), and therefore to be useful, the build tool must be ableto perform incremental builds without compromising consistency.

Correct incremental dependency analysis is hard, and as described above, manyother build tools do a poor job of avoiding stable inconsistent states duringincremental builds. In contrast, Bazel offers the following guarantee: after asuccessful invocation of the build tool during which you made no edits, thebuild will be in a consistent state. (If you edit your source files during abuild, Bazel makes no guarantee about the consistency of the result of thecurrent build. But it does guarantee that the results of the next build willrestore consistency.)

As with all guarantees, there comes some fine print: there are some known waysof getting into a stable inconsistent state with Bazel. We won't guarantee toinvestigate such problems arising from deliberate attempts to find bugs in theincremental dependency analysis, but we will investigate and do our best to fixall stable inconsistent states arising from normal or "reasonable" use of thebuild tool.

If you ever detect a stable inconsistent state with Bazel, please report a bug.

Sandboxed execution

Bazel uses sandboxes to guarantee that actions run hermetically andcorrectly. Bazel runs spawns (loosely speaking: actions) in sandboxes thatonly contain the minimal set of files the tool requires to do its job. Currentlysandboxing works on Linux 3.12 or newer with the CONFIG_USER_NS optionenabled, and also on macOS 10.11 or newer.

Bazel will print a warning if your system does not support sandboxing to alertyou to the fact that builds are not guaranteed to be hermetic and might affectthe host system in unknown ways. To disable this warning you can pass the--ignore_unsupported_sandboxing flag to Bazel.

On some platforms such as Google KubernetesEngine cluster nodes or Debian,user namespaces are deactivated by default due to securityconcerns. This can be checked by looking at the file/proc/sys/kernel/unprivileged_userns_clone: if it exists and contains a 0,then user namespaces can be activated withsudo sysctl kernel.unprivileged_userns_clone=1.

In some cases, the Bazel sandbox fails to execute rules because of the systemsetup. The symptom is generally a failure that output a message similar tonamespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory.In that case, try to deactivate the sandbox for genrules with--strategy=Genrule=standalone and for other rules with--spawn_strategy=standalone. Also please report a bug on ourissue tracker and mention which Linux distribution you're using so that we caninvestigate and provide a fix in a subsequent release.

Phases of a build

In Bazel, a build occurs in three distinct phases; as a user, understanding thedifference between them provides insight into the options which control a build(see below).

Loading phase

The first is loading during which all the necessary BUILD files for theinitial targets, and their transitive closure of dependencies, are loaded,parsed, evaluated and cached.

For the first build after a Bazel server is started, the loading phase typicallytakes many seconds as many BUILD files are loaded from the file system. Insubsequent builds, especially if no BUILD files have changed, loading occursvery quickly.

Errors reported during this phase include: package not found, target not found,lexical and grammatical errors in a BUILD file, and evaluation errors.

Analysis phase

The second phase, analysis, involves the semantic analysis and validation ofeach build rule, the construction of a build dependency graph, and thedetermination of exactly what work is to be done in each step of the build.

Like loading, analysis also takes several seconds when computed in its entirety.However, Bazel caches the dependency graph from one build to the next and onlyreanalyzes what it has to, which can make incremental builds extremely fast inthe case where the packages haven't changed since the previous build.

(Video) Building and Testing with Bazel - A Tutorial Session

Errors reported at this stage include: inappropriate dependencies, invalidinputs to a rule, and all rule-specific error messages.

The loading and analysis phases are fast because Bazel avoids unnecessary fileI/O at this stage, reading only BUILD files in order to determine the work to bedone. This is by design, and makes Bazel a good foundation for analysis tools,such as Bazel's query command, which is implemented atop the loadingphase.

Execution phase

The third and final phase of the build is execution. This phase ensures thatthe outputs of each step in the build are consistent with its inputs, re-runningcompilation/linking/etc. tools as necessary. This step is where the build spendsthe majority of its time, ranging from a few seconds to over an hour for a largebuild. Errors reported during this phase include: missing source files, errorsin a tool executed by some build action, or failure of a tool to produce theexpected set of outputs.

FAQs

Is Bazel a good build system? ›

It operates on the concepts of binaries, libraries, data sets, and scripts. Bazel is fast and builds correctly - It can cache build results and only rebuild what it needs to, which make it fast. Its platform independent - It can run on Linux, macOS, Windows. Bazel scales - It can handle large source files easily.

Why is Bazel so hard? ›

Essentially, Bazel is hard because it generates outputs in a parallel file system hierarchy, instead of putting outputs in the same folder as source code.

How do I build a project with Bazel? ›

Using Bazel
  1. Set up Bazel. Download and install Bazel.
  2. Set up a project workspace, which is a directory where Bazel looks for build inputs and BUILD files, and where it stores build outputs.
  3. Write a BUILD file, which tells Bazel what to build and how to build it. ...
  4. Run Bazel from the command line.

How can I make my Bazel faster? ›

Removing the overhead of Bazel may decrease the overall compilation time and speed up your build/test/revise cycles. For small, quick-to-run unit tests, this can decrease the time it takes to run the tests from 10s of seconds to under a second.

Is Maven better than Bazel? ›

Bazel supports multiple build files and multiple targets per BUILD file, allowing for builds that are more incremental than Maven's. Maven takes charge of steps for the deployment process. Bazel does not automate deployment. Bazel enables you to express dependencies between languages.

Why not to use Bazel? ›

Declarative Programming Languages are Hard To Debug

Bazel's configuration is “declarative-ish.” The BUILD files declare rules in a build graph. There are ways to break out into imperative code, but most configuration is declarative. We are still not good at building debuggers for declarative languages.

Is Bazel better than Gradle? ›

Bazel requires a lot of BUILD files. Gradle doesn't. Gradle also performs well without these fine-grained build files. Even so, Bazel gives you more control over the build with fine granularity.

Why is Bazel faster? ›

Bazel may give you faster build times because it can recompile only the files that need to be recompiled.

Why we should use Bazel for angular builds? ›

Some of the features of Bazel are as follows:
  • Support multiple languages.
  • Support multiple platforms.
  • Support multiple repository.
  • Support high-level build language.
  • Fast and reliable.

Does Google use Bazel? ›

How Google uses Bazel. Bazel builds almost all Google products: Google Search, GMail, Google Docs, …

Why is Bazel so slow? ›

In a similar vein as the above mentioned issues, Bazel can be unnecessarily slow when checking if an action with a large number of inputs is cached. This is because Bazel needs to build a Merkle tree from an action's inputs, which can be expensive if there are many.

Why is Bazel over Gradle? ›

To troubleshoot a Gradle build, you'll wrangle with Java and JVM ecosystem only. Bazel at the heart have ability to detect incremental changes(as well as distributed build cache) and allow you to react, apply plugins/rules to achieve incremental builds.

Why use Bazel for Java? ›

Bazel offers the flexibility to have as many BUILD files as we need, configured to any level of granularity. This would mean we can build a smaller number of Java classes by configuring BUILD rules accordingly. To keep things simple, we will keep minimal BUILD files in our example.

Do I need Bazel for TensorFlow? ›

To build TensorFlow, you will need to install Bazel. Bazelisk is an easy way to install Bazel and automatically downloads the correct Bazel version for TensorFlow.

Does Facebook use Bazel? ›

At Facebook, everything builds with Buck (and Google with Bazel I hear)...which means you learn it once and you know it for your Objective-C library, your Android app, your Cxx service, your python scripts, etc.

Videos

1. How to build with Bazel
(Daniel Persson)
2. Bazel Tutorial - External Dependency with simple build action
(Gisli Konradsson)
3. Introduction to Bazel to build C++ and Python – Xavier Bonaventura – code::dive 2020
(code::dive conference)
4. Multi-platform Python builds with Bazel
(Google Open Source)
5. Bazel Tutorial - How to package and deploy build output and artifacts
(Gisli Konradsson)
6. Building Real-time Systems with Bazel w/ SpaceX
(Google Open Source)
Top Articles
Latest Posts
Article information

Author: Carmelo Roob

Last Updated: 12/22/2022

Views: 5945

Rating: 4.4 / 5 (45 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Carmelo Roob

Birthday: 1995-01-09

Address: Apt. 915 481 Sipes Cliff, New Gonzalobury, CO 80176

Phone: +6773780339780

Job: Sales Executive

Hobby: Gaming, Jogging, Rugby, Video gaming, Handball, Ice skating, Web surfing

Introduction: My name is Carmelo Roob, I am a modern, handsome, delightful, comfortable, attractive, vast, good person who loves writing and wants to share my knowledge and understanding with you.