Making the script more complex
In this section, we are showing a more complex script that includes subfolders, libraries, and executables; all told, just two files and a few lines, as demonstrated in this script. It's not mandatory to create multiple CMakeLists.txt files, because we can specify everything in the main CMakeLists.txt file. However, it is more common to use different CMakeLists.txt files for each project subfolder, thereby making it more flexible and portable.
This example has a code structure folder, which contains one folder for a utils library and the root folder, which contains the main executable:
CMakeLists.txt main.cpp utils/ CMakeLists.txt computeTime.cpp computeTime.h logger.cpp logger.h plotting.cpp plotting.h
Then, we have to define two CMakeLists.txt files, one in the root folder and the other in the utils folder. The CMakeLists.txt root folder file has the following content:
cmake_minimum_required (VERSION 3.0) project (Chapter2) # Opencv Package required FIND_PACKAGE( OpenCV 4.0.0 REQUIRED ) #Add opencv header files to project include_directories(${OpenCV_INCLUDE_DIR}) link_directories(${OpenCV_LIB_DIR})
# Add a subdirectory to the build. add_subdirectory(utils) # Add optional log with a precompiler definition option(WITH_LOG "Build with output logs and images in tmp" OFF) if(WITH_LOG) add_definitions(-DLOG) endif(WITH_LOG) # generate our new executable add_executable(${PROJECT_NAME} main.cpp) # link the project with his dependencies target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} Utils)
Almost all lines are described in previous sections, except some functions which we will explain. add_subdirectory() tells CMake to analyze CMakeLists.txt of a desired subfolder. Before continuing with the main CMakeLists.txt file explanation, we are going to explain the CMakeLists.txt file in utils.
In the CMakeLists.txt file of the utils folders, we are going to write a new library to include in our main project folder:
# Add new variable for src utils lib SET(UTILS_LIB_SRC computeTime.cpp logger.cpp plotting.cpp ) # create our new utils lib add_library(Utils ${UTILS_LIB_SRC}) # make sure the compiler can find include files for our library target_include_directories(Utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
This CMake script file defines a variable, UTILS_LIB_SRC, where we add all source files included in our library, generate the library with the add_library function, and use the target_include_directories function to allow our main project to detect all header files. Leaving the utils subfolder and continuing with the root CMake script, the Option function creates a new variable, in our case WITH_LOG, with a small description attached. This variable could be changed through the ccmake command line or CMake GUI interface, where the description appears, and a check that allows users to enable or disable this option. This function is very useful for allowing the user to decide about compile-time features, such as whether we want enabling or disabling logs or not, compiling with Java or Python support, just as OpenCV does, and so on.
In our case, we use this option to enable a logger in our application. To enable the logger, we use a pre-compiler definition in our code, as follows:
#ifdef LOG logi("Number of iteration %d", i); #endif
This LOG macro can be defined in our CMakeLists.txt through a call to the add_definitions function (-DLOG), which itself can be run or hidden by the CMake variable WITH_LOG with a simple condition:
if(WITH_LOG) add_definitions(-DLOG) endif(WITH_LOG)
Now we are ready to create our CMake script files to compile our computer vision projects in any operating system. Then, we are going to continue with the OpenCV basics before starting with a sample project.