SOCI / soci

Official repository of the SOCI - The C++ Database Access Library
http://soci.sourceforge.net/
Boost Software License 1.0
1.37k stars 472 forks source link

Issue with backend include directories & DLL requirement even when linked statically #1015

Open DizzasTeR opened 1 year ago

DizzasTeR commented 1 year ago

Hi, after several hours of going through documentation, github issues and CMakeLists.txt files I've finally given up in figuring out what I'm doing wrong to use Soci to connect to MySQL backend statically.

There are two parts to my issue, issue (2) only is reached when I manually fix issue (1) which in-itself I'm not sure why isn't already working on its own.

Environment:

Issue (1):

This is my configuration that is relevant for SOCI:

set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Static Build" FORCE)

set(SOCI_SHARED OFF CACHE INTERNAL "SOCI Shared" FORCE)
set(SOCI_STATIC ON CACHE INTERNAL "SOCI Static" FORCE)
set(SOCI_TESTS OFF CACHE INTERNAL "SOCI Tests" FORCE)
set(WITH_BOOST OFF CACHE INTERNAL "SOCI use Boost" FORCE)
set(SOCI_EMPTY OFF CACHE INTERNAL "SOCI Backend" FORCE)
set(WITH_DB2 OFF CACHE INTERNAL "SOCI Backend" FORCE)
set(WITH_FIREBIRD OFF CACHE INTERNAL "SOCI Backend" FORCE)
set(WITH_MYSQL ON CACHE INTERNAL "SOCI Backend" FORCE)
set(WITH_ODBC OFF CACHE INTERNAL "SOCI Backend" FORCE)
set(WITH_ORACLE OFF CACHE INTERNAL "SOCI Backend" FORCE)
set(WITH_POSTGRESQL OFF CACHE INTERNAL "SOCI Backend" FORCE)
set(WITH_SQLITE3 OFF CACHE INTERNAL "SOCI Backend" FORCE)

# (... Other configurations and options ...)

target_link_libraries(myTarget PUBLIC soci_core_static)
target_link_libraries(myTarget PUBLIC soci_mysql_static)

CMake generates the solution files successfully and then I try to include the following:

#include <soci/soci.h>
#include <soci/soci-config.h>
#include <soci/mysql/soci-mysql.h>

and I get this error in every cpp file where these headers are included:

path\...\vendor\soci\include\soci/mysql/soci-mysql.h(37,10): fatal  error C1083: Cannot open include file: 'mysql.h': No such file or directory

Issue (2):

To overcome the above Issue I added following:

find_package(MySQL REQUIRED)
target_include_directories(myTarget PUBLIC ${MYSQL_INCLUDE_DIR})

This solves issue (1) and everything compiles with a test code like so:

soci::register_factory_mysql();
soci::session session(soci::mysql, "...");

Everything builds, but when I run the program, I get missing dependencies for libmysql.dll and if I copy paste that dll from my MySQL installation, the program runs fine, so then what was the point of going through static build if dll is still a requirement at the end?

Conclusion

I'm not sure what I'm doing wrong, at what step am I linking incorrectly or configuring incorrectly which is causing this, any help would be appreciated.

vadz commented 1 year ago

For (1) I think it's normal that you need to use MySQL options explicitly if you include the MySQL-specific SOCI header. The alternative would be to always include all backend-specific include paths into SOCI target itself, but this doesn't seem right, i.e. why would people not using MySQL at all need to have MySQL include paths in their build?

For (2) I'm sure that this behaves as expected: SOCI static build only refers to static libraries of SOCI itself, not the backend-specific libraries. The point of using it is not to have dependencies on SOCI DLLs.

DizzasTeR commented 1 year ago

So basically there is no way to statically link libmysqlclient that means? I really wanted to avoid having a .dll 😋

If that is the case then I guess I have everything configured correctly, this can be closed. Thank you

vadz commented 1 year ago

Does MySQL even come with static libraries in the first place (I don't use it myself, so I don't know)? If yes, it should be possible to convince CMake to use them, I guess... but e.g. libpq for PostgreSQL is only distributed in the shared form normally and even though you could rebuild it as a static library yourself, you wouldn't be able to do it for e.g. Oracle. So I just don't think you can avoid using DLLs in all cases, even though it might be possible with MySQL.

DizzasTeR commented 1 year ago

It seems like MySQL has a mysqlclient.lib (and libmysqlclient.so on linux) that can be used for static linking, however when I do that I get this during CMake generation:

CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
MYSQL_EMBEDDED_LIBRARIES
    linked by target "cmTC_da6ba" in directory path-to-my-project/build/CMakeFiles/CMakeScratch/TryCompile-y7yx45

Also I tried goofing around by first linking with libmysql.lib (which is how linking is being performed now) and invoked cmake, it generated successfully, then I changed the linking library from libmysql to mysqlclient.lib manually in visual studio > Linker settings and compiled, and now I didn't need the .dll. So if there's a way to get rid of the embedded libraries error then surely it can work, however to my knowledge (I could be wrong here) the embedded mysql libraries are related to bundling the entire mysql server so not sure

Edit

So I took your FindMySQL.cmake and added this after the include(...) line at the very top

set(CLIENT_LIB "libmysql")
if(NOT ${BUILD_SHARED_LIBS})
    set(CLIENT_LIB "mysqlclient")
endif()

...

# Both for if(WIN32) and else(WIN32)
find_library(MYSQL_LIBRARIES NAMES ${CLIENT_LIB}
      PATHS
      ${MYSQL_LIB_PATHS}
   )

and modified following

if(${BUILD_SHARED_LIBS})
   set( CMAKE_REQUIRED_LIBRARIES ${MYSQL_EMBEDDED_LIBRARIES} )
   check_cxx_source_compiles( "#include <mysql.h>\nint main() { int i = MYSQL_OPT_USE_EMBEDDED_CONNECTION; }" HAVE_MYSQL_OPT_EMBEDDED_CONNECTION )
endif()

Got a completely static build of mysql, I have no idea how bad, broken or plain stupid this is, but it works atleast on windows. I haven't tried on Linux yet (I have to build my project on linux as well)

Edit 2

Works on linux as well (Debian 10)