Can't link c++ libraries using CMAKE and make install - c++

I am having a problem linking two libraries using CMake on linux (ubuntu). I have the following CMake setup.
cmake_minimum_required(VERSION 3.3)
project(lib1)
set(SOURCE_FILES
source_1.cpp)
# set library output directory
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ../build/)
# Base directory relative to which all includes are
set(BASE_DIR ../)
#include base directory
include_directories ("${BASE_DIR}")
# create a shared library
add_library(lib1 SHARED ${SOURCE_FILES})
# make install target
install(TARGETS lib1 DESTINATION /usr/local/lib)
For Library 2 we have
cmake_minimum_required(VERSION 3.3)
project(lib2)
set(SOURCE_FILES
source_2.cpp)
set(BASE_DIR ../)
#include base directory
include_directories ("${BASE_DIR}")
# create a shared library
add_library(lib2 SHARED ${SOURCE_FILES})
# include lib1 library
target_link_libraries(lib2 PUBLIC lib1)
install(TARGETS lib2 DESTINATION /usr/local/lib)
Running these with
cmake_minimum_required(VERSION 3.3)
project(all)
add_subdirectory(lib1)
add_subdirectory(lib2)
creates liblib1.so and liblib2.so. liblib2.so depends on liblib1.so (ldd liblib2.so gives the link to liblib1.so in the CMAKE_LIBRARY_OUTPUT_DIRECTORY directory.)
After running
make install
I get
-- Install configuration: "Release"
-- Up-to-date: /usr/local/lib/liblib1.so
-- Installing: /usr/local/lib/liblib2.so
-- Set runtime path of "/usr/local/lib/liblib2.so" to ""
and in /usr/local/lib liblib2.so is no longer linked to liblib1.so.
I tried many reworkings of my cmake file, (e.g. using :
set(CMAKE_INSTALL_RPATH "/usr/local/lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
but nothing seemed to help. Anyone can explain me how to get the libraries to link after make install?
I did run ldconfig manually, but no luck. /usr/local/lib is also part of ld.conf and I am running ubuntu 16.04.

Related

CMake imported targets in add_subdirectory not available in main CMakeLists.txt

I want to build an application that depends on the OpenCV (version 3.4.6) viz module. This module has the VTK library (version 7.1.1) as dependency. I want to use ExternalProject to build both, the vtk library and the opencv viz module and subsequently want to build the main application, all in one cmake run.
.
├── CMakeLists.txt
├── deps
│   └── CMakeLists.txt
└── main.cpp
I am using the cmake ExternalProject module to build both opencv and vtk inside a subdirectory like this:
deps/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(dependencies)
include(ExternalProject)
ExternalProject_add(
vtklib
GIT_REPOSITORY https://github.com/Kitware/vtk
GIT_TAG v7.1.1
GIT_PROGRESS TRUE
UPDATE_COMMAND ""
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
-DBUILD_TESTING=OFF
-DBUILD_EXAMPLES=OFF
-DVTK_DATA_EXCLUDE_FROM_ALL=ON
-DVTK_USE_CXX11_FEATURES=ON
-Wno-dev
)
add_library(vtk INTERFACE IMPORTED GLOBAL)
add_dependencies(vtk vtklib)
ExternalProject_add(
ocv
GIT_REPOSITORY https://github.com/opencv/opencv
GIT_TAG 3.4.6
GIT_PROGRESS TRUE
UPDATE_COMMAND ""
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
-DWITH_VTK=ON
-Wno-dev
)
# ExternalProject_Get_Property(ocv install_dir)
# include_directories(${install_dir}/src/ocv/include)
include_directories(${CMAKE_INSTALL_PREFIX}/include)
set(ocv_libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_VS_PLATFORM_NAME}/vc15)
set(OCV_VERSION 346)
add_dependencies(ocv vtklib)
add_library(opencv_core SHARED IMPORTED)
set_target_properties(opencv_core PROPERTIES
IMPORTED_IMPLIB "${ocv_libdir}/lib/opencv_core${OCV_VERSION}.lib"
IMPORTED_LOCATION "${ocv_libdir}/bin/opencv_core${OCV_VERSION}.dll"
)
add_library(opencv_viz SHARED IMPORTED)
set_target_properties(opencv_viz PROPERTIES
IMPORTED_IMPLIB "${ocv_libdir}/lib/opencv_viz${OCV_VERSION}.lib"
IMPORTED_LOCATION "${ocv_libdir}/bin/opencv_viz${OCV_VERSION}.dll"
)
the main CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.14)
project(cmaketest VERSION 0.1 DESCRIPTION "" LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_Flags "${CMAKE_CXX_FLAGS} -std=c++17")
# include_directories(${CMAKE_INSTALL_PREFIX}/include)
add_subdirectory(deps)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} opencv_core opencv_viz)
install(
TARGETS ${PROJECT_NAME}
EXPORT "${PROJECT_NAME}-targets"
LIBRARY DESTINATION lib/
ARCHIVE DESTINATION lib/${CMAKE_PROJECT_NAME}
RUNTIME DESTINATION bin
PUBLIC_HEADER DESTINATION include/${CMAKE_PROJECT_NAME}/${PROJECT_NAME}
)
the main.cpp for completeness:
#include <opencv2/viz.hpp>
int main(){}
but it seems that the include_directories and add_library calls inside deps/CMakeLists.txt do not work on the correct scope as i am getting the following error messages:
error C1083: File (Include) can not be opened: "opencv2/viz.hpp"
if i uncomment the include_directories inside the main CMakeLists.txt then i get a linker error (this is not what i want, included directories should be specified inside deps/CMakeLists.txt):
LNK1181: opencv_core.lib can not be opened
If i just copy the contents of deps/CMakeLists.txt in the main CMakeLists.txt in place of the add_subdirectory call everything works fine.
So, how do i get the include directories and the created targets from the subdirectory in my main CMakeLists?
edit:
call to cmake configure:
cmake.exe -B build -S . -G "Visual Studio 17 2022" -A x64 -T v141 -DCMAKE_INSTALL_PREFIX=D:/test
call to cmake build:
cmake.exe --build build --config Release --target install
Unlike to normal targets, which are global, an IMPORTED target by default is local to the directory where it is created.
For extend visibility of the IMPORTED target, use GLOBAL keyword:
add_library(opencv_core SHARED IMPORTED GLOBAL)
This is written in the documentation for add_library(IMPORTED):
The target name has scope in the directory in which it is created and below, but the GLOBAL option extends visibility.
cmake has couple steps:
configuration
generation (depends on configuration)
build (depends on generation)
test (depends on build)
install (depends on build)
Now problem is that your build step depends on result of install step. This happens here:
set(ocv_libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_VS_PLATFORM_NAME}/vc15)
and when this variable is used.
This is causing that to be able to complete build step you need success in install step. And cmake will do install step after successful build. So you have dependency cycle.
Instead importing opencv as shared library:
add_library(opencv_viz SHARED IMPORTED)
Link your target with targets created by imported project of opnecv.

