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

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.

Related

How to include non Vcpkg on CMakeLists.txt?

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)

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.

Specifying Build Options for External CMake Dependency

I am in the process of writing my project's CMakeLists.txt file. My project relies on an external dependency, GLFW, luckily for me GLFW also uses CMake for its build system. I am using find_package() and git submodules to handle dependency management, currently this is how my CMakeLists.txt file looks like:
# CMake version
cmake_minimum_required(VERSION 3.0)
# project name
project(CHIP-8)
# dependency management
find_package(OpenGL REQUIRED)
find_package(glfw)
if(NOT glfw)
message("Unable to locate glfw.")
message("Cloning the repository.")
execute_process(
COMMAND
git submodule update --init -- libs
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
)
message("Building glfw.")
add_subdirectory(libs/glfw)
endif()
From my limited understanding of CMake the command add_subdirectory(libs/glfw) runs CMake on the recently cloned glfw sub-module. The problem is a lot of unnecessary features are part of the default build for GLFW such as examples, unit tests, and documentation.
The documentation for compiling GLFW lists the CMake options for disabling these features GLFW_BUILD_EXAMPLES, GLFW_BUILD_TESTS, and GLFW_BUILD_DOCS.
I have two questions, the first being how can I specify these options, and the second is the argument I pass for find_package accurate (I do have GLFW installed on my system yet every time I build it still attempts to clone and build the repository).
Found my answer in a similar question.
All I had to do was add:
option(GLFW_BUILD_EXAMPLES OFF)
option(GLFW_BUILD_TESTS OFF)
option(GLFW_BUILD_DOCS OFF)
right before add_subdirectory(libs/glfw).

How do I use cmake to build external libraries as well as my own application?

I am trying to build a cross platform OpenGL application, which means building and including multiple libraries (glfw, glbinding, glm, etc.) Because my application is cross platform, it makes sense to use cmake to generate all the build scripts and not have to muck about with them myself. I am attempting to target Windows and Linux specifically.
A main feature that I need is that the libraries I need are not installed on the host system. Furthermore, they cannot be installed (due to administrative reasons). What I need is to build these libraries and then build my application.
I am mostly working on Windows using Visual Studio 2017, which has cmake support included. Currently, I have attempted to build these libraries myself, however I am having many issues getting find_package to do the right thing.
My directory structure looks like this:
project/
|-src/
|- my sources for my application
|-include/
|- my header files
|-external/
|-glfw-3.2.1/
|-glbinding-2.1.4/
|-glfw-build/
|-glbinidng-build/
So I am attempting to build the external libraries and use them in my application. I am also attempting to follow cmake best practices. My CMakeLists.txt currently looks like this:
cmake_minimum_required(VERSION 3.5)
project(glTestProj)
set(CMAKE_PREFIX_PATH "external/")
find_package(glfw3 3.2 REQUIRED)
find_package(glbinding REQUIRED)
add_executable(glTest src/main.cpp)
target_compile_features(glTest PRIVATE cxx_std_17)
target_compile_options(glTest PRIVATE -Wall -Wextra)
target_link_libraries(
glTest
glfw
glbinding::glbinding
)
The libraries in question (glfw and glbinding) both have instructions on including them via cmake, however I am running into this issue:
CMake Error at CMakeLists.txt:6 (find_package):
By not providing "Findglfw3.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "glfw3", but
CMake did not find one.
Could not find a package configuration file provided by "glfw3" (requested
version 3.2) with any of the following names:
glfw3Config.cmake
glfw3-config.cmake
Add the installation prefix of "glfw3" to CMAKE_PREFIX_PATH or set
"glfw3_DIR" to a directory containing one of the above files. If "glfw3"
provides a separate development package or SDK, be sure it has been
installed.

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