I have decided to make a C++-Qt-GUI for a C program (both languages I don’t know), using KDevelop, which in turn uses CMake.
The C source has no header, so I made one, and migrated some structs into it, as well as the declaration of the only function in the C source i need to call.
The problem is that I can’t call it, because either CMake doesn’t find the C file (and hence the definition), or, when I add the C source to my source set in the CMakeLists.txt, it complains that both my main.cpp and the C source file have main functions.
How do I tell CMake that it should only make the function from the C file available which I declared in the header?
here is it:
project(oregengui)
cmake_minimum_required(VERSION 2.6)
find_package(Qt4 REQUIRED)
include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
set(oregengui_SRCS oregengui.cpp main.cpp qrangeslider/qrangeslider.cpp)
#as soon as i add oregengui/oregengui.c, it won’t work because of the main function
qt4_automoc(${oregengui_SRCS})
add_executable(oregengui ${oregengui_SRCS})
target_link_libraries(oregengui ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
PS: I don’t want to change the C source too much, since it is a independant project. I guess the developer will accept the introduction of the header, but not much more.
Try compiling C file as library and linking it with executable.
add_library(clib oregengui/oregengui.c)
[...]
add_executable(oregengui ${oregengui_SRCS})
target_link_libraries(oregengui ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} clib)
I'm a bit rusty on this, but could you do something along the lines of:
In oregengui.c
#if !defined MYGUIPROJ
int main() {
...
}
#endif
In your CMakeLists that you want both in:
add_definitions( -DMYGUIPROJ )
The compiler should then ignore your second main function.
Your program cannot contain two main functions at the same time. Just try to rename the main function in the C file you included to your project. This is not a big change to the source, but you will have to do it locally.
if your C program has a main function, then it can be executed independently. So why not use the QProcess::execute() method to invoke the application from qt and get the output?
Related
So from what I understand, a static compiled mylib.a file should just be usable as plug-and-play. But I can't use it without the source code, I'm trying to avoid that.
I adapted this tutorial to compile using CMake with the following directory structure:
/
lib
libmy_math.a
main.cpp
my_math.h
my_math.cpp
CMakeLists.txt
The contents of the files are exactly as in the tutorial. The only added file is CMakeLists.txt which basically just runs the library compiling part before building:
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(Test)
### Uncomment this ONCE to compile a libmy_math.a file
# add_library(my_math STATIC my_math.cpp)
add_executable(Test main.cpp)
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
As the CMake file says, uncommenting Line 5 compiles the library, which is then linked to my code when compiling.
I'm trying to package my code so that I don't show my client the source code for the compiled library (my_math), but if I delete the my_math.h and my_math.cpp files, I get a "file not found" error on import:
/Users/Joe/Desktop/Test/main.cpp:1:10: fatal error: 'my_math.h' file not found
#include "my_math.h"
^~~~~~~~~~~
I thought you could compile libraries without needing the source code. What am I missing here?
A static library does not contain each and every definition a header can contain - think of macros, etc. Thus you still need the header. However, you don't need the .cpp anymore to link the library.
Besides the problem stated in Iorro's answer the find_library call here will not work as expected.
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
What this does is, while running CMake, look for the my_math.a file. However, at that point of the build process, my_math.a has not been built yet. You're just running CMake for the first time, so all you have is source files. Nothing has been compiled yet.
What you want to do instead is link to the library target directly, as CMake already knows about that and can resolve the dependency on its own. So you need to replace the two lines above with:
target_link_libraries(Test PUBLIC my_math)
This now introduces a curious asymmetry in how your test consumes the library (as it is part of the same build) vs. how your clients consume the same library (which are not part of the same build and thus need to do a find_package call before they can use it). Look at CMake's config-file packages for a mechanism that allows you to restore symmetry here, at the cost of a significant amount of boilerplate required in your CMake script.
I've already looked at this SO answer but I cannot seem to find the solution for my case.
I just started working in C++ and CLion. I did a basic test project that includes a header file and the main function then executes a method from the included class - all working just fine, CLion compiler is MinGW.
Now the real project I need to work on integrates a SDK from a vendor written in C++. They do have examples as well. Every time I run them, CLion breaks the build and complains about undefined references... the include file paths are all correct and CMakeList.txt looks like this:
project(test_2)
include_directories("../libraries/bin/headers/")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_EXE_LINKER_FLAGS "")
set(PROJECT_HEADERS
"../libraries/bin/headers/SDK.h"
"test.h"
)
set(PROJECT_SOURCES
main.cpp
)
add_executable(test_2 ${PROJECT_SOURCES} ${PROJECT_HEADERS})
the first undefined reference that is listed is the constructor of the SDK class, which is written simply as:
class SDK{
...
SDK();
...
}
Any suggestions what the problem is ?
Because of the current situation I cannot reach anybody on their end, so I thought I ask here...
Thanks !
Solution:
the solution was to compile the libs from the .cpp file an make a clean CMakeList file referencing those libs, this then resolved the undefined reference errors.
I'm not fluent in CMake - but you probably have to also link libraries/directories using something like target_link_libraries()/target_link_directories() if using external SDK. Seems to me that you simply tell the compiler "hey, here is my SDK header, do something" but compiler doesn't know where are the symbols for this SDK defined. Here is a little bit of an explanation what is the basic difference between the two, but I recommend checking CMake documentation directly.
c̛̣o̢̥m̯͕̖̠̙͡p͕̭͚͓̮̲ḭ͓͇͔̟̫l̪͈i͉̟̜̺͖͓͉n̮̻̼g͎̩̳̯ ̻̯̹̦̱̠̀w͕̬̜i̖̭̣th̹̠̕ C̙M̩a̲̮̹͉̻̥̥ķ͕̤̭̠͚e̩̙̼ ̫̮is̻̗͈͓͟ f̧̮͓̦u͏̯ͅń̹̣
I have no clue how the library that you're using is designed, but if there is no definition of the constructor in the header file, it is clearly not header-only. So you either have to link to that library, or add its implementation file (if you have one) to your project so linker gets what you promised. I suggest to look at target_link_libraries to see how to link in CMake (there are more ways to do it though).
Undefined reference error generally means that linker did not find something that was advertised in a header.
the solution was to compile the libs from the .cpp file an make a clean CMakeList file referencing those libs, this then resolved the undefined reference errors.
I'm (cross-)compiling a shared C library with support for many different platforms which is handled by an hierarchy of CMakeLists files. In those files, several platform specific compiler flags are conditionally produced (with add_definitions()). I can successfully compile and link the source code leading to an appropriate .so file.
But to use the library in any project, I need to provide the right header files, too. The following install command of CMake selects the right header files to copy but does not apply the replacement of preprocessor defines/includes:
install(FILES ${headers} DESTINATION include/mylibrary)
So how can I generate/install the "post-compiled" header files?
What I thought of so far:
As add_definitions() should stack my -D's in the COMPILE_DEFINITIONS variable, maybe running a foreach loop on the copied raw headers and replace the define/include placeholders?
Using add_custom_command() to apply some logic before copying?
Edit: As pointed out by Tsyvarev, there is an answer quite near to my needs here, but unfortunately not quite it. In summary, the answer gives 2 options:
Include a special 'config' header in all of the library's headers and leverage the cmakedefine command to call configure_file() on this header. I can't use this approach because I don't want to alter the library headers.
Create a target-specific .cmake file which helps external projects in including the right headers together with all necessary -D defines. I can't use this approach either, because my external projects do not use cmake for building. Plus, I wish to create a library that is as easy to include as possible.
Any other thoughts?
Edit 2: I may have to elaborate on my statement, that the install command of CMake is not replacing defines. Take the following example:
//sampleheader.hpp
#ifndef SAMPLEHEADER_HPP_
#define SAMPLEHEADER_HPP_
#include OS_SPECIFIC_HEADER
//...
Now I have a CMakeLists.txt file that does something like this:
# ...
if (${OS} MATCHES "arm-emblinux")
add_definitions(-DOS_SPECIFIC_HEADER="emblinuxHeader.hpp")
elseif (${OS} MATCHES "linux")
add_definitions(-DOS_SPECIFIC_HEADER="linuxHeader.hpp")
endif()
# ...
Everything compiles fine, but when the install command above gets called, I have a header file in my ../include/ directory still with OS_SPECIFIC_HEADER placeholder in it. And of course, this cannot be properly included in any development project.
I am trying to compile some Qt project, including the QCustomPlot library. As a minimum example, i set up a project consisting of:
qcustomplot.h
qcustomplot.cpp
CMakeLists.txt
../cmake/QCustomPlot.cmake
The original project is bigger, but the problem is already reproducible with only those files.
The CMakeLists.txt contains this code:
cmake_minimum_required(VERSION 3.6)
set(CMAKE_AUTOMOC ON)
include(../cmake/QCustomPlot.cmake)
function(findqt) #(1)
find_package(Qt5Core)
find_package(Qt5Gui)
find_package(Qt5Widgets)
find_package(Qt5PrintSupport)
endfunction() #(1)
findqt() #(1)
#find_package(Qt5Core) #(2)
add_library(
Plots
src/qcustomplot.h
src/qcustomplot.cpp
)
function(linkqt) #(3)
qt5_use_modules(Plots Core Gui Widgets PrintSupport)
endfunction() #(3)
linkqt() #(3)
If either all lines marked (1) or all lines marked (3) are commented out, that means calling find_package() or qt5_use_modules() at file scope, i get a project containing the two qcustomplot files and an additional Plots_automoc.cpp. The additional file is autogenerated and contains the necessary #include "moc_qcustomplot.cpp" and the project compiles and links properly.
However as soon as i move all qt related commands into functions, the automoc.cpp file is no longer generated and no longer part of the project, which leads to quite a few unresolved external symbol during linking.
Calling only a single find_package() on files scope (like line (2)) resolves the issue and generates the automoc file again.
Why does simply moving the calls into a function change the automoc behaviour like this and how can i achieve to still move them into functions?
A little bit background: I already have quite a few targets in my project, expect the number to grow rapidly and want to avoid code redundancy. Also people not really trained with CMake are supposed to use it. Thats why i'm trying to move all those Qt related commands into functions and provide a command like this:
add_my_target(
targetName
SOURCES qcustomplot.h qcustomplot.cpp
QT Core Gui Widgets PrintSupport
BOOST filesystem
)
With the exception of Qt, i already achieved this...
I also tried using
target_link_libraries(${projectName} ${Qt5_Core_LIBRARIES} ...
//or
target_link_libraries(${projectName} Qt5::Core ...
it leads to the same result, as long as not at least one find_package() call is directly on files scope, no automoc is generated.
I am using CMake 3.6.2, Qt 5.7, Visual Studio 2015 and Win 10.
Additional example
oLen got most of my underlying confusion sorted out with his answer, but one case remains:
cmake_minimum_required(VERSION 3.6)
set(CMAKE_AUTOMOC ON)
function(doit) #(4)
find_package(Qt5Core)
add_library(
Plots
qcustomplot.h
qcustomplot.cpp
)
qt5_use_modules(Plots Core Gui Widgets PrintSupport)
endfunction() #(4)
doit() #(4)
Using the lines marked with (4) to put all the generation of the target into a function allows CMake to run properly, i.e. qt5_use_modules() is defined, able to find all the modules and link them (e.g. include directories are set properly). Nowhere outside the function do i rely on variables set by any of the Qt functions. But still automoc does not generate the needed .cpp file. Commenting the marked lines out runs automoc again.
The problem is that CMake functions introduce a scope, so that the variables defined in the find_package are not available outside the function.
An easy solution to your problem is to use CMake macros - you can think of them as the CMake equivalent of C macros. The variables declared there will also be available outside the macro scope.
In your case, this means replacing function by macro and endfunction by endmacro.
In essence I want to be able to moc header files that are not part of any target in cmake with the additional difficulty that I don't know the filenames of those headers.
The actual project is quite complex and part of an automated build system. The following is an easy example.
Consider a project structured like this:
CMakeLists.txt
src/lib/source.cpp
src/lib/CMakeLists.txt
src/include/some_header.hpp # which is included in source.cpp
Content of main CMakeLists.txt:
cmake_mimimum_required(VERSION 2.8.6)
project("automoctest")
add_subdirectory(src/lib)
Content of src/lib/CMakeLists.txt:
include_directories(${CMAKE_HOME_DIRECTORY}/src/include)
find_package(Qt4 4.8 REQUIRED QtCore)
include(UseQt4)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library(foo SHARED source.cpp)
target_link_libraries(foo ${QT_LIBRARIES})
set_target_properties(foo PROPERTIES AUTOMOC true)
Inside source.cpp the file some_header.hpp is included like this:
#include "some_header.hpp"
The Problem:
The file some_header.hpp includes a Q_OBJECT and has some signals, so moc needs to work its magic. But as the header is not inside the actual project the header will not get mocked. I don't even know the filename of some_header.hpp so I can't add it specifically to be mocked. Obviously AUTOMOC does not check the include_directories for mockable files even when a source file includes one of them.
What I tried (unsuccessfully):
use #include moc_some_header.cpp in source.cpp as it is described in the cmake documentation. This leads to an error in which cmake complains that it could not find some_header{.h,.hpp,.hxx,.H}
setting CMAKE_AUTOMOC_RELAXED_MODE to true. Even though it's not clear from the doc what this actually does. Made no difference anyway.
setting AUTOMOC_MOC_OPTIONS to -Isrc/include or -I/path/to/project/src/include or -I${CMAKE_HOME_DIRECTORY}/src/include Doesn't do anything that I could see.
The great thing about AUTOMOC is that I don't need to know which files actually need to be mocked. In this case however I would need to know all the headers that might have a Q_OBJECT inside, that are included by my source files.
Is there a way to tell AUTOMOC where exactly to look for mockable files?
Did you truly set AUTOMOC_MOC_OPTIONS to -Isrc/include, or to -I/path/to/myproject/src/include? The former probably doesn't exist.
I have always used the MOC macros; it looks like AUTOMOC is something new that is built into CMake.
I usually include all headers when creating a library or executable - i.e.
add_library(foo SHARED source.cpp ../include/some_header.hpp )
I assume that this will allow AUTOMOC to work. It will have the added benefit of causing make to work as expected - rebuilding your library when the header changes.
If you are truly unable to add the file to the add_library command ahead of time, then I think you'll have to write a cmake function to search for #include statements within source.cpp, locate those files, and search them for Q_OBJECT. If they match, add them to a variable - perhaps EXTRA_MOCS. Then, the add_library line becomes
add_library(foo SHARED source.cpp ${EXTRA_MOCS} )