Link external library (steamapi) by path with cmake - c++

I am trying to link Steam API with cmake.
I've tried Googling it, and there is close to nothing on steamapi cmake. In my case the Steam SDK is stored in C:/Users/user/Documents/Visual Studio 2022/Libraries/steam-sdk/.
This is my broken cmake:
# Project
cmake_minimum_required (VERSION 3.14)
project (MyProject)
#target_include_directories(${PROJECT_NAME} PUBLIC "C:/Users/user/Documents/Visual Studio 2022/Libraries/steam-sdk/public/steam/")
#target_link_directories(${PROJECT_NAME} PUBLIC "C:/Users/user/Documents/Visual Studio 2022/Libraries/steam-sdk/redistributable_bin/win64/")
#add_library(steamapi SHARED IMPORTED) # or STATIC instead of SHARED
#set_target_properties(bar PROPERTIES
# IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/lib/libbar.so"
# INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libbar"
#)
find_library(
steamapi
#external_library_dependency
#external_library_name
PATHS "C:/Users/user/Documents/Visual Studio 2022/Libraries/steam-sdk/" # you can manually provide a path to search for your library if its not in the PATH
#PATH_SUFFIXES "/redistributable_bin/win64/" # possible subfolders inside the top directory of your library
PATH_SUFFIXES "/redistributable_bin" "/redistributable_bin/win64" # possible subfolders inside the top directory of your library
)
#find_library(steamapi "steam_api64.lib" PATHS "C:/Users/Rico/Documents/Visual Studio 2022/Libraries/steam-sdk/redistributable_bin/win64/")
#target_include_directories(${PROJECT_NAME} PUBLIC "C:/Users/Rico/Documents/Visual Studio 2022/Libraries/steam-sdk/public/steam/")
include_directories(${steamapi_INCLUDE_DIRS})
# Linking
add_executable(${PROJECT_NAME}
"src/Main.cpp"
)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_link_libraries(${PROJECT_NAME}
steamapi
)
How can I do this?

