Get path of Qt 5 additional plugins - dll

In a Qt 4 project, I build a Windows installer using Inno Setup. The required libraries (qsqlite.dll, qjpeg4.dll, etc.) are included in the script with CMake variables such as QT_QSQLITE_PLUGIN_RELEASE or QT_QJPEG_PLUGIN_RELEASE.
ex: setup.iss.in :
[Files]
Source: "myapp.exe"; DestDir: {app}
Source: "${QT_QSQLITE_PLUGIN_RELEASE}"; DestDir: {app}/sqldrivers
Source: "${QT_QJPEG_PLUGIN_RELEASE}"; DestDir: {app}/imageformats
Now the project should migrate to Qt5. Everything works fine, but I can't find pre-defined variables to get Qt5 equivalent for these plugins paths. Of course, I could hardcode them, but I am looking for a way to define it in a clean and independent way.

Qt5 no longer relies on a CMake module file to find the Qt5 installation, but provides its own CMake config file, which sets up the Qt5 libraries as imported CMake targets. To obtain the actual path to the Qt module library file, query the LOCATION property of the module's CMake target or its config specific variant LOCATION_<Config> version, e.g.:
find_package(Qt5Core)
get_target_property(QtCore_location_Release Qt5::Core LOCATION_Release)
find_package(Qt5Widgets)
get_target_property(QtWidgets_location_Release Qt5::Widgets LOCATION_Release)
This strategy probably also applies to Qt plugins, provided you know the plugin's CMake target name (I haven't verified that).
Also see the Qt5 CMake manual.

As of Qt 5.2, plugins are available as IMPORTED targets too:
http://doc.qt.io/qt-5/cmake-manual.html#imported-targets
https://codereview.qt-project.org/#change,63100
Read the LOCATION property from IMPORTED targets, not a configuration-specific LOCATION_ property. CMake will handle the configuration part.

Building on steveire's answer, this is how you would get the absolute paths to the QSqlite and QJpeg plugins:
find_package(Qt5Gui)
find_package(Qt5Sql)
get_target_property(qsqlite_loc Qt5::QSQLiteDriverPlugin LOCATION_Release)
message("QSqlite DLL: ${qsqlite_loc}")
get_target_property(qjpeg_loc Qt5::QJpegPlugin LOCATION_Release)
message("QJpeg DLL: ${qjpeg_loc}")

Related

CMake TARGET_RUNTIME_DLLS is empty

I have git cloned, built (with MSVC for both Debug and Release) and then installed wxWidgets:
cmake -B build wxWidgets
cmake --build build --config <CONFIG>
cmake --install build --prefix my_install --config <CONFIG>
with <CONFIG> = Debug and <CONFIG> = Release.
Then I used the following CMake script to link against it, as suggested by the wiki:
cmake_minimum_required(VERSION 3.16)
project(Test)
add_executable(Test WIN32 Main.cpp)
# wxWidgets
SET(wxWidgets_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/my_install)
find_package(wxWidgets COMPONENTS core base REQUIRED)
include(${wxWidgets_USE_FILE})
target_link_libraries(Test PRIVATE ${wxWidgets_LIBRARIES})
# Copy runtime DLLs to the directory of the executable.
add_custom_command(TARGET Test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Runtime Dlls: $<TARGET_RUNTIME_DLLS:Test>"
)
My goal is to automatically copy the DLLs into the directory of the built executable, so that they can be found at runtime. For that I'm using the TARGET_RUNTIME_DLLS generator expression (follwing the sample code in the docs). In the code above, I only print out the expression at build time for testing purposes. The problem is that it is empty.
The approach worked for me before when installing and linking SDL, but SDL provides package configuration files which create imported targets, defining the DLL location(s) via IMPORTED_LOCATION_RELEASE or IMPORTED_LOCATION_DEBUG. For wxWidgets one is apparently supposed to use the FindwxWidgets.cmake script shipped with CMake, which sadly doesn't define the produced binaries. Maybe that's why TARGET_RUNTIME_DLLS isn't populated.
Does anyone know, either how to get TARGET_RUNTIME_DLLS filled or how to obtain the list of built wxWidgets DLLs for the current configuration (Release/Debug) post build copying?
Thanks a lot in advance!
I am dealing with a similar problem.
First sanity checks:
You have to work on windows platform otherwise this feature does not
work.
Your Cmake is 3.21 or above
Next comes fuzzy part. I think the library that you are trying to include have to be a Shared Imported library and you have to set a set_target_properties for IMPORTED_IMPLIB which is a path to a .lib file of sort (dll import library, I think it is called) So you have to make sure that it is all set in the package library that you trying to link with your executable.
If you have those dll avaiable and you just want to use them and not actually build them then you can write your own cmake script that will do just what I said above. Then you can include that cmake file in your project and then link against your app.
Note: I also work on similar issue right now and what I just said have not been working very reliably. I got some dlls to be copied and some do not.
Edit:
Cmake docs give a more detailed explanation on how this library setting should look like if you use find_package feature.
Found here: https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries
An UNKNOWN library type is typically only used in the implementation
of Find Modules. It allows the path to an imported library (often
found using the find_library() command) to be used without having to
know what type of library it is. This is especially useful on Windows
where a static library and a DLL's import library both have the same
file extension.

