How to include non Vcpkg on CMakeLists.txt? - c++

So I have a project which depends on opencv, which is installed with vcpkg. The project is build with cmake.
CMakeLists.txt
cmake_minimum_required(VERSION 3.19.1)
project(mylib)
set (CMAKE_CXX_STANDARD 14)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
link_libraries(${OpenCV_LIBS})
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
add_library(mylib SHARED mylib.cpp another_lib.cpp)
That works fine.
Now, instead of vcpkg provided opencv, I want to use opencv from
https://sourceforge.net/projects/opencvlibrary/files/4.4.0/opencv-4.4.0-vc14_vc15.exe/download
After installing it on C:\opencv I see there is opencv\build\OpenCVConfig.cmake, which find_package look for, right?
But how do I make cmake get this one instead of the one from vcpkg?

Use <PackageName>_DIR variable pointing to where the config file is located. It works for any library which comes with a config file.
For you it would look like this:
set(OpenCV_DIR "C:/opencv/build")
Since it is incorrect to add hard-coded paths into persistent scripts, you can choose among different methods of providing this variable to your script:
Console invocation: cmake OpenCV_DIR="C:/opencv/build"
CMake presets (user)
Local config by using some LocalConfig.cmake with the content above (set(...)), which you include in your main script like this: include(LocalConfig.cmake)

Related

How to include third party tools with cmake?

I have been working on a CPP project but was using configuration on visual studio IDE. Now, I wanted to use a build system generator CMake. It is a little difficult to getting started with this.
I am trying to add cppunit third-party tool for my testing. For that, I have added include and lib file in a folder third_party. But not sure how to include it in the CMakeLists.txt.
Please find CMakeList.txt
# CMake version setting
cmake_minimum_required(VERSION 3.8)
if(${CMAKE_VERSION} VERSION_LESS 3.19)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.19)
endif()
# Set project name and version
project(myproject
VERSION 1.0
DESCRIPTION "Setup cmake build system"
LANGUAGES CXX
)
# Third party dependencies
set(THIRD_PARTY_DIR "${PROJECT_SOURCE_DIR}/third_party")
# CPP unit
set(CPP_UNIT_LIB_NAME "cppunit")
set(CPP_UNIT_VERSION "1.13.2")
set(CPP_UNIT_DIR "${THIRD_PARTY_DIR}/${CPP_UNIT_LIB_NAME}/${CPP_UNIT_VERSION}")
# NOT sure what to do here
# add_subdirectory(${CPP_UNIT_DIR})
# target_include_directories(${PROJECT_NAME} PRIVATE "${CPP_UNIT_DIR}/include/cppunit")
# target_link_libraries(${PROJECT_NAME} ${CPP_UNIT_LIB_NAME} ${CPP_UNIT_LIBRARIES})
# target_compile_definitions(${PROJECT_NAME} PRIVATE "CPP_UNIT_INCLUDE_NONE")
add_subdirectory(src)
Please find the snap-shot of the folder structure
add_subdirectory(${CPP_UNIT_DIR}) will look in the directory specificied for a CMakeLists.txt and since CppUnit has a CMakeLists.txt file (https://github.com/Ultimaker/CppUnit/blob/master/CMakeLists.txt) it will build the library specified add_library(cppunit STATIC ${Sources}) which is cppunit.
And then when you specify your target to build, you can link in cppunit using target_link_libraries(your_target cppunit). But you need to create your target such as by using add_executable(one two.cpp three.h) which creates the target one.
https://cliutils.gitlab.io/modern-cmake/ is a good introductory resource for CMake. And there are different ways to bring in external projects such as through a git submodule.
If you have a CMakeLists.txt file in the src subdirectory, where you create a target you can link in cppunit.
As for the comment about include_directories, it is generally considered good practice to use target_include_directories instead, see What is the difference between include_directories and target_include_directories in CMake? and the above linked resource for more.

CMake: download precompiled binaries

I am trying to download precompiled binaries from a webserver within cmake. So is there something similar like ExternalProject_Add but without the actual build step?
The downloaded file is a tar.gz and would need to be extracted. It contains /bin /include and /lib and especially also /lib/cmake which should be found by the calling CMake project.
If I ExternalProject_Add results in an error that the build folder does not contain a CMakeLists.txt file.
The minium example is something like
cmake_minimum_required(VERSION 3.0)
project(Foo)
if (TARGET Bar)
message(STATUS "Foo and Bar are unified - how beautiful is that")
else()
include (ExternalProject)
ExternalProject_Add ( Bar # <------ This doesn't work
URL "http://THE-INTERNET"
)
endif()
find_package(Bar REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} Bar::Bar)
Ok, I figured out two things:
The command CONFIGURE_COMMAND "" can be provided to ExternalProject to not build anything.
The find_package() will never work like this. The ExternalProject is executed during compile time, while the find_package needs to find the target at configure time.
In the meantime I found this: https://cmake.org/cmake/help/latest/module/FetchContent.html - this might help to get targets ready during configure time and not just during compile time. However it is only supported from CMake 3.11 on :(

