Link dynamically against sqlite3 but still use a copy of QSqlLiteDriver

This commit is contained in:
John Maguire 2013-11-22 16:05:55 +00:00
parent 331d471b51
commit 4c23072bef
9 changed files with 37 additions and 116579 deletions

View File

@ -21,11 +21,19 @@ qt4_wrap_cpp(SQLITE-SOURCES-MOC ${SQLITE-MOC-HEADERS})
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
add_definitions(-DQT_PLUGIN -DQT_NO_DEBUG)
add_definitions(-DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS)
add_library(sqlite STATIC sqlite3.c)
set_target_properties(sqlite PROPERTIES COMPILE_FLAGS
"-Wno-pointer-to-int-cast -Wno-int-to-pointer-cast")
find_path(SQLITE_INCLUDE_DIRS sqlite3.h)
find_library(SQLITE_LIBRARIES sqlite3)
if (SQLITE_INCLUDE_DIRS AND SQLITE_LIBRARIES)
set(SQLITE_FOUND true)
endif()
if (NOT SQLITE_FOUND)
message(SEND_ERROR "Could not find sqlite3")
endif()
include_directories(${SQLITE_INCLUDE_DIRS})
add_library(qsqlite STATIC
${SQLITE-SOURCES}
@ -33,6 +41,6 @@ add_library(qsqlite STATIC
${SQLITE-WIN32-RESOURCES}
)
target_link_libraries(qsqlite
sqlite
${SQLITE_LIBRARIES}
${QT_LIBRARIES}
)

110643
3rdparty/qsqlite/sqlite3.c vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -304,31 +304,14 @@ if(ENABLE_VISUALISATIONS)
endif(USE_SYSTEM_PROJECTM)
endif(ENABLE_VISUALISATIONS)
# We compile our own qsqlite3 by default now, because in Qt 4.7 the symbols we
# need from it are private.
option(STATIC_SQLITE "Compile and use a static sqlite3 library" ON)
set(HAVE_STATIC_SQLITE ${STATIC_SQLITE})
if(STATIC_SQLITE)
message(STATUS "Building static qsqlite plugin")
add_subdirectory(3rdparty/qsqlite)
include_directories("3rdparty/qsqlite")
else()
if (NOT I_HATE_MY_USERS)
message(FATAL_ERROR "No, really, Clementine needs sqlite to be linked "
"statically. If it's not, Clementine won't be able to resolve the "
"functions it needs to register full text search support. Search will "
"be really slow and users will be unhappy. If you're packaging "
"Clementine for a distribution and you really hate your users and want "
"them to have a bad time please rerun cmake with -DI_HATE_MY_USERS=ON")
else()
if (NOT MY_USERS_WILL_SUFFER_BECAUSE_OF_ME)
message(FATAL_ERROR "So you really hate your users and you want to "
"create a crippled package that doesn't work properly? Please send "
"an email to the devs and help us understand why.")
endif()
endif()
endif(STATIC_SQLITE)
# Build our copy of QSqlLiteDriver.
# We do this because we can't guarantee that the driver shipped with Qt exposes the
# raw sqlite3_ functions required for FTS support. This way we know that those symbols
# exist at compile-time and that our code links to the same sqlite library as the
# Qt driver.
add_subdirectory(3rdparty/qsqlite)
include_directories("3rdparty/qsqlite")
# When/if upstream accepts our patches then these options can be used to link
# to system installed qtsingleapplication instead.

View File

@ -1192,6 +1192,7 @@ target_link_libraries(clementine_lib
${QTSINGLECOREAPPLICATION_LIBRARIES}
${QTIOCOMPRESSOR_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${SQLITE_LIBRARIES}
z
Qocoa
)
@ -1265,11 +1266,8 @@ else (APPLE)
target_link_libraries(clementine_lib ${QXT_LIBRARIES})
endif (APPLE)
# Link against the qsqlite plugin on windows and mac
if(HAVE_STATIC_SQLITE)
set(3RDPARTY_SQLITE_LIBRARY qsqlite)
target_link_libraries(clementine_lib qsqlite)
endif(HAVE_STATIC_SQLITE)
set(3RDPARTY_SQLITE_LIBRARY qsqlite)
target_link_libraries(clementine_lib qsqlite)
if (WIN32)
target_link_libraries(clementine_lib

View File

@ -40,7 +40,6 @@
#cmakedefine HAVE_SKYDRIVE
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_SPOTIFY_DOWNLOADER
#cmakedefine HAVE_STATIC_SQLITE
#cmakedefine HAVE_UBUNTU_ONE
#cmakedefine HAVE_WIIMOTEDEV
#cmakedefine IMOBILEDEVICE_USES_UDIDS

View File

@ -25,6 +25,8 @@
#include <boost/scope_exit.hpp>
#include <sqlite3.h>
#include <QCoreApplication>
#include <QDir>
#include <QLibrary>
@ -86,25 +88,6 @@ struct sqlite3_tokenizer_cursor {
/* Tokenizer implementations will typically add additional fields */
};
int (*Database::_sqlite3_value_type) (sqlite3_value*) = NULL;
sqlite_int64 (*Database::_sqlite3_value_int64) (sqlite3_value*) = NULL;
const uchar* (*Database::_sqlite3_value_text) (sqlite3_value*) = NULL;
void (*Database::_sqlite3_result_int64) (sqlite3_context*, sqlite_int64) = NULL;
void* (*Database::_sqlite3_user_data) (sqlite3_context*) = NULL;
int (*Database::_sqlite3_open) (const char*, sqlite3**) = NULL;
const char* (*Database::_sqlite3_errmsg) (sqlite3*) = NULL;
int (*Database::_sqlite3_close) (sqlite3*) = NULL;
sqlite3_backup* (*Database::_sqlite3_backup_init) (
sqlite3*, const char*, sqlite3*, const char*) = NULL;
int (*Database::_sqlite3_backup_step) (sqlite3_backup*, int) = NULL;
int (*Database::_sqlite3_backup_finish) (sqlite3_backup*) = NULL;
int (*Database::_sqlite3_backup_pagecount) (sqlite3_backup*) = NULL;
int (*Database::_sqlite3_backup_remaining) (sqlite3_backup*) = NULL;
bool Database::sStaticInitDone = false;
bool Database::sLoadedSqliteSymbols = false;
sqlite3_tokenizer_module* Database::sFTSTokenizer = NULL;
@ -218,11 +201,6 @@ int Database::FTSNext(
void Database::StaticInit() {
if (sStaticInitDone) {
return;
}
sStaticInitDone = true;
sFTSTokenizer = new sqlite3_tokenizer_module;
sFTSTokenizer->iVersion = 0;
sFTSTokenizer->xCreate = &Database::FTSCreate;
@ -230,86 +208,7 @@ void Database::StaticInit() {
sFTSTokenizer->xOpen = &Database::FTSOpen;
sFTSTokenizer->xNext = &Database::FTSNext;
sFTSTokenizer->xClose = &Database::FTSClose;
#ifdef HAVE_STATIC_SQLITE
// We statically link libqsqlite.dll on windows and mac so these symbols are already
// available
_sqlite3_value_type = sqlite3_value_type;
_sqlite3_value_int64 = sqlite3_value_int64;
_sqlite3_value_text = sqlite3_value_text;
_sqlite3_result_int64 = sqlite3_result_int64;
_sqlite3_user_data = sqlite3_user_data;
_sqlite3_open = sqlite3_open;
_sqlite3_errmsg = sqlite3_errmsg;
_sqlite3_close = sqlite3_close;
_sqlite3_backup_init = sqlite3_backup_init;
_sqlite3_backup_step = sqlite3_backup_step;
_sqlite3_backup_finish = sqlite3_backup_finish;
_sqlite3_backup_pagecount = sqlite3_backup_pagecount;
_sqlite3_backup_remaining = sqlite3_backup_remaining;
sLoadedSqliteSymbols = true;
return;
#else // HAVE_STATIC_SQLITE
QString plugin_path = QLibraryInfo::location(QLibraryInfo::PluginsPath) +
"/sqldrivers/libqsqlite";
QLibrary library(plugin_path);
if (!library.load()) {
qLog(Error) << "QLibrary::load() failed for " << plugin_path;
return;
}
_sqlite3_value_type = reinterpret_cast<int (*) (sqlite3_value*)>(
library.resolve("sqlite3_value_type"));
_sqlite3_value_int64 = reinterpret_cast<sqlite_int64 (*) (sqlite3_value*)>(
library.resolve("sqlite3_value_int64"));
_sqlite3_value_text = reinterpret_cast<const uchar* (*) (sqlite3_value*)>(
library.resolve("sqlite3_value_text"));
_sqlite3_result_int64 = reinterpret_cast<void (*) (sqlite3_context*, sqlite_int64)>(
library.resolve("sqlite3_result_int64"));
_sqlite3_user_data = reinterpret_cast<void* (*) (sqlite3_context*)>(
library.resolve("sqlite3_user_data"));
_sqlite3_open = reinterpret_cast<int (*) (const char*, sqlite3**)>(
library.resolve("sqlite3_open"));
_sqlite3_errmsg = reinterpret_cast<const char* (*) (sqlite3*)>(
library.resolve("sqlite3_errmsg"));
_sqlite3_close = reinterpret_cast<int (*) (sqlite3*)>(
library.resolve("sqlite3_close"));
_sqlite3_backup_init = reinterpret_cast<
sqlite3_backup* (*) (sqlite3*, const char*, sqlite3*, const char*)>(
library.resolve("sqlite3_backup_init"));
_sqlite3_backup_step = reinterpret_cast<int (*) (sqlite3_backup*, int)>(
library.resolve("sqlite3_backup_step"));
_sqlite3_backup_finish = reinterpret_cast<int (*) (sqlite3_backup*)>(
library.resolve("sqlite3_backup_finish"));
_sqlite3_backup_pagecount = reinterpret_cast<int (*) (sqlite3_backup*)>(
library.resolve("sqlite3_backup_pagecount"));
_sqlite3_backup_remaining = reinterpret_cast<int (*) (sqlite3_backup*)>(
library.resolve("sqlite3_backup_remaining"));
if (!_sqlite3_value_type ||
!_sqlite3_value_int64 ||
!_sqlite3_value_text ||
!_sqlite3_result_int64 ||
!_sqlite3_user_data ||
!_sqlite3_open ||
!_sqlite3_errmsg ||
!_sqlite3_close ||
!_sqlite3_backup_init ||
!_sqlite3_backup_step ||
!_sqlite3_backup_finish ||
!_sqlite3_backup_pagecount ||
!_sqlite3_backup_remaining) {
qLog(Fatal) << "Couldn't resolve sqlite symbols. Please compile "
"Clementine with -DSTATIC_SQLITE=ON.";
sLoadedSqliteSymbols = false;
} else {
sLoadedSqliteSymbols = true;
}
#endif
}
Database::Database(Application* app, QObject* parent, const QString& database_name)
@ -727,10 +626,10 @@ void Database::DoBackup() {
}
bool Database::OpenDatabase(const QString& filename, sqlite3** connection) const {
int ret = _sqlite3_open(filename.toUtf8(), connection);
int ret = sqlite3_open(filename.toUtf8(), connection);
if (ret != 0) {
if (*connection) {
const char* error_message = _sqlite3_errmsg(*connection);
const char* error_message = sqlite3_errmsg(*connection);
qLog(Error) << "Failed to open database for backup:"
<< filename
<< error_message;
@ -753,8 +652,8 @@ void Database::BackupFile(const QString& filename) {
BOOST_SCOPE_EXIT((source_connection)(dest_connection)(task_id)(app_)) {
// Harmless to call sqlite3_close() with a NULL pointer.
_sqlite3_close(source_connection);
_sqlite3_close(dest_connection);
sqlite3_close(source_connection);
sqlite3_close(dest_connection);
app_->task_manager()->SetTaskFinished(task_id);
} BOOST_SCOPE_EXIT_END
@ -768,26 +667,26 @@ void Database::BackupFile(const QString& filename) {
return;
}
sqlite3_backup* backup = _sqlite3_backup_init(
sqlite3_backup* backup = sqlite3_backup_init(
dest_connection, "main",
source_connection, "main");
if (!backup) {
const char* error_message = _sqlite3_errmsg(dest_connection);
const char* error_message = sqlite3_errmsg(dest_connection);
qLog(Error) << "Failed to start database backup:" << error_message;
return;
}
int ret = SQLITE_OK;
do {
ret = _sqlite3_backup_step(backup, 16);
const int page_count = _sqlite3_backup_pagecount(backup);
ret = sqlite3_backup_step(backup, 16);
const int page_count = sqlite3_backup_pagecount(backup);
app_->task_manager()->SetTaskProgress(
task_id, page_count - _sqlite3_backup_remaining(backup), page_count);
task_id, page_count - sqlite3_backup_remaining(backup), page_count);
} while (ret == SQLITE_OK);
if (ret != SQLITE_DONE) {
qLog(Error) << "Database backup failed";
}
_sqlite3_backup_finish(backup);
sqlite3_backup_finish(backup);
}

View File

@ -143,27 +143,6 @@ class Database : public QObject {
void (*) (sqlite3_context*, int, sqlite3_value**),
void (*) (sqlite3_context*));
// Sqlite3 functions. These will be loaded from the sqlite3 plugin.
static int (*_sqlite3_value_type) (sqlite3_value*);
static sqlite_int64 (*_sqlite3_value_int64) (sqlite3_value*);
static const uchar* (*_sqlite3_value_text) (sqlite3_value*);
static void (*_sqlite3_result_int64) (sqlite3_context*, sqlite_int64);
static void* (*_sqlite3_user_data) (sqlite3_context*);
// These are necessary for SQLite backups.
static int (*_sqlite3_open) (const char*, sqlite3**);
static const char* (*_sqlite3_errmsg) (sqlite3*);
static int (*_sqlite3_close) (sqlite3*);
static sqlite3_backup* (*_sqlite3_backup_init) (
sqlite3*, const char*, sqlite3*, const char*);
static int (*_sqlite3_backup_step) (sqlite3_backup*, int);
static int (*_sqlite3_backup_finish) (sqlite3_backup*);
static int (*_sqlite3_backup_pagecount) (sqlite3_backup*);
static int (*_sqlite3_backup_remaining) (sqlite3_backup*);
static bool sStaticInitDone;
static bool sLoadedSqliteSymbols;
static sqlite3_tokenizer_module* sFTSTokenizer;
static int FTSCreate(int argc, const char* const* argv, sqlite3_tokenizer** tokenizer);

View File

@ -106,10 +106,8 @@ using boost::scoped_ptr;
#endif
// Load sqlite plugin on windows and mac.
#ifdef HAVE_STATIC_SQLITE
# include <QtPlugin>
Q_IMPORT_PLUGIN(qsqlite)
#endif
#include <QtPlugin>
Q_IMPORT_PLUGIN(qsqlite)
void LoadTranslation(const QString& prefix, const QString& path,
const QString& language) {