CMake complains about debug library not found when building release - cmake

I'm waiting for the debug version of the library from an external source, they have delivered the release version already.
We use a Find... module to locate the library. This now results in something like:
optimized;libfoo.a;debug;foo-NOTFOUND
The CMakeLists.txt file:
...
add_executable(main main.c)
target_link_libraries(main ${foo})
Initiating the build with:
cmake source/dir -DCMAKE_BUILD_TYPE=Release
But cmake still complains about the debug library missing.
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
foo
linked by target "main" in directory source/dir
Is this the expected behaviour? Can I avoid this problem without changing our Find module or force setting the foo variable before each use?

I've given it a try and you can't suppress this error. Looking at the responsible source code cmGlobalGenerator::CheckTargetProperties() this check is only skipped with INTERFACE link libraries (which you obviously don't want since it would not link anything to main).
But you can declare a placeholder IMPORTED library of the name causing the error like:
add_library(foo-NOTFOUND STATIC IMPORTED)
To reproduce your problem and test the fix I've setup the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.3)
project(FooNotFound)
cmake_policy(SET CMP0057 NEW)
set(foo "optimized;libfoo.a;debug;foo-NOTFOUND")
file(WRITE main.c "int main(void) { return 0; }")
if ("foo-NOTFOUND" IN_LIST foo)
add_library(foo-NOTFOUND STATIC IMPORTED)
endif()
add_executable(main main.c)
target_link_libraries(main INTERFACE ${foo})

Related

Linking against GTest fails

I have the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)
# adding library
set(ST_SRC simple_tree.cpp)
add_library(st ${ST_SRC})
target_include_directories(st PUBLIC ${PROJECT_SOURCE_DIR}/include/data_structures/simple_tree/)
# adding googletest
set(GOOGLETEST_PATH ~/local/googletest)
set(GTEST_INCLUDE_DIR ~/local/include/)
set(GTEST_LIBRARY ~/local/lib/)
set(GTEST_MAIN_LIBRARY ~/local/lib/)
find_package(GTest REQUIRED)
# adding tests
set(TEST_TARGET test_simple_tree)
add_executable(${TEST_TARGET} test_simple_tree.cpp)
target_include_directories(${TEST_TARGET}
PUBLIC
${PROJECT_SOURCE_DIR}/include/data_structures/simple_tree
${GOOGLETEST_PATH}
${GTEST_INCLUDE_DIR})
target_link_libraries(${TEST_TARGET} PUBLIC st)
target_link_libraries(${TEST_TARGET} PUBLIC gtest gtest_main)
Basically, I've installed googletest into my home directory rather than system-wide.
The find_package() command apparently succeeds. However, trying to build test_simple_tree fails with:
/usr/bin/ld: cannot find -lgtest
/usr/bin/ld: cannot find -lgtest_main
Inside this CMakeLists.txt, how else can I tell the linker to look elsewhere
for the gtest?
EDIT: After reading the docs, I've fixed the Gtest issue as described below. However, the following issue cropped up: CMake imported target includes non-existent path
If find_package() was successful in finding the GTest includes/libraries, it should populate targets for you, per the CMake FindGTest documentation:
This module defines the following IMPORTED targets:
GTest::GTest:
The Google Test gtest library, if found; adds Thread::Thread automatically
GTest::Main:
The Google Test gtest_main library, if found
You should use these in your target_link_libraries() command instead. Also, CMake will populate GTEST_INCLUDE_DIRS, but the GTest include directories should be pulled in from the imported targets mentioned above.
Another important note: I'm not sure if you posted all of your CMake code, but I don't see a project() call in your code. As a result, the ${PROJECT_SOURCE_DIR} variable may not be what you expect. In general, it is good practice to declare your project with project() at the top of your CMake.
Your CMake file with these modifications could look something like this:
cmake_minimum_required(VERSION 3.15)
project(simple_tree_example)
set(CMAKE_CXX_STANDARD 17)
# adding library
set(ST_SRC simple_tree.cpp)
add_library(st ${ST_SRC})
target_include_directories(st PUBLIC
${PROJECT_SOURCE_DIR}/include/data_structures/simple_tree/)
# adding googletest
set(GOOGLETEST_PATH ~/local/googletest)
set(GTEST_INCLUDE_DIR ~/local/include/)
set(GTEST_LIBRARY ~/local/lib/)
set(GTEST_MAIN_LIBRARY ~/local/lib/)
find_package(GTest REQUIRED)
# adding tests
set(TEST_TARGET test_simple_tree)
add_executable(${TEST_TARGET} test_simple_tree.cpp)
target_include_directories(${TEST_TARGET}
PUBLIC
${PROJECT_SOURCE_DIR}/include/data_structures/simple_tree
${GOOGLETEST_PATH})
target_link_libraries(${TEST_TARGET} PUBLIC st GTest::GTest GTest::Main)
Targets gtest and gtest_main are created only when GTest is used via add_subdirectory() approach.
When use GTest via find_package(), one need to use either IMPORTED targets GTest::GTest and GTest::Main, or variables GTEST_LIBRARIES and GTEST_MAIN_LIBRARIES correspondingly. This is described in the documentation:
find_package(GTest REQUIRED)
...
target_link_libraries(test_simple_tree PUBLIC GTest::GTest gtest_main)
or
find_package(GTest REQUIRED)
...
# That case we need to add include directories
target_include_directories(test_simple_tree ${GTEST_INCLUDE_DIRS})
target_link_libraries(test_simple_tree PUBLIC ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})