How can I add Vulkan to a cross platform CMake project?

In order to make a CMake project as simple and as portable as it can get I have consider to add the "whole" repositories of the libraries I need to the project.
The project structure is as follows:
MyProject/
└──CMakeLists.txt
└──src/
└──MyProject/
└── *.h & *.cpp
└── CMakeLists.txt
└──ThirdParty/
└──Vulkan-Hpp/
└──(Vulkan Files)
└──glfw/
└──(glfw Files)
└──SFML/
└──(SFML Files)
All the third party directories are the git submodules of the following repositories:
https://github.com/KhronosGroup/Vulkan-Hpp
https://github.com/SFML/SFML
https://github.com/glfw/glfw
Summarizing everything up, I'm having trouble integrating the vulkan and sfml libraries to the project.
MyProject/CMakeLists.txt is as follows:
cmake_minimum_required (VERSION 3.8 FATAL_ERROR)
project ("MyProject")
set (MyProject_VERSION_MAJOR 0)
set (MyProject_VERSION_MINOR 2)
set (MyProject_VERSION_PATCH 1)
set (CMAKE_CXX_STANDARD 17)
# Include sub-projects.
add_subdirectory ("src/MyProject")
add_subdirectory ("ThirdParty/glfw")
add_subdirectory ("ThirdParty/SFML")
add_subdirectory ("ThirdParty/Vulkan-Hpp")
MyProject/src/MyProject/CMakeLists.txt:
cmake_minimum_required (VERSION 3.8 FATAL_ERROR)
project ("MyProject")
find_package(Vulkan REQUIRED FATAL_ERROR) # error
find_package(SFML REQUIRED network audio) # error
find_package(glfw REQUIRED FATAL_ERROR) # error
# Add source to this project's executable.
add_executable (MyProject "MyProject.cpp")
target_include_directories (MyProject
PUBLIC ${GLFW_INCLUDE_DIRS}
PUBLIC ${SFML_INCLUDE_DIR}
PUBLIC ${VULKAN_INCLUDE_DIRS}
)
target_link_libraries (MyProject glfw)
target_link_libraries (MyProject ${VULKAN_LIB_LIST})
target_link_libraries (MyProject ${SFML_LIBRARIES})
How can I tweak CMake in order to use the third party libraries at my main project?
Is the project structure incorrect?
If your find_package(Vulkan REQUIRED FATAL_ERROR) line is failing, you need to make sure the Vulkan SDK is properly installed, i.e. that you have a VULKAN_SDK environment variable that points to the correct location.
Additionally, do not embed the KhronosGroup/Vulkan-Hpp repository. This repository is for building the Vulkan C++ bindings, but shouldn't be used directly. Instead you should be using the vulkan.hpp header that is bundled with your installation of the Vulkan SDK. Otherwise when people try to build your project and have a different version of the Vulkan SDK installed than is referred to by your embedded KhronosGroup/Vulkan-Hpp
More generally, you are using find_package and then later you're using add_subdirectory to try to incorporate these external projects. That's not how it works. find_package will look for a pre-existing binary of the package, while add_subdirectory isn't designed to just swallow entire existing external CMake projects.
If you want to have your project build these others from source you should investigate the use of CMake's external project functionality. However, you'll probably find this to be more of a burden than it's worth. Alternatively, install vcpkg for your target platform, and use vcpkg to build and install glfw and sfml, then tell CMake to use the vcpkg dependencies (see the vcpkg docs on how to pass the CMAKE_TOOLCHAIN_FILE to your cmake configure line.

