Skip to content

Conversation

@jagerman
Copy link
Contributor

@jagerman jagerman commented Feb 3, 2026

I have recently been working on a project that is looking to use SQLite Multiple Ciphers rather than sqlite (or sqlcipher), and stumbled into some CMake inflexibility in SQLiteCpp that makes this difficult to achieve:

  1. SQLiteCpp's cmake only supports "build internal sqlite" or "use find_package". This has been a bit of a nuissance for me before, requiring this workaround before add_directory(SQLiteCpp):

    ... custom code to set up a build of sqlite and make an SQLite3::SQLite target ...
    
    # Hack around SQLiteCpp's attempts to locate sqlite3 because we *don't* want to link against the
    # system one, but don't download and build the embedded one until build time.  Thankfully it
    # actually links against the SQLite::SQLite3 cmake target if it already exists, so all we have to do
    # is set that up and circumvent some of the non-target bits of its FindSQLite3.cmake.
    set(SQLite3_FOUND TRUE CACHE BOOL "" FORCE)
    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/ignored")
    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/ignored/sqlite3.h" "#define SQLITE_VERSION \"${SQLite3_VERSION}\"")
    set(SQLite3_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/ignored" CACHE STRING "" FORCE)
    set(SQLite3_LIBRARY "ignored" CACHE STRING "" FORCE)
    set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "don't build SQLiteCpp's internal sqlite3" FORCE)

    Basically: setting a bunch of cache variables to make the find_package(SQLite) inside SQLiteCpp short-circuit itself and return immediately, so that the target_link_libraries(SQLiteCpp PUBLIC SQLite3::SQLite) links to what I already set up.

    This was a bit gross, but it worked, with plain SQLite3.

  2. The SQLITE_HAS_CODEC option forces a pkg-config search for sqlcipher. I am not using sqlcipher, and so this is obviously not what I want. I could go make a fake package config file to short circuit that search, but that feels like yet another layer of hacks.

    An alternative hack to make this work was to set cmake's SQLITE_HAS_CODEC=OFF but then, after the add_directory, modifying the SQLiteCpp target to add -DSQLITE_HAS_CODEC to bypass the sqlcipher search but still actually enable the key API. I.e. adding these to the above hacks:

    set(SQLITE_HAS_CODEC OFF CACHE BOOL "" FORCE)
    add_subdirectory(SQLiteCpp)
    target_compile_definitions(SQLiteCpp PRIVATE SQLITE_HAS_CODEC)

    This works, but again feels quite dirty.

This PR

Hence this PR: this adds an "escape hatch" to the cmake code so that I can tell SQLiteCpp to let me worry about SQLite3 via a SQLite3::SQLite pre-existing target, and then lets the SQLITE_USE_CIPHER cmake option be usable for this case.

With this:

  • Existing builds shouldn't be affected as all the defaults remain the same, including support for finding sqlcipher when using the (default) non-internal-find-sqlite path.
  • More complex builds (such as my case) can drop a bunch of hacks to circumvent cmake implementation and internal compile definitions, and instead just becomes:
    ... go build sqlite-multiple-ciphers ..
    ... add a SQLite3::SQLite target that sets up sqlite-mc linkage and includes ...
    
    set(SQLITE_HAS_CODEC ON CACHE BOOL "" FORCE)
    set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "" FORCE)
    set(SQLITECPP_FIND_SQLITE OFF CACHE BOOL "" FORCE)
    add_subdirectory(SQLiteCpp)

The PR also makes some closely related changes to this part of the cmake code:

  • fatal error when SQLITE_HAS_CODEC and SQLITECPP_INTERNAL_SQLITE are both enabled (because the internal build will certainly fail as it doesn't provide the key API).
  • update comments to remove unused sqlite3_key_v2 function and add sqlite3_rekey function
  • improve option descriptions around these options to reflect what happens
  • update cmake options descriptions
  • make the SQLITE_HAS_CODEC definition PRIVATE instead of PUBLIC. This only affects the internal Database.cpp code and does not need to be carried by things linking to SQLiteCpp.

Currently the SQLite3 code is quite limited, and really only has two
options:
- build bundled sqlite3 version
- use find_package() to find it

This commit adds an option to enable a third case: letting an external
cmake project worry about finding or building and providing sqlite by
setting `SQLITECPP_FIND_SQLITE` to `OFF`.  This requires that the parent
project has already set up some SQLite3::SQLite cmake target that
SQLiteCpp can then simply use without trying to find anything.

This is particularly useful when building a custom sqlite3 (such as
SQLite3 Multiple Ciphers) which will not be found via `find_package`.
Currently you can *somewhat* hack around this by setting a bunch of
cache variables to make the find_package short-circuit, but that feels
inelegant.
The `SQLITE_HAS_CODEC` option currently does two separate things: it
enables usage of the key API, and it forces searching for sqlcipher
headers when finding SQLite.

When attempting to use an alternative to sqlcipher (such as sqlite-ee or
sqlite-multiple-ciphers) the former is wanted, and the latter is
absolutely not wanted.

The previous commit allows working around the sqlcipher search by simply
bypassing the find process entirely and allowing a parent project to set
up SQLite3::SQLite however it wants.  That, combined with
SQLITE_HAS_CODEC=ON, allows using SQLiteCpp with encryption API with
some alternative to sqlcipher.

This commit adds some small "niceness" updates:

- make the SQLITE_HAS_CODEC compile definition PRIVATE as it only
  affects internal code in Database.cpp and does not require propagation
  to linking code.  (Building sqlcipher itself requires this definition,
  but SQLiteCpp does not support building sqlcipher, it only finds an
  already-built one).
- sqlite3_key_v2 is not actually required or used (and appears to be
  sqlcipher-specific), but sqlite3_rekey is.  (`sqlite3_key` and
  `sqlite3_rekey` are supported by all of sqlcipher, sqlite-mc, and
  sqlite-ee).
- SQLITE_HAS_CODEC combined with SQLITECPP_INTERNAL_SQLITE will not
  compile as the internal version is stock sqlite3, and this adds a
  check and fatal error if attempting that configuration.
@jagerman jagerman changed the title Generalized sqlite & key api to allow easier use of SQLite Multiple Ciphers Generalized cmake sqlite & key api to allow easier use of SQLite Multiple Ciphers Feb 3, 2026
@jagerman
Copy link
Contributor Author

jagerman commented Feb 3, 2026

(I did see PR #392, but the approach here seems considerably simpler by just letting the caller worry about it.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant