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?
Related
I have git cloned, built (with MSVC for both Debug and Release) and then installed wxWidgets:
cmake -B build wxWidgets
cmake --build build --config <CONFIG>
cmake --install build --prefix my_install --config <CONFIG>
with <CONFIG> = Debug and <CONFIG> = Release.
Then I used the following CMake script to link against it, as suggested by the wiki:
cmake_minimum_required(VERSION 3.16)
project(Test)
add_executable(Test WIN32 Main.cpp)
# wxWidgets
SET(wxWidgets_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/my_install)
find_package(wxWidgets COMPONENTS core base REQUIRED)
include(${wxWidgets_USE_FILE})
target_link_libraries(Test PRIVATE ${wxWidgets_LIBRARIES})
# Copy runtime DLLs to the directory of the executable.
add_custom_command(TARGET Test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Runtime Dlls: $<TARGET_RUNTIME_DLLS:Test>"
)
My goal is to automatically copy the DLLs into the directory of the built executable, so that they can be found at runtime. For that I'm using the TARGET_RUNTIME_DLLS generator expression (follwing the sample code in the docs). In the code above, I only print out the expression at build time for testing purposes. The problem is that it is empty.
The approach worked for me before when installing and linking SDL, but SDL provides package configuration files which create imported targets, defining the DLL location(s) via IMPORTED_LOCATION_RELEASE or IMPORTED_LOCATION_DEBUG. For wxWidgets one is apparently supposed to use the FindwxWidgets.cmake script shipped with CMake, which sadly doesn't define the produced binaries. Maybe that's why TARGET_RUNTIME_DLLS isn't populated.
Does anyone know, either how to get TARGET_RUNTIME_DLLS filled or how to obtain the list of built wxWidgets DLLs for the current configuration (Release/Debug) post build copying?
Thanks a lot in advance!
I am dealing with a similar problem.
First sanity checks:
You have to work on windows platform otherwise this feature does not
work.
Your Cmake is 3.21 or above
Next comes fuzzy part. I think the library that you are trying to include have to be a Shared Imported library and you have to set a set_target_properties for IMPORTED_IMPLIB which is a path to a .lib file of sort (dll import library, I think it is called) So you have to make sure that it is all set in the package library that you trying to link with your executable.
If you have those dll avaiable and you just want to use them and not actually build them then you can write your own cmake script that will do just what I said above. Then you can include that cmake file in your project and then link against your app.
Note: I also work on similar issue right now and what I just said have not been working very reliably. I got some dlls to be copied and some do not.
Edit:
Cmake docs give a more detailed explanation on how this library setting should look like if you use find_package feature.
Found here: https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries
An UNKNOWN library type is typically only used in the implementation
of Find Modules. It allows the path to an imported library (often
found using the find_library() command) to be used without having to
know what type of library it is. This is especially useful on Windows
where a static library and a DLL's import library both have the same
file extension.
I would like to use the Antlr framework in a project. I'm using CMake to build the project.
I would like to use the SHARED library version of Antlr, not the STATIC one. Its CMake file contains targets for both.
Antlr's github site explicity tells me to use the following code:
find_package(antlr4-runtime REQUIRED)
# add runtime include directories on this project.
include_directories( ${ANTLR4_INCLUDE_DIR} )
# add runtime to project dependencies
add_dependencies( Parsertest antlr4_shared )
# add runtime to project link libraries
target_link_libraries( Parsertest PRIVATE
antlr4_shared)
(another target, antlr4_static, exists, but shouldn´t be used.)
I copied it exactly like this and am getting the following error:
CMake Error at /usr/lib64/cmake/antlr4-runtime/antlr4-targets.cmake:82 (message):
The imported target "antlr4_static" references the file
"/usr/lib/libantlr4-runtime.a"
but this file does not exist.
I dont have the static library installed in my system as I have no intention of using it. Still, how do I make CMake stop looking for the wrong target in the first place? I use it nowhere in my CMakeLists.txt file and am puzzled by this behavior.
I am trying to get a project running that is using dynamic openCASCADE libraries.
So first i set up a minimal test project using the following CMake file:
...
include_directories(/home/user/occt/build_r/include/opencascade/)
add_executable(testOCCT
main.cpp
step2stl.cpp
)
find_package(OpenCASCADE REQUIRED NO_DEFAULT_PATH)
set(OCCT_LIBS TKMesh; TKSTEP; TKSTL; TKXSBase; TKernel)
target_link_libraries(testOCCT ${OCCT_LIBS})
This is working as it should.
Now i want to link the same libraries to another library that is used in a larger project.
For the project there are 3 CMake files, one for the project and two subdirectory, one for the executable one for the myLib, which are added by add_subdirectory().
In the CMake file for myLib which is inside one of the subdirectories I've added:
...
include_directories(/home/user/occt/build_r/include/opencascade/)
...
add_library(${MY_LIB_NAME} SHARED ${my_sources})
find_package(OpenCASCADE REQUIRED NO_DEFAULT_PATH)
set(OCCT_LIBS TKMesh; TKSTEP; TKSTL; TKXSBase; TKernel)
target_link_libraries(${MY_LIB_NAME} ${OCCT_LIBS})
so basically the same as in the test project.
However now I get an error (at runtime):
symbol lookup error: myLib.so: undefined symbol: _ZN24BRepMesh_IncrementalMeshC1ERK12TopoDS_Shapedbdb
Ok, so i found the problem myself. The reason it did not work was not because of CMake, but that there was some other version of the libraries installed over the packet manager, which then got loaded instead of the right one.
purging those libs solved the problem.
However what I still don't get is why it loaded the correct library version on the test project and the wrong on the other (both tested on the same machine)
I am specifying a shared library build from source files in my CMakeLists.txt file like so:
# Library setup
file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Source/*.cpp)
file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Source/*.h)
Inside the source directories contain all my .h and .cpp files required to build my shared library. So I then do something like this:
add_library(mylibrary SHARED ${SOURCES} ${HEADERS} )
I also link a bunch of other .libs with mylibrary later on as well (Could there be a clashing issue?). The problem arises when I try to build mylibrary. I receive linking errors such as:
Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol __imp_cosf mylibrary ***.obj 1
even though the symbol is defined in my source files that I have included. I am not exactly sure what to do in order to properly let my project find those symbols. The funny thing is is that when I build as a static library it is fine. However, when I try to build as a dynamic library, these errors appear.
So, I'm not exactly sure why this worked. But there was a conflict warning between linking to MSVRCT and libcmt. It said something like this in the output log:
Resolving LNK4098: defaultlib 'MSVCRT' conflicts with ...
This is because libcmt is a static library for release build and uses \MT flags. MSVRCT is a release DLL version and compiled with \MD flag. Because of this conflict, I had to change my compiler flags to be:
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
Then the symbols were able to be found. If anyone has any comments/corrections to why this worked please add.
I am working on a larger C++ library that is using CMake and depends on Qt.
We moved from Qt4 to Qt5 and now I encounter a problem when using our lib
in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:
https://github.com/philthiel/cmake_qt5_upstream
It contains two separate CMake projects:
MyLIB: a tiny library that uses QString from Qt5::Core.
It generates and installs package configuration files
MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake
in order to be searchable by CMake find_package()
MyAPP: a tiny executable depending on MyLIB
The project uses find_package(MyLIB) and creates an executable that uses MyLIB
The problem is that CMake gives me the following error message when configuring the MyAPP project:
CMake Error at CMakeLists.txt:11 (add_executable):
Target "MyAPP" links to target "Qt5::Core" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.
Now, I simply can resolve this by using
find_package(Qt5Core 5.X REQUIRED)
in the MyAPP project.
However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?
The CMake docu on package file generation
https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?
Best,
Philipp
[edit of the edit] Full Source Example
You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).
Tip, use the ECM cmake modules to ease the creation of that:
find_package(ECM REQUIRED NO_MODULE)
include(CMakePackageConfigHelpers)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX ATCORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
SOVERSION 1
)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
and the KF5AtCoreConfig.cmake.in:
#PACKAGE_INIT#
find_dependency(Qt5Widgets "#REQUIRED_QT_VERSION#")
find_dependency(Qt5SerialPort "#REQUIRED_QT_VERSION#")
find_dependency(KF5Solid "#KF5_DEP_VERSION#")
include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")
This will generate the correct FindYourSortware.cmake with all your dependencies.
[edit] Better explanation on what's going on.
If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)
Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.
find_package(Qt5 REQUIRED COMPONENTS Core)
then you link your library with
target_link_libraries(YourTarget Qt5::Core)