Encapsulating a JNI library inside a jar file

I am trying to develop a plugin for Fiji/ImageJ that relies on a native library (JNI).
The JNI library itself depends on libtiff and fftw. On OSX and Linux, I use the class NativeUtils and everything works fine.
On windows, I included binary versions of libtiff and fftw in the CMake package and managed to link the JNI library against those (either statically of dynamically). However, the resulting JNI module does not include libtiff or fftw and I obtain an error when I try to load the JNI library with NativeUtils.loadLibraryFromJar. This is also the case when I include the dependent .dll in the .jar since they are not extracted by NativeUtils.
Here are the relevant lines in CMakeLists.txt:
add_library(fftw STATIC IMPORTED GLOBAL)
set_target_properties(fftw PROPERTIES IMPORTED_LOCATION "${libdir}/libfftw3f-3.lib"
INTERFACE_INCLUDE_DIRECTORIES "${incdir}")
SWIG_ADD_LIBRARY(javainterf
TYPE MODULE
LANGUAGE java
SOURCES javainterf.i javainterf.c src1.c)
SWIG_LINK_LIBRARIES(javainterf libcode1 fftw)
add_jar(Foo
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/java/foo1.java
INCLUDE_JARS java/resources/ij-1.51p.jar
VERSION ${JAR_VERSION})
add_dependencies(Foo javainterf)
add_custom_command(TARGET Foo POST_BUILD
COMMAND "${Java_JAR_EXECUTABLE}" -uf Foo-${JAR_VERSION}.jar
-C ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} ${JNI_LIB_NAME})
How would you make sure that all the dependencies are properly included in the jar and loaded?
You can't load library from inside JAR without extracting it in a first place.
Take a look here at full sample where native code is embedded inside JAR and extracted when needed.
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo031
Update
Well, in that case, when you need to pack more libs and you want to properly resolve locations, you need to play with runtime env a little bit.
Take a look here:
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo035
git clone https://github.com/mkowsiak/jnicookbook
cd jnicookbook/recipes/recipeNo035
make
make test
Have fun with JNI!

Creating a findable shared library with cmake

I am rewriting libraries from hand-written Makefiles to using cmake. I am getting stuck at the point where I need to library library A from library B.
I can find the libraries using find_package, but when they are being linked cmake complains about not having a rule for building the .so file because it is looking for it in the build directory instead of the installed directory.
This is explained if I look at the /usr/lib/cmake/library/libraryConfigVersion.cmake file, which contains this hardcoded path. This file was created with the following steps:
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/libraryConfigVersion.cmake"
VERSION ${LIBRARY_VERSION}
COMPATIBILITY AnyNewerVersion
)
export(EXPORT libraryTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/library/libraryConfigVersion.cmake"
NAMESPACE library::
)
(i have replaced my library name with 'library'). How can I get cmake to write the correct path so that I can easily link against my library from other cmake projects?
Command export actually exports build tree. This is explicitely written in the documentation.
For export install tree, use install(TARGETS ... EXPORT) plus install(EXPORT). Both flows are described in documentation for install command.
See also CMake tutorial Exporting and Importing Targets.

CMake package configuration files for upstream projects using Qt5 problems

