简体   繁体   中英

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

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 .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM