Building a project that depends on OpenCV with CMake (FetchContent)

138 views Asked by At

I have a goal, that is create an example project that gets OpenCV as a dependency with CMake, in Windows but using Clang through a MinGW installation.

There's some constraints (for the project and dependencies):

  • They all must be built using the latest C++ standard
  • Clang as compiler, LDD as linker and LIBC++ and the standard library (so basically, all the core tools of a LLVM setup)

This is my current working approach:

cmake_minimum_required(VERSION 3.5)
project(opencv_example_project CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/install)

# The toolchain file that will be used later to pass our project configuration also to the OpenCV build
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/clang-x86_64_windows_gnu.cmake)


# ------- Project variables -------

set(PROJECT_BUILD_DIRECTORY     ${CMAKE_CURRENT_SOURCE_DIR}/build)
set(PROJECT_INSTALL_DIRECTORY   ${CMAKE_CURRENT_SOURCE_DIR}/install)

# Set the installation directory
set(OpenCV_INSTALL_DIR ${PROJECT_INSTALL_DIRECTORY}/opencv)
# Set the OpenCV build dir
set(OpenCV_BUILD_DIR ${PROJECT_BUILD_DIRECTORY}/opencv/build)
# Set the OpenCV_DIR, required to found the installation
set(OpenCV_DIR ${OpenCV_INSTALL_DIR})

# Attempt to find OpenCV in quiet mode. This will allow us to skip CMake code 
# in the consecutive iterations of the build process
find_package(OpenCV QUIET)

# Autogenerating the installation directories
if(NOT EXISTS ${PROJECT_INSTALL_DIRECTORY})
    execute_process(COMMAND mkdir ${PROJECT_INSTALL_DIRECTORY})
    message(STATUS "install folder created")
endif()

if(NOT EXISTS ${OpenCV_INSTALL_DIR})
    execute_process(COMMAND mkdir ${OpenCV_INSTALL_DIR})
endif()


# Check if OpenCV was found
if(OpenCV_FOUND)
    message(STATUS "OpenCV found. Version: ${OpenCV_VERSION}")
else()
    message(WARNING "OpenCV not found. Cloning the project, building it and installing it")
endif()

if(NOT OPENCV_FOUND)
    # Download and extract OpenCV sources
    message(STATUS "Downloading from GitHub OpenCV")
    execute_process(
        COMMAND git clone --branch 4.6.0 --single-branch https://github.com/opencv/opencv.git
        WORKING_DIRECTORY ${PROJECT_BUILD_DIRECTORY}
    )
    execute_process(COMMAND mkdir ${OpenCV_BUILD_DIR})

    # Configure the later build of OpenCV
    message(STATUS "Configuring the build and installation of OpenCV")
    execute_process(
        COMMAND cmake -G "Ninja"
                    -DCMAKE_INSTALL_PREFIX=${OpenCV_INSTALL_DIR}
                    -DBUILD_TESTS=OFF
                    -DBUILD_PERF_TESTS=OFF
                    -DBUILD_EXAMPLES=OFF
                    -DBUILD_opencv_apps=OFF
                    -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
                    -DWITH_ADE=OFF
                    -Wno-dev
                    -S ${CMAKE_CURRENT_SOURCE_DIR}/build/opencv
                    -B ${OpenCV_BUILD_DIR}
                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    )

    # Build and install OpenCV using execute_process
    message(STATUS "Building and installing OpenCV")
    execute_process(
        COMMAND cmake --build . --target install
        WORKING_DIRECTORY ${OpenCV_BUILD_DIR}
    )
else()
    message (STATUS "OpenCV installation found. Version: ${OpenCV_VERSION}. Path: ${OpenCV_DIR}")
endif()

# Find the OpenCV build/installation, so their own variables for the include/link are correctly set up
find_package(OpenCV REQUIRED)

