Skip to content

Generalized cmake sqlite & key api to allow easier use of SQLite Multiple Ciphers#532

Merged
SRombauts merged 2 commits into
SRombauts:masterfrom
jagerman:generalized-key-api
May 25, 2026
Merged

Generalized cmake sqlite & key api to allow easier use of SQLite Multiple Ciphers#532
SRombauts merged 2 commits into
SRombauts:masterfrom
jagerman:generalized-key-api

Conversation

@jagerman

@jagerman jagerman commented Feb 3, 2026

Copy link
Copy Markdown
Contributor

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::SQLiteSQLite::SQLite3 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.

@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

jagerman commented Feb 3, 2026

Copy link
Copy Markdown
Contributor Author

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

@dbaudio-bernhardfiedler

Copy link
Copy Markdown

Thank you for this PR @jagerman! I just wanted to work on my own PR fixing the behavior or linking SQLite if using an external build with encryption but not using sqlcipher - but now I found yours and fully support it!
BTW: if you are not using that terribly old CMake Version 3.5 (which is almost 10 years old!) but at least 3.13 you can use set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) to get rid of overriding options using CACHE BOOL "" FORCE but simply set them like variables.

@SRombauts It would be very nice to have this PR merged quickly. It does not break anything but provides more flexibility.

@dbaudio-bernhardfiedler

Copy link
Copy Markdown

@jagerman : I just found an issue in your PR: The target of the "bundled" sqlite3 is named SQLite::SQLite3 which is also used for linking on line 347. But in your fix on line 342 (https://github.com/jagerman/SQLiteCpp/blob/generalized-key-api/CMakeLists.txt#L342) you check for the target via if (NOT TARGET SQLite3::SQLite) which has the "3" at the wrong place. The Error message is then correct while the status message on line 364 is wrong again. See these comments:

if (NOT TARGET SQLite3::SQLite) # <--- should be SQLite::SQLite3
    message(FATAL_ERROR "SQLITECPP_FIND_SQLITE=OFF requires a pre-existing SQLite::SQLite3 cmake target")
endif()

message(STATUS "Using pre-existing SQLite3::SQLite cmake target") # <--- should be SQLite::SQLite3
target_link_libraries(SQLiteCpp PUBLIC SQLite::SQLite3)

Please fix this.

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 force-pushed the generalized-key-api branch from d74ec06 to 0fb37d6 Compare February 18, 2026 20:52
@jagerman

Copy link
Copy Markdown
Contributor Author

Thanks @dbaudio-bernhardfiedler, I've pushed a fix (there were also a couple occurrences of the wrong target in some of the message strings, also fixed).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves SQLiteCpp’s build-system flexibility to support custom SQLite builds (e.g., SQLite Multiple Ciphers) by allowing consumers to bypass SQLite discovery and link against a pre-defined SQLite::SQLite3 CMake target, while also refining the codec/key API configuration behavior.

Changes:

  • Add SQLITECPP_FIND_SQLITE CMake option to disable automatic SQLite/sqlcipher discovery and rely on a pre-existing SQLite::SQLite3 target.
  • Harden/clarify codec configuration: fatal error when SQLITE_HAS_CODEC is enabled with the internal sqlite3 build; update codec comments; make SQLITE_HAS_CODEC a PRIVATE compile definition.
  • Update Meson option documentation to reflect sqlite3_key/sqlite3_rekey usage and broaden wording beyond SQLCipher.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
CMakeLists.txt Adds SQLITECPP_FIND_SQLITE “escape hatch”, adjusts codec behavior/diagnostics, and changes SQLITE_HAS_CODEC compile-definition visibility.
meson_options.txt Updates codec/key API comments to reference sqlite3_key/sqlite3_rekey and mention other cipher-enabled SQLite variants.

Comment thread CMakeLists.txt
# Enable database encryption API. Requires implementations of sqlite3_key & sqlite3_rekey.
# SQLCipher, SQLite Multiple Ciphers, and the commercial SQLite Encryption Extensions provide
# these API functions for encrypting a database.
target_compile_definitions(SQLiteCpp PRIVATE SQLITE_HAS_CODEC)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please explicitly add SQLITE_HAS_CODEC to the SQLiteCpp_tests target when the option is enabled.
edit: it's not a big deal with the current setup, as we aren't testing with CODEC ON

@SRombauts SRombauts merged commit d66a92a into SRombauts:master May 25, 2026
17 checks passed
@SRombauts

Copy link
Copy Markdown
Owner

Thanks for providing this PR!
I am sorry for not even answering, I have been drawn under notifications that I cannot all read :(

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants