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 andLIBC++
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).