Depending on the INSTALL target of a CMake External Project - c++

Is there a way to identify dependencies of the installation-step of a target in cmake? Here's my situation:
My goal is to be able to download the source code of this project and build it without first installing the dependencies. In other words, I'd like the dependencies to be recognized and installed prior to trying to build the main target. For example, I'm working on including Leptonica as an external project:
set(leptonica_build "${CMAKE_CURRENT_BINARY_DIR}/leptonica")
ExternalProject_Add(
leptonica
DOWNLOAD_DIR ${download_dir}
BINARY_DIR ${leptonica_build}
GIT_REPOSITORY ${OpenCV_git_repository}
GIT_TAG ${OpenCV_git_tag}
TLS_VERIFY true
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=${DOC_READER_INSTALL_PREFIX}
)
Running the target leptonica correctly builds and installs the library into a temporary directory, making itself available to other targets to consume:
add_dependencies(myProgram leptonica)
find_library(LEPT_LIB lept)
target_link_libraries(myProgram ${LEPT_LIB})
The problem is that, when /tmp is cleared and cmake is first executed with the target of myProgram, liblept.so isn't found because it hasn't yet been installed, and consequently an upstream dependency of myProgram hasn't been met until after make install has been run.
In other words, I'd like the build script to first download and install then dependencies, then try to lookup the location of the libraries needed by downstream build steps. Is this possible to do with cmake or should I be accomplishing this goal some other way?

Build and install leptonica from a separate CMakeLists.txt. Alternatively, you can use the same CMakeLists and selectively enable either the ExternalProject-section or the main section of your CMakeLists with a control variable (-DMYPROJECT_INSTALL_DEPS=1)
You can trigger the configure/build steps of leptonica from shell script, or call cmake from the main CMakeLists with execute_process:
execute_process(
COMMAND ${CMAKE_COMMAND} -H... -B...
COMMAND ${CMAKE_COMMAND} --build ... --target install ...
)
That way the entire configuration/build/install steps will get executed in the configuration step of your main project.

Related

Include googletest into CMake installation process

I have a C++ project that I am able to compile into a static library using CMake. I am also testing this project using googletest but after sifting through previous answers on getting the utility working with CMake projects I am stuck.
The root dir of my project contains the necessary code to compile my project into a static lib in the standard paths. Here is an example of the CMakeLists.txt file in my tests/ directory :
# Download and install GoogleTest
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
FetchContent_MakeAvailable(googletest)
# TESTS
add_executable(
bin test.cpp
)
# enable testing
enable_testing()
target_link_libraries(
bin
lib
# GTest::gtest
GTest::gtest_main
pthread
)
include(GoogleTest)
gtest_discover_tests(bin)
This successfully build the googletest library and my tests but doesn't run them automatically. I had to run ctest manually after my process to see the result of my tests. I want my typical cmake.. , make, make install process to build my project upon successful tests. Is there a way to do this? I think it makes sense for tests to pass as the first step before installing the library itself. Is there also a way to check for an installation of googletest on the system before installing the package from source?
To my understanding - both gtest_discover_tests() and gtest_add_tests() are only for replacing CMake's add_test() i.e. they discover and add tests to the ctest executable .
It is also not standard that you run tests during cmake <...>, make <...>, make install. So a good thing to think about is, to make an option that allows the end-user to decide if he/she wants to run tests.
That being said the easiest way on how to get your tests to run let's say - post build. Is to add_custom_command(), e.g.:
if(RUN_MTPK_TESTS)
add_custom_command(TARGET test_openMTPK
POST_BUILD
COMMAND ctest --output-on-failure)
endif()
Then by running: cmake -S[source] -B[build] -DRUN_MTPK_TESTS=TRUE you will, after running make, execute your tests through ctest.
To answer your last question, is there a way on how to check if googletest is already installed? Yes there is and it requires some additional conditions in your CMakeLists.txt. Example:
find_package(GTest)
if(NOT GTest_FOUND)
#FetchContent, etc...
endif()
#rest of your cmakelists
EDIT: Check find_package() for more information regarding the use of find_package and what variables it sets and how can you customize the behavior of said command.

How to install a Library for C++ like Eigen and sharkML at vs code?

I am trying to install libraries like eigen, sharkMl, xtensor, and others in VSCode for C++.
Please if anyone can help me to know the right way to do that.
All of these libraries use CMake for their build system so what I do is use CMake as my build system. My favorite way to do this is to use the libraries build systems to install them and then inlcude them with cmakes find_package function. This you can do by cloning the git repository for the library then build it and install it with cmake. On linux you do this by:
git clone https://gitlab.com/libeigen/eigen.git
cd eigen
mkdir build
cd build
cmake ..
sudo make install
VSCode has good integration for cmake so if you have the C/C++ Extension pack you will be able to build with cmake. In your project folder make a CMakeLists.txt file and add the packages you want:
add_executable(main main.cpp)
find_package(Eigen3 3.4 NO_MODULE)
target_link_libraries(main Eigen3::Eigen)
(This example assumes the main cpp file is main.cpp and creates an executable called main) Then when you press ctr+shift+p and perform CMake: Configure you can select your compiler and build the executable.

how can i make some install command run before compile process?

I will use install command in my CMakeLists like this:
install(DIRECTORY lib-mmm/src/infra/ DESTINATION /home/nick/infra FILES_MATCHING PATTERN "*.h")
this is command to install some directory to some place.
I want this run before other compile process.
but i found when i define it as install, it will be called only when make install, which is after make process.
how can i make install directory command run before real compile process?
Afaik there is no way to do this by using the same project. The install target depends on the targets being build and any dependency of building on the install target would result in a circular dependency.
There are alternatives though:
Use file(COPY)
Use execute_process to set up, build & install another cmake project during configuration. It can be problematic though to get cmake to use the same options for that build. This could also be refined by getting add_custom_command involved...
In your case though simply adding the correct include directory using target_include_directories will probably work better though.

How can I use OpenCV without running 'make install'?

I am new to cmake and OpenCV.
Is there a way that I can use OpenCV on my machine by just building the source code and not installing them to /usr/local/lib on my machine, i.e. without running make install after building the binaries?
The solution would be to set CMAKE_INSTALL_PREFIX to a specific location:
# in opencv/build
cmake .. -DCMAKE_INSTALL_PREFIX=/home/user/path/to/deps/
cmake --build . --target install
Then, configure your project with the same prefix:
# in your project/build
cmake .. -DCMAKE_PREFIX_PATH=/home/user/path/to/deps/
In your cmake files, simply use find_package(OpenCV)

cmake install does not trigger custom command

In my project I use add_custom_command to generate some output file:
add_custom_command(
OUTPUT ${LIB_NAME}
# commands
)
add_custom_target(Core-static DEPENDS ${LIB_NAME})
I then have instruction to install the library:
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}"
DESTINATION "${CORE_INSTALL_DIR}/lib/"
)
When I manualy build Core-static target, I can then successfuly run installation. However, running install does not trigger the custom command and the library is not produced resulting in an error. Also, for some reason rebuilding the solution (in Visual Studio) does not trigger Core-static project build.
In CMake, installing triggers only ALL (pseudo-)target.
For make your file installable, you need to force ALL target to build your file. Currently, your custom target Core-static is not buit by default (by ALL target). For fix that, add ALL keyword when create the target:
add_custom_target(Core-static ALL DEPENDS ${LIB_NAME})