CMake and Ninja - "missing and no known rule to make it"

I have this CMakeLists.txt file:
cmake_minimum_required(VERSION 3.8)
include(${CMAKE_CURRENT_SOURCE_DIR}/src/Something.cmake)
add_executable(execute main.cpp)
add_dependencies(somethingInterface Something)
add_dependencies(execute somethingInterface)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_compile_options(execute
PRIVATE
-std=c++11
-g
)
add_library(library SHARED IMPORTED)
set_target_properties(library PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/library.so)
target_link_libraries(execute
PRIVATE
library
)
The library shared imported will be created in file Something.cmake, but tt must be built first.
It was a add_custom_command(TARGET POST_BUILD...) in file Something.cmake.
I don't have any problem in using CMake builds here, but when I am using Ninja there an error.
ninja: error: 'library.so', needed by 'execute', missing and no known rule to make it
Or do you have any suggestion on how can you do this?
I think Ninja has a requirement that "library.so" must exist first, but CMake it is different. It checks whether the library is there at runtime.
There is indeed a divergence between the way Make and Ninja handle imported targets. What works with Make, may sometimes not work with Ninja.
In particular, the following lines of code work with Make, but not with Ninja:
ExternalProject_Add(extProject
GIT_REPOSITORY <GIT_URL>
CMAKE_CACHE_ARGS "-
DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_INSTALL_PREFIX}"
)
add_library(extLib SHARED IMPORTED)
add_dependencies(extLib extProject)
set_target_properties(extLib
PROPERTIES IMPORTED_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/libext.so
)
target_link_libraries(project extLib)
The CMake configure step will work fine, but at build time Ninja will complain:
ninja: error: '/path/to/libext.so', needed by 'project', missing and no known rule to make it
But this will work fine with Make.
You need to specify the library as a byproduct of the ExternalProject_Add comment as mentioned by Tsyvarev, as ExternalProject runs at build time.
The following works fine for me:
ExternalProject_Add(extProject
GIT_REPOSITORY <GIT_URL>
CMAKE_CACHE_ARGS "-
DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_INSTALL_PREFIX}"
BUILD_BYPRODUCTS ${CMAKE_INSTALL_PREFIX}/lib/libext.so
)
add_library(extLib SHARED IMPORTED)
add_dependencies(extLib extProject)
set_target_properties(extLib
PROPERTIES IMPORTED_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/libext.so
)
target_link_libraries(project extLib)

CMake library not found

I try to run the makefile that using cmake produced. It generate an error
ld: library not found for -lhello
clang: error: linker command failed with exit code 1 (use -v to see invocation)
the file directory is:
the cmakelists.txt is:
the main.c file is:
the ERROR:
I think I set the right directory. How to solve this ERROR?
CMake has a system if you want to link libraries. For many standard libraries we have cmake modules which will allow you to use the find_package command. This will set some variables for include directories and libraries. If there is no such thing for your library you can use find_path for the include files and find_library to search for a library.
Here is what you could do (untested, just out of my head):
add_executable(main main.c)
target_include_directories(
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC ${CMAKE_SOURCE_DIR}/include/hello
)
find_library (
HELLO_LIB
NAMES hello libhello # what to look for
HINTS "${CMAKE_SOURCE_DIR}/lib" # where to look
NO_DEFAULT_PATH # do not search system default paths
)
# check if we found the library
message(STATUS "HELLO_LIB: [${HELLO_LIB}]")
if (NOT HELLO_LIB)
message(SEND_ERROR "Did not find lib hello")
endif
target_link_libraries(main
${HELLO_LIB}
)
Use message to debug your cmake files. If you define the library in cmake as well you can link directly against the cmake target.
When your library isn't in a standard path liking /usr/lib, you should use link_directories() in your CMakeLists.txt to specify a non-standard library path which contains your library. Notice that you MUST put your link_directories() ahead of add_executable() as the following shows:
link_directories(../../lib)
add_executable(newhello main.c)
include_directories(../../include)
target_link_libraries(newhello hello)

cmake doesn't support imported libraries?