install TARGETS given unknown argument "DIRECTORY"

Tried to build a project and install directory using cmake. Used following cmakefile.
CMake version used: 3.8.2
# Specifying minimum cmake version
cmake_minimum_required(VERSION 3.8.2)
# Project name
project(pro LANGUAGES C CXX VERSION 0.1.0)
# Set C++11 compiler
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# Global Install Directories
include(GNUInstallDirs)
# Source files
SET(SRC_FILES
src/file.cpp
)
# Project requirements
find_package(OpenCV REQUIRED)
# Creating static library
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<BUILD_INTERFACE:${OpenCV_INCLUDE_DIRS}>
$<INSTALL_INTERFACE:include>)
# Linking opencv dynamically
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OpenCV_LIBS})
# Set correct Install directories
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Config
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
It is giving me following error while installing the directory
install TARGETS given unknown argument "DIRECTORY".
-- Configuring incomplete, errors occurred!
I am not able to understand the error, can anyone pleae help me out? Thank you !

How to make ExternalProject_Add acting like ADD_SUBDIRECTORY command with cmake?

I'm creating a native library under Android Studio, and I'm hurting the following problem.
In my AndroidStudio project CMakeLists.txt, I have this:
cmake_minimum_required(VERSION 3.7.0)
add_library(native-lib
SHARED
src/main/cpp/native-lib.cpp )
IF(USE_EXTERNAL)
include(ExternalProject)
ExternalProject_Add(
project_mylib
DOWNLOAD_COMMAND ""
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/mylib/"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}
)
add_dependencies(native-lib project_mylib)
ELSE()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/mylib/)
ENDIF()
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries(native-lib
${log-lib}
mylib
)
A self-made library is located in src/main/cpp/mylib/, with a CMakeLists.txt:
cmake_minimum_required(VERSION 3.7.0)
project(lib)
add_library(mylib SHARED lib.cpp)
INSTALL(TARGETS mylib
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
)
When I use the "traditional" add_subdirectory(...) everything goes well. But, if I use the ExternalProject_Add(...) version, linker is skipping the compiled libmylib.so library and so cannot link mylib to native-lib.
I have the following message: skipping incompatible /home/.../app/.externalNativeBuild/cmake/debug/arm64-v8a/lib/libmylib.so when searching for -lmylib
My guess is that all the flags set by AndroidStudio for the root CMakeLists.txt are not set when the ExternalProject is compile leading to an incompatible shared library.
So, I wonder if there is a way to compile a cmake ExternalProject like it was part of the root project (sharing the same compile flags etc) ?
Thanks for any advice

