I need to resolve a simple issue with a test project. However despite my attempts to look at stack overflow I cannot resolve it. The toy project has one main CMakeLists and two sub-folders. One mathlib and one is a unittest.
CMakeLists.txt
├───QTMathLib
└───QTUnitTest
the sources:
testmathlib.cpp
#include "testmathlib.h"
#include <QDebug>
TestMathLib::TestMathLib()
{
qDebug() << __FILE__ <<" Created!";
}
int32_t TestMathLib::Add(int32_t a, int32_t b)
{
return a+b;
}
tst_testadd.cpp
void TestAdd::initTestCase()
{
TestMathLib testMathLib;
int32_t result = testMathLib.Add(10, 20);
qDebug() << "Result =" << result ;
QVERIFY(30 == result);
}
However I want the UnitTest project to include the mathlib sources as below:
Add library to Cmake project
I tried this:
set (sources2
../QTMathLib/testmathlib.cpp
)
add_executable(TestAdd
tst_testadd.cpp
)
add_library( mylib ${sources2} )
add_test(NAME TestAdd COMMAND TestAdd)
target_link_libraries(TestAdd PRIVATE Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Test
Qt${QT_VERSION_MAJOR}::Core
mylib)
But this always give me a building error since I cannot resolve QDebug.h header file. Notice that other includes may be added, so don't just patch for the QDebug.h, assume any QTCore header can be included in the future.
D:\gmmo\qt_qml\QTTest\QTMathLib\testmathlib.cpp:2: error: QDebug: No such file or directory
D:/gmmo/qt_qml/QTTest/QTMathLib/testmathlib.cpp:2:10: fatal error: QDebug: No such file or directory
2 | #include <QDebug>
| ^~~~~~~~
The fix should be on these files, not the source file itself.
└───QTUnitTest\CMakeLists.txt
├───QTMainApp\CMakeLists.txt
Any clues why it cannot file QT headers?
thank you #273K for the help, this worked:
target_link_libraries(mylib PRIVATE
Qt${QT_VERSION_MAJOR}::Core)
target_link_libraries(TestAdd PRIVATE
mylib
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Test)
Adding two target_link_libraries.
Related
I want to build a simple application based on a .cpp and a .h file.
I couldn't make my project work so i started from a basic example but didn't succeed as i'm just starting creating project in Linux. From what i've seen, my CMakeLists should be like this :
My CMakeLists.txt :
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 11)
project(test C CXX)
add_executable(${PROJECT_NAME} main_new.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR})
My main_new.cpp :
#include <read.h>
int main(int argc, char* argv[])
{
int a, b, c, d, e = 0;
std::cout << "hello im example " << std::endl;
read_int(&a, &b, &c, &d, &e);*
return 0;
}
My read.h :
#ifdef __cplusplus
extern "C" {
#endif
int read_int(int *vectorA, int *vectorB, int *matrixA, int *matrixB, int *flags);
#ifdef __cplusplus
}
#endif
My .cpp and .h file are in the same folder. cmake . is giving me no error, but after using make i get
main_new.cpp:(.text+0x68) : undefined reference to « read_int »
I'm using the makefile created by the cmake command. Should i create a custom makefile ?
Edit : Added question :
I also have to implement .so files, but doing target_link_libraries(test ${CMAKE_SOURCE_DIR}/libA.so ${CMAKE_SOURCE_DIR}/libB.so) in my CMakeLists.txt file doesn't work. How can i link these libraries to my executable ?
This is my C++ code:
#include "stdlib.h"
#include "stdio.h"
#include <iostream>
int main(int argc, char *argv[] ) {
int width, height;
unsigned char *rgba;
FILE *fp = fopen("/home/pic.tif", "rb");
if(!fp)
std::cout<<"failed"<<std::endl;
rgba = floadtiff(fp, &width, &height);
fclose(fp);
if(rgba == 0)
printf("TIFF file unreadable\n");
}
I am using this library by #MalcolmMcLean, and that's what my loadtiff.c is.I have compiled it using gcc and am trying to link that library.
This is my CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.12.2)
project (test)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} cmake/)
add_executable(test tiffs.cpp)
target_link_libraries(test loadtiff)
and these are the errors I get when trying to make the program:
error: ‘floadtiff’ was not declared in this scope
Why can't I access this function, which is defined in loadtiff.c?
In tipps.cpp add:
extern "C" {
#include "loadtiff.h"
}
In CMakeLists.txt change to:
cmake_minimum_required(VERSION 2.8.12.2)
project(tiffs)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} cmake/)
add_library(loadtiff tiffloader/loadtiff.c)
target_include_directories(loadtiff PUBLIC tiffloader/loadtiff.h)
add_executable(tiffs tiffs.cpp)
target_link_libraries(tiffs loadtiff)
where "tiffloader/" is wherever you put the "loadtiff" files.
Do not name projects or targets after reserved words like "test", or you will get CMake warnings.
So you've got 2 problems.
1) your code is an abhorrent mixture of C and C++. For example, you're outputting text using C++
std::cout<<"failed"<<std::endl;
and C
printf("TIFF file unreadable\n");
Pick just one language and stick to it. Given it appears that floadtiff is expecting a FILE *, you'll probably be better off writing your code in C.
2) You're trying to use a library without telling the compiler anything about it. That's what header files are for. They tell the compiler you're using code from a different file and how the functions in that file are called. There should be a "loadtiff.h" file somewhere - you need to include that. That will contain definitions for the functions inside "loadtiff.c", such as floadtiff.
Without those definitions, your compiler has no idea if you're passing in the right number and/or type of parameters to those functions. It doesn't know what the return type of the function is or if it doesn't have one.
In C++ this information is especially important as you have function overloading, so it has to know exactly which function you're calling. In C, it's not quite so rigid and will make assumptions - which are often incorrect - about the function, but it will still warn you that it's done this.
If I use the following source
#include <cstdlib>
#include <cstdio>
#include <iostream>
extern "C" {
#include "loadtiff.h"
}
int main(int argc, char argv[] ) {
int width, height;
unsigned char* rgba;
FILE* fp = fopen("/home/user/pic.tif", "rb");
if(!fp)
std::cout << "failed" << std::endl;
rgba = floadtiff(fp, &width, &height);
fclose(fp);
if(rgba == 0)
printf("TIFF file unreadable\n");
return 0;
}
with the following CMakeLists.txt file under Visual Studio 14 and CMake 3.8.2
cmake_minimum_required(VERSION 2.8.12.2)
project (test)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} cmake/)
add_executable(test tiffs.cpp)
add_library(loadtiff STATIC loadtiff.c)
target_link_libraries(test loadtiff)
CMake generates a fully functional solution and Visual Studio is able to build it without errors.
Edit:
I assumed you have tiffs.cpp, loadtiff.c and loadtiff.h located in the same directory.
Here is the cmake file that i am using
cmake_minimum_required (VERSION 3.0)
project (midasd)
set (midas VERSION_MAJOR 0)
set (midas VERSION_MINOR 0)
set (midas VERSION_REVISION 1)
find_library(libconfig libconfig)
add_executable(midasd src/main.cpp)
target_link_libraries(midasd "${libconfig_LIBS}")
The problem i am facing is undefined reference for config_init. The main function is as follows
#include <libconfig.h>
int main(int argc, char *argv[])
{
midas::midasCtx *container = new midas::midasCtx(argc,argv);
config_t cfg;
config_init(&cfg);
return 0;
}
Where am i going wrong with CMAKE ?
Actually the libconfig is recognized as simply -lconfig not -llibconfigin linking argument. The CMakeLists.txt should contain
target_link_libraries(my_project config)
Source
This manual(https://hyperrealm.github.io/libconfig/libconfig_manual.html) says " To link with the library, specify ‘-lconfig++’ as an argument to the linker. "
So I fixed like following code and build was completed.
target_link_libraries(my_project config++)
I’m new to cmake.
I want to create code to create instances of some classes (like ClassA) and collect them in a handler class. For this i have created a template class Creator.
In each class implementation a instance of this class is created with Creator class. (see ClassA.cpp line 8)
I have following folder structure
├── CMakeLists.txt
├── main.cpp
└── SubFolder
├── ClassA.cpp
├── ClassA.h
├── CMakeLists.txt
└── Creator.h
./main.cpp
#include <iostream>
#include "SubFolder/ClassA.h"
int main(int argc, char **argv) {
//classA a;
std::cout << std::endl << "Hello, world!" << std::endl;
return 0;
}
./CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(teststaticcmake)
add_executable(teststaticcmake main.cpp)
add_subdirectory(SubFolder)
target_link_libraries(teststaticcmake SubFolder)
install(TARGETS teststaticcmake RUNTIME DESTINATION bin)
SubFolder/ClassA.h
#ifndef __CLASSA__
#define __CLASSA__
class classA
{
public:
classA();
};
#endif //__CLASSA__
SubFolder/ClassA.cpp
#include "ClassA.h"
#include "Creator.h"
classA::classA()
{
}
classA* pClassA = Creator<classA>::create();
SubFolder/Creator.h
#ifndef __CREATOR__
#define __CREATOR__
#include <iostream>
template<typename T>
class Creator
{
public:
static T* create()
{
T* p = new T();
// Do Something here
// ... like output
std::cout << std::endl << "created: " << p;
return p;
}
};
#endif //__CREATOR__
SubFolder/CMakeLists.txt
add_library(SubFolder ClassA.cpp)
I compile this project and run it. So I get only the output "Hello, world!".
When I remove the comment (main.cpp line 5) a instance of ClassA is used. So I get also the output of class Creator. The code for ClassA is linked.
When I move the class ClassA to root directory it works also.
I have also tried to use parameters like PUBLIC_LINK, debug and general for target_link_libraries. But nothing works.
My intention use a Collection Class in this main.cpp file and get the instanced object from the collection. In the main.ccp file i don't want to know each instanced class because all class ClassA ... ClassZ have the same interface (not shown in this example).
How can i force the link of "unused" code?
Edit: Do don't know if it's neccessary. I use KDevelop4.
See How to force gcc to link an unused static library
I've tested your code with GNU 4.8.1 compilers and in your example just replace your target_link_libraries() line with:
target_link_libraries(
teststaticcmake
PRIVATE
"-Wl,--whole-archive"
SubFolder
"-Wl,--no-whole-archive"
)
From target_link_libraries() documentation:
A link flag: Item names starting with -, but not -l or -framework, are treated as linker flags. Note that such flags will be treated like any other library link item for purposes of transitive dependencies, so they are generally safe to specify only as private link items that will not propagate to dependents.
More References
How to force inclusion of an object file in a static library when linking into executable?
I'm having problems to compile my code, that links with POCO C++ libraries, to create a shared library for Linux (Mint 13, just in case). This is my reduced environment.
I have these 3 files:
IL_Notify.h
#ifndef __IL_NOTIFY_H__
#define __IL_NOTIFY_H__
#include <string>
#include "Poco/Logger.h"
#include "Poco/LogStream.h"
using Poco::Logger;
using Poco::LogStream;
namespace mynamespace
{
// Get logger. Inherits root channel
LogStream lstr(Logger::get("MyLogger"));
// From any other class, call logger this way:
//lstr << "This is a test" << std::endl;
}
#endif
IL_Class1.cpp
#include "IL_Class1.h"
#include "IL_Notify.h"
namespace mynamespace {
void IL_Class1::foo()
{
// Stuff...
lstr << "This is a test msg from IL_Class1::foo" << std::endl;
}
}
IL_Class2.cpp
#include "IL_Class2.h"
#include "IL_Notify.h"
namespace mynamespace {
void IL_Class2::bar()
{
// Stuff...
lstr << "This is a test msg from IL_Class2::bar" << std::endl;
}
}
IL_Class1 and IL_Class2 are declared at IL_Class1.h and IL_Class2.h. No inclussion of IL_Notify.h inside those headers.
And this is my CMakeLists.txt file
# Set search path to find PocoConfig.cmake
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${CMAKE_SOURCE_DIR}/cmake/Modules/)
# Look for needed packages
find_package(Poco REQUIRED)
# Now, we can use poco
include_directories(
${Poco_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Libraries which we are linking against
link_directories(
${Poco_LIBRARY_DIRS}
)
# Get all the cpp files to build my library
file(GLOB_RECURSE all_sources
${CMAKE_CURRENT_SOURCE_DIR}/src/IL_Class1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/IL_Class2.cpp
)
# Library creation
add_library(mylib SHARED ${all_sources})
I can execute cmake successfully, to create the Makefile. But when I run make, I get this error
CMakeFiles/mylib.dir/src/IL_Class2.cpp.o:(.bss+0x0): multiple definition of `mynamespace::lstr'
CMakeFiles/mylib.dir/src/IL_Class1.cpp.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [libmylib.so] Error 1
make[1]: *** [CMakeFiles/mylib.dir/all] Error 2
make: *** [all] Error 2
So, even when I'm preventing headers to be included twice, via #ifndef, make can't compile my code because a symbol declared in that header is detected twice. Why?
After seeing my question is duplicated, I got the right solution.
My IL_Notify.h
#ifndef __IL_NOTIFY_H__
#define __IL_NOTIFY_H__
#include <string>
#include "Poco/Logger.h"
#include "Poco/LogStream.h"
using Poco::Logger;
using Poco::LogStream;
namespace openil
{
// Get logger. Inherits root channel
extern LogStream lstr;
}
#endif
My new IL_Notify.cpp
#include "IL_Notify.h"
namespace openil
{
// TODO: More flexibility here: more channels, different formatting...
// Maybe a IL_Utils function should do that
// Get logger. Inherits root channel
LogStream lstr(Logger::get("OpenILLogger"));
// From any other class, call logger this way:
//lstr << "This is a test" << std::endl;
}