I would end up with a solution similar to CPM.cmake for hands-free installation
# get_steamapi.cmake (located in myproject/cmake)
set(STEAMAPI_ZIP_LOCATION "${CMAKE_BINARY_DIR}/cmake/steamworks_sdk.zip")
set(STEAMAPI_LOCATION "${CMAKE_BINARY_DIR}/cmake/steamworks_sdk")
set(STEAMAPI_BINARY_DIR "${STEAMAPI_LOCATION}/sdk/redistributable_bin/win64/steam_api64.lib")
set(STEAMAPI_SOURCE_DIR "${STEAMAPI_LOCATION}/sdk/public/steam")
set(STEAMAPI_SHARED_DIR "${STEAMAPI_LOCATION}/sdk/redistributable_bin/win64/steam_api64.dll")
#set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
if(NOT (EXISTS ${STEAMAPI_ZIP_LOCATION}))
message(STATUS "Downloading Steam SDK to ${STEAMAPI_ZIP_LOCATION}")
file(DOWNLOAD
https://partner.steamgames.com/downloads/steamworks_sdk.zip
${STEAMAPI_ZIP_LOCATION}
)
endif()
if(NOT(EXISTS ${STEAMAPI_LOCATION}))
message(STATUS "Unzipping Steam SDK to ${STEAMAPI_ZIP_LOCATION}")
file(ARCHIVE_EXTRACT INPUT ${STEAMAPI_ZIP_LOCATION} DESTINATION ${STEAMAPI_LOCATION})
endif()
#include(${STEAMAPI_ZIP_LOCATION})
The CMakeLists.txt
#CMakeLists.txt
# Project
cmake_minimum_required (VERSION 3.14)
project (MyProject)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
include(get_steamapi)
# Libraries
find_package(Threads REQUIRED)
# Linking
add_executable(${PROJECT_NAME}
"src/Main.cpp"
)
target_include_directories(${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PUBLIC ${STEAMAPI_SOURCE_DIR}
#PUBLIC "C:/Users/user/Documents/Visual Studio 2022/Libraries/steam-sdk/public/steam"
)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_link_libraries(${PROJECT_NAME}
PRIVATE Threads::Threads
PUBLIC ${STEAMAPI_BINARY_DIR}
#"C:/Users/user/Documents/Visual Studio 2022/Libraries/steam-sdk/redistributable_bin/win64/steam_api64.lib"
)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/steam_appid.txt
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(COPY ${STEAMAPI_SHARED_DIR}
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
)
The commented out portions also work but I think the method I came up with is pretty neat.

Related

Cmake using git-submodule inside a shared library

I try to add the library spdlog to a dll (.so file). The spdlog is just a git submodule from the spdlog library. Looking at the documentation, it's recommended to use it as a static library. So i think i have a problem trying to compile it inside a .so file.
To get a clear view of what i'm doing, here is a pic of my system:
My root CMakeLists.txt is :
cmake_minimum_required(VERSION 3.23)
# set the project name
project(Test VERSION "0.1.0" LANGUAGES CXX)
configure_file(config/config.h.in config.h)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O3")
# Set location for .so files
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}")
# Set location for executables
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
add_subdirectory(Engine)
list(APPEND EXTRA_LIBS Engine)
add_subdirectory(Game)
target_link_libraries(Test PUBLIC ${EXTRA_LIBS})
target_include_directories(Test PUBLIC
"${PROJECT_BINARY_DIR}"
)
And inside the Engine folder:
message(STATUS "BUILD Engine shared library File")
add_subdirectory(spdlog)
add_library(Engine SHARED Log.cpp Log.h)
target_include_directories(Engine
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(Engine
spdlog
)
target_include_directories(Engine
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/spdlog/include
)
Inside the Game (not relevant at my opinion)
message(STATUS "BUILD .exe File")
# add the executable
add_executable(Test main.cpp)
But currently, if i try to use the spdlog inside my Log file, i have this cryptic error:
[build] /usr/bin/ld: spdlog/libspdlogd.a(spdlog.cpp.o): relocation R_X86_64_TPOFF32 against `_ZGVZN6spdlog7details2os9thread_idEvE3tid' can not be used when making a shared object; recompile with -fPIC
Does anyone have an idea?
Thanks to fabian in the comments, I add
set(CMAKE_POSITION_INDEPENDENT_CODE 1)
Just before adding the spdlog subdirectory and it just works fine.

How to configure TGUI + SFML with CMake

I'm currently working on a project and I decided to use TGUI with SFML for creating a menu. SFML works fine with CMake and I thought that configuring TGUI would be pretty much the same thing but I am not sure... How do configure TGUI?
My code looks like this at the moment:
#documentation for configuring SFML with CMake : https://en.sfml-dev.org/forums/index.php?topic=24070.0
cmake_minimum_required(VERSION 3.17.3)
set(CMAKE_CXX_STANDARD 14)
project(AlgorithmsSimulator)
#location of project's files
include_directories(${CMAKE_SOURCE_DIR})
#directory for excutables
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
#object files
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib)
#configuring SFML for windows
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(WINDOWS TRUE)
set(SFML_STATIC_LIBRARIES TRUE)
set(SFML_DIR "./SFML_Win/lib/cmake/SFML")
#MacOS
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(MACOSX TRUE)
set(SFML_INCLUDE_DIR "./SFML_macOS/include")
set(SFML_LIBRARY_DIR "./SFML_macOS/lib")
link_directories(SFML_LIBRARY_DIR)
include_directories(SFML_INCLUDE_DIR)
#Linux
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(LINUX TRUE)
#set(SFML_STATIC_LIBRARIES TRUE)
set(SFML_DIR "./SFML_Linux/lib/cmake/SFML")
else()
message(FATAL_ERROR "Your Operating System is not supported")
endif()
# TGUI configuration
set(TGUI_DIR "./TGUI/lib/cmake/TGUI")
#after configuring the paths of sfml for windows, macOS and linux cmake needs only to find the below packages
find_package(SFML 2.5 COMPONENTS audio graphics window system network REQUIRED)
find_package(TGUI 0.8 REQUIRED)
#compiling & list the header an source files in the solution explorer
set(HEADERS AlgorithmsImplementation.h)
set(SOURCES AlgorithmsImplementation.cpp Main.cpp)
add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES})
# sfml .dll files and the .dll files for tgui; when tgui-d is added I get this linking error: tgui-d.lib cannot be opened and when I exclude it, it says that it cannot found tgui-d.dll
target_link_libraries(${PROJECT_NAME} sfml-audio sfml-graphics sfml-window sfml-system sfml-network tgui tgui-d)
#this will allow us to install an .exe file of the project
install(TARGETS ${PROJECT_NAME} DESTINATION bin) #${CMAKE_INSTALL_PREFIX}/bin
install(FILES Main.cpp DESTINATION src) #${CMAKE_INSTALL_PREFIX}/src

how do i distribute static library built using cmake

I have a cmake project which is a static library that i have to share with other teams in my company but just the .lib file and not the source code.
This library depends on Boost.
Now i build the library and transfer the install folder onto another pc (exe_pc) and use it in a exe project (this exe also depends on boost).
Now at compile time i get a linking error saying that E:/Development/vcpkg/installed/x64-windows/lib/boost_system-vc140-mt.lib cannot be opened.
so i open and check the generated LibTargets.cmake and it contains absolute paths of boost library for pc on which the library was built.
# The installation prefix configured by this project.
set(_IMPORT_PREFIX "C:/Program Files/cpp_licensing")
# Create imported target Licensing::liblicensing
add_library(Licensing::liblicensing STATIC IMPORTED)
set_target_properties(Licensing::liblicensing PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "_LICENSING_DEBUG=0"
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "\$<\$<NOT:\$<CONFIG:DEBUG>>:E:/Development/vcpkg/installed/x64-windows/lib/boost_system-vc140-mt.lib>;\$<\$<CONFIG:DEBUG>:E:/Development/vcpkg/installed/x64-windows/debug/lib/boost_system-vc140-mt-gd.lib>;\$<\$<NOT:\$<CONFIG:DEBUG>>:E:/Development/vcpkg/installed/x64-windows/lib/boost_filesystem-vc140-mt.lib>;\$<\$<CONFIG:DEBUG>:E:/Development/vcpkg/installed/x64-windows/debug/lib/boost_filesystem-vc140-mt-gd.lib>;cryptopp-static;wbemuuid"
)
LibLicensingTargets-release.cmake
et_target_properties(Licensing::liblicensing PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
IMPORTED_LOCATION_RELEASE "C:/Program Files/cpp_licensing/lib/licensing.lib"
)
list(APPEND _IMPORT_CHECK_TARGETS Licensing::liblicensing )
list(APPEND _IMPORT_CHECK_FILES_FOR_Licensing::liblicensing "C:/Program Files/cpp_licensing/lib/licensing.lib" )
The user is supposed to have boost installed, the only problem i have is that because absolute paths are used in targets file user has to manually change them on his pc in the targets file.
what changes do i make to cmake so that the libraries built folder can be shared. How do i distribute a library built using cmake ??
Here is the cmake for the library project
cmake_minimum_required(VERSION 3.10)
project(liblicensing)
message("~~ Project: " ${PROJECT_NAME})
set(LIB_NAME "${PROJECT_NAME}")
set(PROJECT_VERSION 1.0)
include_directories(
${PROJECT_SOURCE_DIR}/include
)
if (WIN32)
find_package(Boost REQUIRED system filesystem)
find_package(cryptopp REQUIRED)
find_package(unofficial-date REQUIRED)
include_directories(
${Boost_INCLUDE_DIR}
)
else()
find_package(date REQUIRED)
endif ()
file(GLOB_RECURSE HEADER_FILES include/*.h include/*.hpp)
file(GLOB_RECURSE SOURCES src/*.cpp)
add_library(${LIB_NAME} STATIC ${SOURCES} ${HEADER_FILES} )
set_target_properties(
${LIB_NAME}
PROPERTIES
OUTPUT_NAME "licensing"
POSITION_INDEPENDENT_CODE ON
CXX_STANDARD 14
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
LINKER_LANGUAGE CXX
)
if (MSVC)
set_target_properties(${LIB_NAME} PROPERTIES DEBUG_POSTFIX "_d")
endif()
add_library(Licensing::liblicensing ALIAS ${LIB_NAME})
set(INSTALLATION_DIR "${CMAKE_INSTALL_PREFIX}")
set(CMAKE_INSTALL_LIBDIR "${INSTALLATION_DIR}/lib")
set(CMAKE_INSTALL_BINDIR "${INSTALLATION_DIR}/bin")
set(CMAKE_INSTALL_INCLUDEDIR "include")
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${LIB_NAME})
target_include_directories(${LIB_NAME}
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
if (WIN32)
target_link_libraries(
${LIB_NAME}
${Boost_LIBRARIES}
cryptopp-static
wbemuuid
)
else()
target_link_libraries(
${LIB_NAME}
cryptopp
boost_system
boost_filesystem
)
endif ()
if(CMAKE_BUILD_TYPE MATCHES Debug)
target_compile_definitions(${LIB_NAME} PUBLIC _LICENSING_DEBUG=1)
elseif(CMAKE_BUILD_TYPE MATCHES Release)
target_compile_definitions(${LIB_NAME} PUBLIC _LICENSING_DEBUG=0)
endif()
# Expose Projects's public includes to other subprojects through cache variable.
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
###############
# Installation
##
install(TARGETS ${LIB_NAME}
EXPORT LibLicensingTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${LIB_NAME}
FILES_MATCHING PATTERN "*.h*")
install(EXPORT LibLicensingTargets
FILE LibLicensingTargets.cmake
NAMESPACE Licensing::
DESTINATION ${INSTALL_CONFIGDIR}
)
#####################
# ConfigVersion file
##
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/LibLicensingConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
${CMAKE_CURRENT_LIST_DIR}/CMake/LibLicensingConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/LibLicensingConfig.cmake
INSTALL_DESTINATION ${INSTALL_CONFIGDIR}
)
## Install all the helper files
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/LibLicensingConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/LibLicensingConfigVersion.cmake
DESTINATION ${INSTALL_CONFIGDIR}
)
Not an entire answer but too much for a comment:
If you inspect your file LibLicensingTargets.cmake closely, you see that cryptopp-static and wbemuuid are not resolved down to the library level.
Looking at how you reference Boost you use the oldstyle version (${Boost_LIBRARIES}) that resolves down to the library level.
Try instead to use the targets provided by FindBoost.cmake module as follows:
if (WIN32)
target_link_libraries(
${LIB_NAME}
Boost::system
Boost::filesystem
cryptopp-static
wbemuuid
)
else()
target_link_libraries(
${LIB_NAME}
cryptopp
Boost::system
Boost::filesystem
)
endif()
Another thing that puzzles me is why you added the ALIAS:
add_library(Licensing::liblicensing ALIAS ${LIB_NAME})
This ALIAS is properly created in the LibLicensingTargets.cmake file, so you do not need to create it on your own.
Another thing is, that you are giving your INSTALL command absolute paths. To make the package entirely relocatable you need to use relative paths (relative to the CMAKE_INSTALL_PREFIX, the installation directory).
The following commands should therefore be changed to:
set(CMAKE_INSTALL_LIBDIR "lib")
set(CMAKE_INSTALL_BINDIR "bin")
set(CMAKE_INSTALL_INCLUDEDIR "include")
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${LIB_NAME})
If you further add the line:
export(TARGETS liblicensing NAMESPACE LibLicensing:: FILE LibLicensingTargets.cmake)
to your CMakeLists.txt, outside projects are able to import target from your build tree folder as of liblicensing was installed therein. See the CMake documentation of the export command.

How to install a cmake package in a custom directory and link it with target_link_libraries() by name?

I have a custom library which exports include/, lib/ and lib/cmake/ which contains MyProjectConfig.cmake with the following contents:
set(MyProject_INCLUDE_DIRS "/home/.../cmake-build-debug/thirdparty/myproj/include")
set(MyProject_LIBRARY_DIRS "/home/.../cmake-build-debug/thirdparty/myproj/lib")
set(MyProject_LIBRARIES "MyProject")
message(STATUS "MyProject found. Headers: ${MyProject_INCLUDE_DIRS}")
I use it in another project like this:
include(ExternalProject)
ExternalProject_Add(MyProjectExternal
PREFIX "${CMAKE_BINARY_DIR}/external/myproject"
GIT_REPOSITORY "git#bitbucket.org:myproject.git"
GIT_TAG "master"
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/thirdparty/myproject
)
add_dependencies(${PROJECT_NAME} MyProjectExternal)
# prevent error on first project use when dir doesn't exist
if(EXISTS ${CMAKE_BINARY_DIR}/thirdparty/myproject/lib)
find_package(MyProject REQUIRED HINTS ${CMAKE_BINARY_DIR}/thirdparty/myproject/lib/cmake)
find_library(MyProject_LIB MyProject HINTS ${MyProject_LIBRARY_DIRS})
target_link_libraries(${PROJECT_NAME} PUBLIC ${MyProject_LIB})
target_include_directories(${PROJECT_NAME} PRIVATE ${MyProject_INCLUDE_DIRS})
endif()
I expected that the variables set in MyProjectConfig.cmake would be picked up automatically by cmake to find the library by name and this would work:
find_package(MyProject REQUIRED HINTS ${CMAKE_BINARY_DIR}/thirdparty/myproject/lib/cmake)
target_link_libraries(${PROJECT_NAME} PUBLIC MyProject)
But it doesn't:
[ 87%] Built target MyProjectExternal
[ 90%] Linking CXX executable RootProject
/usr/bin/ld: cannot find -lMyProject
collect2: error: ld returned 1 exit status
Part II (as requested here) The full code and the steps to reproduce the problem
Library Code (mylib branch)
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(MyLib VERSION 1.0.0 LANGUAGES CXX)
add_library(${PROJECT_NAME} SHARED
src/mylib/hello.cpp
)
target_include_directories(${PROJECT_NAME}
PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)
include(cmake/install.cmake)
cmake/install.cmake
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
include(GenerateExportHeader)
generate_export_header(${PROJECT_NAME}
EXPORT_MACRO_NAME EXPORT
NO_EXPORT_MACRO_NAME NO_EXPORT
PREFIX_NAME MYLIB_
EXPORT_FILE_NAME ${CMAKE_BINARY_DIR}/include-exports/mylib/export.h)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include-exports>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
install(DIRECTORY ${CMAKE_BINARY_DIR}/include-exports/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
include(CMakePackageConfigHelpers)
set_property(TARGET ${PROJECT_NAME} PROPERTY VERSION ${PROJECT_VERSION})
set_property(TARGET ${PROJECT_NAME} PROPERTY SOVERSION ${PROJECT_VERSION_MAJOR})
set_property(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_${PROJECT_NAME}_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY COMPATIBLE_INTERFACE_STRING ${PROJECT_VERSION_MAJOR})
write_basic_package_version_file(
"${CMAKE_BINARY_DIR}/CMakePackage/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
export(EXPORT ${PROJECT_NAME}Targets
FILE "${CMAKE_BINARY_DIR}/CMakePackage/${PROJECT_NAME}.cmake"
)
SET(CONFIG_SOURCE_DIR ${CMAKE_SOURCE_DIR})
SET(CONFIG_DIR ${CMAKE_BINARY_DIR})
SET(${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_SOURCE_DIR}/include")
configure_package_config_file(${CMAKE_SOURCE_DIR}/cmake/Config.cmake.in
"${CMAKE_BINARY_DIR}/CMakePackage/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
PATH_VARS ${PROJECT_NAME}_INCLUDE_DIR)
install(EXPORT ${PROJECT_NAME}Targets
FILE ${PROJECT_NAME}.cmake
DESTINATION lib/cmake/${PROJECT_NAME}
)
install(
FILES
"${CMAKE_BINARY_DIR}/CMakePackage/${PROJECT_NAME}Config.cmake"
"${CMAKE_BINARY_DIR}/CMakePackage/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION lib/cmake/${PROJECT_NAME}
COMPONENT Devel
)
cmake/Config.cmake.in
#PACKAGE_INIT#
set_and_check(#PROJECT_NAME#_INCLUDE_DIRS "#CMAKE_INSTALL_PREFIX#/#CMAKE_INSTALL_INCLUDEDIR#")
set_and_check(#PROJECT_NAME#_LIBRARY_DIRS "#CMAKE_INSTALL_PREFIX#/#CMAKE_INSTALL_LIBDIR#")
set(#PROJECT_NAME#_LIBRARIES "#PROJECT_NAME#")
check_required_components(#PROJECT_NAME#)
message(STATUS "#PROJECT_NAME# found. Headers: ${#PROJECT_NAME#_INCLUDE_DIRS}")
include/mylib/hello.h
#ifndef MYLIB_HELLO_H
#define MYLIB_HELLO_H
#include <mylib/export.h>
namespace mylib {
extern MYLIB_EXPORT void hello();
}
#endif
src/mylib/hello.cpp
#include <mylib/hello.h>
#include <iostream>
namespace mylib {
void hello() {
std::cout << "Hello, MyLib!" << std::endl;
}
}
Application Code (master branch)
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(MyLibConsumer VERSION 1.0.0 LANGUAGES CXX)
add_executable(${PROJECT_NAME}
main.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)
include(ExternalProject)
set(LIB_INSTALL_DIR ${CMAKE_BINARY_DIR}/thirdparty/mylib)
ExternalProject_Add(MyLibExternal
PREFIX "${CMAKE_BINARY_DIR}/external/mylib"
GIT_REPOSITORY "https://github.com/arteniioleg/stackoverflow-question-46772541.git"
GIT_TAG "mylib"
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIB_INSTALL_DIR}
)
add_dependencies(${PROJECT_NAME} MyLibExternal)
if(EXISTS ${LIB_INSTALL_DIR}/lib) # prevent error on first cmake load
find_package(MyLib REQUIRED HINTS ${LIB_INSTALL_DIR}/lib/cmake)
# fixme: make this work
target_link_libraries(${PROJECT_NAME} PUBLIC MyLib)
# to test: comment the above line and uncomment the below lines
#find_library(MyLib_LIB MyLib HINTS ${MyLib_LIBRARY_DIRS})
#target_link_libraries(${PROJECT_NAME} PRIVATE ${MyLib_LIB})
#target_include_directories(${PROJECT_NAME} PRIVATE ${MyLib_INCLUDE_DIRS})
endif()
main.cpp
#include <mylib/hello.h>
int main()
{
mylib::hello();
return 0;
}
The Error
main.cpp:1:25: fatal error: mylib/hello.h: No such file or directory
#include <mylib/hello.h>
^
Using the MyLib_* variables created by find_package() fixes the problem but it's too verbose.
As suggested here:
However, recommended way is to use CMake functionality for create configuration file. Such way, fully-fledged target will be created, and can be used for linking.
How to do that?
I want to use my library in 2 steps, like Qt:
find_package(Qt5Widgets)
target_link_libraries(myApp Qt5::Widgets)
Just include MyProject.cmake in MyProjectConfig.cmake (it is not included by default)
include(${CMAKE_CURRENT_LIST_DIR}/MyProject.cmake)
The final version of key files:
LIBRARY/cmake/Config.cmake.in
Removed redundant variables: *_INCLUDE_DIRS, *_LIBRARY_DIRS, *_LIBRARIES
#PACKAGE_INIT#
include(${CMAKE_CURRENT_LIST_DIR}/#PROJECT_NAME#.cmake)
check_required_components(#PROJECT_NAME#)
message(STATUS "#PROJECT_NAME# found.")
EXECUTABLE/CMakeLists.txt
Moved external projects before executable and return() if external projects are not built.
cmake_minimum_required(VERSION 3.8)
project(MyLibConsumer VERSION 1.0.0 LANGUAGES CXX)
set(LIB_INSTALL_DIR ${CMAKE_BINARY_DIR}/thirdparty/mylib)
include(ExternalProject)
ExternalProject_Add(MyLibExternal
PREFIX "${CMAKE_BINARY_DIR}/external/mylib"
GIT_REPOSITORY "https://github.com/arteniioleg/stackoverflow-question-46772541.git"
GIT_TAG "mylib"
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIB_INSTALL_DIR}
)
if(NOT EXISTS ${LIB_INSTALL_DIR}/lib)
# Happens on first CMake run.
# Can't continue because the below `find_package(REQUIRED)` will fail.
# Build all external project targets then rerun CMake and build the project target.
message(AUTHOR_WARNING "Build all external projects then reload cmake.")
return()
endif()
add_executable(${PROJECT_NAME} main.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)
add_dependencies(${PROJECT_NAME} MyLibExternal)
find_package(MyLib REQUIRED HINTS ${LIB_INSTALL_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
I expected that the variables set in MyProjectConfig.cmake would be picked up automatically by cmake to find the library by name.
The most "magic" in find_package command is how it searches *Config.cmake script. After the script is found, it is simply executed in the context of the caller.
In you case, CMake sets variables MyProject_INCLUDE_DIRS, MyProject_LIBRARY_DIRS and MyProject_LIBRARIES. Nothing more. It doesn't create MyProject target and so.
If you want find_package() preparing linking with MyProject library, you need to write your MyProjectConfig.cmake script accordingly (e.g., call link_directories() from it).
However, recommended way is to use CMake functionality for create configuration file. Such way, fully-fledged target will be created, and can be used for linking. See cmake-packages documentation for more info.

including external libraries in cmakelists.txt file

I'm using cmake to build an executable to run on an Intel Galileo board.
My question is how do I include the external mraa library in the build process.
Mraa library
When I download the library from git (1) do I need to build it as described here
Mraa compiling instructions
What do I need to put in my CMakeLists.txt file to pick up the library?
This is what I have thus far in my CMakeLists.txt file but I believe it is incorrect.
### MRAA ###
add_subdirectory(mraa-master/src)
file(GLOB mraa_SRC
"mraa-master/src/*.c"
)
include_directories( "${PROJECT_SOURCE_DIR}/mraa-master/include" )
add_library( ${MRAA_LIBRARY_NAME} SHARED ${mraa_SRC} )
Thank you
cmake_minimum_required(VERSION 2.8)
MESSAGE( STATUS "Starting build process")
SET( CMAKE_VERBOSE_MAKEFILE on )
if (CMAKE_BUILD_TYPE EQUAL "Debug")
MESSAGE(STATUS "Building in debug mode")
elseif (CMAKE_BUILD_TYPE EQUAL "Release")
MESSAGE(STATUS "Building in release mode")
endif()
SET(PROJECT_NAME "TestProject")
SET(APPLICATION_NAME "TestApplication")
SET(SAFE_STRING_LIBRARY "SafeString")
SET(APPLICATION_LIBRARY "Applibrary")
PROJECT( ${PROJECT_NAME} )
MESSAGE( STATUS "PROJECT: " ${PROJECT_NAME} )
SET(WRSDK_PATH "$ENV{WINDRIVER_SDK_DIR}")
IF (WRSDK_PATH)
else()
SET(WRSDK_PATH /opt/windriver/wrlinux/5.0-intel-quark/)
endif()
SET(APPLIBRARY_NAME ${APPLICATION_LIBRARY} )
SET(SAFE_STRING_LIBRARY_NAME ${SAFE_STRING_LIBRARY} )
### SAFE STRING ###
add_subdirectory(SafeStringStaticLibrary/safeclib)
file(GLOB safestring_SRC
"SafeStringStaticLibrary/safeclib/*.c"
)
include_directories( "${PROJECT_SOURCE_DIR}/SafeStringStaticLibrary /safeclib" )
add_library( ${SAFE_STRING_LIBRARY_NAME} SHARED ${safestring_SRC} )
include(ExternalProject)
ExternalProject_Add(mraa
GIT_REPOSITORY https://github.com/intel-iot-devkit/mraa.git
GIT_TAG v0.8.0
UPDATE_COMMAND ""
INSTALL_COMMAND "" )
file(GLOB app_SRC
"classes/*.cpp"
"Logger.cpp"
"sqlite3.c"
"shell.c"
)
add_library( ${APPLIBRARY_NAME} SHARED ${app_SRC})
include_directories( "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/SafeStringStaticLibrary/include" )
add_executable( ${APPLICATION_NAME} ${APPLICATION_NAME}.cpp
include_directories( "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/SafeStringStaticLibrary/include" "${CMAKE_SOURCE_DIR}/classes")
TARGET_LINK_LIBRARIES( ${APPLICATION_NAME} ${APPLIBRARY_NAME} ${SAFE_STRING_LIBRARY_NAME} -lrt -lpthread -lgcov -ldl)
The simplest way for build your project alongside with 3d party project is add_subdirectory() that subproject. Approach below implies that you (manually) download(git clone) sources of mraa project into mraa-lib subdirectory of your project's sources.
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
MESSAGE( STATUS "Starting build process")
# Configure subproject before definition of variables for main project.
#
# Subproject defines *mraa* library target.
add_subdirectory(mraa-lib)
# Before installation, public mraa headers are contained under *api* subdirectory.
include_directories(mraa-lib/api)
... # create executable ${APPLICATION_NAME}
# Linking with mraa library is straightforward.
target_link_libraries(${APPLICATION_NAME} mraa)
That way mraa subproject will be configured, built and installed alongside with your project. So, if you cross-compile your project(using toolchain file, or inside IDE), the subproject will also be cross-compiled.