I am working on a larger C++ library that is using CMake and depends on Qt.
We moved from Qt4 to Qt5 and now I encounter a problem when using our lib
in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:
https://github.com/philthiel/cmake_qt5_upstream
It contains two separate CMake projects:
MyLIB: a tiny library that uses QString from Qt5::Core.
It generates and installs package configuration files
MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake
in order to be searchable by CMake find_package()
MyAPP: a tiny executable depending on MyLIB
The project uses find_package(MyLIB) and creates an executable that uses MyLIB
The problem is that CMake gives me the following error message when configuring the MyAPP project:
CMake Error at CMakeLists.txt:11 (add_executable):
Target "MyAPP" links to target "Qt5::Core" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.
Now, I simply can resolve this by using
find_package(Qt5Core 5.X REQUIRED)
in the MyAPP project.
However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?
The CMake docu on package file generation
https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?
Best,
Philipp
[edit of the edit] Full Source Example
You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).
Tip, use the ECM cmake modules to ease the creation of that:
find_package(ECM REQUIRED NO_MODULE)
include(CMakePackageConfigHelpers)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX ATCORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
SOVERSION 1
)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
and the KF5AtCoreConfig.cmake.in:
#PACKAGE_INIT#
find_dependency(Qt5Widgets "#REQUIRED_QT_VERSION#")
find_dependency(Qt5SerialPort "#REQUIRED_QT_VERSION#")
find_dependency(KF5Solid "#KF5_DEP_VERSION#")
include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")
This will generate the correct FindYourSortware.cmake with all your dependencies.
[edit] Better explanation on what's going on.
If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)
Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.
find_package(Qt5 REQUIRED COMPONENTS Core)
then you link your library with
target_link_libraries(YourTarget Qt5::Core)

How to make CMake find google protobuf on windows?

I am using Google Protobuf with CMake. On Linux the Protobuf library is found by:
find_package( Protobuf REQUIRED )
CMake knows where to look for the library. How though do I get this to work in Windows? Is there an environment variable I should create, such as PROTOBUF_LIB? I have looked in FindProtobuf.cmake but cannot work out what is required.
I also struggled with this. To be more clear.
On Windows (7, similar on older windows):
Start → Control Panel → System → Advanced System Settings → Environment Variables
Then either on the top panel or the bottom panel (if you want it to apply to other users do it on the bottom), create two new variables. The 1st one is
CMAKE_INCLUDE_PATH which points at the bottom of your include path (should contain a "google" folder)
CMAKE_LIBRARY_PATH which should contain "libprotobuf" "libprotobuf-lite" "liteprotoc" .lib files.
After you create the variables press OK and then re-start cmake (or clean the cache).
Newest protobuf v3 have CMake support out of the box.
You could use protobuf repository as submodule and just use
add_subdiretory("third-party/protobuf/cmake")
to get all protobuf targets.
Then you can add dependency to protobuf with
target_link_libraries(YourLibrary libprotobuf libprotobuf-lite libprotoc)
Another possible way is available. With protobuf's CMake configuration you can build and install protobuf binaries once and use them across several projects in your development:
git clone https://github.com/google/protobuf.git
mkdir protobuf\tmp
cd protobuf\tmp
cmake ..\cmake
cmake --build .
cmake --build . --target install
Then you can use find_package with hint paths like
find_package(protobuf REQUIRED
HINTS
"C:/Program Files/protobuf"
"C:/Program Files (x86)/protobuf")
if (NOT PROTOBUF_FOUND)
message("protobuf not found")
return()
endif()
Hope this helps.
Protobuf on windows calls find_library which will search your PATH and LIB variables.
I found the way to use protobuf v2 with cmake on Windows and build it with your project settings. Please, try look to cmake-external-packages project and protobuf-v2 CMakeLists which do the job.
In fact, I wrote it because ExternalProject_Add is wrong (because does stuff in build phase instead of generation phase).
This CMakeLists.txt will download protobuf from protobuf's github releases, extract, and emit cmake targets which you should add reference to with target_link_libraries.
Use git-subtree, git-submodule or just copy this repository contents to your repository subfolder.
Then add packages you want to use with add_subdiretory. For protobuf, use:
add_subdirectory(path/to/cmake-external-packages/protobuf-v2)
Protobuf's includes will be copied to path/to/cmake-external-packages/include folder. You can customize its location in your top-level CMakeLists:
set (EXTERNAL_PACKAGES_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/third-party/include
CACHE STRING "Directory for third-party include files, where include folders will be copied")
include_directories(${EXTERNAL_PACKAGES_INCLUDE_DIR})
Just reference protobuf for your executable:
add_executable(your_exe ${your_exe_sources})
target_link_libraries(your_exe libprotobuf libprotobuf-lite libprotoc)
Hope this helps.