Either this is really easy and I'm just not able to find the correct way to do it, or I've wildly misunderstood something. I'm attempting to add a conditional to a CMakeLists.txt file to include the proper .lib file depending on which build configuration type is being used (within visual studio at the moment). So for example, if configuration in visual studio is set to Debug then use file zlibstaticd.lib vs zlibstatic.lib. Below is what I have that's not working:
add_library(ZLIB_LIBRARY OBJECT IMPORTED)
# zlib added via assimp, and I can't get CMAKE_DEBUG_POSTFIX value to overwrite (because it's set within zlibs cmake file when using MSVC)
# so we have to do this check
if($<CONFIG:Debug>)
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib)
else()
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib)
endif()
I've also tried CMAKE_BUILD_TYPE but it's always an empty string. Below is my entire CMakeLists.txt file so you can see what it is I'm doing (building a singular static library which contains many other static libraries):
cmake_minimum_required(VERSION 3.20.0)
# Define our project name
set(PROJECT_NAME myProjectName)
project(${PROJECT_NAME})
# Make sure binary directory is not the same as source directory
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(
FATAL_ERROR
"In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there."
)
endif()
# This Project Depends on External Project(s)
include(ExternalProject)
set(libGLFW glfw)
ExternalProject_Add(${libGLFW}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.3.4
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}/install
-DGLFW_BUILD_DOCS:BOOL=OFF
-DGLFW_BUILD_EXAMPLES:BOOL=OFF
-DGLFW_BUILD_TESTS:BOOL=OFF
)
set(libGLAD glad)
ExternalProject_Add(${libGLAD}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}
GIT_REPOSITORY https://github.com/Dav1dde/glad.git
GIT_TAG origin/master
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}/install
-DGLAD_INSTALL:BOOL=ON
-DGLAD_PROFILE:STRING="core"
-DGLAD_ALL_EXTENSIONS:BOOL=ON
-DUSE_MSVC_RUNTIME_LIBRARY_DLL:BOOL=OFF
)
set(libGLM glm)
ExternalProject_Add(${libGLM}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLM}
GIT_REPOSITORY https://github.com/g-truc/glm.git
GIT_TAG origin/master
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLM}/install
-DBUILD_SHARED_LIBS:BOOL=OFF
-DBUILD_STATIC_LIBS:BOOL=OFF
-DGLM_TEST_ENABLE:BOOL=OFF
)
set(libAssimp assimp)
ExternalProject_Add(${libAssimp}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libAssimp}
GIT_REPOSITORY https://github.com/assimp/assimp.git
GIT_TAG v5.0.1
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libAssimp}/install
-DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT:BOOL=OFF
-DASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT:BOOL=OFF
-DBUILD_SHARED_LIBS:BOOL=OFF
-DASSIMP_BUILD_ASSIMP_TOOLS:BOOL=OFF
-DASSIMP_BUILD_TESTS:BOOL=OFF
-DASSIMP_BUILD_FBX_IMPORTER:BOOL=ON
-DASSIMP_BUILD_OBJ_IMPORTER:BOOL=ON
-DASSIMP_BUILD_OBJ_EXPORTER:BOOL=ON
-DASSIMP_LIBRARY_SUFFIX:STRING=
-DLIBRARY_SUFFIX:STRING=
-DCMAKE_DEBUG_POSTFIX:STRING=
-DASSIMP_INJECT_DEBUG_POSTFIX:BOOL=OFF
)
# Note set_target_properties will need conditionals for windows/linux since extensions differ
# Create the oject files we will join together to create our singular static library, using the projects
# that were previously added above via ExternalProject_Add
# INSTALL_DIR not being set to value of CMAKE_INSTALL_PREFIX, so manuallysetting
#ExternalProject_Get_Property(${libGLFW} INSTALL_DIR)
# SETUP GLFW
set(GLFW_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}/install)
add_library(GLFW_LIBRARY OBJECT IMPORTED)
set_target_properties(GLFW_LIBRARY PROPERTIES IMPORTED_OBJECTS ${GLFW_INSTALL_DIR}/lib/glfw3.lib)
# SETUP GLAD
set(GLAD_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}/install)
add_library(GLAD_LIBRARY OBJECT IMPORTED)
set_target_properties(GLAD_LIBRARY PROPERTIES IMPORTED_OBJECTS ${GLAD_INSTALL_DIR}/lib/glad.lib)
# SETUP GLM
# GLM is header only library, so we simply include it's include directory in target_include_directories below
set(GLM_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLM}/install)
# SETUP ASSIMP and it's dependencies
set(ASSIMP_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libAssimp}/install)
add_library(ASSIMP_LIBRARY OBJECT IMPORTED)
set_target_properties(ASSIMP_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/assimp.lib)
add_library(IRRXML_LIBRARY OBJECT IMPORTED)
set_target_properties(IRRXML_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/IrrXML.lib)
add_library(ZLIB_LIBRARY OBJECT IMPORTED)
# zlib added via assimp, and I can't get CMAKE_DEBUG_POSTFIX value to overwrite (because it's set within zlibs cmake file when using MSVC)
# so we have to do this check
if($<CONFIG:Debug>)
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib)
else()
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib)
endif()
# Documentation states not to do this, but do it anyway for the time being since it prevents us from having
# to manually list all project files
file(GLOB_RECURSE headers CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/inc/*.h")
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# Create a single .lib file containing our compiled objects, and the compiled objects of all other dependencies
add_library(${PROJECT_NAME} STATIC ${headers} ${sources}
$<TARGET_OBJECTS:GLFW_LIBRARY>
$<TARGET_OBJECTS:GLAD_LIBRARY>
$<TARGET_OBJECTS:ASSIMP_LIBRARY>
$<TARGET_OBJECTS:IRRXML_LIBRARY>
$<TARGET_OBJECTS:ZLIB_LIBRARY>
)
# Add all include file paths
target_include_directories(${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc
PUBLIC ${GLFW_INSTALL_DIR}/include
PUBLIC ${GLAD_INSTALL_DIR}/include
PUBLIC ${GLM_INSTALL_DIR}/include
PUBLIC ${ASSIMP_INSTALL_DIR}/include
)
# Specify the order in which libs depend on each other, use the name of the ExternalProject, not the name of the
# library object you create and use with add_library
add_dependencies(${PROJECT_NAME} ${libGLFW} ${libGLAD} ${libGLM} ${libAssimp})
add_library(ZLIB_LIBRARY OBJECT IMPORTED)
# zlib added via assimp, and I can't get CMAKE_DEBUG_POSTFIX value to overwrite (because it's set within zlibs cmake file when using MSVC)
# so we have to do this check
if($<CONFIG:Debug>)
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib)
else()
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib)
endif()
Generator expressions are evaluated after the configuration step has run, so they're just literal strings when the if() statement sees them. Basically, the CMake configure step is meta-programming a declarative language of targets and generator expressions that gets compiled into Ninja build files (or whatever) by the generator.
You can set the library up as follows:
add_library(zlib OBJECT IMPORTED)
set_target_properties(
zlib
PROPERTIES
IMPORTED_OBJECTS_RELEASE "${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib"
IMPORTED_OBJECTS_DEBUG "${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib"
)
CMake first tries IMPORTED_OBJECTS_$<CONFIG> before trying IMPORTED_OBJECTS when resolving a library path.
All that said, I have to wonder why you don't just use find_package, vcpkg, Conan, or maybe add_subdirectory / FetchContent to manage your dependencies. This seems like a lot of pain given that all of those libraries (I think) either provide their own find_package config packages or CMake provides a find module for them.
Related
I have a cpp file from a program that I want to open separately from the whole file structure. I need to do that in order to use this cpp file in ros. I have the header files included but I need to include the source files as well if I am correct.
my cpp file is called open_camera.cpp and includes a header file /usr/include/ids_peak-1.3.0/peak/backend/peak_backend.h
the peak_backend.h file contains declarations like this:
PEAK_C_API PEAK_Library_GetLastError(
PEAK_RETURN_CODE* lastErrorCode, char* lastErrorDescription, size_t* lastErrorDescriptionSize);
My Cmake File looks like this:
cmake_minimum_required(VERSION 3.0.2)
project(ros_package)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES ros_package
# CATKIN_DEPENDS roscpp rospy std_msgs
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
add_executable(open_camera_node src/open_camera.cpp)
#############
## Install ##
#############
include_directories(/usr/include/ids_peak-1.3.0)
if I run catkin_make I get errors like:
/usr/bin/ld: CMakeFiles/open_camera_node.dir/src/open_camera.cpp.o: in function `void peak::core::ExecuteAndMapReturnCodes<(anonymous namespace)::CallAndCheckCInterfaceFunction(std::function<int ()> const&)::{lambda()#1}>((anonymous namespace)::CallAndCheckCInterfaceFunction(std::function<int ()> const&)::{lambda()#1} const&)':
open_camera.cpp:(.text+0x516): undefined reference to `PEAK_Library_GetLastError'
From my understanding the problem is that I need to link the source files for the header. How can I do that and where do I find the source files for my headers? I searched for quiet some time but could not locate them.
The open_camera.cpp has its own CMake file looking like this:
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
project ("open_camera_cpp")
message (STATUS "[${PROJECT_NAME}] Processing ${CMAKE_CURRENT_LIST_FILE}")
set (SAMPLE_TARGET_NAME ${PROJECT_NAME})
set (CMAKE_SCRIPTS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../_cmake_scripts" CACHE STRING "The path of the cmake scripts directory.")
set (SAMPLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/output/bin")
include (${CMAKE_SCRIPTS_PATH}/cmake_detect_architecture.cmake)
detect_target_architecture (ARCH)
add_executable (${SAMPLE_TARGET_NAME}
open_camera.cpp
)
set (LIBRARY_NAME_VISION_API "ids_peak")
string (TOUPPER ${LIBRARY_NAME_VISION_API} LIBRARY_NAME_UPPER_VISION_API)
if (NOT TARGET ids_peak)
file (TO_CMAKE_PATH "$ENV{IDS_PEAK_SDK_PATH}/api" ${LIBRARY_NAME_UPPER_VISION_API}_PACKAGE_DIR)
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${${LIBRARY_NAME_UPPER_VISION_API}_PACKAGE_DIR}/cmake_finder")
message (STATUS "[${PROJECT_NAME}] Will find IDS peak API library.. CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}")
find_package (ids_peak REQUIRED)
endif ()
target_include_directories (${SAMPLE_TARGET_NAME}
PRIVATE ${${LIBRARY_NAME_UPPER_VISION_API}_INCLUDE_DIR}
)
find_package (Threads REQUIRED)
target_link_libraries (${SAMPLE_TARGET_NAME}
ids_peak
${CMAKE_THREAD_LIBS_INIT}
)
if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
target_link_libraries (${SAMPLE_TARGET_NAME}
atomic
)
endif ()
# Set output directories for all configuration types (Debug, Release, etc.)
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE "Debug")
endif()
if (NOT CMAKE_CONFIGURATION_TYPES)
set (CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
endif ()
if (CMAKE_CONFIGURATION_TYPES)
foreach (CONFIGURATION_TYPE ${CMAKE_CONFIGURATION_TYPES})
string (TOUPPER ${CONFIGURATION_TYPE} CONFIGURATION_TYPE_UPPER)
if (CONFIGURATION_TYPE_UPPER STREQUAL "RELEASE")
set (SAMPLE_RUNTIME_OUTPUT_NAME ${SAMPLE_TARGET_NAME})
set (SAMPLE_RUNTIME_OUTPUT_DIRECTORY ${SAMPLE_OUTPUT_PATH}/${ARCH})
else ()
string (TOLOWER ${CONFIGURATION_TYPE} CONFIGURATION_TYPE_LOWER)
set (SAMPLE_RUNTIME_OUTPUT_NAME "${SAMPLE_TARGET_NAME}_${CONFIGURATION_TYPE_LOWER}")
set (SAMPLE_RUNTIME_OUTPUT_DIRECTORY ${SAMPLE_OUTPUT_PATH}/${ARCH}/${CONFIGURATION_TYPE})
endif ()
set_target_properties (${SAMPLE_TARGET_NAME} PROPERTIES
RUNTIME_OUTPUT_NAME_${CONFIGURATION_TYPE_UPPER} ${SAMPLE_RUNTIME_OUTPUT_NAME}
RUNTIME_OUTPUT_DIRECTORY_${CONFIGURATION_TYPE_UPPER} ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}
)
message (STATUS "[${PROJECT_NAME}] Cfg ${CONFIGURATION_TYPE} -> Output directory: ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}, Output name: ${SAMPLE_RUNTIME_OUTPUT_NAME}")
endforeach ()
endif ()
set_target_properties(${SAMPLE_TARGET_NAME} PROPERTIES
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS NO
)
if (MSVC)
target_compile_options (${SAMPLE_TARGET_NAME}
PRIVATE "/bigobj"
PRIVATE "/MP"
)
endif ()
GET_PROPERTY(${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED_LOCAL GLOBAL PROPERTY ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED)
if(NOT ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED_LOCAL)
file (GLOB ids_peak_LIBS
"${${LIBRARY_NAME_UPPER_VISION_API}_LIBRARY_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}"
)
foreach (ids_peak_LIBRARY ${ids_peak_LIBS})
message (STATUS "[${PROJECT_NAME}] Add PostBuildStep for copy of ${ids_peak_LIBRARY}.")
add_custom_command (TARGET ${SAMPLE_TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${ids_peak_LIBRARY}
$<TARGET_FILE_DIR:${SAMPLE_TARGET_NAME}>
COMMENT "Post build copy of ${ids_peak_LIBRARY} to output dir." VERBATIM
)
endforeach ()
SET_PROPERTY(GLOBAL PROPERTY ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED ON)
endif()
# For Unix Build we need the environment variable GENICAM_GENTL32_PATH respectivily GENICAM_GENTL64_PATH to find the GenTL producer libraries.
# To set these environment variables a shell script is used which can be found in the samples root folder in _cmake_scripts.
# To run the samples run this script not the binary.
if (UNIX)
string (TOLOWER ${CMAKE_BUILD_TYPE} CONFIGURATION_TYPE_LOWER)
if(${CONFIGURATION_TYPE_LOWER} STREQUAL "release")
set(VSSL_SAMPLE_BINARY_NAME ${PROJECT_NAME})
else()
set(VSSL_SAMPLE_BINARY_NAME ${PROJECT_NAME}_${CONFIGURATION_TYPE_LOWER})
endif()
configure_file(${CMAKE_SCRIPTS_PATH}/sample_starter.in ${CMAKE_CURRENT_BINARY_DIR}/${VSSL_SAMPLE_BINARY_NAME}.sh)
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/${VSSL_SAMPLE_BINARY_NAME}.sh
DESTINATION ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
endif (UNIX)
I don't understand much of the original cmake file since I am quiet new to the topic.
The path of the cpp file is: /usr/local/src/ids/samples/peak/cpp/open_camera/open_camera.cpp
According to CMake documentation we shouldn't use the global settings for include directories or such anymore, but use the target_ versions. And to be honest, I don't think, that the second, complicated CMakeLists.txt is used (or needed), it doesn't seem to be included with the first one (but it is hard to say without knowing the directory structure.
But, never the less, if you want to use some library, you need two things: the header file(s) with the declaration of the provided items and usually the compiled library containing the definition/implementation of the items (static or dynamic library). In principle, you can also compile the library on your own, if you have access to the libraries source files. In this case my suggestion would be:
add_library(ids_peak
${IDS_PEAK_SOURCE_FILES}
)
target_include_directories(ids_peak PUBLIC /usr/include/ids_peak-1.3.0)
...
add_executable(open_camera
src/open_camera.cpp
)
target_include_directories(open_camera PRIVATE ${catkin_INCLUDE_DIRS})
target_link_libraries(open_camera PRIVATE ids_peak)
This will define two targets to compile:
a library target, compiling any source files which are in the list ${ID_PEAK_SOURCE_FILES} and with the corresponding include directories attached
an executable target, compiling your open_camera.cpp source file. There is this catkin include directory attached (perhaps we should opt for an other library target here? Are there sources to compile or is there only a lib+headers?). Last but not least a dependency is added to this target.
Since the include directories of the library target are declared public, they are forwarded to all targets, that depend on it (same happens with target_compile_definitions, target_link_libraries, target_link_options, etc.).
These links could be of interest to you:
https://cmake.org/cmake/help/latest/command/add_library.html
https://cmake.org/cmake/help/latest/command/add_executable.html
https://cmake.org/cmake/help/latest/command/target_include_directories.html
https://cmake.org/cmake/help/latest/command/target_link_libraries.html
What do linkers do?
And, if you'd be so kind as to drop the FILE(GLOB...) call. I was told by some CMake contributor once, that this feature wasn't released, but escaped and shouldn't be used at all being pretty error prone. I know it comes in handy, but you can't really control, what your build is really doing. It is better to name the files explicitly. Or, in case of install (https://cmake.org/cmake/help/latest/command/install.html#directory) or copy, you can apply to whole directories.
# file(COPY ${CMAKE_SOURCE_DIR}/libs/glew32.lib DESTINATION ${PROJECT_BINARY_DIR}/libs)
# file(COPY ${CMAKE_SOURCE_DIR}/libs/libglfw3dll.a DESTINATION ${PROJECT_BINARY_DIR}/libs)
add_executable(${PROJECT_NAME} main.cpp)
# libs/glew32.lib
# libs/libglfw3dll.a
# "main.cpp"
# )
target_link_libraries(${PROJECT_NAME}
libs/glew32.lib
libs/libglfw3dll.a
)
I've tried doing every option here but they end up causing linking errors. I tried both compiling from src and using every available format glfw and glew provided.
I usually create a CMake target first to import the prebuilt/precompiled library, then use target_link_libraries like y ou normally link to a CMake library target. The benefit is you can control the dependency being a PRIVATE dependency or a PUBLIC one.
project(YourCoolProject)
# Import a prebuilt library to a CMake target
add_library(Foo SHARED IMPORTED)
set_target_properties(Foo PROPERTIES
IMPORTED_LOCATION_DEBUG "/absolute-path/to/prebuilt-debug-library"
IMPORTED_LOCATION_RELEASE "/absolute-path/to/prebuilt-release-library"
IMPORTED_LOCATION_RELWITHDEBINFO "/absolute-path/to/prebuilt-relwithdebinfo-library"
INTERFACE_INCLUDE_DIRECTORIES "/absolute-path/to/include-dir"
)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE Foo)
Notes:
The choice of IMPORTED_LOCATION_<CONFIG> depends on the build type you provide to CMake (cmake -DCMAKE_BUILD_TYPE=<CONFIG> ...).
In order to replace the absolute path, you can use find_library to utilize CMake to find your library and store it in a variable and use find_path to find the include directory.
You probably need to use target_link_directories() as well to tell the compiler where to find the libraries:
target_link_directories(${PROJECT_NAME} ${PROJECT_BINARY_DIR}/libs/)
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 cli wrapper function which i am trying to configure in cmake. After i generate the project with cmake the generated .proj file does not have the property of clr support is set to no common languaage runtime support. below is my cmake file
# This is the root ITK CMakeLists file.
cmake_minimum_required(VERSION 2.8.9)
if(COMMAND CMAKE_POLICY)
cmake_policy(SET CMP0003 NEW)
endif()
set_target_properties(${TargetName} PROPERTIES COMPILE_FLAGS "/clr")
SET(LINK_LIBRARIES
D:\\2016\\RandomSlicing\\Processing\\lib\\obliquePlane.lib
)
# The header files
SET(HEADERS
ObliquePlaneWrapper.h
obliquePlane.h
)
# The implementation files
SET(SOURCES
ObliquePlaneWrapper.cpp
)
# Find ITK.
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
# Add this as include directory
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}
${SOURCE_PATH}
${VXL_INCLUDE_DIRS}
)
# Main library
#ADD_EXECUTABLE(obliquePlane ${HEADERS} ${SOURCES})
ADD_LIBRARY(ObliquePlaneWrapper SHARED ${HEADERS} ${SOURCES})
TARGET_LINK_LIBRARIES(ObliquePlaneWrapper ${LINK_LIBRARIES} ${ITK_LIBRARIES})
I manually set this property in the All_build project and the corresponding .proj file. When i build the project it is searching for the ObliquePlaneWrapper.dll which it should be generating. Is this a problem because of some flag not set for common language runtime support
You can manually supply Compile Flags to specific sources to be compiled with specific flags. This includes \CLR for Visual C++. See example here.
https://cmake.org/pipermail/cmake/2011-April/043773.html
I've wrote a C++ library MyLib and I'd like to integrate it with another project ExternPro. So in ExternPro I wrote CMakeLists.txt like this:
add_subdirectory(MyLib)
ADD_EXECUTABLE(test test.cpp)
include_directories(${MyLib_INCLUDE_DIRS})
target_link_libraries(test ${MyLib_LIBRARIES})
To set variables MyLib_LIBRARIES and MyLib_INCLUDE_DIRS I wrote:
set(MyLib_LIBRARIES ${PROJECT_SOURCE_DIR}/src/MyLib.a CACHE INTERNAL "")
set(MyLib_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "")
But something wrong "No rule to make target MyLib/src/MyLib.a, needed by test. Stop."
So my question is, how should I wrote CMakeLists.txt correctly so cmake could help me build MyLib first and then take care of dependencies of ExternPro?
If those are two separate projects, I normally use "CMake find scripts" to reference one library from the other: http://www.vtk.org/Wiki/CMake:How_To_Find_Libraries#Writing_find_modules
But I normally use slightly different find script than described there (FindMyLibrary.cmake):
# Find MyLibrary installation
#
# This module needs following variables specified (e.g. through cmake -Dvar=)
# MyLibrary_ROOT_DIR - root directory of the library installation
#
# This module defines the following variables:
# MyLibrary_INCLUDE_DIRS - Where to find the public headers
# MyLibrary_LIBRARIES - List of mandatory and optional libraries
# MyLibrary_FOUND - True if an installation was found
#
# Configuration variables for tis module:
# MyLibrary_USE_STATIC_LIBS - Set to ON to force the use of the static
# libraries. Default is OFF.
# If MyLibrary_ROOT_DIR was defined in the environment, use it.
if(NOT MyLibrary_ROOT_DIR AND NOT $ENV{MyLibrary_ROOT_DIR} STREQUAL "")
set(MyLibrary_ROOT_DIR $ENV{MyLibrary_ROOT_DIR})
endif()
if(NOT MyLibrary_ROOT_DIR)
set(MyLibrary_ROOT_DIR /usr)
endif()
message(STATUS "Using MyLibrary_ROOT_DIR: ${MyLibrary_ROOT_DIR}")
find_path(MyLibrary_INCLUDE_DIRS
NAMES mylib/mylib.hpp
PATHS ${MyLibrary_ROOT_DIR}
PATH_SUFFIXES include)
# Here we set the default components
if(NOT MyLibrary_FIND_COMPONENTS)
set(MyLibrary_FIND_COMPONENTS mylibrary)
endif()
# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
if(MyLibrary_USE_STATIC_LIBS)
set(_mylib_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif()
endif()
foreach(COMPONENT ${MyLibrary_FIND_COMPONENTS})
find_library(MyLibrary_${COMPONENT}_LIBRARY
NAMES ${COMPONENT}
HINTS ${MyLibrary_ROOT_DIR}
PATH_SUFFIXES lib64 lib
NO_DEFAULT_PATH)
set(MyLibrary_LIBRARIES ${MyLibrary_LIBRARIES} ${MyLibrary_${COMPONENT}_LIBRARY})
endforeach()
# Restore the original find library ordering
if(MyLibrary_USE_STATIC_LIBS)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_mylib_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
# handle the QUIETLY and REQUIRED arguments and set MyLibrary_FOUND to
# TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
MyLibrary "Could NOT find MyLibrary: set MyLibrary_ROOT_DIR to a proper location"
MyLibrary_LIBRARIES
MyLibrary_INCLUDE_DIRS)
mark_as_advanced(MyLibrary_INCLUDE_DIRS MyLibrary_LIBRARIES)
Then used like this:
find_package(MyLibrary REQUIRED)
include_directories(SYSTEM ${MyLibrary_INCLUDE_DIRS})
target_link_libraries(${TARGET}
${MyLibrary_LIBRARIES}
)
Basically, it goes like this:
The library is built and installed (make install) to either the default location (e.g. /usr), or some other location (usual in development).
The FindMyLibrary.cmake is part of the library installation (for RPM the library devel package) and installs as well (into ${instdir}/share/cmake/Modules, for example).
The dependent project then adds the path to the CMAKE_MODULE_PATH and uses the find script to find the public headers and libraries as installed.
The advantage is that this way you can either use it during the development (when you have the library sources and build the library), or without the library sources as well (with just the library and headers - the devel package - installed in the system).
Similar technique is normally used by Boost etc. (the find scripts provided already by the CMake).
Instead of path to the library, use library target for target_link_libraries.
Assuming your library project contains
add_library(MyLib ...)
Linking of executable in main project should be performed with
target_link_libraries(test MyLib)
First of all this doesn't work because variables set in a subdirectory are not set for the parent directory.
So to solve this properly you should define MyLib like:
add_library(MyLib ...)
target_include_directories(MyLib INTERFACE ${PROJECT_SOURCE_DIR}/include)
And for the ExternPro you just need to link to MyLib:
target_link_libraries(test MyLib)
This will automatically add the include directory to test and link MyLib properly.