BEAR(1)
okay so this is the BEAR(1) page โ General Commands Manual, bestie edition โ and honestly? it's giving โจbuild-tooling fairy godmotherโจ. grab a snack, we're going through the whole thing ๐
๐ป NAME ๐ป
bear โ generate a compilation database for Clang tooling
๐ SYNOPSIS ๐
bear [OPTIONS] -- BUILD_COMMAND...
bear intercept [OPTIONS] --output FILE -- BUILD_COMMAND...
bear semantic [OPTIONS]
bear parse-sh [OPTIONS]
๐ DESCRIPTION ๐
So Bear produces a JSON compilation database, aka compile_commands.json. Clang-based tools like clangd and clang-tidy read that file to learn how each source file of a project is compiled: with which compiler, which flags, from which directory. Build systems literally know all of this and most of them just... do not export it ๐ญ so Bear recovers it from the build itself. main character energy, no cap.
Bear works in two stages, and the way it splits them is lowkey iconic:
- First it captures the commands a build executes, and writes them as a stream of execution events. The capture either observes a real build run, or parses the text of a dry run.
- Then semantic analysis recognizes the compiler invocations among those events, parses their command lines, and writes the compilation database.
๐ Modes ๐
- Combined mode (default) โ
bear -- <build command>runs the build, captures and analyzes in one step, and writes the database. This is the recommended way to use Bear: it observes the commands the build actually executes, so the result is exact. Use it whenever you can run the build. slay ๐ - Intercept mode โ
bear interceptruns the build but only captures, writing the raw event stream to a file. Genuinely useful when the build is expensive and you want to run it once and process the events several times, for example to try different output configurations. - Semantic mode โ
bear semanticruns no build: it is a filter that reads an event stream (frombear intercept, or any producer of the documented event format) and writes the compilation database. Combine it with intercept mode to re-generate the database without rebuilding. obsessed. - Parse-sh mode โ
bear parse-shproduces the compilation database from shell command text, without executing anything. Typical input is a build system's dry run (make -n) or a saved build log. It is a text parser and inherently lower fidelity than interception; reach for it when the build cannot be run, for example to recover a database from a CI log. See its limitations under COMMANDS.
๐ฎ Interception methods ๐ฎ
Interception itself has two methods, selectable in the configuration file.
- Preload โ the default on Linux and the BSDs. It injects a small library into every process the build starts and observes its
exec()calls. It's transparent to the build, but it cannot observe statically linked executables, and it is unavailable on Windows and on macOS while System Integrity Protection is enabled; forcing it there is a startup error that names wrapper mode, not a silent fallback ๐. - Wrapper โ the default on macOS and Windows. It substitutes the known compilers with a reporting wrapper executable. Works on every platform, but the build has to pick the wrapper up: a "configure" step that discovers compilers must itself run under Bear (see TROUBLESHOOTING).
โจ OPTIONS โจ
-c,--configFILE โ path of the configuration file. It controls the interception method, compiler recognition, source filtering, duplicate handling, and output formatting (see CONFIGURATION). Given before a subcommand it applies to that subcommand too.-o,--outputFILE โ path of the compilation database to write (default:compile_commands.json).-is not accepted here, because in combined mode standard output belongs to the build. To stream the database, usebear semantic --output -(see COMMANDS).-a,--appendโ append to an existing output file instead of overwriting it. New entries are placed before the existing ones, so a rebuilt file's newest invocation survives duplicate filtering and replaces the stale entry (see duplicates under CONFIGURATION).--overwriteโ replace the output file with only this run's entries. This is what Bear already does when neither flag is given; the flag exists so a script can name the behaviour it depends on rather than rely on the default. Giving it together with--appendis an error. A future release makes appending the default, and a script that passes--overwritetoday keeps its current behaviour across that change.-h,--helpโ print help.-V,--versionโ print version.
๐ ๏ธ COMMANDS ๐ ๏ธ
๐ฆ bear intercept ๐ฆ
Runs the build and captures execution events to a file, without analyzing them. (capture now, analyze later โ the "let me think about it" of build tooling)
bear intercept [OPTIONS] --output FILE -- BUILD_COMMAND...
-o,--outputFILE โ path of the event file to write. Required, and-is not accepted: the build owns standard output, and there is no default event-file name.
๐ง bear semantic ๐ง
Reads an event stream and writes the compilation database. It runs no build, so it behaves as a plain filter: diagnostics go to standard error, and both ends can be standard streams. pipes on pipes on pipes ๐ซถ
bear semantic [OPTIONS]
-i,--inputFILE โ path of the event file to read (default:-, standard input). Any producer of a conforming event stream can pipe into it. When standard input is a terminal, or the stream turns out to be empty, a warning is printed on standard error.-o,--outputFILE โ path of the compilation database to write (default:compile_commands.json). Pass-to write to standard output; that write is neither atomic nor appendable, so--output -together with--appendis rejected.-a,--appendโ same as in combined mode: place new entries before the existing ones in the output file.--overwriteโ same as in combined mode: name the current default explicitly. Not accepted together with--append.
๐ธ bear parse-sh ๐ธ
Produces the compilation database from shell command text, without running anything. Typical input is a build system's dry-run output, such as make -n, or a saved build log:
make -n | bear parse-sh
bear parse-sh [OPTIONS]
-i,--inputFILE โ path of the shell text to parse (default:-, standard input).-o,--outputFILE โ path of the compilation database to write (default:compile_commands.json). Pass-to write to standard output; that write is neither atomic nor appendable, so--output -together with--appendis rejected.-a,--appendโ same as in combined mode: place new entries before the existing ones in the output file.--overwriteโ same as in combined mode: name the current default explicitly. Not accepted together with--append.-C,--directoryDIR โ initial working directory for the parsed commands. Use it for input captured elsewhere (a CI log, a dry run from another checkout). Give an absolute path; the directory need not exist on this machine. yes, really โ it does not have to exist here ๐
The commands recognized in the text go through the same semantic analysis and output stage as an intercepted build, so the configuration applies exactly as in combined mode. Parsed commands that are not compiler invocations (ar, mv, mkdir) simply produce no entries. they're just vibing, contributing nothing ๐
It understands a documented subset of POSIX shell syntax, and the list is:
- word splitting and quoting;
- the
;,&&,||,&, and|separators; - comments;
- redirections;
cd;- brace groups (
{ ...; }, whosecdpersists past the closing brace); - and make's Entering directory / Leaving directory markers, which track the working directory across a recursive build.
Sub-makes print these markers by default; run make -nw to have the top-level make print them too, so the log itself names the build root ๐.
A line using anything outside that subset is skipped and reported on standard error with its line number and reason. This covers subshells, command substitution, parameter expansion, globs in the executable position, here-documents, unterminated quotes, and shell keywords such as if or for. The run succeeds as long as at least one line parsed as a command.
Interception remains the higher-fidelity default: it observes theexec()calls a build really makes, whilebear parse-shreconstructs approximate events from text the build system chose to print. A dry run can omit commands (recursive make does not always propagate-n, and commands behind not-yet-generated sources never print); the environment andPATHused to resolve bare executable names are the parse-time ones, not the real build's; and only POSIX sh text is supported. Preferbear -- <build command>whenever the build can actually be run. fr fr, don't skip straight to the parser unless you have to ๐ฅบ
The source files named in the parsed commands need not exist: entries are reconstructed from the text alone. The one exception is the canonical path format, which resolves symlinks on disk; when the sources are absent, configure absolute instead (see format.paths under CONFIGURATION).
โจ OUTPUT โจ
So like, Bear writes a JSON compilation database that conforms to the Clang JSON Compilation Database specification (peep SEE ALSO ๐): it's a JSON array of entry objects, and each object has these fields, bestie:
directoryโ the working directory of the compilation. Like, where the build was actually standing, yk?fileโ the main translation unit source file. The star of the show ๐argumentsโ the compilation command as an array of strings. This is the default, and Bear lowkey prefers it overcommandbecause it dodges all those shell-escaping issues. Iconic behavior, honestly.commandโ the compilation command as a single shell-escaped string (written instead ofargumentswhenformat.entries.use_array_formatisfalse).outputโ the file produced by the compilation (optional).
By default Bear does not transform paths: each entry records them exactly as they appeared in the intercepted invocation, so file and output are often relative to directory. If you want them normalized, use format.paths in the configuration. Simple as that ๐ซถ
Two compilers produce an entry shape that's worth knowing about, fr fr:
swiftc: a whole-module invocation naming several.swiftsources produces one entry per source, and each one carries the complete invocation's arguments (so like, every source of the module, not just its own). This matches the shape CMake emits and SourceKit-LSP consumes, because in whole-module compilation each file's semantics depend on every other source. The repeated argument data is expected, not a bug โ don't come for it ๐ญ. The internalswift-frontendjobs thatswiftcspawns are filtered out automatically.valac: one entry pervalacinvocation (valaccompiles all of a target's.vala/.gssources together as one unit); the entry'sfileis the first source and every source is kept in the command. Sincevalactranspiles to C and compiles the result, the database also contains entries for the generated C files (see TROUBLESHOOTING for the clangd consequences ๐).
๐ CONFIGURATION ๐
Bear reads a YAML configuration file, found by search (see FILES) or named with --config. No file? Built-in defaults apply, and honestly that's a vibe. But a file that is written at all must name schema; every section below it is optional. The example below shows every single section:
schema: "4.2"
intercept:
mode: wrapper # default: preload on Linux and the BSDs
compilers:
- path: /usr/bin/cc
as: gcc
- path: /usr/local/bin/gcc
ignore: true
sources:
directories:
- path: /project/tests
action: exclude
files:
- pattern: "moc_*.cpp"
action: exclude
- pattern: "*.pb.cc"
action: exclude
duplicates:
match_on: # default: directory, file
- file
- arguments
format:
paths:
directory: canonical # default: as-is
file: canonical # default: as-is
entries:
use_array_format: true
include_output_field: true
arguments:
from_response_files: false
from_environment: true
headers:
enabled: true # default: false
strategy: siblings
Every value above is illustrative, bestie โ the non-default ones are annotated inline so you can tell what's what. Each section below states its actual defaults, so no guessing game ๐
intercept
Controls the interception method (see DESCRIPTION for the trade-offs, because there are trade-offs bestie):
modeโpreload(default on Linux and the BSDs) orwrapper(default on macOS and Windows; works everywhere).
compilers
Hints for compiler recognition. Bear recognizes GCC- and Clang-compatible drivers (including cross-compiler prefixed names), the common vendor compiler drivers and standalone assemblers, swiftc and valac, compiler launchers, and MPI compiler wrappers. Run bear semantic --print-compilers for the full list of recognized compiler names, each with the as value it maps to. That's your cheat sheet, iykyk โจ
A few recognition behaviors are worth knowing. Compiler launchers (ccache, distcc, sccache, icecc) are dropped from the recorded command: ccache gcc -c main.c produces an entry for gcc -c main.c. MPI compiler wrappers are recorded as invoked, not expanded to the compiler they wrap; Clang tooling that needs the wrapper's baked-in include paths can point at it directly, for example with clangd's --query-driver. And C++20 module-interface units (.cppm, .ixx, and similar) are recognized as sources, while precompiled .pcm artifacts never appear as an entry's file. Not me knowing all this ๐
In wrapper mode this section also decides what gets wrapped. With no entry other than ignore ones, Bear scans PATH at startup and wraps every compiler it recognizes. As soon as one entry is not ignored, Bear wraps exactly the listed paths and skips the scan โ so listing one unusual compiler stops gcc and clang from being intercepted unless they are listed too ๐. Compilers named in the compiler environment variables (CC, CXX, and similar) are wrapped either way. Preload mode is unaffected: it intercepts every executed program regardless of this section.
Use this section when a compiler at a given path is not recognized, or is recognized wrongly:
pathโ Path of the compiler executable. Required, no cap.asโ Compiler type hint for semantic analysis. Optional; when omitted, Bear guesses the family from the executable's filename and falls back togccwhen nothing matches. The accepted values are theasnames shown bybear semantic --print-compilers, pluswrapperfor a compiler launcher. A launcher is recognized only by its own basename, such asccacheordistcc, sowrapperon a path with another basename does not make it recognized. Rules are rules ๐ignoreโ Exclude this executable's invocations from the database. Optional, defaultfalse.
The generic names cc, c++, and the HPE Cray PrgEnv wrapper CC are classified by probing the executable's --version output, since the same basename can be a different compiler depending on the platform or the loaded environment module. When the probe cannot classify the executable, override it:
compilers:
- path: /usr/bin/cc
as: clang
sources
Filters entries by source file location and filename. Gatekeeping, but make it fashion ๐ฆ
directoriesโ List of directory-based rules, each with apathand anaction(includeorexclude).filesโ List of filename-glob rules, each with apatternand anaction(includeorexclude).
Rules of each list are evaluated in order, the last matching rule wins, and an entry matched by no rule is included; an empty list includes everything. The two lists compose: an entry is emitted only when both accept it. A file pattern without a path separator matches the source file's basename; a pattern containing a separator matches the full source path as it appears in the entry, so use the same path format as configured in format.paths.file. An invalid pattern is rejected during configuration validation with an error naming the offending rule (called out by name, embarrassing for the rule ngl). Typical use for file patterns is dropping machine-generated sources (Qt moc output, protobuf stubs) so that linters and editors act only on hand-written code; see EXAMPLES ๐ธ
duplicates
Controls duplicate detection.
match_onโ List of entry fields to compare (file,arguments,directory,command,output). Two entries are duplicates when all of the configured fields match; the first occurrence is kept. The default isdirectoryandfile, so one entry is kept per source file per directory, regardless of arguments; when a build compiles the same file with different flags, addargumentsto keep an entry per configuration. Combined with--append(new entries first), the default means a rebuilt file's newest invocation replaces its stale entry. Out with the old, in with the new โจ
format
Controls output formatting. The glow-up section ๐
paths.directory,paths.fileโ How to format these fields' paths:as-is(default, no transformation),canonical(resolve symlinks; requires the path to exist),relative(to thedirectoryfield), orabsolute.entries.use_array_formatโ Use theargumentsarray (default) instead of thecommandstring. Set tofalsefor consumers that read only thecommandfield.entries.include_output_fieldโ Include theoutputfield in entries.arguments.from_response_filesโ Replace@fileresponse-file references with the file's tokenized contents (resolved relative to the compilation's working directory, expanded recursively, using the compiler's quoting convention). Disabled by default, in which case an@fileargument is recorded verbatim; a missing or unreadable file is left literal with a warning ๐ซถarguments.from_environmentโ Fold compiler environment variables that act as implicit flags into the arguments. GCC/Clang header-search paths (CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH) become include flags, and MSVC'sCL/_CL_become leading / trailing options. Enabled by default; set tofalseto record only the command-line flags. (Unrelated to theCC="gcc -std=c11"convention handled during interception; see TROUBLESHOOTING.)
headers
Editors and linters often need compile flags for header files, not only for the translation units that were compiled. When enabled, Bear synthesizes an entry for a header by cloning the arguments of a compiled C/C++/Objective-C translation unit, with the source path replaced by the header path and the output flag removed. Off by default, no cap.
enabledโ Turn header-entry synthesis on or off. Defaultfalse.strategyโ How headers are discovered and which translation unit donates the flags:siblings(default) โ headers receive an entry cloned from a compiled source in the same directory. Zero prerequisites, but the flags are approximate, and headers in directories without compiled sources (the splitinclude/+src/layout) get nothing ๐ญdependency-filesโ reads the make-style.ddependency files the build already emitted (for example via-MMD) and synthesizes an entry for each header prerequisite that resolves inside the compilation's working directory. Accurate, and reaches headers in other directories, but requires the build to have left dependency files on disk. No files, no magic โจ
The header extension set is fixed (the built-in C-family headers). Synthesized entries pass through duplicate detection like any other entry, so a header with a real compilation entry is not duplicated. We don't do repeats here ๐
๐ EXIT STATUS ๐
okay so let's talk about how Bear bails, because the exit code is literally the whole vibe check of a run โจ
- In combined and intercept mode, Bear exits with the build command's exit code:
0when the build succeeds, and the same non-zero code when it fails. no cap, it just passes the receipt straight through ๐งพ - When the build is killed by a signal, Bear exits non-zero. ๐
- When the build handles the signal and exits on its own, Bear exits with the build's code,
0included. yes bestie, even a zero, we don't argue with the build's choices ๐ซถ - In semantic mode, Bear exits
0on success and non-zero when the analysis fails. ๐ธ - In parse-sh mode, Bear exits
0when the input could be parsed โ even when the database comes out empty because the text named no compiler invocations โ and also on empty input (with a warning on standard error). it's giving generous queen energy ๐ - It exits non-zero when every non-empty input line was skipped, so a run that understood nothing cannot pass for a successful one. periodt, no fake wins around here ๐
- If Bear itself encounters an internal error, it exits non-zero regardless of the build command's status. internal drama = non-zero, always ๐
๐ธ ENVIRONMENT ๐ธ
RUST_LOG
Selects the diagnostic format and verbosity on standard error. very demure, very configurable โจ
When unset, Bear uses the UNIX style, like bear: message (and wrapper: or preload: from its helper processes), showing warnings and errors only. clean, quiet, minimal ๐
When set to a level (error, warn, info, or debug, in increasing verbosity), Bear switches to a developer format that tags every line with a timestamp, the level, the emitting process and its pid, and the source location. it's giving forensic main character energy ๐
Debug output is essential for troubleshooting; see TROUBLESHOOTING. fr fr, don't skip this one ๐ซถ
๐ฆ FILES ๐ฆ
The configuration file bear.yml is searched in the following locations, in order; the first file found is loaded. first come, first served, no auditions ๐
./bear.ymlโ the current working directory. ๐$XDG_CONFIG_HOME/bear.yml,$XDG_CONFIG_HOME/Bear/bear.yml(Unix) โ when$XDG_CONFIG_HOMEis set. ๐$HOME/.config/bear.yml,$HOME/.config/Bear/bear.yml(Unix) โ when$XDG_CONFIG_HOMEis unset. โญ%LOCALAPPDATA%\bear.yml,%LOCALAPPDATA%\Bear\bear.yml(Windows) โ when%LOCALAPPDATA%is set. ๐ช%APPDATA%\bear.yml,%APPDATA%\Bear\bear.yml(Windows) โ when%APPDATA%is set. ๐ช
โจ EXAMPLES โจ
okay this is the fun part, the actual receipts ๐ธ
Generate a database for a Make project:
bear -- make
For a CMake project in preload mode, only the build needs Bear:
cmake -B build
bear -- cmake --build build
In wrapper mode the configure step must also run under Bear, so it discovers the wrapper as the compiler; discard that run's output:
bear -- cmake -B build
bear -- cmake --build build
Capture once, analyze many times. This allows trying output configurations without rebuilding. obsessed ๐ญ
bear intercept --output events.json -- make
bear semantic --input events.json
bear --config strict.yml semantic --input events.json --output strict.json
Recover a database from a dry run, without building:
make -n | bear parse-sh
For a recursive Make build, add -w. The top-level make then prints Entering directory markers too, and parse-sh resolves every command against the right directory. iykyk ๐ง
make -nw | bear parse-sh
Update the database after rebuilding one part of the project:
bear --append -- make -C src/module
Drop generated sources (Qt moc output, protobuf stubs) with a bear.yml:
sources:
files:
- pattern: "moc_*.cpp"
action: exclude
- pattern: "*.pb.cc"
action: exclude
- pattern: "*.pb.h"
action: exclude
Synthesize entries for headers in a split include/ + src/ layout, when the build emits .d dependency files:
headers:
enabled: true
strategy: dependency-files
๐ฉน TROUBLESHOOTING ๐ฉน
we love a debugging era ๐ this is where you go when the database is giving nothing.
๐ Debug logging
Before reporting any issue, run Bear with debug logging enabled and include the output in the report. no gatekeeping, just bring the logs bestie ๐
RUST_LOG=debug bear -- <build command>
๐ซ Empty output
The most common cause is that the build executed no compiler: an incremental build with everything up to date runs nothing. Bear intercepts executed commands only; it does not read the build files. soโฆ run a clean build ๐ธ
In wrapper mode, a "configure" step that detects compilers captures the real compiler path before Bear can substitute the wrapper. Run the configure step under Bear too (discarding that output), then run the build under Bear. sneaky little configure step, we see you ๐
๐ท๏ธ Compiler variables with flags
In wrapper mode Bear accepts the GNU Make convention of a compiler variable carrying a trailing flag or two (CC="gcc -std=c11" make): it splits the value on whitespace, resolves the first token as the compiler, and rewrites the variable so the build still sees the flags. iconic behaviour honestly ๐
This is a Unix / GNU Make convention; native Windows build systems (MSBuild, nmake) do not consume CC/CXX from the environment. ๐ช
For anything beyond simple whitespace-separated tokens (quoting, metacharacters, substitutions), use CFLAGS / CXXFLAGS / LDFLAGS instead; Bear passes those through untouched. untouched = zero drama ๐ซถ
๐งต Preload errors in cross-compilation
An error like version 'GLIBC_2.33' not found (required by .../libexec.so) means Bear's preload library was built against a newer glibc than the one the SDK's compilers load: the library must be ABI-compatible with the libc of the intercepted process, not only with the host's. ๐ญ
Use a Bear build linked against a glibc no newer than the SDK's. ngl this one bites everyone at least once.
The project wiki's Troubleshooting page lists diagnostic commands. ๐
๐ง Language servers on Vala projects
vala-language-server reads the command field and ignores the arguments array; build the database with format.entries.use_array_format: false. ๐
In a mixed C/Vala project, clangd also indexes the valac entries and emits unknown-argument noise on them; suppress it with a .clangd file:
If:
PathMatch: .*\.vala
Diagnostics:
Suppress: '*'
๐ Getting help
Consult the documentation site for known problems and search existing issues before opening a new report. Follow the bug report template, and always include the RUST_LOG=debug output. everyone says this and everyone means it ๐ซถ
๐ SEE ALSO ๐
clangd(1)clang-tidy(1)make(1)
Documentation site, with task pages for build systems, platforms, and toolchains: https://rizsotto.github.io/Bear/ ๐
The Clang JSON Compilation Database specification: https://clang.llvm.org/docs/JSONCompilationDatabase.html ๐
Project homepage and issue tracker: https://github.com/rizsotto/Bear ๐ก
๐ COPYRIGHT ๐
Copyright (C) 2012-2026 by Lรกszlรณ Nagy https://github.com/rizsotto/Bear
๐ AUTHORS ๐
Lรกszlรณ Nagy.
and that's the whole manual bestie, you made it to the end ๐ this page is from the Bear User Manuals, dated November 2, 2026, for BEAR(1). go build something and let Bear take the notes ๐ฆโจ
๐ฆ where this page comes from
- arch rolling: bear 4.2.4-1 ยท GPL-3.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms