Make sure to have cloned the SDK repository and have the submodules appropriately synced (git submodule update --init --recursive).
The C++ core utilizes the CMake Package Manager (CPM) to include depencies. These can be set to a cache directory and can be used for future builds. Periodically the dependencies should be updated. So, in general it is good practice to configure the build environment by setting the CPM cache.
npm run prebuild -- --configure --set-cpm-cache --use-boringsslNote: Section under construction
Set the cache directory CXXCBC_CACHE_DIR:
export CXXCBC_CACHE_DIR=$PWD/deps/couchbase-cxx-cacheRemove the cache directory
rm -rf $CXXCBC_CACHE_DIRConfigure the build:
$ npx cmake-js configure \
--runtime node \
--runtime-version $(node --version) \
--CDUSE_STATIC_OPENSSL=OFF \
--CDCPM_DOWNLOAD_ALL=OFF \
--CDCPM_USE_NAMED_CACHE_DIRECTORIES=ON \
--CDCPM_USE_LOCAL_PACKAGES=OFF \
--CDCPM_SOURCE_CACHE=$CXXCBC_CACHE_DIRnpm run prebuild -- --use-boringsslNote: Section under construction
NOTE: If using the
compilecommand, the build will automatically clean and re-execute a build upon a failure. Use thebuildcommand to only attempt a single build.
Set the cache directory (if it has not already been set) CXXCBC_CACHE_DIR:
export CXXCBC_CACHE_DIR=$PWD/deps/couchbase-cxx-cachenpx cmake-js compile \
--runtime node \
--runtime-version $(node --version) \
--CDUSE_STATIC_OPENSSL=OFF \
--CDCPM_DOWNLOAD_ALL=OFF \
--CDCPM_USE_NAMED_CACHE_DIRECTORIES=ON \
--CDCPM_USE_LOCAL_PACKAGES=OFF \
--CDCPM_SOURCE_CACHE=$CXXCBC_CACHE_DIRIMPORTANT: Autogen is only needed for maintainers of the library. If not making updates to the core bindings, running the autogen tooling should NOT be required.
The generator parses the C++ core headers with libclang and writes the generated code into
the //#region blocks of lib/binding.ts, src/connection.cpp, src/connection.hpp,
src/connection_autogen.cpp, src/constants.cpp and src/jstocbpp_autogen.hpp.
What gets parsed and what gets emitted is configured in
tools/autogen/config/bindings.yaml — adding a binding
should mean editing that file, not the generator.
If you have never run the tool before, start with
tools/autogen/QUICK_START.md.
tools/autogen/README.md is the full reference.
NOTE: All autogen commands are run from the repository root.
The CPM cache must be populated first (see Set CPM Cache), and the C++ core submodule must be checked out:
git submodule update --init --recursive deps/couchbase-cxx-clientNOTE: Python >= 3.9 required
Setup virtual env:
python3 -m venv <path to virtualenv>Example: python3 -m venv $(pwd)/couchnode
Activate virtual env:
source <path to virtualenv>/bin/activateExample: source $(pwd)/couchnode/bin/activate
Install the tool requirements:
python3 -m pip install -r tools/autogen/tools_requirements.txtOn macOS the tool locates LLVM automatically. If your environment is non-standard, override it with flags or environment variables:
python3 -m tools.autogen bindings generate \
--llvm-version $(llvm-config --version) \
--llvm-includedir $(llvm-config --includedir) \
--llvm-libdir $(llvm-config --libdir) \
--system-headers $(xcrun --show-sdk-path)Available environment variables:
CN_LLVM_VERSION: LLVM versionCN_LLVM_INCLUDE: LLVM include directory pathCN_LLVM_LIB: LLVM lib directory pathCN_SYS_HEADERS: System headers path
NOTE: The pip
clangpackage binds to the systemlibclang. If the pip package is newer than your system LLVM you may hit loading or parsing errors; the tool warns when it detects this. Eitherbrew upgrade llvmor install a matching pip package.
python3 -m tools.autogen bindings generateOr, equivalently, npm run gen:bindings. The npm scripts shell straight out to python3, so
the virtualenv still has to be active.
This parses the C++ core, renders the generated regions, then finishes with the post-processing
tail: format the generated files, and restore the ones that did not really change.
clang-format and prettier must be available (see
Post-processing below).
To find out whether a regeneration would change anything without modifying the working tree:
python3 -m tools.autogen bindings generate --dry-runThis does the real thing — generate and format — then puts every file back, so it reaches the same answer as a real run rather than an approximation of one.
For CI, --check (or npm run gen:bindings:check) is the same measurement with an exit code:
non-zero when the committed bindings are out of date.
Add --verbose for detailed parser and clang output. Use --parse-only to write just the
parsed type model (tools/bindings.json) without rendering. --no-format and
--no-restore-unchanged opt out of the two post-processing steps individually; without
formatting the output will not match what is committed.
For a full list of options:
python3 -m tools.autogen bindings generate --helpThe parsed model is checked before anything is rendered. Generation aborts, listing every
problem, if a struct parsed with no fields, a struct lost a field named under
validation.required_fields in the config, or an enum parsed with no values:
couchbase::core::operations::query_request: parsed with no fields
Error: 1 validation error(s); nothing was generated.That almost always means the C++ core changed the shape of a declaration and the parser
mis-read it — see Debugging a struct. A struct that really is empty
belongs in validation.allow_empty_fields.
When a generated binding looks wrong or empty, dump exactly what the libclang pass sees. This renders nothing and writes no files:
# a single struct — fully-qualified name, leaf name, or substring
python3 -m tools.autogen bindings inspect --type couchbase::core::operations::query_request
python3 -m tools.autogen bindings inspect --type query_request
# several at once, as JSON
python3 -m tools.autogen bindings inspect --type query_request --type analytics_request --as-json
# everything declared in one header
python3 -m tools.autogen bindings inspect --header core/operations/document_get.hxxA struct reported as (no fields) that should have fields means the parser mis-read the header
— most often because the C++ core changed the shape of the declaration.
bindings generate finishes with two extra steps:
- Format — runs the formatter configured for each file suffix under
format.formatters; today that isclang-formatfor the C++ files andprettierforlib/binding.ts. - Restore unchanged — restores any generated file whose only delta against
HEADis run metadata, so a regeneration that changes nothing leaves a cleangit status.
On MacOS, make sure LLVM clang-format is used (configure the PATH appropriately):
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"Opt out with --no-format and --no-restore-unchanged. If generation and formatting were
done by hand, run the same tail on its own:
python3 -m tools.autogen bindings tidyOr npm run gen:bindings:tidy.
tidy parses nothing and needs no LLVM. Any file that ends up byte-identical keeps its
original mtime, so a no-op regeneration does not trigger a rebuild.
tools/bindings.json is an intermediate artifact and is gitignored. It can be removed once
generation is complete:
rm tools/bindings.jsonThis should rarely be needed (e.g. updating the autogen logic).
python3 -m pip install autopep8 flake8
autopep8 -i -a -a --max-line-length 120 -r tools/autogen
flake8 --max-line-length 120 tools/autogenIf a virtualenv was setup (hopefully it was ;)), deactivate and remove the environment
deactivate
rm -rf <path to virtualenv>Example: deactivate && rm -rf $(pwd)/couchnode