How can I avoid linking directly to library files in cmake?

I'm writing a c project using cmake on a mac. I use homebrew. I installed libpqxx via homebrew. I have the following CMakeLists.txt.
cmake_minimum_required(VERSION 3.11)
project(imagedb)
set(CMAKE_CXX_STANDARD 14)
add_executable(imagedb main.cpp)
target_link_libraries( imagedb /usr/local/lib/libpqxx.dylib)
While this builds I would like to avoid using an absolute path here. How can I do this using cmake given that /usr/local is already in the path prefix?
Usually you should use find_package to find dependencies.
Looking at libpqxx's repo, you can see that they provide a CMake config file.
So in your CMakeLists.txt file you just have to do this:
find_package(libpqxx REQUIRED)
target_link_libraries(imagedb libpqxx::pqxx_shared)
If for some reason libpqxx-config.cmake is not shipped with the homebrew version, you have to write a find file.

C++ How to run programs in Clion when you need to include OpenGL libraries?

Hello I need to work with OpenGL and want to create my project in Clion. But Clion cannot compile and run my projects because of the libraries I need to include. I can create my own makefile and run the program in terminal, but I want to do it in the IDE. How can I make this happen?
First make sure you installed all libraries correctly using the compiler you configured in clion/cmake. Assuminf you have a fresh CMakeLists.txt like
cmake_minimum_required(VERSION 3.3.2)
project(MyGL CPP)
add_executable(demo-run main.cpp)
For linking your libraries you need two things. First tell the compiler where to find the include files and second which libraries to link. You could just hard code you local installation like
target_link_libraries(demo-run path/to/glfw.lib path/to/opengl.lib path/to/jpeg.lib ...)
target_include_directories(demo-run PRIVATE path/to/glfw/include path/to/opengl/include path/to/jpeg/include ...)
however this is not very portable and if you want to work with another compiler or on another machine your project file will fail. Instead you can use the package system of cmake
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
find_package(JPEG REQUIRED)
find_package(GLEW REQUIRED)
find_package (OpenGL REQUIRED)
find_package (GLM REQUIRED)
target_link_libraries(demo-run ${GLFW_LIBRARIES} ${GLEW_LIBRARIES} ${JPEG_LIBRARIES} ${OPENGL_LIBRARIES})
target_include_directories(demo-run PRIVATE ${GLFW_INCLUDE_DIRS} ${GLEW_INCLUDE_DIR} ${JPEG_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${GLM_INCLUDE_DIR})
The glfw part is a bit tricky and works only on linux i guess see http://www.glfw.org/docs/3.0/build.html.
This code is not tested at all and you may need to specify some enviroment variables so cmake can find the packages or provide additional find scripts like https://github.com/lighttransport/nanogi/blob/master/cmake/FindGLM.cmake.
I would recommend to use the CMake build tool which does the work generating Makefiles for you and is also directly supported by clion. When you open the directory containing a CMakeLists.txt (CMake Project File) with clion, it should be automatically be loaded and compiled (if not just hit build)
A very simple example CMake project would look like this
cmake_minimum_required (VERSION 2.8.9)
project (OpenGl-Stuff)
include_directories(src)
add_executable(your-binary src/your-code.c src/your-code.h)
target_link_libraries(your-binary opengl)
# target_link_libraries will search for libopengl on standard system paths,
# maybe the library is not called libopengl, then you have to adjust the name above
this cmake project will generate the binary for you and link it against opengl