# A little bit of debug information about the OpenCV installation 
message(STATUS "OpenCV_INCLUDE_DIRS ${OpenCV_INCLUDE_DIRS}")
message(STATUS "OpenCV_LIBS ${OpenCV_LIBS}")
message(STATUS "OpenCV build and installation finished. Launching the build of the example project")

# Declare the executable target built from your sources
add_executable(opencv_example main.cpp)

# Adding the OpenCV needed headers
target_include_directories(opencv_example PRIVATE ${OpenCV_INCLUDE_DIRS})

# Link your application with OpenCV libraries
target_link_libraries(opencv_example PRIVATE  ${OpenCV_LIBS})

And this is my toolchain file:

# Assuming that you already have a LLVM installation in your path...
set(CMAKE_C_COMPILER "clang.exe")
set(CMAKE_CXX_COMPILER "clang++.exe")

# Set the triple-target
set(CMAKE_CXX_COMPILER_TARGET x86_64-windows-gnu)

# Linker flags
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld -stdlib=libc++ -lc++abi -lunwind -funwind-tables -fexceptions -frtti")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -lunwind -funwind-tables -fexceptions -frtti")

Well, everything works. Even the installation of OpenCV in the indicated directory seems like a real installation, just with the files (or whatever) required to work.

But this is my first time with CMake, and I know that there's things wrong.

Specially, the part where I get the OpenCV as a dependency of the project. Reading CMake's documentation, I reached the following approach:

include(FetchContent)
FetchContent_Declare(
    opencv
    GIT_REPOSITORY https://github.com/opencv/opencv.git
    GIT_TAG 4.6.0
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
    CONFIGURE_COMMAND cmake -G "Ninja"
                    -DCMAKE_INSTALL_PREFIX=${OpenCV_INSTALL_DIR}
                    -DBUILD_TESTS=OFF
                    -DBUILD_PERF_TESTS=OFF
                    -DBUILD_EXAMPLES=OFF
                    -DBUILD_opencv_apps=OFF
                    -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
                    -DWITH_ADE=OFF
                    -Wno-dev
                    -S ${CMAKE_CURRENT_SOURCE_DIR}/build/_deps/opencv-src
                    -B ${CMAKE_CURRENT_SOURCE_DIR}/build
    BUILD_COMMAND  cmake --build . --target install WORKING_DIRECTORY ${OpenCV_BUILD_DIR}
)
FetchContent_MakeAvailable(opencv)

But I have problems. First of them is this:

set(OpenCV_DIR ${PROJECT_BUILD_DIRECTORY})

With this one, I encounter the following error(s) that just recurses up until the point where I can't scroll up in my terminal to see the command that I've launched to configure the project.

But with this OpenCV dir:

set(OpenCV_DIR ${PROJECT_BUILD_DIRECTORY}/win-install)

The configuration step goes almost well, but it has a flaw:

-- OpenCV_INCLUDE_DIRS
-- OpenCV_LIBS opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio

It founds the OpenCV libraries but not the includes. And the build process:

   87 | using result_of_t = typename std::result_of<T>::type;
      |                     ~~~~~~~~~~~~~~^~~~~~~~~
C:/Users/Alex Vergara/Desktop/code/opencv_example/build/_deps/opencv-build/3rdparty/ade/ade-0.1.1f/sources/ade/include/ade/util/type_traits.hpp:87:44: error: expected ';' after alias declaration
   87 | using result_of_t = typename std::result_of<T>::type;
      |                                            ^
      |                                            ;

This are just ADE compilation problems, where I explicitly disabled them with -DWITH_ADE=OFF, but now with the FetchContent approach, is not taking those CMAKE commands.

The question is:

Can I just make it work with this last approach? Can someone spot my errors and help me to fix them having a clear and solid CMake script? Why is not taking my configuration options now within FetchContent? PD: Sorry if some paths are not correct in the FetchContent approach, (I lost the count of how many times I tried).

0

There are 0 answers