CMake static link Qt5 - cmake

I've been developing a program with Qt5 on Linux without a problem, now I'm trying to compile it on Windows using CMake (with Qt5CoreConfig.cmake, etc.) and mingw32.
Everything works OK, except that I don't know how to static link my project.
This is how I add Qt5 to my project:
foreach(lib Qt5Core Qt5Widgets Qt5Gui Qt5Xml)
find_package(${lib} REQUIRED)
include_directories(${${lib}_INCLUDE_DIRS})
list(APPEND LIBS ${${lib}_LIBRARIES})
add_definitions(${${lib}_DEFINITIONS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${lib}_EXECUTABLE_COMPILE_FLAGS}")
endforeach(lib)
What should I do to make it static?

You cannot build a static application with the windows version installed from the QT web site. You need to compile a windows binary from source with -static option enabled.

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.

Building a rust library through CMake and using it as imported library target

I'm restucturing the CMake based build of a cross platform (macOS/Windows, Linux should be added soon) C++ project that has a third party rust library as dependendcy. Until now the rust lib dependency was supplied as precompiled library but I want to make its compilation part of my CMake build.
I got it working on macOS using the CMake makefile exporter by referencing the compiled library as a static imported library target and setting up a custom target with the command to build the rust library through cargo like this
add_library (rustlib STATIC IMPORTED)
add_custom_target (rustlib_cargo
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/Ext/rustlib/c-api
COMMAND cargo rustc --release -- --crate-type staticlib)
# Note: RUSTLIB_OUTPUT is set above refering to the absolute path of the produced platform specific library
set_target_properties (rustlib PROPERTIES IMPORTED_LOCATION ${RUSTLIB_OUTPUT})
add_dependencies (rustlib rustlib_cargo)
On macOS the cargo rustc command is invoked before the targets that link against my rustlib target are built and in case the rust library has been built previously this is detected by cargo and it just skips that compilation steph. But on Windows this fails with the built-in ninja exporter of Microsoft Visual Studio 2019 with an error like this:
ninja : error : '../../../Ext/rustlib/target/release/deps/rustlib.lib', needed by 'SomeTargetLinkingAgainstRustlib', missing and no known rule to make it
If I remove the line set_target_properties (rustlib PROPERTIES IMPORTED_LOCATION ${RUSTLIB_OUTPUT}) the build starts correctly, the rust build gets triggered, but as expected I end up with a linker error as the library to link against is not found. So is there any way to refer to a file that is not existent at configuration time but is guranteed to be created during compilation?

CMake find protobuf compiled from source

I am trying to build a project that depends on Google Protocol Buffers compiled from source. My project should be platform independent and also should support cross-compilation, which is the reason that i prefer to use a locally built protobuf. However I would prefer not to include the whole library as a subproject as it would take too much to build.
My simplified CMakeLists.txt is:
cmake_minimum_required(VERSION 3.5)
project(sample-protobuf)
# find a boost install with the libraries filesystem and system
find_package(Protobuf REQUIRED)
set(SOURCES
main.cpp
)
add_executable(sample
${SOURCES}
)
target_link_libraries(sample
PRIVATE
protobuf::libprotobuf
)
I invoke CMake on Linux as:
cmake -DCMAKE_PREFIX_PATH=/path/to/built/protobuf/ ..
but it does not find the library and I get the following message:
Could not find a package configuration file provided by "Protobuf" with any
of the following names:
ProtobufConfig.cmake
protobuf-config.cmake
Add the installation prefix of "Protobuf" to CMAKE_PREFIX_PATH or set
"Protobuf_DIR" to a directory containing one of the above files. If
"Protobuf" provides a separate development package or SDK, be sure it has
been installed.
On Windows this procedure works.
I built the library on Linux using the suggested approach, which is not with CMake but with autotools.
What should I do differently?
cd protobuf/cmake
mkdir build
cd build
cmake....
make...
sudo make install

Clion, cMake and POCO

I'm a new guy to c++ and cmake here. I decided to test out cLion and cMake. I'm trying to write a simple email client for the command line. Other sources told me that the best way to implement a POP3 and SMTP functions would be to use POCO. Unfortunately, cMake is giving me trouble. The version that came with CLion is 3.2 but the version that my machine is running is 2.8.
~$ cmake --version
cmake version 2.8.12.2
First problem. I thought that I could bypass this by just installing POCO and doing the same thing that I used for openssl which I also had to download.
cMakeList.txt:
cmake_minimum_required(VERSION 3.0)
project(Email_Reader)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#included paths for openssl and POCO.
INCLUDE_DIRECTORIES("/usr/include/openssl")
INCLUDE_DIRECTORIES("/usr/local/include/Poco/Net")
set(SOURCE_FILES main.cpp)
add_executable(Email_Reader ${SOURCE_FILES})
The documentation for POCO tells me that I need at least 3.0 to work but I feel I have 2 different cMakes on my machine. Can you help me, please?
You can get the latest CMake release from: http://www.cmake.org/download/
For Linux, it's this archive: http://www.cmake.org/files/v3.2/cmake-3.2.2.tar.gz
An easy way to use it is to put the extracted files in /opt/cmake/cmake-3.2 then create the following aliases (e.g. in ~/.bash_aliases:
alias ccmake3='/opt/cmake/cmake-3.2/bin/ccmake'
alias cmake3='/opt/cmake/cmake-3.2/bin/cmake'
alias cmake3-gui='/opt/cmake/cmake-3.2/bin/cmake-gui'
alias cpack3='/opt/cmake/cmake-3.2/bin/cpack'
alias ctest3='/opt/cmake/cmake-3.2/bin/ctest'
Then, make sure that you have properly built and installed POCO.
The Getting Started page has all the information you need for doing that. But, basically, you should get the sources from here and extract them somehwere:
wget http://pocoproject.org/releases/poco-1.6.0/poco-1.6.0.tar.gz
tar xvfz poco-1.6.0.tar.gz
cd poco-1.6.0
mkdir -p cmake_build cmake_install/debug cmake_install/release
cd cmake_build
cmake3-gui ..
In the CMake 3 GUI, press Configure. In the new window, keep the default option Unix Makefiles and click on Finish. An error message should appear (which is fine), click Ok.
To build the Debug version, set the following:
CMAKE_BUILD_TYPE : Debug
CMAKE_INSTALL_PREFIX : the absolute path to "cmake_install/debug"
To get you started quickly with POCO, unckeck all the options, except for the following, they have to be enabled:
ENABLE_JSON
ENABLE_NET
ENABLE_UTIL
ENABLE_XML
POCO_STATIC
(You can consider the other options later if you need to...)
Quit the GUI, then build/install POCO:
make clean
make -j8
make install
Now, POCO should be installed in cmake_install/debug. To build/install the other versions, just do the same procedure, but replace Debug in CMAKE_BUILD_TYPE with Release, RelWithDebInfo or MinSizeRel (cf. CMake's doc) (also, you'll have to change the install directories)
Finally, you can use POCO in you C++ projects.
For instance, your CMakeLists.txt should look like this:
cmake_minimum_required(VERSION 3.0)
project(Email_Reader)
# define the project
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
add_executable(Email_Reader ${SOURCE_FILES})
# set the POCO paths and libs
set(POCO_PREFIX "/path/to/cmake_install/debug") # the directory containing "include" and "lib"
set(POCO_INCLUDE_DIR "${POCO_PREFIX}/include")
set(POCO_LIB_DIR "${POCO_PREFIX}/lib")
set(POCO_LIBS "${POCO_LIB_DIR}/libPocoNetd.a"
"${POCO_LIB_DIR}/libPocoUtild.a"
"${POCO_LIB_DIR}/libPocoJSONd.a"
"${POCO_LIB_DIR}/libPocoXMLd.a"
"${POCO_LIB_DIR}/libPocoFoundationd.a"
"pthread")
# set the include path for the app
target_include_directories(Email_Reader PRIVATE "${POCO_INCLUDE_DIR}")
# link the app against POCO
target_link_libraries(Email_Reader "${POCO_LIBS}")
My CMakeLists.txt for using Poco looks like this:
cmake_minimum_required(VERSION 3.10.0)
project(MyProject VERSION 0.1.0)
find_package(Poco REQUIRED COMPONENTS Foundation Net Zip )
add_executable(my_exe main.cpp)
target_link_libraries(my_exe PUBLIC Poco::Foundation Poco::Zip Poco::Net)
This configuration automatically add the needed include directories and libraries.
The Foundation component is mandatory, it seems it provides the include directories.
Don't add Poco to target_link_libraries, the linker will then look for a 'Poco' library.

How do I tell CMake to link in a static library in the source directory?

I have a small project with a Makefile which I'm trying to convert to CMake, mostly just to get experience with CMake. For purposes of this example, the project contains a source file (C++, though I don't think the language is particularly relevant) and a static library file which I've copied from elsewhere. Assume for argument's sake that the source code to the library is unavailable; I only have the .a file and the corresponding header.
My handmade Makefile contains this build rule:
main: main.o libbingitup.a
g++ -o main main.o libbingitup.a
which works fine. How do I tell CMake to reproduce this? Not literally this exact makefile, of course, but something that includes an equivalent linking command. I've tried the obvious but naive ways, like
add_executable(main main.cpp libbingitup.a)
or
add_executable(main main.cpp)
target_link_libraries(main libbingitup.a)
as well as various things with link_directories(.) or add_library(bingitup STATIC IMPORTED) etc. but nothing so far that results in a successful linkage. What should I be doing?
Version details: CMake 2.8.7 on Linux (Kubuntu 12.04) with GCC 4.6.3
CMake favours passing the full path to link libraries, so assuming libbingitup.a is in ${CMAKE_SOURCE_DIR}, doing the following should succeed:
add_executable(main main.cpp)
target_link_libraries(main ${CMAKE_SOURCE_DIR}/libbingitup.a)
If you don't want to include the full path, you can do
add_executable(main main.cpp)
target_link_libraries(main bingitup)
bingitup is the same name you'd give a target if you create the static library in a CMake project:
add_library(bingitup STATIC bingitup.cpp)
CMake automatically adds the lib to the front and the .a at the end on Linux, and .lib at the end on Windows.
If the library is external, you might want to add the path to the library using
link_directories(/path/to/libraries/)
I found this helpful...
http://www.cmake.org/pipermail/cmake/2011-June/045222.html
From their example:
ADD_LIBRARY(boost_unit_test_framework STATIC IMPORTED)
SET_TARGET_PROPERTIES(boost_unit_test_framework PROPERTIES IMPORTED_LOCATION /usr/lib/libboost_unit_test_framework.a)
TARGET_LINK_LIBRARIES(mytarget A boost_unit_test_framework C)
I want to add to the other comments, the project name is the first argument. I had a project called cmakecompile and i wanted to add libusb to it, the code is as follows,
add_executable(cmakecompile main.c)
target_link_libraries(cmakecompile "D:/msys2/mingw64/lib/libusb-1.0.a")
the project had just only a main.c file, the first parameter in target_link_libraries is the name of your project and the second parameter is the path of the library.
Note that may help: Since i am compiling under windows, i had to install msys2 because the library you have has to be compiled with the same compiler. For example if you get libusb and try to use it in a qt-creator project, it will not work and you may get unreferenced functions, therefore i had to install msys2 and install libusb from inside msys2, install make and create a QT Cmake project and compile from Qt creator using the msys2 make.
The full cmakelists.txt is as follow
cmake_minimum_required(VERSION 3.5)
project(cmakecompile LANGUAGES C)
add_executable(cmakecompile main.c)
target_link_libraries(cmakecompile "D:/msys2/mingw64/lib/libusb-1.0.a")