How to reuse an interface library in another project? - cmake

I want to reuse an interface library in another project. I tried it with:
find_package(mylib CONFIG REQUIRED)
target_link_libraries(project mylib)
Which gives the error:
/usr/bin/ld: cannot find -lmylib
Which I do not understand because I want to use an interface library why there is a linker error?
I made a minimal example of the interface library and the consumer project. Based on this stackoverlow answer
Console output install library:
walde#localhost build]$ cmake .. ; cmake --build . ; sudo cmake --install .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/walde/projects/sandbox/cmake_get_target/myLib/build
-- Install configuration: ""
-- Up-to-date: /usr/local/lib/cmake/mylib/mylibTargets.cmake
-- Up-to-date: /usr/local/lib/cmake/mylib/mylibConfigVersion.cmake
-- Up-to-date: /usr/local/lib/cmake/mylib/mylibConfig.cmake
-- Up-to-date: /usr/local/include
-- Up-to-date: /usr/local/include/calc.hxx
-- Up-to-date: /usr/local/include/calc.cxx
-- Up-to-date: /usr/local/include/CMakeLists.txt
Console output consumer:
[walde#localhost build]$ cmake .. ; cmake --build .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/walde/projects/sandbox/cmake_get_target/use_my_lib_in_another_project/build
Consolidate compiler generated dependencies of target project
[ 50%] Linking CXX executable project
/usr/bin/ld: cannot find -lmylib
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/project.dir/build.make:97: project] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/project.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
[walde#localhost build]$

I want to reuse an interface library in another project. I tried it with:
find_package(mylib CONFIG REQUIRED)
target_link_libraries(project mylib)
Three things:
Absolutely never use target_link_libraries without a visibility specifier.
When exporting targets, always include a namespace (via the NAMESPACE argument to install(EXPORT)) so that the IMPORTED target name contains a :: sigil in it.
For consistency in the build and install trees, create an ALIAS target in the build with the same namespace prefix as your install will have.
The reason for (1) is that no-visibility is not the same as any of simply PRIVATE, INTERFACE, or PUBLIC, and it drops into a weird legacy compatibility mode when the styles are mixed. Absolutely always include the appropriate one of the three.
The reason for (2) is that names that contain :: are always interpreted as CMake targets. That would make the error you observed absolutely impossible. CMake would instead tell you that namespace::mylib doesn't exist and you could correct the typo.
When target_link_libraries gets a name without a :: sigil, it tries to find a target with the same name, but if that fails, then it forwards it on to the compiler driver with the -l flag (or equivalent).
For (3), consistency is nice and this will also help users of add_subdirectory or FetchContent switch between that and find_package more easily.

Related

How to add Ziplib library in Clion on Ubuntu

I'm trying to add ZipLip into my project using Clion on ubuntu, but I have this output:
====================[ Build | TryZip | Debug ]==================================
/home/david/Snap/clion-2019.2.4/bin/cmake/linux/bin/cmake --build
/home/david/CLionProjects/TryZip/cmake-build-debug --target TryZip -- -j 2
[ 13%] Built target bzip2
[ 31%] Built target zlib
[ 83%] Built target lzma
[ 95%] Built target ZipLib
Scanning dependencies of target TryZip
[ 97%] Linking CXX executable ../bin/TryZip
/usr/bin/ld: cannot find -lExternalLibrary/ZipLib
collect2: error: ld returned 1 exit status
CMakeFiles/TryZip.dir/build.make:102: recipe for target '../bin/TryZip' failed
make[3]: *** [../bin/TryZip] Error 1
CMakeFiles/Makefile2:109: recipe for target 'CMakeFiles/TryZip.dir/all' failed
make[2]: *** [CMakeFiles/TryZip.dir/all] Error 2
CMakeFiles/Makefile2:116: recipe for target 'CMakeFiles/TryZip.dir/rule' failed
make[1]: *** [CMakeFiles/TryZip.dir/rule] Error 2
Makefile:131: recipe for target 'TryZip' failed
make: *** [TryZip] Error 2
This is my Cmakefile.txt
cmake_minimum_required(VERSION 3.15)
project(TryZip)
if(BOOST_FILESYSTEM)
include_directories(${BOOST_INCLUDE_DIR})
link_directories(${BOOST_LIB_DIR})
add_definitions(-DUSE_BOOST_FILESYSTEM)
else()
if(MSVC)
add_definitions(-DFILESYSTEM_EXPERIMENTAL)
endif()
endif()
if(BOOST_FILESYSTEM)
if(UNIX)
find_package(Boost COMPONENTS system filesystem REQUIRED)
target_link_libraries(${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY})
endif()
endif()
add_subdirectory(ExternalLibrary/ZipLib)
link_libraries(ExternalLibrary/ZipLib)
include_directories(ExternalLibrary/ZipLib)
set(CMAKE_CXX_STANDARD 17)
add_executable(TryZip main.cpp ExternalLibrary/ZipLib/ZipFile.cpp)
target_link_libraries(TryZip ZipLib)
Can someone help me to solve this please?
My ZipLib folder is in the same folder as my cmakefile.txt file.
The call to link_libraries() appears to accept the wrong arguments in this case. The link_libraries() command takes arguments of existing CMake targets, or library names. It is also redundant with your target_link_libraries() call, as this already links ZipLib to TryZip.
Try removing the call to link_libraries(), as this CMake function is deprecated and its use is highly discouraged. The include_directories() call is similarly deprecated, in favor of the target-specific command, so consider using target_include_directories() instead.
Assuming your added sub-directory ExternalLibrary/ZipLib contains an additional CMakeLists.txt file for configuring the ZipLib target, you should not need to add the ZipFile.cpp file again. If this file is already compiled in the sub-directory into the target ZipLib, you do not need to compile it again into TryZip.
add_subdirectory(ExternalLibrary/ZipLib)
set(CMAKE_CXX_STANDARD 17)
add_executable(TryZip main.cpp)
target_include_directories(TryZip PRIVATE ExternalLibrary/ZipLib)
target_link_libraries(TryZip PRIVATE ZipLib)
EDIT: Based on your feedback, it appears ZipLib also depends on pthread but somehow it is not getting linked correctly. You might try to add the following to your ExternalLibrary/ZipLib/CMakeLists.txt file (if it doesn't already exist), to utilize CMake's FindThreads module:
find_package(Threads REQUIRED)
...
target_link_libraries(ZipLib PUBLIC Threads::Threads)

You have called ADD_LIBRARY for library pugixml without any source files

I am working on quickrank: https://github.com/hpclab/quickrank. when I compile it I get error
cmake .. -DCMAKE_CXX_COMPLIER=/usr/bin/g++ -DCMAKE_BUILD_TYPE=Release
You have called ADD_LIBRARY for library pugixml without any source files. This typically indicates a problem with your CMakeLists.txt file
-- Configuring done
CMake Error: Cannot determine link language for target "pugixml".
CMake Error: CMake can not determine linker language for target: pugixml
CMake Error: CMake can not determine linker language for target: pugixml
-- Generating done
-- Build files have been written to: /home/students/s4438236/quickrank/build_
s4438236#moss:~/quickrank/build_$ make
make[2]: *** No rule to make target `CMakeFiles/pugixml.dir/build'. Stop.
make[1]: *** [CMakeFiles/pugixml.dir/all] Error 2
make: *** [all] Error 2
I do find source file under the lib\pugixml folder, how can I fix this error?
When you call the add_library CMake command, you must provide source files for this target. If we examine the top-level CMakeLists.txt file, we see where the error is occurring:
# external libraries
file(GLOB_RECURSE pugixml_sources ${CMAKE_SOURCE_DIR}/lib/pugixml/src/*.cpp)
add_library(pugixml STATIC ${pugixml_sources})
The CMake error suggests that the pugixml_sources variable is empty, which hints that the /lib/pubixml may have also been empty. If you initially didn't run the git clone command with --recursive, you would not have gotten the pugixml submodule.
Seeing as you said the pugixml sources are now there, I would suggest deleting your CMake cache and the CMake build folder. Running CMake again from scratch will likely allow it to see the pugixml source files.

cmake error with catkin_make, ROS installation

I have created a workspace as catkin_ws. Then, catkin_make was run successful.
After I type catkin_create_pkg ros_basics_tutorials std_msgs rospy roscpp and then the all folders and files created in ros_basics_tutorials folder.
However After this command, I type cd catkin_ws
and then catkin_make
Below error is shown Cmake Error, Could NOT find cpp (missing: cpp_DIR), cmake_check_build_system' failed
Base path: /home/selcuk/catkin_ws
Source space: /home/selcuk/catkin_ws/src
Build space: /home/selcuk/catkin_ws/build
Devel space: /home/selcuk/catkin_ws/devel
Install space: /home/selcuk/catkin_ws/install
####
#### Running command: "make cmake_check_build_system" in "/home/selcuk/catkin_ws/build"
####
-- Using CATKIN_DEVEL_PREFIX: /home/selcuk/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /home/selcuk/catkin_ws/devel;/opt/ros/melodic
-- This workspace overlays: /home/selcuk/catkin_ws/devel;/opt/ros/melodic
-- Using PYTHON_EXECUTABLE: /home/selcuk/python/anaconda2/bin/python2
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/selcuk/catkin_ws/build/test_results
CMake Error: Target gtest has dependency information when it shouldn't.
Your cache is probably stale. Please remove the entry
gtest_LIB_DEPENDS
from the cache.
CMake Error: Target gtest_main has dependency information when it shouldn't.
Your cache is probably stale. Please remove the entry
gtest_main_LIB_DEPENDS
from the cache.
CMake Error: Target gmock has dependency information when it shouldn't.
Your cache is probably stale. Please remove the entry
gmock_LIB_DEPENDS
from the cache.
CMake Error: Target gmock_main has dependency information when it shouldn't.
Your cache is probably stale. Please remove the entry
gmock_main_LIB_DEPENDS
from the cache.
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.14
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~ traversing 2 packages in topological order:
-- ~~ - ros_basics_tutorials
-- ~~ - naoqi_driver
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'ros_basics_tutorials'
-- ==> add_subdirectory(ros_basics_tutorials)
-- Could NOT find cpp (missing: cpp_DIR)
-- Could not find the required component 'cpp'. The following CMake error indicates that you either need to install the package with the same name or change your environment so that it can be found.
CMake Error at /opt/ros/melodic/share/catkin/cmake/catkinConfig.cmake:83 (find_package):
Could not find a package configuration file provided by "cpp" with any of
the following names:
cppConfig.cmake
cpp-config.cmake
Add the installation prefix of "cpp" to CMAKE_PREFIX_PATH or set "cpp_DIR"
to a directory containing one of the above files. If "cpp" provides a
separate development package or SDK, be sure it has been installed.
Call Stack (most recent call first):
ros_basics_tutorials/CMakeLists.txt:10 (find_package)
-- Configuring incomplete, errors occurred!
See also "/home/selcuk/catkin_ws/build/CMakeFiles/CMakeOutput.log".
See also "/home/selcuk/catkin_ws/build/CMakeFiles/CMakeError.log".
Makefile:320: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
Invoking "make cmake_check_build_system" failed
I couldn't solve? How can solve it?
The error was due to anathor project folder which i canceled under the catkin_ws. I deleted it and complied again. The error solved.

CMake: satisfying dependencies when building shared object file (.so) from object file (.o)

I am able to do this without CMake using a handwritten Makefile, like so:
g++ $(CXSCINC) -c -fPIC cellComplex_extern.cpp -o cellComplex_extern.o
g++ $(CXSCINC) -shared -Wl -o cellComplex_lib.so cellComplex_extern.o $(CXSCLIB) -lcxsc
This gets me shared library cellComplex_lib.so, which then gets picked up by ctypes as a dynamically linked library (lib = ctypes.cdll.LoadLibrary('./cellComplex_lib.so') for later use.
My project has moved to CMake as a build system and I am looking to emulate the functionality of my Makefile above.
So far I have discovered the add_library() command for CMakeLists.txt, but the link to the CXSC library is never made (as evidenced by horrible complaining when I run make after cmake.
How can I tell CMake to build cellComplex_lib with the third-party library CXSC?
-- non-working CMakeLists.txt --
add_library(include/python/cellComplex_extern OBJECT
include/python/cellComplex_extern.cpp ${all_headers})
add_library(include/python/cellComplex_lib SHARED
include/python/cellComplex_extern)
target_link_libraries(include/python/cellComplex_lib ${CXSC_LIB_DIR}/libcxsc.a)
Result of running cmake followed by make:
.
.
.
[ 75%] Built target include/python/cellComplex_extern
Linking CXX shared library libinclude/python/cellComplex_lib.dylib
ld: can't open output file for writing: libinclude/python/cellComplex_lib.dylib, errno=2 for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [libinclude/python/cellComplex_lib.dylib] Error 1
make[1]: *** [CMakeFiles/include/python/cellComplex_lib.dir/all] Error 2
make: *** [all] Error 2
I think you need to use target_link_libraries
target_link_libraries(include/python/cellComplex_lib ${CXSLIB})
This is what I use during Win32 development:
link_directories(${LIB_ROOT_DIR}/lib ${LIB_ROOT_DIR2}/lib/morelibs)
add_library(MyDll1 SHARED File1.cpp File2.cpp)
add_library(MyDll2 SHARED File3.cpp File4.cpp)
add_dependencies(MyDll2 Dll1)
target_link_libraries(MyDll2 Dll1 some.lib another.lib)
Here you specify that Dll2 requires Dll1 and two other external lib's.

How to pass a compile flag to cmake initial compiler test?

I'm trying to use CMake for building a project which uses the MSPGCC cross-compiler for a MSP430 microcontroller. To successfully compile any simple program with it, we need to pass a compile flag indicating the target processor, or else it fails like this:
$ msp430-gcc -o test test.c
In file included from test.c:1:0:
/usr/local/lib/gcc/msp430/4.6.3/../../../../msp430/include/msp430.h:813:2: warning: #warning Unable to identify and include MCU header, use -mmcu=MCU [-Wcpp]
/usr/local/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: cannot open linker script file memory.x: No such file or directory
collect2: ld returned 1 exit status
Hence, if I indicate the processor using the -mmcu switch it works fine. The problem is, although I'm already specifying this in my CMakeLists.txt file:
cmake_minimum_required (VERSION 2.6)
project (test-project C)
set (SOURCES
test.c
)
add_executable (test-project ${SOURCES})
set (CPU_FLAG "-mmcu=msp430f148")
set (CMAKE_C_FLAGS ${CPU_FLAG})
set (CMAKE_EXE_LINKER_FLAGS ${CPU_FLAG})
CMake complains the compiler failed the test to compile a simple program, which I bet is happening because it is probably not using the -mmcu switch (note the message about not being able to open linker script file memory.x):
$ cd ~/git/test-project
$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=../msp430.cmake ..
-- The C compiler identification is GNU 4.6.3
-- Check for working C compiler: /usr/local/bin/msp430-gcc
-- Check for working C compiler: /usr/local/bin/msp430-gcc -- broken
CMake Error at /usr/share/cmake-2.8/Modules/CMakeTestCCompiler.cmake:52 (MESSAGE):
The C compiler "/usr/local/bin/msp430-gcc" is not able to compile a simple
test program.
It fails with the following output:
Change Dir: /home/claudio/git/test-project/build/CMakeFiles/CMakeTmp
Run Build Command:/usr/bin/gmake "cmTryCompileExec2889462763/fast"
/usr/bin/gmake -f CMakeFiles/cmTryCompileExec2889462763.dir/build.make
CMakeFiles/cmTryCompileExec2889462763.dir/build
gmake[1]: Entering directory
`/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp'
/usr/bin/cmake -E cmake_progress_report
/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp/CMakeFiles 1
Building C object
CMakeFiles/cmTryCompileExec2889462763.dir/testCCompiler.c.o
/usr/local/bin/msp430-gcc -o
CMakeFiles/cmTryCompileExec2889462763.dir/testCCompiler.c.o -c
/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp/testCCompiler.c
Linking C executable cmTryCompileExec2889462763
/usr/bin/cmake -E cmake_link_script
CMakeFiles/cmTryCompileExec2889462763.dir/link.txt --verbose=1
/usr/local/bin/msp430-gcc
CMakeFiles/cmTryCompileExec2889462763.dir/testCCompiler.c.o -o
cmTryCompileExec2889462763 -rdynamic
/usr/local/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: cannot open
linker script file memory.x: No such file or directory
collect2: ld returned 1 exit status
gmake[1]: Leaving directory
`/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp'
gmake[1]: *** [cmTryCompileExec2889462763] Error 1
gmake: *** [cmTryCompileExec2889462763/fast] Error 2
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:3 (project)
-- Configuring incomplete, errors occurred!
Just for the record, my toolchain file is as follows, and my PATH variable allows it to find the compiler binaries at /usr/local/bin:
# the name of the target operating system
#SET(CMAKE_SYSTEM_NAME Linux)
# which C and C++ compiler to use
SET(CMAKE_C_COMPILER msp430-gcc)
SET(CMAKE_CXX_COMPILER msp430-g++)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/local/msp430)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
All that said, can anyone tell me how to check which compile flags CMake is using to carry the compiler test, and how can we pass custom flags (like -mmcu, for instance) so it doesn't fail it?
According to the Docs:
http://www.cmake.org/Wiki/CMake_Cross_Compiling#The_toolchain_file
you should use the CMakeForceCompiler thing
INCLUDE(CMakeForceCompiler)
# this one is important
SET(CMAKE_SYSTEM_NAME eCos)
# specify the cross compiler
CMAKE_FORCE_C_COMPILER(arm-elf-gcc GNU)
CMAKE_FORCE_CXX_COMPILER(arm-elf-g++ GNU)
# where is the target environment
SET(CMAKE_FIND_ROOT_PATH /home/alex/src/ecos/install )
# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
(copy&paste from the docs)
Using it fine here for my MSP430 too
The other answer here is outdated.
The toolchain file should include the required flags in the appropriate CMAKE_<KIND>_FLAGS(_<CONFIG>)_INIT variables, like so:
set(CMAKE_C_FLAGS_INIT "-mmcu=msp430f148")
set(CMAKE_CXX_FLAGS_INIT "-mmcu=msp430f148")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-mmcu=msp430f148")
CMake's compiler detection routines will use these flags when compiling a test executable. The full list is available in the CMake variables documentation, but the full list (at time of writing) is:
CMAKE_<LANG>_FLAGS_<CONFIG>_INIT
CMAKE_<LANG>_FLAGS_INIT
CMAKE_EXE_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_EXE_LINKER_FLAGS_INIT
CMAKE_MODULE_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_MODULE_LINKER_FLAGS_INIT
CMAKE_SHARED_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_SHARED_LINKER_FLAGS_INIT
CMAKE_STATIC_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_STATIC_LINKER_FLAGS_INIT
Where <CONFIG> is any ALL CAPS config name including, but not limited to, DEBUG, RELWITHDEBINFO, MINSIZEREL, and RELEASE. The non-<CONFIG> variants apply to all configurations and are augmented by the <CONFIG> variants.
And, where <LANG> is any of the languages known to enable_language(), currently including CXX, C, CUDA, OBJC, OBJCXX, Fortran, HIP, ISPC, and ASM. The current list may be found in the enable_language documentation.