Perhaps I simply can't find it, but I want to add some code to a project of mine (libunwind found here http://www.nongnu.org/libunwind/download.html)
This library does not come with a CMakeLists.txt file and when I try to include it cmake complains about this fact. Right now I've simply added the libunwind directory to my external code and added a reference in my main CMakeLists.txt
Any input would be great.
Dealing with libraries there are 2 options for you :
If you've downloaded and was able to build and install it you can try to find it later on inside you CMAKE like this ( in case of Boost ) and link to your target:
find_package( Boost COMPONENTS date_time system serialization thread program_options filesystem unit_test_framework regex chrono REQUIRED )
if( NOT Boost_FOUND )
message( FATAL_ERROR "Cannot find boost!" )
endif( NOT Boost_FOUND )
message(STATUS "boost found")
include_directories( ${Boost_INCLUDE_DIRS} )
link_directories( ${Boost_LIBRARY_DIRS} )
target_link_libraries(YOUR_TARGET_NAME ${Boost_LIBRARIES})
2. You can add external library sources as a stand-alone target and use smth like this for CMake to build it :
set (sources
async_waiter.h
async_waiter_impl.h
async_waiter_impl.cpp
)
add_library( async_waiter ${sources} )
and later on link you target to it with :
target_link_libraries(YOUR_TARGET_NAME async_waiter)
If you want to build it each time along with your project, the easiest way would be to:
Add the source code somewhere into your project tree
Add a custom CMake target which should run before the compilation starts
In that custom target, run whatever is needed to compile the library (in your case it's ./configure -> make -> make install.
However that is rarely needed and most of the times you should just build the library once and link it as any other external library.
Related
I would like to link my Debug executable with external library built in Release version using FetchContent.
I'm able to link my Debug executable with Debug built library and similar with Release and Release using:
project(CMakeDemo)
set(FETCHCONTENT_QUIET OFF)
FetchContent_Declare(
ZLIB
URL https://zlib.net/zlib-1.2.11.tar.gz
)
FetchContent_MakeAvailable(ZLIB)
add_executable(CMakeDemo main.cpp)
target_link_libraries(CMakeDemo ZLIB)
So when I execute from a build directory on Windows:
cmake ../
cmake --build .
Then zlib and my executable is built in Debug version and my executable is linked with that zlib Debug version.
But how to enhance the CMake to build my executable in Debug version but zlib in Release version and link my Debug executable with the zlib Release version? How to achieve that using FetchContent_Declare?
(I believe this has to be some common approach because for example when someone wants to use Google Test framework or zlib in a project then for sure he wants to use these external libraries in Release version always)
FetchContent() will integrate the dependency, here ZLIB, in your worktree like an add_subdirectory() so flags will be identical (if ZLIB is correctly configured to be use as subproject, spoiler: this is not the case you'll need to patch it...).
If you really want to build it in Release, you should try to use ExternalProject() and execute_process()
to build and install it at configure time then you can use find_package() to retrieve this pre-installed dependency.
I know that the question is old, but as I have been struggling a whole day with the same issue, and wanted to share my progress. Please bear in mind I'm a cmake newbie, and I'm not sure if what I'm doing conforms to best practices, and the example code I provide might have mistakes. It can also definitely be significantly improved - but I believe is sufficient to get someone off the ground, if they're having the same issue.
For my use case, I wanted the external libraries to be built at cmake configure time, instead of build time. To that effect, I used execute_process to configure and build the external libraries. This is the function I created for that effect:
function(fetch_and_build_lib)
set(options "")
set(oneValueArgs LIB_NAME GIT_REPOSITORY GIT_TAG PACKAGE_NAME)
set(multiValueArgs CONFIG_ARGS CONFIG_TYPES BUILD_ARGS COMPONENTS)
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (NOT DEFINED ARG_LIB_NAME)
message(FATAL_ERROR "fetch_and_build_lib called without LIB_NAME")
endif()
if (NOT DEFINED ARG_GIT_REPOSITORY)
message(FATAL_ERROR "fetch_and_build_lib called without GIT_REPOSITORY")
endif()
if (NOT DEFINED ARG_GIT_TAG)
message(FATAL_ERROR "fetch_and_build_lib called without GIT_TAG")
endif()
if (DEFINED ARG_PACKAGE_NAME)
set(PACKAGE_NAME ${ARG_PACKAGE_NAME})
else()
set(PACKAGE_NAME ${ARG_LIB_NAME})
endif()
include(FetchContent)
FetchContent_Declare(${ARG_LIB_NAME}
GIT_REPOSITORY "${ARG_GIT_REPOSITORY}"
GIT_TAG "${ARG_GIT_TAG}"
)
FetchContent_GetProperties(${ARG_LIB_NAME}
POPULATED LIB_POPULATED
)
message(STATUS "Checking if ${ARG_LIB_NAME} is populated: ${LIB_POPULATED}")
if (NOT LIB_POPULATED})
message(STATUS "Populating ${ARG_LIB_NAME}...")
FetchContent_Populate(${ARG_LIB_NAME})
set(LIB_BINARY_DIR ${${ARG_LIB_NAME}_BINARY_DIR})
set(LIB_SOURCE_DIR ${${ARG_LIB_NAME}_SOURCE_DIR})
message(STATUS "Configuring ${ARG_LIB_NAME}...")
execute_process(
COMMAND ${CMAKE_COMMAND}
"-S ${LIB_SOURCE_DIR}"
"-B ${LIB_BINARY_DIR}"
"-DCMAKE_GENERATOR=${CMAKE_GENERATOR}"
"-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}"
${ARG_CONFIG_ARGS}
WORKING_DIRECTORY "${LIB_BINARY_DIR}"
COMMAND_ECHO STDOUT
RESULT_VARIABLE result_config
)
if(result_config)
message(FATAL_ERROR "Failed to config ${ARG_LIB_NAME} exited with result: ${result_config}")
else()
message(STATUS "${ARG_LIB_NAME} configuring complete!")
endif()
foreach(config_type IN LISTS ARG_CONFIG_TYPES)
set(${ARG_LIB_NAME}_CONFIG_TYPE "${config_type}" CACHE INTERNAL "Config/build type for ${ARG_LIB_NAME}")
message(STATUS "Building ${ARG_LIB_NAME}... with CONFIG: ${config_type}")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${LIB_BINARY_DIR}"
--config "${config_type}"
WORKING_DIRECTORY "${LIB_BINARY_DIR}"
COMMAND_ECHO STDOUT
${ARG_BUILD_ARGS}
RESULT_VARIABLE result_build
)
endforeach()
if(result_build)
message(FATAL_ERROR "Failed to build ${ARG_LIB_NAME} with result: ${result_build}")
else()
message(STATUS "${ARG_LIB_NAME} build complete!")
endif()
endif()
if (DEFINED ARG_COMPONENTS)
find_package(${PACKAGE_NAME} REQUIRED
COMPONENTS ${ARG_COMPONENTS}
PATHS ${LIB_BINARY_DIR}
NO_DEFAULT_PATH
)
else()
find_package(${PACKAGE_NAME} REQUIRED
PATHS ${LIB_BINARY_DIR}
NO_DEFAULT_PATH
)
endif()
endfunction()
What it does is as follows:
Downloads from git a repository with a specific tag
Configures the build system of the downloaded library
Builds the library as part of the main project configure stage
Makes sure that FindPackage can discover the newly built library
Then, in my CMakeLists.txt for my project, I use it like so:
add_executable(main main.cpp)
fetch_and_build_lib(
LIB_NAME "mylib"
GIT_REPOSITORY "https://github.com/myRepo/myLib.git"
GIT_TAG "1.2.3"
CONFIG_ARGS "-DMYLIB_DOC=OFF;-DMYLIB_TEST=OFF"
CONFIG_TYPES "debug, release"
PACKAGE_NAME "MyLIB"
)
find_package(MyLIB REQUIRED)
#Use Release version of library for Debug, MinSizeRel, RelWithDebInfo build types:
set_target_properties(MyLIB PROPERTIES
MAP_IMPORTED_CONFIG_MINSIZEREL Release
MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release
MAP_IMPORTED_CONFIG_DEBUG Release
)
target_link_libraries(main myLib::myLib)
This invokes the previously defined function that downloads, configures and builds the library. It assumes that the library correctly exports its targets, and then remaps the imported configs to the current project config.
This is what actually ends up linking the debug lib with the release executable.
CMake documentation for MAP_IMPORTED_CONFIG_
Mandatory disclaimer:
Mixing release libs and debug executables is filled with pitfalls, both for shared and static libraries. I'm not discussing whether this is a good idea or not, or what the pitfalls are. Be sure you are aware of the limitations and what is safe and what is not safe to do when doing such a mix.
In a project, we use ExternalProject_add to manage regular third parties and drive their download and build process (some come from regular URL, others from a git repository)
Recently, I came across the need to add an extra thirdparty. It is so far the only header-only thirdparty we would have. For those interested, it is kvasir_mpl.
However, when I try to target_link_libraries with kvasir_mpl, CMake always considers it as a regular library and in the end the build fails:
[ 83%] Linking CXX executable app
/usr/bin/ld: cannot find -lkvasir_mpl
I devised a minimal example to reproduce the problem:
./CMakeLists.txt:
cmake_minimum_required( VERSION 3.7.0 )
project( Test CXX )
add_subdirectory( kvasir )
add_subdirectory( app )
./app/CMakeLists.txt:
project( App CXX )
add_executable( app main.cpp )
target_link_libraries( app kvasir_mpl )
kvasirmpl/CMakeLists.txt:
cmake_minimum_required( VERSION 3.7.0 )
project( KvasirMpl )
include( ExternalProject )
ExternalProject_Add(
3rdparty_kvasirmpl
GIT_REPOSITORY https://github.com/kvasir-io/mpl
GIT_TAG origin/development
INSTALL_COMMAND ""
BUILD_COMMAND "" )
Note that if I use the keyword signature target_link_libraries( app INTERFACE kvasir_mpl ) my issue is resolved. However in our real use case, the target_link_libraries is run through custom CMake functions and can be passed anything from a regular library file to a CMake target forcing us to use the plain signature.
Is there a way to make the plain signature work in this case?
In kvasirmpl/CMakeLists.txt, add the following lines:
add_library(kvasir_mpl INTERFACE)
target_include_directories(kvasir_mpl PUBLIC <includedirs>)
set_target_properties(kvasir_mpl PROPERTIES LINKER_LANGUAGE CXX)
This tells CMake there is a library not built by CMake (Interface), what the include directories are when linking with that library... You could also add extra compile flags etc.
The linker language must be specified because CMake wishes to know whether it's C or C++, and won't deduct that in a header-only library.
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
I have installed opencv2.4.9(With No CUDA) by unzip opencv2.4.9.zip in home.
Many successful codes are using this library.
Now I wanna rebuild opencv2.4.9(with CUDA) in another folder.
I don't wanna delete the previous folder because I don't wanna face any problem later on and make my older code can't function.
So, the question is how to change the name of the directory? Seems like we link the package with library in CMake like below:
include_directories( ${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} )
find_package( OpenCV REQUIRED )
find_package(catkin REQUIRED COMPONENTS cv_bridge image_transport
OpenCV roscpp rospy std_msgs )
the name of directory is just OpenCV.
So if I got more than one OpenCV library in home, how could I link them separately?
And how to make c++ link to the library if we could change the name?
add_executable(xxx src/xxx.cpp)
target_link_libraries(xxx ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
Libraries can be included and linked with include_directories() and link_directories(), like this:
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
...
include_directories(${PROJECT_SOURCE_DIR})
include_directories(/path/to/opencv/OpenCV-2.4.1/include)
link_directories(/path/to/opencv/OpenCV-2.4.1/lib)
...
# Set the build type. Options are:
# Coverage : w/ debug symbols, w/o op ...
So you should not forget the linking in the CMakeLists.txt and maybe remove the standard linking to your current OpenCV libs.
I use DCMTK in my application and for compilation use cmake file. cmake finds all libraries (at least headers, because in compiles source files to .o files) the only problem is that during linking it tries to find dynamic libraries for DCMTK. I compiled one as static, so I do not have .so files. As a result it gives me error :No rule to make target /usr/lib/libdcmdata.so, needed by dcm_seg. Stop.
I use Ubuntu 14.04 x64.
It confuses me pretty much. So, what's the problems?
cmake file:
cmake_minimum_required(VERSION 2.6)
project(dcm_segm)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
set(Boost_USE_STATIC_LIBS ON)
set(OpenCV_USE_STATIC_LIBS ON)
set(DCMTK_USE_STATIC_LIBS ON)
set(OpenCV_STATIC ON)
find_package( VTK REQUIRED )
find_package( OpenCV REQUIRED )
find_package( Boost COMPONENTS system filesystem REQUIRED )
find_package( DCMTK REQUIRED )
include(${VTK_USE_FILE} )
link_directories(${OpenCV_LIB_DIR})
add_executable(dcm_seg main.cpp DICOMin.cpp Ensemble.cpp Ensemble3dExtension.cpp point_3d.cpp RegionGrow.cpp)
target_link_libraries(dcm_seg ${VTK_LIBRARIES} ${OpenCV_LIBS} ${DCMTK_LIBRARIES} ${Boost_LIBRARIES})
Can you check the content of ${DCMTK_LIBRARIES} (it should be a list of paths to DCMTK static libraries) ?
you can also check the following CMake entries during the CMake configuration:
DCMTK_DIR /path/to/DCMTK/install
DCMTK_config_INCLUDE_DIR /path/to/DCMTK/install/include/dcmtk/config
DCMTK_dcmdata_INCLUDE_DIR /path/to/DCMTK/install/dcmdata/include/dcmtk/dcmdata
DCMTK_dcmdata_LIBRARY_DEBUG /path/to/DCMTK/install/dcmdata/libsrc/libdcmdata.a
DCMTK_dcmdata_LIBRARY_RELEASE /path/to/DCMTK/install/dcmdata/libsrc/libdcmdata.a
[...]
Another hint: I noted in the past that find DCMTK from a build instead of an install not always works properly.
If you have trouble finding DCMTK with the script provided with CMake
(${DCMTK_LIBRARIES} doesn not content the path to you static DCMTK libs for example) you can try to use this alternative script