When I try to import a library using
add_library(libname SHARED IMPORTED)
set_property(TARGET libname PROPERTY IMPORTED_LOCATION /<foldername>/<sub-foldername>/lib")
The cmake shouts :
CMake Warning (dev) at /CMakeLists.txt:28
(target_link_libraries): Cannot specify link libraries for target
"libname" which is not built by this project.
CMake does not support this but it used to work accidentally and is
being allowed for compatibility.
Policy CMP0016 is not set: target_link_libraries() reports error if
only argument is not a target. Run "cmake --help-policy CMP0016"
for policy details. Use the cmake_policy command to set the policy
and suppress this warning. This warning is for project developers.
Use -Wno-dev to suppress it.
If this is true, what is the other best way to include a library somewhere in my build tree into another project.
I have a library setup and another place has executable which will be using the libraries.
Reading through the cmake documentation, it felt like this would be the best way forward but seems its a broken piece which is just being supported.
Cannot specify link libraries for target "libname" which is not built by this project
When you use target_link_libraries to some target you're specifying how to build it,
but imported library is already build. CMake told you that...
Example of linking imported target to executable:
add_library(boo SHARED IMPORTED)
set_target_properties(boo PROPERTIES IMPORTED_LOCATION "/path/to/boo/library")
add_executable(foo foo.cpp)
target_link_libraries(foo boo)
Note: using imported targets
I was getting the same error as navderm when trying to import the Poco C++ libPocoFoundation.so library into my project, and after trying different solutions unsuccessfully, I managed to find one that worked for me:
cmake_minimum_required(VERSION 3.5)
project(MyProject)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_library(PocoLib SHARED IMPORTED GLOBAL)
# It's important to specify the full path to the library you want to import
set_target_properties(PocoLib PROPERTIES IMPORTED_LOCATION "/usr/local/lib/Poco_1.7.2/lib/libPocoFoundation.so")
# create my executable
set(EXEC_SOURCE_FILES main.cpp)
add_executable(MyProject ${EXEC_SOURCE_FILES})
target_link_libraries(MyProject PocoLib)

How do I tell CMake to link in a static library in the source directory?

I have a small project with a Makefile which I'm trying to convert to CMake, mostly just to get experience with CMake. For purposes of this example, the project contains a source file (C++, though I don't think the language is particularly relevant) and a static library file which I've copied from elsewhere. Assume for argument's sake that the source code to the library is unavailable; I only have the .a file and the corresponding header.
My handmade Makefile contains this build rule:
main: main.o libbingitup.a
g++ -o main main.o libbingitup.a
which works fine. How do I tell CMake to reproduce this? Not literally this exact makefile, of course, but something that includes an equivalent linking command. I've tried the obvious but naive ways, like
add_executable(main main.cpp libbingitup.a)
or
add_executable(main main.cpp)
target_link_libraries(main libbingitup.a)
as well as various things with link_directories(.) or add_library(bingitup STATIC IMPORTED) etc. but nothing so far that results in a successful linkage. What should I be doing?
Version details: CMake 2.8.7 on Linux (Kubuntu 12.04) with GCC 4.6.3
CMake favours passing the full path to link libraries, so assuming libbingitup.a is in ${CMAKE_SOURCE_DIR}, doing the following should succeed:
add_executable(main main.cpp)
target_link_libraries(main ${CMAKE_SOURCE_DIR}/libbingitup.a)
If you don't want to include the full path, you can do
add_executable(main main.cpp)
target_link_libraries(main bingitup)
bingitup is the same name you'd give a target if you create the static library in a CMake project:
add_library(bingitup STATIC bingitup.cpp)
CMake automatically adds the lib to the front and the .a at the end on Linux, and .lib at the end on Windows.
If the library is external, you might want to add the path to the library using
link_directories(/path/to/libraries/)
I found this helpful...
http://www.cmake.org/pipermail/cmake/2011-June/045222.html
From their example:
ADD_LIBRARY(boost_unit_test_framework STATIC IMPORTED)
SET_TARGET_PROPERTIES(boost_unit_test_framework PROPERTIES IMPORTED_LOCATION /usr/lib/libboost_unit_test_framework.a)
TARGET_LINK_LIBRARIES(mytarget A boost_unit_test_framework C)
I want to add to the other comments, the project name is the first argument. I had a project called cmakecompile and i wanted to add libusb to it, the code is as follows,
add_executable(cmakecompile main.c)
target_link_libraries(cmakecompile "D:/msys2/mingw64/lib/libusb-1.0.a")
the project had just only a main.c file, the first parameter in target_link_libraries is the name of your project and the second parameter is the path of the library.
Note that may help: Since i am compiling under windows, i had to install msys2 because the library you have has to be compiled with the same compiler. For example if you get libusb and try to use it in a qt-creator project, it will not work and you may get unreferenced functions, therefore i had to install msys2 and install libusb from inside msys2, install make and create a QT Cmake project and compile from Qt creator using the msys2 make.
The full cmakelists.txt is as follow
cmake_minimum_required(VERSION 3.5)
project(cmakecompile LANGUAGES C)
add_executable(cmakecompile main.c)
target_link_libraries(cmakecompile "D:/msys2/mingw64/lib/libusb-1.0.a")