I have a QT Project I am working on, it has a couple of sub-modules, which I list in my project's .pro file as:
if(!include(module/my_module.pri)){
error("module my_module not found")
}
What I tried:
Well, I have found a library which I intend to use, which is a CMake project libcrashreporter-qt. I am just linking the project for completeness - there is nothing wrong with this library (to my knowledge)
Problem:
I figured I will try an include the CMakeLists.txt file as I would a .pri file:
if(!include(libcrashreporter-qt/CMakeLists.txt)){
error("module libcrashreporter-qt not found")
}
where the libcrashreporter-qt folder is in the root of my project
Some Code:
In doing so, I get a horde of compiler errors:
$project_dir/libcrashreporter-qt/CMakeLists.txt:1: 'project' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:2: 'cmake_minimum_required' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:4: Extra characters after test expression.
$project_dir/libcrashreporter-qt/CMakeLists.txt:5: 'cmake_policy' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:6: 'endif' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:10: 'find_package' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:12: Opening parenthesis without prior test name.
$project_dir/libcrashreporter-qt/CMakeLists.txt:16: 'string' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:17: 'string' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:18: 'endif' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:20: 'add_subdirectory' is not a recognized test function.
$project_dir/libcrashreporter-qt/CMakeLists.txt:21: 'add_subdirectory' is not a recognized test function.
CMake file content (note, I changed the file slightly trying to resolve build issues by removing the multi-line if-statement and commented the option line):
project(libcrashreporter-qt)
cmake_minimum_required(VERSION 3.1)
if(POLICY CMP0071)
cmake_policy(SET CMP0071 NEW)
endif()
#option(ENABLE_GPL_CODE OFF)
find_package(Qt5 COMPONENTS Core Network Widgets)
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_FLAGS) OR (UNIX AND NOT APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
# Breakpad uses GNU compiler extensions like typeof.
# Luckily these features are not used on OSX, so we can build the
# crashreporter there with the normal C++11 standard.
string(REPLACE "-std=c++11" "-std=gnu++11" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
string(REPLACE "-std=c++14" "-std=gnu++14" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
endif()
add_subdirectory(3rdparty)
add_subdirectory(src)
This leads me to believe there is an issue with Qt .pro file compatibility and CMake projects being used within each other.
Question:
How can access the library functions of this CMake project, and compile it with my project (i.e. w/o changing the CMake project itself), or alternatively how best can I convert the CMake project to a compatible .pro project?
AFAIK CMake and QMake cannot be mixed together in one project, they are two different build systems and if you want to use a CMake project in a QMake project you have "two" options:
if you want to use the source files (.cpp and .h) or even modify them in your project you have to import them to your QMake project (you can easily do that in your QtCreator) and compile all of the files of your project
if the CMake library that you are using doesn't need any change (most of the times it's like this when you're using a third party library) and you just want to import it to your project and link it against your executable, you just run and compile the CMake project (separate from your own QMake project) and then use the output dynamic or static library of that project to link against your QMake project
As far as I remember, in Qt you can specify the custom compiler settings for the extra target, so, if you need your CMake project to be rebuilt just before the target Qt application is built, you can try to use this way
A possible solution is here:
https://stackoverflow.com/a/15766946/2333496
Related
I have a project and I need to prepare a CMakeLists.txt file for it.
I also have tests which I need to get an executables for after building the project.
Tests are located in a separate backEndTest folder with their own CMakeLists.txt file.
In order to achieve that I decided to use qtwindeploy tool for that. However, when I compile everything and try to run backEndText.exe file I have errors related to missing dlls.
That's what my main CMakeLists.txt file looks like:
add_subdirectory(backEndTest)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Test)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Test)
set(QtBinDir "C:/Qt/6.2.3/mingw_64/bin")
set(winDeploy "${QtBinDir}/windeployqt.exe")
set(backEndTest ${CMAKE_BINARY_DIR}/backEndTest/backEndTest.exe)
set(testBackEnd TRUE)
if (testBackEnd)
execute_process(COMMAND ${winDeploy} ${backEndTest} --compiler-runtime )
endif()
Do you have any idea why dlls are not getting linked?
I've looked at similar questions but haven't found one for this basic scenario. I'm relatively new to CMake. I have a CMake-based Qt 5 project. It's a simple test application; during its build I want to build and statically link the open-source Paho MQTT C lib and the C++ wrapper for it. Those are two separate projects with their own CMakeLists.txt files.
Per Qt's default, it builds into a directory outside the source tree.
I've copied the source trees for these open-source libs under the parent directory of my project, and edited the top-level CMakeLists.txt file to add_subdirectory them.
I also added target_link_libraries. I can get the C lib by itself to build and link into the parent project, but if I add the C++ wrapper, the processing for the C++ wrapper complains that it can't find the C lib... which is true because it hasn't been built yet. A similar complaint for the C lib was solved by simply using Qt's "build all projects" menu item, but that doesn't work when the C++ wrapper lib is added. The wrapper's CMakeLists.txt files issues this:
CMake Error at paho.mqtt.cpp/src/CMakeLists.txt:150 (message):
Could not find Paho MQTT C library
And sure enough it doesn't exist because it has not been built when this preprocessing is done.
UPDATED: Here's my top-level CMakeLists.txt file, revised per Corristo's suggestion, which was successful in getting CMake to parse the entire hierarchy. The project now builds. I'm perplexed that the last two lines here result in an empty string, though. So does a similar attempt for the link directories.
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
task.h
task.cpp
task.ui
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(MQTTTest
${PROJECT_SOURCES}
)
else()
if(ANDROID)
add_library(MQTTTest SHARED
${PROJECT_SOURCES}
)
else()
add_executable(MQTTTest
${PROJECT_SOURCES}
)
endif()
endif()
add_subdirectory(paho.mqtt.c)
set(PAHO_MQTT_C_LIB paho-mqtt3a)
set(PAHO_MQTT_C_PATH "${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.c")
add_subdirectory(paho.mqtt.cpp)
target_link_libraries(MQTTTest PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_directories(MQTTTest PUBLIC
"${CMAKE_CURRENT_LIST_DIR}/build/paho.mqtt.c/src"
"${CMAKE_CURRENT_LIST_DIR}/build/paho.mqtt.cpp/src")
target_link_libraries(MQTTTest PUBLIC paho-mqtt3a)
target_link_libraries(MQTTTest PUBLIC paho-mqttpp3)
target_include_directories(MQTTTest PUBLIC
"${PROJECT_BINARY_DIR}"
"${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.c/src"
"${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.cpp/src")
get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
message("Top-level include dirs = ${inc_dirs}")
It is a bit of a hack, but you can use the fact that the CMake find_* commands don't perform a search if the result variable is already set.
From the paho.mqtt.cpp/src/CMakeLists.txt file we find that the output variable for find_library is called PAHO_MQTT_C_LIB and the include directory is expected to be in PAHO_MQTT_C_INC_DIR, which in the original CMakeLists.txt from version 1.0.0 (which seems to be the version you're using) is itself computed from PAHO_MQTT_C_PATH.
Setting these two variables between the two add_subdirectory calls should then make this work:
add_subdirectory(paho.mqtt.c)
set(PAHO_MQTT_C_LIB paho-mqtt3a)
set(PAHO_MQTT_C_PATH "${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.c")
add_subdirectory(paho.mqtt.cpp)
This makes use of the fact that target_link_libraries can be called both with library files (which is what the original paho.mqtt.cpp project expected) and with existing CMake targets (which is what we replaced it with). Linking to a CMake target also automatically introduces a build-order dependency, so this simultaneously ensures that the c library is built before the cpp library.
However, since this relies on the names of the variables used in the paho.mqtt.cpp project as well as the target name of the library target in the paho.mqtt.c project this can break any time you update one of these libraries to a newer version.
I am trying to create a simple CMake that retrieves the DLLs of Qt and copy it in the directory in which cmake creates my executable.
It works great using g++ or clang, but MSVC (Visual Studio 2017) creates a Debug or Release directory.
I can't find a way to retrieve the path to the real directory in which the executable is written (${CMAKE_CURRENT_BINARY_DIR} returns the directory parent of Release or Debug).
I've seen people using the target property RUNTIME_OUTPUT_DIRECTORY but it is empty when I use it.
Any idea how I can do this ? I do not want to change the output directory, I just want to know its path (so I do not want to change the value of RUNTIME_OUTPUT_DIRECTORY)
Thanks!
In Visual Studio, during configuration step (when CMakeLists.txt files are processed) build type is not set, so no build-type-dependent variable or property is usable directly. Instead, generator-expressions should be used.
E.g., output directory for executable or library target can be extracted with $<TARGET_FILE_DIR:tgt> generator expression. It will return full directory, with "Release/" or "Debug/" already appended.
Note, that generator expressions can be used only when their usage is explicitly allowed in documentation. E.g., they cannot be used in message() command.
Alternatively, you may explicitely set variable CMAKE_RUNTIME_OUTPUT_DIRECTORY, so for every build type will just append appropriate subdirectory to it. But for extracting this subdirectory, you should again resort to generator expressions: $<CONFIG>.
Technically, it is possible to set the same output directory for any build type. But this is not recommended, because a file from one build type will be overwritten by the file from another build type.
Example for Visual Studio 2022 and CMake.
Place this at the end of CMakeLists.txt:
if (WIN32)
add_custom_command(
TARGET qcpp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/include/external/c.dll" "${CMAKE_BINARY_DIR}"
COMMAND_EXPAND_LISTS
)
endif()
See list of CMake variables.
Note the "qcpp" in the preceding command. This is the project name and should match this line at the start:
project ("qcpp")
Appendix A - Testing
To verify, if you generate a Visual Studio Project using mkdir x && cd x && cmake .., you can see that CMake has added a post-build step to the solution config:
As of CMake 3.21+, the $<TARGET_RUNTIME_DLLS:tgt> generator expression can help copy dependent DLLs to the build tree. Quoting the documentation:
List of DLLs that the target depends on at runtime. This is determined by the locations of all the SHARED and MODULE targets in the target's transitive dependencies. Using this generator expression on targets other than executables, SHARED libraries, and MODULE libraries is an error. On non-DLL platforms, it evaluates to an empty string.
This generator expression can be used to copy all of the DLLs that a target depends on into its output directory in a POST_BUILD custom command.
Docs link: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS
An example of how to use this (adapted from the docs) follows:
find_package(foo REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE foo::foo)
if (WIN32)
add_custom_command(
TARGET main POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:main> $<TARGET_FILE_DIR:main>
COMMAND_EXPAND_LISTS
)
endif ()
The if (WIN32) check ensures that $<TARGET_RUNTIME_DLLS:main> won't be empty, which would cause the command to fail (rather than do nothing). COMMAND_EXPAND_LISTS makes sure that the semicolon-delimited list returned by $<TARGET_RUNTIME_DLLS:main> will be split into multiple arguments, rather than passed as a single argument with (escaped) semicolons in it.
Note also that UNKNOWN libraries will be ignored by this generator expression. These are common when using the built-in Find modules, rather than using a library's first-party CMake config-mode package. In these cases, you will have to manually inspect the module variables to find the library paths and add custom commands for each one yourself.
For Qt specifically, I would expect the newer CMake integration in Qt6 to "just work", though I haven't tested it. It might also work in Qt5, but again I haven't tested it.
I have a custom Manifest file and would like to embed it inside the executable. I use MS Visual Studio 2010 compiler and Qt 5.2.1.
I use Qt Creator as the IDE and CMake for making release builds.
What options should I set in .pro and CMake files?
I tried to pass '/MANIFEST...' like flags to the linker, but they seem to be unsupported by VS 2010 linker.
Eventually I've found the solution.
First it is necessary to add the following line to the .pro file:
CONFIG -= embed_manifest_exe
this will disable embedding of the default manifest file. After that it is necessary to add a windows resource file:
RC_FILE = app_resources.rc
.rc file is usually included to embed version information into .exe, but as soon as manifest is also a part of the executable resources we could reference a custom manifest file in it, just add the following line into app_resources.rc:
1 24 myapp.exe.manifest
where 1 is the resource ID, 24 is the resource type - RT_MANIFEST, and myapp.exe.manifest is the file with our custom manifest.
If you don't need version info then app_resources.rc may contain just this single line.
That's it.
For CMake the steps are as follows:
1) include app_resources.rc in the list of sources of the target
2) add the following line to disable embedding of a default manifest file:
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST:NO")
For some unknown for me reasons /MANIFEST:NO didn't work in .pro file. The linker failed with an unknown option error. However it works in CMake. The linker is the same from VS 2010...
Using below qmake script based manifest injection you do not need to include the manifest in any *.rc file (works for MakeFile based compile where qmake does generate the MakeFile)
QMAKE_MANIFEST = $$PWD/x86_user.manifest.xml
Note:
this works even if we have set the RC_FILE = Res.rc (i.e. since this takes action and injects the manifest to .exe after the compile is done)
you need to recompile to see effect...
I can't help you with the qmake side, but for CMake, you should be able to just list the manifest file as one of the sources of the target. This requires CMake 3.4 or later (see release notes).
I compiled a library using the MinGW toolchain provided with Qt 5.0.2 on Windows. As a result I received a library.so file. First I failed using the library in a Qt application, but now I found out that everything works fine when I make a copy of the liblibrary.so file and call it liblibrary.dll or liblibrary.lib (which is the only file ending supported by the add library wizard in QtCreator).
Now I wonder if this is normal or if I should change something in order not to have both files (which are exact copies). Leaving one away makes the application crash during start up. I added the library as follows to my Qt pro file:
LIBS += -L"../path/to/library" -llibrary
INCLUDEPATH += $$quote(../path/to/library)
EDIT: I compiled the library using the MinGW of Qt, not as Qt project but using mingw32-make and the provided Makefile. As a result I get the liblibrary.so.
EDIT: It seems to work also when renaming the copy to liblibrary.dll instead of .lib. But still, I need two files to make the application work -- the .so and the .dll.
Chris
That's weird, I think you should get a *.a and *.dll files when building a shared lib with MinGW on Windows, as said in the documentation:
In windows, MinGW will output .a and .dll, MSVC2010 will ouput .lib and .dll. In linux, MinGW will output .so, .so.1, .so.1.0 and .so.1.0.0 – .lib, .a and .so are import libraries.
You definitely shouldn't rename your file!
Be careful to:
not to include the "lib" prefix after "-l" in your project file.
put everything after after "-l" in lower case as you're on Windows
not adding any extension to your library name after "-l"
add and reference the .h file used in your library
A real example using QtWebsocket lib:
INCLUDEPATH += "$${PWD}/include/"
LIBS += -L"$${PWD}/libs/" -lqtwebsocket
...
HEADERS += ... \
$${PWD}/include/QWsSocket.h \
...
In my include/ folder, I have the following file:
QWsSocket.h (taken from original project - required)
In my libs/ folder, I have the following file:
libQtWebsocket.a
QtWebsocket.dll
Edit: I struggled with this too initially. Have you tried to build your lib as a static lib instead (CONFIG += staticlib in your library project)? This might help you getting you *.pro file right before switching to using the shared library.
Edit 2: Ok, the fact that you get a *.so file is still a bit odd. In this question
the user has the same issue as you and keep both files, which is just a workaround. According to a later answer it seems that you need to modify your makefile to generate a file with the proper extension. Maybe this will help: http://www.mingw.org/wiki/sampleDLL