How to build and deploy an external library with CMake [duplicate] - cmake

This question already has answers here:
CMake link to external library
(6 answers)
Closed 6 months ago.
I would like to use and deploy an external library in my program.
My project's structure is as follow (simplified):
ProjectDir
|_ _build
|_ CMakeLists.txt
|_ Src
| |_ CMakeLists.txt
| |_ .h and .cpp files
|_ ThirdParty
|_ CMakeLists.txt
|_ ExternalLib
|_ includes
| |_ .h files
|_ lib
|_ Windows
| |_ .dll files
|_ Linux
|_ .so files
For this library, I've only the include files and the binaries for Windows and Linux.
I'm able to find the includes files by using target_include_directories() in the CMakeLists.txt of the ThirdParty directory but I cannot build my program even by declaring the libraries with :
target_link_libraries(${CMAKE_PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty/ExternalLib/lib/Windows/extLib)
Note: this command is also in the CMakeLists.txt of ThirdParty directory.
I get the following error:
'../../../ThirdParty/ExternalLib/lib/Windows/extLib', needed by 'program' missing and no known rule to make it
I develop on a Windows platform with VS2022 and my program will be build and installed on a Linux server.
On Windows I've the latest version of CMake but on Linux the version is 3.16.
Can somebody help me in fixing this error?

You should import library as a target of you project.
For instance something like
add_library(your_lib SHARED IMPORTED)
set_property(TARGET your_lib PROPERTY
IMPORTED_LOCATION
"${CMAKE_SOURCE_DIR}/ThirdParty/ExternalLib/lib/Linux/extLib.so") # to be adapted for windows
target_include_directories(your_lib
PUBLIC
${CMAKE_SOURCE_DIR}/ThirdParty/ExternalLib/include)
then you should be able to use it as any other library in cmake:
target_link_libraries(yourExecutable PRIVATE your_lib)
see doc in details here:
https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html

Related

CMake fix_bundle how to ignore embedded dll

My system has some dlls that are linked in other embedded executables, like commands from MSYS.
Directories structure:
MySystem/
|_ mysystem.exe
|_ CMakeLists.txt
|_ embedded system/
|_ msys_command1.exe
|_ msys_command2.exe
|_ msys-1.0.dll
When it is running fixup_bundle from CMake, this warning is showed:
EXEC : warning : cannot resolve item 'msys-1.0.dll'
possible problems:
need more directories?
need to use InstallRequiredSystemLibraries?
run in install tree instead of build tree?
EXEC : -- warning : gp_resolved_file_type non-absolute file 'msys-1.0.dll' returning type 'other' -- possibly incorrect
--
EXEC : warning : cannot resolve item 'msys-1.0.dll'
possible problems:
need more directories?
need to use InstallRequiredSystemLibraries?
run in install tree instead of build tree?
The MSYS commands are within the software embedded directory.
If I put the embedded directory on fixup_bundle paths, the dlls are copied to my executable directory, but I don't want that behavior.
Is there a way to ignore that dlls?
I've tried with fixup_bundle macro IGNORE_ITEM, but it didn't work.
Besides that, the problem propagates to CPack:
CPack: Create package using NSIS
CPack: Install projects
CPack: - Install project: MySystem
Error copying file "msys-1.0.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/msys-1.0.dll".
Error copying file "msys-intl-8.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/msys-intl-8.dll".
Error copying file "Qt5Core.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/Qt5Core.dll".
Error copying file "Qt5Gui.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/Qt5Gui.dll".
Error copying file "Qt5Network.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/Qt5Network.dll".
Error copying file "Qt5Widgets.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/Qt5Widgets.dll".
Error copying file "libprotobuf.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/libprotobuf.dll".
Error copying file "lua.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/lua.dll".
Error copying file "qwt.dll" to "D:/mysystem/solution/build/_CPack_Packages/win64/NSIS/MySystem/qwt.dll".
CPack: Create package
Not sure if this is what you need but I made a custom fixup_bundle function which also uses the IGNORE_ITEM key to skip libraries.
I call fixup_bundle2 as follows:
install(CODE "
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/dist/cmake)
include(InstallRequiredSystemLibraries)
include(BundleUtilities)
include(FixUp)
fixup_bundle2(\"\${CMAKE_INSTALL_PREFIX}/${APPS}\" \"${LIBS}\" \"${DIRS}\" IGNORE_ITEM \"exe_with_z64;exe_with_zip;libopenvr_api_so\")"
)
Note the set(CMAKE_MODULE_PATH... line which is there to include my own provided fixup_bundle2 from my FixUp.cmake file. Also note that I need to specify libopenvr_api_so while in reality it is libopenvr_api.so.
fixup_bundle2 is a copy of fixup_bundle with the following added in the foreach(key ${keys}) loop:
# also ignore libs in INGORE_ITEM
if(key IN_LIST CFG_IGNORE_ITEM)
message(STATUS "skipping ${key}")
continue()
endif()
You'll also need to set
cmake_policy(SET CMP0057 NEW)
in the FixUp.cmake file apparently.

How to add C++REST SDK as a submodule with CMake?

I am trying to build a project with numerous dependencies such as Boost, OpenSSL, and C++ REST SDK. However, it is required that the source code is included in the project workspace and that the library is built from said source code.
The most consistently successful way I have found to achieve this is though the use of git submodule add <URL>, add_subdirectory, target_link_libraries, and some clever projects built for this purpose such as boost-cmake and openssl-cmake.
Take for example the following project structure:
prjct
| include/
| libs/
| | boost-cmake/
| | openssl-cmake/
| | cpprestsdk/
| src/
| tests/
| CMakeLists.txt
For which the top-level CMakeLists.txt would contain:
...
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/boost-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/cpprestsdk)
target_link_libraries(${PROJECT_NAME_L}
PUBLIC
Boost::system
Boost::thread
Boost::log
Boost::program_options
Boost::chrono
ssl # OpenSSL::SSL
crypto # OpenSSL::Crypto
cpprestsdk::cpprest
)
...
However, in the case of the cpprestsdk library, I recieve the following error upon running cmake .. from build/:
CMake Error at CMakeLists.txt:55 (add_library):
Target "prjct" links to target "cpprestsdk::cpprest" but the target
was not found. Perhaps a find_package() call is missing for and IMPORTED
target, or an ALIAS target is missing?
How can I link and use the C++ REST SDK within these constraints?

How to make intermediate object file not a library using qmake?

Filesystem layout:
MyProject
|_ myproject.pro
|_ FuncA
|_ core.cpp
|_ core.h
|_ core.pro
|_ app
|_ main.cpp
|_ app.pro
I want just to compile "core.cpp" in FuncA to make a object file not a library. That is "gcc -c core.cpp". And in app I want to make main program linking core.o created previously.
In this case how do I make core.pro? Which TEMPLATE should I use?
Use can use generic app template for core.pro. It will create intermediate core.o anyway, which you can link later in app.pro like so:
LIBS += $$PWD/../FuncA/core.o
I solved this problem with "static library config" so that it will not make ".so" libs and then link that static library with main program.
TEMPLATE = lib
CONFIG += staticlib

How to add source files in another folder

I'm using cmake to build my project in C++. Assume I have the following directories on my Source folder
Source
|_Dir1
| |_Class.cpp
| |_Class.hpp
|
|_Dir2
|_Main.cpp
In Dir1 there's a class with its header and implementation files (Class.cpp and Class.hpp).
In Dir2 there's the main application which uses the class in Dir1
What is the good way to tell the CMakeLists in Dir2 to build the executable with Dir1/Class.cpp file?
EDIT: To be more specific, I want to define that the source file for Class.cpp has to be used in Dir1's CMakeLists.txt, and not in Dir2's. Doing it the other way feels plain wrong to me and it's hard to use, so if there's a reason they're enforcing me to do this some clarification on the topic would be nice.
What I'm currently doing is hard-coding the Class.cpp file location in Dir2/CMakeLists.txt but that just doesn't scale when I've got a bunch of classes interacting together.
Supposed you have a single CMakeLists.txt file at the Source directory, you'll create two variables using different file() commands
file(GLOB Dir1_Sources RELATIVE "Dir1" "*.cpp")
file(GLOB Dir2_Sources RELATIVE "Dir2" "*.cpp")
and add both sets generated by the file() commands to your target's source list:
add_executable(MyProgram ${Dir1_Sources} ${Dir2_Sources})
Alternatively you can place a CMakeLists.txt file under Dir1 and Dir2 (Main) looking as follows
Source
|
|_ CMakeLists.txt
| > project(MyProgram)
| > cmake_minimum_required(VERSION 3.8)
| > add_subdirectory("Dir1")
| > add_subdirectory("Dir2")
|
|_ Dir1
| |_ CMakeLists.txt
| > file(GLOB Sources "*.cpp")
| > add_library(Dir1 STATIC ${Sources})
|_ Dir2
|_ CMakeLists.txt
> file(GLOB Sources "*.cpp")
> add_executable(MyProgram ${Sources})
> target_link_libraries(MyProgram Dir1)
to add subdirectories as further (static) libraries linked to your main target.

Add a dependency not in a subdirectory using CMake

Let's say there's following directory structure:
root
|
+--projects
| |
| +-test
| |
| +-CMakeFiles.txt
|
+--libs
|
+-testlib
|
+-CMakeFiles.txt
test contains CMakeFiles.txt and testlib also contains CMakeFiles.txt. "test" produces an executable and "testlib" produces a static library.
I want "test" to link with "testlib" without using symlinks and without moving "testlib" library into a subdirectory within "test".
Because "testlib" isn't a subdirectory of "test", I can't do
add_subdirectory("../../libs/testlib")
In test's CMakeFiles.txt - CMake will complain about "testlib" not being in the "test" subdirectory.
Also, because system has several different compilers, I can't simply install "testlib" libraries into some kind of central directory, so I want test to compile a local copy of testlib and link with it (i.e. as if testlib was a subdirectory). I also want the "test" project to automatically rebuild "testlib" if it has been changed.
So, how can I deal with it? I am using CMake 2.8.4 on Windows XP SP3.
You could either provide a top-level CMakeLists.txt in root, or provide a binary directory to the add_subdirectory command; e.g.
add_subdirectory("../../libs/testlib" "${CMAKE_CURRENT_BINARY_DIR}/testlib_build")
This creates a subdirectory called testlib_build in your current build directory which contains the generated project files for testlib, but not the source.
For further info, run
cmake --help-command ADD_SUBDIRECTORY
The only way I see to do this - create CMakeLists.txt in root and put the following code there:
add_subdirectory(projects/test)
add_subdirectory(lib/testlib)
When you have done this, you can do target_link_libraries(test testlib) in test/CMakeLists.txt, and it will be automatically rebuilt if you change something in testlib.