I am using a third party macOS framework called CrashReporter in my CMake project like so:
cmake_minimum_required(VERSION 3.15)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
project(bug CXX)
find_package(CrashReporter REQUIRED)
add_executable(bug
"${CMAKE_CURRENT_SOURCE_DIR}/main.mm"
)
set_target_properties(bug PROPERTIES LINK_FLAGS "-ObjC")
target_link_libraries(bug PUBLIC "-framework AppKit")
target_link_libraries(bug PRIVATE ${CRASHREPORTER_FRAMEWORK})
If I copy my executable to another machine it complains that the library is not found.
Is it possible to statically link (not embed) the framework in the executable?
A Framework and a static library are two different things. You can't change the nature of a framework to it to be statically linked. BUT! Your third party provider may offer you an installation package that includes a framework, a dynamic library and a static library, so you may have the option to choose the one to link. Or if your third party library is open source you can build it yourself as you prefer. It is even possible that the static and dynamic libraries are shipped inside the framework, because a framework is symply a directory similar to an app bundle. If you installed a package with several flavors, then you may set this variable to influence the find_package results:
CMAKE_FIND_FRAMEWORK(NEVER)
Before find_package() so CMake will ignore frameworks and search only for unix libraries.
If you know that there is a static library, and where it is, you may provide the full name of the static library to the target_link_libraries() command:
target_link_libraries(bug PRIVATE ${CRASHREPORTER_STATIC_LIBRARY})
Assuming that there is a CRASHREPORTER_STATIC_LIBRARY variable holding the full name and path of the static library (something like '/path/to/crashreporting.a').
Related
My target linked with several libraries using TARGET_LINK_LIBRARIES with PUBLIC keyword, The INSTALL command looks like INSTALL(TARGETS foo DESTINATION ${CMAKE_INSTALL_PREFIX}/bin). I want somehow to force the cmake to include all (preferably excluding system libraries) libraries (SOs only) I link with to be included in the installation process. I've tried EXPORT keyword but looks like it affects only libraries which I build with in my project and marked with the same EXPORT as foo library.
Is it possible?
EDIT001: Additional information that may affect answer.
I'm using vcpkg to manage third parties. So the TARGET_LINK_LIBRARIES looks like
TARGET_LINK_LIBRARIES(foo PUBLIC
GTest::GTest
GTest::Main
${GOOGLE_MOCK}
event
${THRIFT_LIBRARIES}
${Boost_LIBRARIES}
lzo2
sqlite3
${ZeroMQ_LIBRARY}
gRPC::grpc
gRPC::grpc++
xml2
stdc++fs
bfd
-l:libisal.so.2
sgutils2
pthread
uuid
rt
)
So, essentially what I want to achieve is to take all these libraries which are macro'ed by vcpkg, like ${THRIFT_LIBRARIES}, ${Boost_LIBRARIES} and gRPC::grpc and so on
As of cmake 3.21, you can now do with:
install(IMPORTED_RUNTIME_ARTIFACTS gRPC::grpc)
install(IMPORTED_RUNTIME_ARTIFACTS ${Boost_LIBRARIES})
etc.
See new Install command.
CMake itself does not allow to install dependencies automatically. This would be a rather hard task, because it would have to consider a lot of corner cases.
Just think of transitive dependencies (I don't know if this is the right word), like: Your libA depends on libB, which depends on libC. How should CMake get this from the CMakeLists, where only libB is listed?
Or: What do you consider a system library? Everything that is not in PATH? How do you know which libraries are installed system-wide on the client's machine?
You see, there are some really tricky things to consider.
Here are some possibilities you have:
Ask your users to install the dependencies.
Statically link libraries into your binary.
Copy library files using install(FILES files... DESTINATION <dir>). Maybe your dependency manager can help creating the list of files.
Write a script that does something like windeployqt for Qt-based applications on Windows: Analyze the binary file (e.g. using ldd myApp) and automatically copy over the required dependencies.
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
I have a application which need to use two libraries (pugixml and lua) and need to be an multi-platform build capable. I am trying to use Cmake for this. Since I have three different solution (two for creating static libraries and one solution which actually uses that libraries). So far what I do is run Cmake for those two libraries and copy those static libraries manually to the lib folder into application and run cmake again.
I need to reduce the three step and make it as a single step so that I can handle the multi-platform build in a single shot.
I need to know, should we need to create a dynamic link library or shared library or static library for these kind of operation?
And need help on how to do it. I tried creating the source folder of pugixml and copy the cpp/hpp/h file and wrote a cmakelists file like
set(HEADERS pugixml.hpp pugiconfig.hpp)
set(SOURCES ${HEADERS} pugixml.cpp)
add_library(pugixmlLib STATIC ${SOURCES})
target_link_libraries(pugixmlLib pugixml)
On the solution I could see my application project and pugixml project, but on my application project linker property I could find pugixml library.
I've just been reading about CMake's Config-File Package "concept" which sounds very promising. What I like very much about it is that if I create a Config-File Package myself I can specify other packages on which it depends. My Question is: How can I create a Config-File package that is "relocatable" and depends on a Find-Module Package (e.g. boost)?
In more detail: Suppose I want to create a package named HyDi. The cmake documentation explains then very nicely how I can create the corresponding HydiConfig.cmake and HydiTargets.cmake files automatically. A very simple version of the CMakeLists.txt that does this is:
project(HyDi)
find_package(Boost COMPONENTS program_options)
add_library(HyDi foo.cpp foo.hpp)
target_include_directories(HyDi PUBLIC INTERFACE ${Boost_INCLUDE_DIRS})
target_link_libraries(HyDi ${Boost_LIBRARIES})
target_compile_options(HyDi INTERFACE PUBLIC "-std=c++11")
install(TARGETS HyDi EXPORT HyDiTarget
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
install(FILES foo.hpp DESTINATION include)
configure_file(cmake/HyDiConfig.cmake
"${CMAKE_CURRENT_BINARY_DIR}/HyDi/HyDiConfig.cmake"
COPYONLY
)
set(ConfigPackageLocation lib/cmake/HyDi)
install(EXPORT HyDiTarget FILE HyDiTargets.cmake
NAMESPACE Upstream:: DESTINATION ${ConfigPackageLocation} )
install(FILES cmake/HyDiConfig.cmake DESTINATION ${ConfigPackageLocation})
The corresponding HydiConfig.cmake is:
include(CMakeFindDependencyMacro)
find_dependency(Boost COMPONENTS program_options)
include("${CMAKE_CURRENT_LIST_DIR}/HyDiTargets.cmake")
However if I install this library, the HyDiTargets.cmake file will contain the include path to the Boost Libraries hardcoded and is thus not relocatable.
Note that the cmake documentation gives an example of how not to include the boost libraries that is essentially my version. But they unfortunately don't explain how to do it better.
I understand that I could build boost using cmake and could then import boost as a Config-file package so that my HydiTargets.cmake would relocatable. But this approach doesn't work with every other library that provides a Findxxx.cmake file.
Actually CMake doing this correct, when inject a "hardcoded" path to boost libraries (and you doing it wrong). Because after your library gets compiled and installed, it should "links" w/ very particular boost version (when it was at the moment of your library compilation) -- i.e. its header files and static/dynamic libraries.
Consider scenario: after successfull installation of your library, someone installs a new version of boost library (or any other third party library you depending on) in parallel (yeah, boost and some other libs could coexists in the same install prefix). To make things looks like a real world example, assume it is ABI incompatible w/ the previous version. Now if that "lucky" developer wants to use your (already compiled and installed) library (using exported targets and provided HyDiConfig.cmake) he'll get a trouble:
your library already linked to a "previous" boost version (remember ABI incompatible w/ a newer one);
so when you somehow replace that "hardcoded" paths and would find a newer version (as you trying to do in HyDiConfig.cmake) your "lucky" customer would angry on you for that mess!
That is not only about boost… same policy for all third party libraries: they should remains the same as it was at the moment of compilation (or at least ABI compatible if we are talking about dynamic linking at run time, but this is a separate story).
Moreover, your user probably even do not use boost in his app (but have more than one version installed) -- why you should find smth? You already know (thanks to CMake and hardcoded paths) what boost version "required" for your library! So finding smth new is completely wrong in this case! It is "too late… Your library already compiled, linked and installed!
Another case: he wants to use some other (newer) version of boost… Depending on order of find_package(boost) and find_package(yourLib) results may vary… but he'll be angry on you anyway!
I have been working on a fun project (a game engine) for awhile now and figured i could make it more portable and easy to compile across platforms if I use cmake. Right now i have it set up like so, with a main executable and then a bunch of shared libraries that the executable is linked to. I've found all the material needed to produce the libraries and the executable, and linking those to the executable, but what of linking a dependency like a static library or another shared library to one of the libraries i produce? Here is a visual
Sentiment (name of project)
-Root (all the interfaces and components of the engine. main.cpp is here
-Sentiment_OGL4Renderer (the files for the Renderer library)
-Sentiment_SFMLGui (the files for the Gui library)
-Sentiment_TestGame (the code for a game)
now i want all of these, the executable and the shared libraries built and put into the bin folder in the top level directory. What i found suggested online for a setup like this was to make cmakelists.txt files in each folder, and then one in the root, for each project. What i have thus far is this.
#Sentiment
cmake_minimum_required(VERSION 2.6)
project(Sentiment)
set(RENDERER Sentiment_OGL4Renderer)
set(GUI Sentiment_SFMLGui)
set(GAME Test_Game)
add_definitions(-DBUILD_DLL)
list( APPEND CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
set(EXECUTABLE_OUTPUT_PATH "${Sentiment_SOURCE_DIR}/bin")
set(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}")
link_directories("${LIBRARY_OUTPUT_PATH}")
add_subdirectory("${RENDERER}")
add_subdirectory("${GUI}")
add_subdirectory("${GAME}")
add_subdirectory(Root)
in root
project(Sentiment_exe)
link_directories("${Sentiment_SOURCE_DIR}/bin")
AUX_SOURCE_DIRECTORY(. new_source_list)
add_executable("${CMAKE_PROJECT_NAME}" ${new_source_list})
target_link_libraries("${CMAKE_PROJECT_NAME}" "${LIBRARY_OUTPUT_PATH}/${RENDERER}" "${LIBRARY_OUPUT_PATH}/${GUI}" "${LIBRARY_OUTPUT_PATH}/${GAME}" "${ADDITIONAL_DEPENDENCIES}")
in Sentiment_OGL4Renderer
project(Sentiment_OGL4-3Renderer)
include_directories(${Sentiment_SOURCE_DIR})
add_definitions(-DGLEW_STATIC)
add_library(Sentiment_OGL4-3Renderer SHARED Sentiment_OGL4Renderer.cpp GL/glew.cpp)
in Sentiment_SFMLGui
project(Sentiment_SFMLGui)
include_directories(${Sentiment_SOURCE_DIR})
add_library(Sentiment_SFMLGui SHARED Sentiment_SFMLGui.cpp)
in Sentiment_TestGame
project(Sentiment_Game)
include_directories(${Sentiment_SOURCE_DIR})
add_library(Sentiment_Game SHARED Game.cpp)
As you can tell there are a lot of third party libraries, and i tried various methods of linking, like with target_link_libraries, and i cannot for the life of me figure how to link an external library to the ones i've made. First off, the renderer uses GLEW but it needs no external dependency so ignore that. Then it needs OpenGL32.lib and Gdi32.lib from the windows sdk (only for windows). As for SFML, i've got the DLL's in the bin folder which need to be linked, (can easily get the .so's when working in linux and can distribute with the final product if I ever choose to do so). I need these all linked as dependencies to the libraries i create, but nothing seems to work. The project is all c++ and I am currently using mingw32 to compile it. I'm brand new to cmake so please be gentle if it is really simple.
To link external libraries, best practice is to use or create FindModule for given external library.
CMake comes with numerous modules that aid in finding various well-known libraries and packages.
The list of standard modules is in the official documentation
In case there is no standard module for your external library, you should write your own.
The OpenGL library has standard module FindOpenGL:
find_package (OpenGL)
if (OPENGL_FOUND)
include_directories(${OPENGL_INCLUDE_DIR})
target_link_libraries (Sentiment_OGL4-3Renderer ${OPENGL_gl_LIBRARY})
endif (OPENGL_FOUND)