Skip to content

Commit d66a92a

Browse files
authored
Generalized cmake sqlite & key api to allow easier use of SQLite Multiple Ciphers (#532)
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)`: ```cmake ... 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: ```cmake 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~~SQLite::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: ```cmake ... 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.
2 parents 6798c78 + 0fb37d6 commit d66a92a

2 files changed

Lines changed: 22 additions & 8 deletions

File tree

CMakeLists.txt

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,12 @@ if (SQLITE_ENABLE_ASSERT_HANDLER)
228228
target_compile_definitions(SQLiteCpp PUBLIC SQLITECPP_ENABLE_ASSERT_HANDLER)
229229
endif (SQLITE_ENABLE_ASSERT_HANDLER)
230230

231-
option(SQLITE_HAS_CODEC "Enable database encryption API. Not available in the public release of SQLite." OFF)
231+
option(SQLITE_HAS_CODEC "Enables usage of the Database key() and rekey() methods. Requires a custom SQLite providing the key API such as sqlcipher/sql-ee/sqlite-multi-ciphers" OFF)
232232
if (SQLITE_HAS_CODEC)
233-
# Enable database encryption API. Requires implementations of sqlite3_key & sqlite3_key_v2.
234-
# Eg. SQLCipher (libsqlcipher-dev) is an SQLite extension that provides 256 bit AES encryption of database files.
235-
target_compile_definitions(SQLiteCpp PUBLIC SQLITE_HAS_CODEC)
233+
# Enable database encryption API. Requires implementations of sqlite3_key & sqlite3_rekey.
234+
# SQLCipher, SQLite Multiple Ciphers, and the commercial SQLite Encryption Extensions provide
235+
# these API functions for encrypting a database.
236+
target_compile_definitions(SQLiteCpp PRIVATE SQLITE_HAS_CODEC)
236237
endif (SQLITE_HAS_CODEC)
237238

238239
option(SQLITE_USE_LEGACY_STRUCT "Fallback to forward declaration of legacy struct sqlite3_value (pre SQLite 3.19)" OFF)
@@ -279,14 +280,19 @@ endif ()
279280
## Build provided copy of SQLite3 C library ##
280281

281282
option(SQLITECPP_INTERNAL_SQLITE "Add the internal SQLite3 source to the project." ON)
283+
option(SQLITECPP_FIND_SQLITE "Attempt to find SQLite (or sqlcipher, with SQLITE_HAS_CODEC) automatically. Requires SQLITECPP_INTERNAL_SQLITE=OFF. If disabled then a SQLite::SQLite3 cmake target must already exist." ON)
282284
if (SQLITECPP_INTERNAL_SQLITE)
285+
if (SQLITE_HAS_CODEC)
286+
message(FATAL_ERROR "Internal sqlite3 source does not support SQLITE_HAS_CODEC")
287+
endif()
288+
283289
message(STATUS "Compile sqlite3 from source in subdirectory")
284290
option(SQLITE_ENABLE_RTREE "Enable RTree extension when building internal sqlite3 library." OFF)
285291
option(SQLITE_ENABLE_DBSTAT_VTAB "Enable DBSTAT read-only eponymous virtual table extension when building internal sqlite3 library." OFF)
286292
# build the SQLite3 C library (for ease of use/compatibility) versus Linux sqlite3-dev package
287293
add_subdirectory(sqlite3)
288294
target_link_libraries(SQLiteCpp PUBLIC SQLite::SQLite3)
289-
else (SQLITECPP_INTERNAL_SQLITE)
295+
elseif (SQLITECPP_FIND_SQLITE)
290296
# When using the SQLite codec, we need to link against the sqlcipher lib & include <sqlcipher/sqlite3.h>
291297
# So this gets the lib & header, and links/includes everything
292298
if(SQLITE_HAS_CODEC)
@@ -332,7 +338,14 @@ else (SQLITECPP_INTERNAL_SQLITE)
332338
set_target_properties(SQLiteCpp PROPERTIES COMPILE_FLAGS "-DSQLITECPP_HAS_MEM_STRUCT")
333339
endif()
334340
endif()
335-
endif (SQLITECPP_INTERNAL_SQLITE)
341+
else ()
342+
if (NOT TARGET SQLite::SQLite3)
343+
message(FATAL_ERROR "SQLITECPP_FIND_SQLITE=OFF requires a pre-existing SQLite::SQLite3 cmake target")
344+
endif()
345+
346+
message(STATUS "Using pre-existing SQLite::SQLite3 cmake target")
347+
target_link_libraries(SQLiteCpp PUBLIC SQLite::SQLite3)
348+
endif ()
336349

337350
## disable the optional support for std::filesystem (C++17)
338351
option(SQLITECPP_DISABLE_STD_FILESYSTEM "Disable the use of std::filesystem in SQLiteCpp." OFF)

meson_options.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
option('SQLITE_ENABLE_COLUMN_METADATA', type: 'boolean', value: false, description: 'Enable Column::getColumnOriginName(). Require support from sqlite3 library.')
55
## Enable the user definition of a assertion_failed() handler (default to false, easier to handler for beginners).
66
option('SQLITE_ENABLE_ASSERT_HANDLER', type: 'boolean', value: false, description: 'Enable the user definition of a assertion_failed() handler.')
7-
## Enable database encryption API. Requires implementations of sqlite3_key & sqlite3_key_v2.
8-
## Eg. SQLCipher (libsqlcipher-dev) is an SQLite extension that provides 256 bit AES encryption of database files.
7+
## Enable database encryption API. Requires implementations of sqlite3_key & sqlite3_rekey.
8+
## SQLCipher, SQLite Multiple Ciphers, and the commercial SQLite Encryption Extensions provide
9+
## these API functions for encrypting a database.
910
option('SQLITE_HAS_CODEC', type: 'boolean', value: false, description: 'Enable database encryption API. Not available in the public release of SQLite.')
1011
## Force forward declaration of legacy struct sqlite3_value (pre SQLite 3.19)
1112
option('SQLITE_USE_LEGACY_STRUCT', type: 'boolean', value: false, description: 'Fallback to forward declaration of legacy struct sqlite3_value (pre SQLite 3.19)')

0 commit comments

Comments
 (0)