Newbee here on QT creator and CMake and apologies for the basic question but struggling to link simple external library to my main project. Here are the project paths:
build-QMLTest-Desktop_Qt_6_3_1_MinGW_64_bit-Debug // application binary path
QMLLib
build-mylib-Desktop_Qt_6_3_1_MinGW_64_bit-Debug // lib binary path
mylib
CMakeLists.txt
mylib.cpp // lib source path
mylib.h
QMLTest
CMakeLists.txt
main.cpp // application source path
Here is my how I am trying to link the static library (snipped of QMLTest/CMakeLists.txt). I am using this thread as reference:
How do I explicitly specify an out-of-tree source in CMake?
add_subdirectory(../QMLLib/mylib ../QMLLib/build-mylib-Desktop_Qt_6_3_1_MinGW_64_bit-Debug)
target_link_libraries(mylib)
set(PROJECT_SOURCES
main.cpp
qml.qrc
)
main.cpp
#include "../QMLLib/mylib/mylib.h"
int main(int argc, char *argv[])
{
Mylib mylib;
Yet, it won't resolve, here is the output
C:/Qt/Tools/mingw1120_64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/QMLTest.dir/main.cpp.obj: in function `qMain(int, char**)':
C:/myroot/UITest/QMLTest/main.cpp:13: undefined reference to `Mylib::Mylib()'
collect2.exe: error: ld returned 1 exit status
I could not get an answer, so 50 points for grabs, since I cannot resolve this issue.
Ideally if you can point me out to recent project using CMake and QT Creator 8.0 making a simple project and library and link them together, it would be great.
At first, try to separate the directories to add in the add_subdirectory command arguments to be sure that everything within the library subdirectories is compiled. Then use target_link_libraries command properly:
add_subdirectory(../QMLLib/mylib)
set(PROJECT_SOURCES
main.cpp
qml.qrc
)
include_directories(../QMLLib/mylib/include)
# Link subdir target AFTER definition of the project target
add_library(myproject ${PROJECT_SOURCES})
target_link_libraries(myproject mylib)
I suggest you refer to the actual CMakeLists.txt file I used when importing my library into the existing project (despite being ROS-based, CMake works the same way). Just extract the sequence of commands from there.
I ended up re-arranging the folders and the solution is here:
Cannot add library source to cmake project on QT
where I just include the sources from a separate library project
Related
I am learning CMake but unfortunately most examples are either too simple, too complicated or the folder structure is different to what I'm designing.
I am getting an error but first I will explain the folder structure (please do critique):
MyProject
bin
build
src
ComponentA
ObjectA.cpp
CMakeLists.txt
ComponentB
ObjectB.cpp
CMakeLists.txt
CMakeLists.txt
main.cpp
CMakeLists.txt
I would like to be able to include some files using their absolute path, for example main.cpp might look like this:
#include <ComponentB/ObjectB.h>
int main()
{
ComponentB cb(1, 2, 3);
}
but within a source file I'd like to include it's header using the relative path:
#include <ComponentB.h>
ComponentB::ComponentB(int a, int b, int c) : _ca(a, b){}
(if this causes problems I can include using absolute paths)
My CMakeLists files look like:
MyProject/CMakeLists.txt:
cmake_minimum_required(VERSION 3.9.1)
project(MyProject)
add_subdirectory(src)
MyProject/src/CMakeLists.txt:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_ROOT_DIR}/bin)
add_executable(MyProject main.cpp)
add_subdirectory(ComponentA)
add_subdirectory(ComponentB)
MyProject/src/ComponentA/CMakeLists.txt:
target_sources(MyProject PUBLIC ComponentA.cpp)
MyProject/src/ComponentB/CMakeLists.txt:
target_sources(MyProject PUBLIC ComponentB.cpp)
target_include_directories(MyProject PUBLIC ComponentA)
However when I do:
cd build
cmake ..
I get this this error:
CMake Error at src/ComponentA/CMakeLists.txt:2 (target_sources):
Cannot specify sources for target "MyProject" which is not built by
this project.
CMake Error at src/ComponentB/CMakeLists.txt:2 (target_sources):
Cannot specify sources for target "MyProject" which is not built by
this project.
CMake Error at src/ComponentB/CMakeLists.txt:3 (target_include_directories):
Cannot specify include directories for target "MyProject" which is not
built by this project.
The ability for target_sources to add source files via relative path to a target in a different directory was added in CMake 3.13. Since you have specified a minimum version of 3.9.1, this will simply not work.
The policy in question is CMP0076, which is documented as follows:
New in version 3.13.
The target_sources() command converts relative paths to absolute.
In CMake 3.13 and above, the target_sources() command now converts relative source file paths to absolute paths in the following cases:
Source files are added to the target's INTERFACE_SOURCES property.
The target's SOURCE_DIR property differs from CMAKE_CURRENT_SOURCE_DIR.
It is the second bullet point that applies here.
You really ought to use a newer version of CMake. Anything more than a few versions behind the newest (3.23) is plain masochism.
I have a cmake project with many libraries (standalone additional packages) which are build within my project and then my project is linked against them.
If i have the following ...
CMakeLists.txt (1)
main.cpp
main.hpp
library/CMakeLists.txt (2)
library/dummy.cpp
library/dummy.hpp
... add have "add_definitions(-DMYDEF=15)" inside the library cmakelists (2). Can i somehow make this available to main.cpp and main.hpp, so they "see" the macro definition which is made inside the lib at preprocessing?
So not only sources/headers within the lib shall work with my definition but also any other dependency, like the main project with main.cpp/main.hpp
Yes, there is a way; use target_compile_definitions(mylib PUBLIC MYDEF=15) for your library, instead of add_definifions(-DMYDEF=15). That way all other targets that are linked against mylib will inherit compile definitions from mylib
Please note that target_compile_definitions should be added after the target is created, otherwise, you will receive the error.
Correct usage would be as follows:
#add library first
add_library(mylib)
#compile definitions for the target mylib
target_compile_definitions(
mylib
PUBLIC
MYDEF=15
)
More about the subject might be found in cmake documentation for target_compile_definitions
I'm currently struggling with cmake.
I'm using Cmake for an embedded platform with GCC.
My project is separate into several modules. Each module is build into a static library. At link time, all of these libraries are collected and linked into one binary.
The problem: I created a new folder for some unit tests. All sources are build into a library libunit_tests.a.(I checked the library actually gets created).
However in my linker call other libraries are passed to the linker, mine however gets omitted resulting in an undefined reference error.
My folder structure looks like this
*
unit_tests/
*
unit_tests/inc
*unit_tests/src
There is one Cmake file located at
- /unit_tests/CMakeLists.txt
My actual CMakeLists.txt file is pretty basic
include_directories("./inc")
set(module_name "unit_tests")
set(MODULE_SOURCES
./inc/active_tests.h
./inc/Run_All_Tests.h ./src/Run_All_Tests.c
)
###########################
# add library
###########################
if(MODULE_SOURCES)
# add files to library
add_library("${module_name}"
${MODULE_SOURCES})
target_link_libraries("${module_name}"
-Wl,--start-group
-Wl,--end-group)
endif()
How do i pass this library to the linker to resolve the undefined reference error?
I thought this is done via add_libary and target_link_libraries?
I'm building a dynamic library that is meant to be loaded dynamically like a plugin. When present, the library is loaded. When not present, it can't.
Naturally, I made a test app...and it doesn't work.
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
PROJECT(MYLIB)
enable_testing()
INCLUDE(CPack)
SET(SRCS
src/source1.cpp
src/source2.cpp
)
ADD_LIBRARY(mylib SHARED ${SRCS})
ADD_SUBDIRECTORY(test)
test/CMakeLists.txt
ADD_EXECUTABLE(test_loader main.c)
TARGET_LINK_LIBRARIES(test_loader dl)
ADD_TEST(NAME test_loader COMMAND test_loader)
test/main.c
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
void* handle;
handle = dlopen("./mylib.so", RTLD_LAZY);
if (handle == 0)
{
fprintf(stderr, "%s\n", dlerror());
}
return 1;
}
and then to build
mkdir build
cd build
cmake ..
make
The result is that there is a mylib.so file in /build. There is a test_loader executable in /build/test.
And this doesn't work out.
What I need is for there to be a copy of mylib.so under /build/test/ so that I can dynamically load it with the test app.
While the answers given helped me greatly (and anyone reading this should review those answers as well as the comments), I found an even better solution:
add_custom_command(TARGET test_loader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:mylib>" $<TARGET_FILE_DIR:test_loader>)
This solution results in two copies of the library. One copy is next to the test_loader, so that the unit tests can work. The other is in the default output location. Since it's still in the default output location, other projects that depend on mylib know where to find them, by default.
There are cmake variables that let you control where libraries, shared libraries, and executables are placed. See cmake documentation Variables that Control the Build. I do not think it is a good idea to mix executables and libraries. (Of course this is my opinion--you can use whatever layout you want.) I use the following:
# Directory for output files
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
CACHE PATH "Output directory for static libraries.")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
CACHE PATH "Output directory for shared libraries.")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
CACHE PATH "Output directory for executables and DLL's.")
If you used this, then you would need to adjust your dlopen statement to handle = dlopen("../lib/libmylib.so", RTLD_LAZY); Note that I adjusted the name of mylib because I believe cmake will, by default on Linux, use a lib prefix when naming libraries.
I am new to ROS (Indigo), and I want to write a C++ program to use the MoveIt! package.
However, I am confused as to what I need to have in my CMakeLists.txt file, such that the header and library files can be found.
For example, here is the file so far:
cmake_minimum_required(VERSION 2.8.1)
project(MicoMoveIt)
set(CMAKE_CXX_FLAGS "-std=c++11")
file(GLOB srcs *.cpp)
include_directories(/opt/ros/indigo/include)
link_directories(/opt/ros/indigo/lib)
add_executable(${PROJECT_NAME} ${srcs})
And my main.cpp file is:
#include <ros/ros.h>
#include <moveit/move_group_interface/move_group.h>
int main()
{
moveit::planning_interface::MoveGroup group("right_arm");
return 0;
}
But compiling this gives me the error:
/opt/ros/indigo/include/moveit/robot_model/joint_model.h:47: error: Eigen/Geometry: No such file or directory
#include <Eigen/Geometry>
^
So, I need to specify where to find these Eigen header files. But given that Eigen is a dependency of MoveIt!, then I shouldn't have to manually include all these header file directories.
How should I be writing the CMakeLists.txt file so that all header and library directories of dependencies are included?
Try with this changes:
cmake_minimum_required(VERSION 2.8.3)
project(<project_name>)
set(CMAKE_CXX_FLAGS "-std=c++11")
find_package(catkin REQUIRED COMPONENTS
<other_packages_you_need>
moveit_ros_planning_interface
)
catkin_package(CATKIN_DEPENDS)
include_directories(include ${catkin_INCLUDE_DIRS})
set(BINNAME <executable_name>)
set(SOURCES <cpp_source_files>)
add_executable (${BINNAME} ${SOURCES})
target_link_libraries(${BINNAME} ${catkin_LIBRARIES})
The key factor for your problem is the inclusion of package moveit_ros_planning_interface in the find_package() directive. Everytime you have to build some code, you have to add every package dependancies to your project (in this case you need the moveit interface package). Notice that the package.xml file plays a crucial role too.
Lastly you have to tell the linker to retrieve and link the libraries you are using in your project. To do so use target_link_libraries() and the useful catkin_LIBRARIES variable which almost does what you expected (you could manually add libraries, but it could be messy in big projects).
Have a look here and here for more info.
EDIT: in this case you do not need the link_directories() directive, which has to be used only when the linker has to know where to retrieve the external library.