CMake: Create DLL including dependencies instead of separate dll's - c++

Im writing a SDK for Windows and Mac OS in C++, and im using CMake.
On windows, I'd like the compiled DLL to contain all necessary dependencies, instead of having separate DLLs for all third party libraries im using.
Here are the relevant sections of the MakeFile:
find_package(OpenSSL REQUIRED)
find_package(CURL CONFIG REQUIRED)
find_package(nlohmann_json 3.2.0 REQUIRED)
find_package(spdlog REQUIRED)
find_package(unofficial-sqlite3 CONFIG REQUIRED)
....
add_library(${PROJECT_NAME} SHARED ${SRC_FILES})
...
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::Crypto CURL::libcurl nlohmann_json::nlohmann_json spdlog::spdlog_header_only unofficial::sqlite3::sqlite3)
This generates the following separate DLLs:
fmt.dll
libcrypto-1_1.dll
libcurl.dll
sqlite3.dll
zlib1.dll
Is it possible to create a library containing all dependecies, like it is on Mac OS with the generated dylib?

I'm using Vcpkg for simplicity but you should compile your dependencies as static libraries instead of shared.
If you're using vcpkg you can install the dependencies as static like such
vcpkg.exe install openssl:x86-windows-static
Make sure you run CMake with VCPKG_TARGET_TRIPLET set to x86-windows-static or whatever platform you're on.
As you can see example.dll is now statically linked to OpenSSL.
Cheers

Related

Using CMake to create an executable that can run independently on other machines

I’m using LibTorch and OpenCV for a program in Cpp. The compilation and building is done on Linux using CMake. The program builds and runs as expected.
I want to use the executable that CMake created on another Linux machine.
The problem is that I don’t want to install either LibTorch nor OpenCV on the other machine. I’d rather supply the user with a single executable if possible.
How can CMake create a single independent executable?
If making just a single file is irrelevant, how can CMake copy all needed libraries to a single directory?
The current CMake file:
cmake_minimum_required(VERSION 2.8)
project(prediction)
list(APPEND CMAKE_PREFIX_PATH “libtorch”) # the folder where libtorch in found
set(CMAKE_BUILD_TYPE Release)
find_package( OpenCV REQUIRED )
find_package( Torch REQUIRED )
if(NOT Torch_FOUND)
message(FATAL_ERROR “Pytorch Not Found!”)
endif(NOT Torch_FOUND)
message(STATUS “Pytorch status:”)
message(STATUS " libraries: ${TORCH_LIBRARIES}")
message(STATUS “OpenCV library status:”)
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
file(GLOB SOURCES ".h" ".cpp") # Link all headers and sources in root dir
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable(entrypoint ${SOURCES})
target_link_libraries(entrypoint ${TORCH_LIBRARIES} ${OpenCV_LIBS})
set_property(TARGET entrypoint PROPERTY CXX_STANDARD 14)
####### EDIT
Thanks for the answers.
Following Phesho_T answer bellow, I got the static compilation of LibTorch, but it won't compile with the set() instruction. It throws C10_LIBRARY NOTFOUND.
I think I'll try to use the shared libraries. How can CMake be instructed to copy the releveant shared libraries to the "build" folder, so I can pack everything in a .zip file and send it to the user.
Like another answer said, you need to link the static libs of Torch and OpenCV in your executable.
There are a few pre-requisites for this:
The two libraries need to have static (.a) libraries installed on your system. If they don't, you may have to manually build them. Steps for this differ between different packages.
You need to tell CMake to search for the static libraries ONLY. This is done via the CMAKE_FIND_LIBRARY_SUFFIXES variable. The chances are the default for this is .so;.a, meaning it will find the shared library first.
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
The fact that you're using variables in your target_link_libraries command, instead of imported libraries (the modern CMake way) makes me think that this should be enough - these variables should expand to full paths to the static libraries, which should then be added to your linker command.
Things are a bit more complicated to explain if imported targets were used, but this might be out-of-scope for this question.
Try it out and let us know how you get on.
To create a single executable you need to statically link the dependencies into your executable. Check your libraries to see if they provide static-libs else you need to recompile libtorch or opencv to make static libraries.

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.

Include Boost library in C++ cross platform project using CMake

I need to include a Boost library (specifically Context) in a C++ project that uses CMAKE as build management system.
Since, given the source code of the repository, the project needs to be built using cmake and make without any other software or library installation in the target system (unix,windows or whatever), I need to configure Cmake to take the source of Boost from my repository, compile it, and link it to my project without installing Boost library in the target system in a separated step.
Is this feasible?
CMake has a specific module for handling boost` libraries, see FindBoost.
The CMakeLists.txt file normally includes something like this to link to a boost library:
find_package(Boost REQUIRED COMPONENTS context )
if(Boost_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} INTERFACE Boost::context)
endif(Boost_FOUND)
This will just link the boost::context library. You must either build the boost::context lib files as suggested in #Hugo's answer, download them from somewhere like here or use a package manager to install them on linux.
If Context was header only, you would only require:
find_package(Boost REQUIRED COMPONENTS boost)
if(Boost_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
endif(Boost_FOUND)
In either case you can include the boost::context files in your project and then set the variables BOOST_ROOT or BOOST_INCLUDEDIR as described in the FindBoost documentation.
Yes, you can use ExternalProject_Add, see the documentation at https://cmake.org/cmake/help/latest/module/ExternalProject.html
Take a look at the link below for an example of use which compiles boost
https://github.com/arnaudgelas/ExternalProject/blob/master/External-Boost.cmake
HTH

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

How to stop cmake add wxjpeg.lib to visual studio project?

I have a project that uses both OpenCv and wxWidgets in a static library. These two libraries have definitions for jpeg and hence are generating conflicts during compilation.
As I am not using jpeg which is inside wxwidget, I would like to remove this library from my application. I tested my application and if I remove this library manually from MSVC poroject, it works well.
In cmake I have this line to add wxwidgets to my project:
set(wxWidgets_CONFIGURATION msvc)
find_package(wxWidgets COMPONENTS core base adv REQUIRED)
include(${wxWidgets_USE_FILE})
How can I instruct cmake not to add wxjpeg.lib to the requested linked libraries?
Based on the documentation to this cmake module (link) I would say that adding
set(wxWidgets_EXCLUDE_COMMON_LIBRARIES TRUE)
before using the find_package command would be enough to exclude wxjpeg.lib. Since this also excludes other common libraries (e.g. png), you may have to explicitly include more in your call to find_package
find_package(wxWidgets COMPONENTS core base adv png REQUIRED)