cmake fails to look up external library(boost) directory

I am trying to use cmake to build a simple parser project. I used boost::program_options in my code, but it seems cmake does not look up the boost lib directory. Get confused and frustrated..
My CMakeLists.txt is
# basic info
CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0)
PROJECT(parser CXX)
SET(CMAKE_CXX_STANDARD 14)
# Boost
FIND_PACKAGE(Boost 1.61.0 REQUIRED PATHS /path/to/boost NO_DEFAULT_PATH)
MESSAGE(STATUS "Boost version: ${Boost_VERSION}" )
MESSAGE(STATUS "Boost include dirs: ${Boost_INCLUDE_DIRS}" )
MESSAGE(STATUS "Boost library dirs: ${Boost_LIBRARY_DIRS}" )
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
# main
FILE(GLOB main_SRC *.cpp)
ADD_EXECUTABLE(main ${main_SRC})
TARGET_LINK_LIBRARIES(main boost_program_options)
I use a modified BoostConfig.cmake (which points to my own Boost library)
The result for running cd build; cmake .. is
-- Boost version: 1.61.0
-- Boost include dirs: /path/to/boost/include
-- Boost library dirs: /path/to/boost/lib
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/build
Thus I believe cmake has found the my Boost library. But then if I run make I will end up with a bunch of errors like
undefined reference to `boost::program_options ... `
If I run make VERBOSE=1 I will see
/path/to/g++ -rdynamic CMakeFiles/main.dir/main.cpp.o -o main -lboost_program_options
the command does not have -L or -Wl,rpath for ${Boost_LIBRARY_DIRS}. If I add the flag manually then I can compile the project successfully.
I also tried linking to static lib by TARGET_LINK_LIBRARIES(main ${Boost_LIBRARY_DIR}/libboost_program_options.a) instead of LINK_DIRECTORIES(), but the same error was thrown.
Not sure what makes things wrong..
Thanks in advance
What happens with the standard method using the imported targets? That is,
# Use and set variable/-Dflag/environment for custom Boost location
set(BOOST_ROOT /path/to/boost)
find_package(Boost 1.61.0 REQUIRED
COMPONENTS program_options)
add_executable(main ...)
target_link_libraries(main Boost::program_options)

CMake user built libraries; cannot specify link libraries for target

I'm building a project in Cpp that will communicate with my Java apps via rabbitmq and post updates to twitter. I'm using a few libraries from github
rabbitmq-c
Rabbit installed to /usr/local/lib64
jansson - json library
I installed this a while back for another project, went to /usr/local/lib
twitcurl - C lib for Twitter API
Got installed to /usr/local/lib
If it matters, I'm using CLion as my IDE, which displays jansson and rabbit under auto-complete when defining includes - so that's picking the libs off my system somehow
e.g.
#include <jansson.h>
#include <amqp.h>
I link them using the target_link_libraries(name libs...) and I see output saying
build$ cmake ..
CMake Error at CMakeLists.txt:30 (target_link_libraries):
Cannot specify link libraries for target "twitcurl" which is not built by
this project.
I set LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
I try to set the CMAKE_LIBRARY_PATH to include usr/local/lib and lib64 but doesn't seem to have any effect. Here's my CMakeLists.txt file
#
# This is a CMake makefile. You can find the cmake utility and
# information about it at http://www.cmake.org
#
cmake_minimum_required(VERSION 2.6)
set(PROJECT_NAME twitterUpdater)
set(SOURCE_FILES main.cpp)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "/usr/local/lib"
"/usr/local/lib64")
project(${PROJECT_NAME})
find_package(X11 REQUIRED)
find_package(OpenCV REQUIRED)
IF (X11_FOUND)
INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR})
LINK_LIBRARIES(${X11_LIBRARIES})
ENDIF ( X11_FOUND )
IF (OpenCV_FOUND)
include_directories(${OpenCV_INCLUDE_DIRS})
link_libraries(${OpenCV_LIBS})
ENDIF(OpenCV_FOUND)
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_link_libraries(${project_name} twitcurl jansson rabbitmq)
What's confusing me is another project I have uses jansson by simply adding it here TARGET_LINK_LIBRARIES(${project_name} dlib jansson)
What did I miss?? Thanks
CMake variables are case sensitive, thus the variable ${project_name} results in an empty string. Use ${PROJECT_NAME} instead, i.e.:
target_link_libraries(${PROJECT_NAME} twitcurl jansson rabbitmq)
Running CMake with the flag --warn-uninitialized helps you detect mistakes like this.