How to compile a c file with Qt and CMake? [duplicate] - qt

I have worked on a project where I was using g++ to compile C code in files that end in .c. The reason is that I'm told that g++ has better warning messages.
I am switching the build process for this project to use CMake. I found that initially CMake wanted to use gcc to compile C files. This failed because of things like declaring variables at use time. So I tried to use g++ to compile C files by using the setting
set(CMAKE_C_COMPILER_INIT g++)
in the CMakeLists.txt file. But this results in the error message:
#error "The CMAKE_C_COMPILER is set to a C++ compiler"
I have been renaming my .c files to .cpp to fix this problem as that seems to be the easiest way for me to make things work, and perhaps the best way too. But I was wondering if it is possible to force CMake to use g++ to compile C files.

You should not override the compiler for this purpose. If you really need to compile your C files as C++ then you should teach cmake that your files belong to C++ language:
set_source_files_properties(filename.c PROPERTIES LANGUAGE CXX )

To have cmake treat all C files as C++ files use:
file(GLOB_RECURSE CFILES "${CMAKE_SOURCE_DIR}/*.c")
SET_SOURCE_FILES_PROPERTIES(${CFILES} PROPERTIES LANGUAGE CXX )

If you need to switch the whole project, set it in the project directive:
project(derproject LANGUAGES CXX)

set_source_files_properties
The CMake setting of (my) choice here would be the set_source_files_properties command. https://cmake.org/cmake/help/latest/command/set_source_files_properties.html
set(qpid_dispatch_SOURCES
alloc.c
alloc_pool.c
aprintf.c
amqp.c
atomic.c
# [...]
)
set_source_files_properties(${qpid_dispatch_SOURCES} PROPERTIES LANGUAGE CXX)
add_library(qpid-dispatch OBJECT ${qpid_dispatch_SOURCES})
As described in the linked docs, CMake 3.18 changed the scoped effect of set_source_files_properties. See the DIRECTORY and TARGET_DIRECTORY options. Therefore, to apply source file property recursively to all files in your project, your CMakeLists.txt should look something like this
cmake_minimum_required(VERSION 3.20)
project(qpid-dispatch LANGUAGES C CXX)
# [...]
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(router)
# [...]
file(GLOB_RECURSE CFILES "*.c")
set_source_files_properties(${CFILES}
DIRECTORY src tests router
PROPERTIES LANGUAGE CXX)

Related

How do you build depended-upon libs before the main project with CMake in Qt?

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.

Import CMake Project into an existing QT Project .pro

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

Qt using CMake: ui_mainwindow.h: No such file or directory

I use Qt with CMake because CMake integrates with my team's work easier than my own. I have frequently encountered an error along the lines of
ui_*.h: No such file or directory
Usually when my project already has a ui_*.h file to start with it will just modify that .h file. I do use the below commands in my CMake file, so it should be wrapping my .ui file with the appropriate ui_*.h file.
qt4_wrap_ui (mainwindow mainwindow.ui)
target_linked_library (mainwindow ${QT_LIBRARIES})
But sometimes that doesn't work and I have to completely rebuild the entire ui_*.h file. What am I doing wrong?
For anyone having this problem in the future. I pretty much followed the demo here.
http://doc.qt.io/qt-5/cmake-manual.html
Adding, the following line to the CMakeLists.txt should get rid of this problem.
set(CMAKE_AUTOUIC ON)
From the CMake documentation at
https://cmake.org/cmake/help/v3.0/prop_tgt/AUTOUIC.html
AUTOUIC is a boolean specifying whether CMake will handle the Qt uic code generator automatically, i.e. without having to use the QT4_WRAP_UI() or QT5_WRAP_UI() macro. Currently Qt4 and Qt5 are supported.
One small note, this property is available in CMake versions 3.0.2+. So below that, #rbaleksandar's solution should be more appropriate.
Hope that helps.
The quick solution is to use UIC. In bash navigate to the directory containing your *.ui file and run (for the mainwindow.ui example)
uic mainwindow.ui -o ui_mainwindow.h
and then move the newly generated ui_mainwindow.h file to your build directory.
mv ui_mainwindow.h ../build_Qt_4_8_5-Debug/
You shouldn't see the 'No such file or directory' error anymore and can confidently move on to the many other wonderful errors to find in the world of Qt with CMake.
If I remember correctly you actually have to add your UI files to the add_executable(...) like this:
qt4_wrap_ui(UI_HEADERS mainwindow.ui ...) # Add all UI files here like you've done it
...
add_executable(${PROJECT_NAME} ${SRC} ${UI_HEADERS}) # Add them to the executable
...
After all UI files are actually converted to header and source files, which naturally have to be compiled along with the rest of your code.
Building with CMake seems to have an error in
if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()
remove if in your CMakeLists.txt like this:
set(CMAKE_INCLUDE_CURRENT_DIR ON)
This works in my system with CMake 3.12.1 and Windows 10.
when the ui files are stored in a different location the CMAKE_AUTOUIC_SEARCH_PATHS can be set to include the custom locations so that the CMAKE_AUTOUIC option will find the ui files.
None of the previous answers have helped me.
I tried Ctrl + RMB on #include "./ui_mainwindow.h" in Qt Creator and after that the error did not appear since.
Few details to mention:
set(CMAKE_AUTOUIC ON) was enabled before add_executable()
cmake_minimum_required(VERSION 3.5)
I was using qt6

Qt: mingw compiled library does only work with both library.so and library.lib file present

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

Qmake: Avoid file name conflicts in different folders without introducing libraries

I have a project with some folders which happen to contain source files with the same names.
My source tree looks like this:
project.pro
foo/
conflict.h
conflict.cpp
bar/
conflict.h
conflict.cpp
some.h
other.h
files.h
main.cpp
Per default, qmake generates a Makefile which will produce a build tree like this:
conflict.o
main.o
target
Where conflict.o is the object file resulting for both foo/conflict.cpp and foo/conflict.h.
I can't to change their names because they are generated using an external tool and forcing different file names would imply to change their contents, so this is not an option.
I also don't want to use qmake SUBDIRS template because this would imply that (1) every subdir is built separately as a library and thus very much complicate the overall build process (in my eyes at least) and (2) in the top level directory I can't have any source files. Or am I wrong?
Can't I just tell qmake to write the object files into separate directories within the build directory? So my build tree will look like this:
foo/
conflict.o
bar/
conflict.o
main.o
target
Or are there any other solutions neither requiring to rename the source files nor introducing something complicated like static libraries? I just can't believe that Qt didn't solve this (in my eyes simple) problem for years. (I already hat this problem 4 years ago but could rename the files in that project, while here I can't.)
If it's important: I use Qt 4.8 on both Ubuntu with G++ and Windows with mingw32.
Are you tied to qmake? If not, an alternative could be to use cmake. I just verified your usecase with a simple CMakeLists.txt like
cmake_minimum_required (VERSION 2.6)
project (conflict)
add_executable(conflict foo/conflict.cpp bar/conflict.cpp main.cpp)
which even included a source file in the top level directory (main.cpp). This properly builds the executable - the object files are created in sub directories like
./CMakeFiles/conflict.dir/main.cpp.o
./CMakeFiles/conflict.dir/bar/conflict.cpp.o
./CMakeFiles/conflict.dir/foo/conflict.cpp.o
cmake also includes support for Qt4, to automatically pull in the required include paths and libraries. It might require some effort to migrate from qmake to cmake, but given the requirements you have I would give it a try.

Resources