Linking external packages as library? - c++

So I am still pretty new to linux and CMake, I want to add an X package as Library to a currently existing program. The instructions say Now, link the X library to your project by extending the target_link_libraries command of your executable:
target_link_libraries(target-name X package [other-libraries])
What does the executable mean? Does it mean the name of the executable file .sh ? or the project name in CMakeLists.txt as adding the latter gives this cmake error:
CMake Error at CMakeLists.txt:79 (target_link_libraries):
Cannot specify link libraries for target "Simulation" which is not built by
this project.
Thank you for any advice!
EDIT 1: CMakeList.txt as requested
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
cmake_policy(SET CMP0079 NEW)
# Set project name:
project(Simulation)
########## The project ##########
# Traverse source folder and find extra includes.
file(GLOB_RECURSE files ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR} *.h *.hh)
option(BUILD_SHARED_LIBS "Build package with shared libraries." OFF)
set(last_include_path "")
foreach(file ${files} )
get_filename_component(path ${file} PATH)
# Check if the path has not been processed before.
string(COMPARE EQUAL "${path}" "${last_include_path}" already_included)
if(NOT ${already_included})
# Adapt last_include_path.
set(last_include_path "${path}")
# Add include path if include subdirectory exits.
if(IS_DIRECTORY ${path})
message(STATUS "Added include: ${path}")
include_directories(${path})
endif()
endif()
endforeach()
# make documentation (after all subproject (which add dependencies to the documentation) are build):
add_custom_target(documentation ALL
COMMAND echo Creating documentation
COMMAND rm -rf ../documentation
COMMAND mkdir -p ../documentation
COMMAND doxygen GODDeSS.dox > /dev/null
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# add_custom_command(TARGET documentation
# POST_BUILD
# COMMAND echo ARGS Creating documentation pdf-files
# COMMAND sed ARGS -e "s#makeindex#makeindex -q#" -i Makefile
# COMMAND make all > /dev/null
# COMMAND cp refman.pdf ../documentation.pdf
# COMMAND touch ../documentation.html
# COMMAND echo ARGS \"<html> <head> <meta http-equiv=\\\"refresh\\\" content=\\\"0\\; URL=html/index.html\\\"/> </head> </html>\" > ../documentation.html
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../documentation/latex)
# Add subdirectories which contain CMakeLists, too (they will be executed after this project or, if this project depends on them, before this project):
message(STATUS "Added subproject: ${CMAKE_CURRENT_SOURCE_DIR}/Simulation")
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Simulation)
message(STATUS "Added subproject: ${CMAKE_CURRENT_SOURCE_DIR}/G4BasicObjects")
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/G4BasicObjects)
#added G4Sipm
add_subdirectory(externals/g4sipm)
include_directories(externals/g4sipm/g4sipm/include)
include_directories(externals/g4sipm/externals/gtest/include)
target_link_libraries(Simulation g4sipm boost_date_time)

Related

CMAKE: How do I install executable along with required dylib to custom directory?

So I'm using CMake to build a C++ project (on Mac OS) and my project relies on a dylib (I'm using TBB https://www.threadingbuildingblocks.org/ but the specific library itself doesn't matter)
If I do a standard "cmake" and "make" it builds the executable where I want it and when I run my app, the dylib links correctly and everything works perfectly.
The problem comes in when I try to do a "make install" and try to run the resulting executable from the install directory. I get an "image not found" error:
dyld: Library not loaded: #rpath/libtbb.dylib
Referenced from:
/Users/MyName/Desktop/ProjectRoot/install/./MyApp
Reason: image not found
Interestingly, if I do a regular "make" without an install, and then manually copy over the executable to the install directory, then that will link against my dylib properly. I have no idea why that is.
My directory structure is as follows:
Root
CMakeLists.txt
Source/
Libraries/
tbb/
include/
lib/
libtbb.dylib
install/
...and my CMakeLists.txt file is below:
# Start of CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project (MyApp)
# Set C++ version and output paths
set (CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
# Find TBB
find_library (
TBB_LIBRARIES
NAMES tbb libtbb # what to look for
HINTS "${CMAKE_SOURCE_DIR}/Libraries/tbb/lib" # where to look
NO_DEFAULT_PATH # do not search system default paths
)
# Set Custom Include Files + TBB header files
include_directories(Source/Headers Libraries/tbb/include)
# Set Source Files
file(GLOB_RECURSE SRC_FILES "Source/*.cpp")
add_executable(MyApp ${SRC_FILES})
# Link Libraries
target_link_libraries(MyApp ${TBB_LIBRARIES})
# Set compile flags
set_target_properties(MyApp PROPERTIES CXX_STANDARD 14) #LINK_FLAGS "-Wl")
target_compile_features(MyApp PUBLIC cxx_std_14)
# Install executable
install(TARGETS MyApp DESTINATION .)
If I try to also add the following line, and install the dylib as well:
install(TARGETS ${TBB_LIBRARIES} DESTINATION lib)
then when I do a "make install" I get the following error instead:
install TARGETS given target
"/Users/MyName/Desktop/ProjectRoot/Libraries/tbb/lib/libtbb.dylib"
which does not exist in this directory.
So I just can't seem to get this install to work. How do I fix it so that both my executable and my library get installed in the right place and that my executable will be able to link against my library when run?

CMake run command on all generated binaries

I have a relatively big CMake project with a lot of subfolders and files. I want to run a custom command after any binary is created when building this project. I've been testing with Hello World and I know I'll need something like this:
EDIT: I've updated the question to reflect my current progress.
# Get list of all files and folders in current dir recursively
set(SUBFDIRS)
file(GLOB_RECURSE ALLFILES LIST_DIRECTORIES true "*" "*")
foreach(SUBFILE ${ALLFILES})
IF(IS_DIRECTORY ${SUBFILE} AND NOT ${SUBFILE} MATCHES ".*CMakeFiles.*")
message("Adding directory: ${SUBFILE}")
LIST(APPEND SUBDIRS ${SUBFILE})
ENDIF()
endforeach()
# Also add current directory to directory list
LIST(APPEND SUBDIRS .)
LIST(REMOVE_DUPLICATES SUBDIRS)
message("-- Detected subdirectories: ${SUBDIRS}")
# Loop over all subdirectories
foreach(subdir ${SUBDIRS})
# Get a list of all targets
get_property(BUILDSYSTEM_TARGETS DIRECTORY ${subdir} PROPERTY BUILDSYSTEM_TARGETS)
# For each target, add a custom target that will run a custom command
foreach(TARGET_DEFINED ${BUILDSYSTEM_TARGETS})
get_target_property(target_type ${TARGET_DEFINED} TYPE)
if (target_type STREQUAL "EXECUTABLE")
message("-- Adding custom target for executable ${TARGET_DEFINED}...")
add_custom_target(custom_${TARGET_DEFINED} ALL)
add_custom_command(TARGET custom_${TARGET_DEFINED}
POST_BUILD
COMMAND my_custom_command $<TARGET_FILE:${TARGET_DEFINED}> $<TARGET_FILE:${TARGET_DEFINED}>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS $<TARGET_FILE:${TARGET_DEFINED}>
)
else()
message("-- Target ${TARGET_DEFINED} is not an executable. Ignoring!")
endif()
endforeach()
endforeach()
This seems to work the way I want it to, except for the fact that it generates CMake errors like this one when trying to get a list of targets for a directory:
CMake Error at CMakeLists.txt:34 (get_property):
get_property DIRECTORY scope provided but requested directory was not
found. This could be because the directory argument was invalid or, it is
valid but has not been processed yet.

CMake does not produce .exe file

I have built a CERN's ROOT script which based on c++ and i write(edit an example) CMakeList.txt. I am so rokie at CMake btw.
When I command to compile with cmake .., it done correctly -i think- with no errors. But .exe file what i want to produce does not appear.
My directory orders
/Project
../TLV.cpp
../CMakeLists.txt
../build
There is my CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(TLV)
#Set CXX flags to compile with c++11 and error warnings quiet
set(CMAKE_CXX_FLAGS "-O3 -fPIC -Wall -Wextra -std=c++11 -m64")
#Load root
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} $ENV{ROOTSYS}/etc/cmake)
#print conf
message(STATUS "Environmental CMAKE_MODULE_PATH is $ENV{ROOTSYS}")
#find the package with extra libraries needed
find_package(ROOT MODULE REQUIRED Cling TreePlayer Tree Rint Postscript Matrix RIO Core Foam RooStats RooFit RooFitCore Gpad Graf3d Graf Hist Net TMVA XMLIO MLP)
#include ROOT stuff
include(${ROOT_USE_FILE})
message(STATUS "Environmental ROOTSYS is $ENV{ROOTSYS}")
message(STATUS "found root at: ${ROOT_USE_FILE}")
message(STATUS "ROOT_LIBRARIES=${ROOT_LIBRARIES}")
#produce executables in bin path
set(EXECUTABLE_OUTPUT_PATH bin)
#include_directories(./../Framework Headers)
#${FROM_OTHERS_INCLUDE})
#defines all .cpp support class with corresponding Headers
#file(GLOB SRCS Sources/*.cpp Headers/*.hpp )
#${FROM_OTHERS_HEADER} ${FROM_OTHERS_SOURCE})
#add executable
add_executable( TLV TLV.cpp )
#link the executable with the root libraries
target_link_libraries(TLV ${ROOT_LIBRARIES})
I do not get it where I am wrong.
A typical scenario on a project which uses cmake is
cd src_directory # for example cd ~/src/root-6.08.06/
mkdir build # skip this if dir build already exists
cd build
cmake .. # the .. just says your source home dir is up a dir
cmake-gui .. # (optional) skip this unless you need a GUI alternative to cmake where you can edit settings
cmake --build # if you have a quad core CPU could use: make -j8 ... or make -j $(nproc) # on linux
then launch binary and confirm its OK then if desired install it using
sudo make install

Deploy icu libraries when linking a cmake project with Qt5

I've the following CMakeLists.txt for creating a little application:
cmake_minimum_required (VERSION 3.5.0)
project (sampleapp)
# Setting project flags
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib)
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/bin)
set (CMAKE_INCLUDE_CURRENT_DIR ON)
set (CMAKE_AUTOMOC ON)
# Finding needed packages
find_package (Qt5Widgets REQUIRED)
find_package (Qt5Core REQUIRED)
find_package (Qt5Gui REQUIRED)
# Setting project files
include_directories (${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR})
file (GLOB_RECURSE PROJECT_SRC *.cpp)
# Creating project
add_executable(${PROJECT_NAME} ${PROJECT_SRC})
# Linking dependencies
target_link_libraries (${PROJECT_NAME} somelibrary Qt5::Widgets Qt5::Gui Qt5::Core)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:${PROJECT_NAME}>)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:${PROJECT_NAME}>)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:${PROJECT_NAME}>)
When I run it and then build the application the Qt dlls are copied into target folder. In particular I copy:
Qt5Core.dll
Qt5Gui.dll
Qt5Widgets.dll
When I run the application it does not start anyway because the ICU libraries needed for Qt are not copied. When I start the application, Windows tells me that following libraries are missing:
icuin53.dll
icuuc53.dll
If I copy these libraries manually from Qt insallation folder it works (ok, I've an error regarding "platform plugins windows" missing but it's another story).
Is there a way to copy the icu libraries in a standard way, like the post build commands that I'm using for copying libraries? Or what's the best way to copy them in a transparent way, if possible (CMake can know what are dependencies of Qt and copy them where Qt are needed)?
Instead of copying each dll by hand, you can install all Qt dependencies using windeployqt, the tool provided with Qt for deployment on Windows.
You can first declare windeployqt as an imported executable:
find_package(Qt5
# ...
)
if(Qt5_FOUND AND WIN32 AND TARGET Qt5::qmake AND NOT TARGET Qt5::windeployqt)
get_target_property(_qt5_qmake_location
Qt5::qmake IMPORTED_LOCATION
)
execute_process(
COMMAND "${_qt5_qmake_location}" -query QT_INSTALL_PREFIX
RESULT_VARIABLE return_code
OUTPUT_VARIABLE qt5_install_prefix
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(imported_location "${qt5_install_prefix}/bin/windeployqt.exe")
if(EXISTS ${imported_location})
add_executable(Qt5::windeployqt IMPORTED)
set_target_properties(Qt5::windeployqt PROPERTIES
IMPORTED_LOCATION ${imported_location}
)
endif()
endif()
Now the imported executable can be used as follows:
add_executable(foo
# ...
)
if(TARGET Qt5::windeployqt)
add_custom_command(TARGET foo
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/windeployqt"
COMMAND set PATH=%PATH%$<SEMICOLON>${qt5_install_prefix}/bin
COMMAND Qt5::windeployqt --dir "${CMAKE_CURRENT_BINARY_DIR}/windeployqt" "$<TARGET_FILE:foo>"
)
install(
DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/windeployqt/"
DESTINATION ${FOO_INSTALL_RUNTIME_DESTINATION}
)
endif()

Building Google glog with CMake on Linux

I want to build Google glog with CMake as part of bigger project (solution, in words of Visual Studio). What I want to have as a result:
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug
-DCMAKE_INSTALL_PREFIX:PATH=xxx {MAIN CMakeLists.txt location}
cmake --build . --target install --config Debug
will build solution in Debug configuration and install files to xxx folder.
Ok, glog is sub project of main solution:
add_subdirectory(third_party/glog_0.3.4)
On Windows everything is ok (see CMakeLists.txt): everything works as expected.
To build glog on Linux, I need to configure .h.in files too (among other work). CMake configure_file does not works: I have .h files but they contain #undef's only. But glog's ./configure works fine, so I found that ExternalProject_Add() may help:
if(UNIX)
include(ExternalProject)
ExternalProject_Add(glog
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/configure
CMAKE_GENERATOR 'Unix Makefiles'
BUILD_COMMAND ${MAKE})
endif()
And cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=xxx . works fine, but cmake --build . --target install --config Debug will give me:
make: *** No rule to make target 'install'. Stop.
If I invoke cmake --build . --config Debug, then it will build and install glog to /usr/local/lib. Next try:
if(UNIX)
include(ExternalProject)
get_filename_component(glog_absolute_install_dir ${CMAKE_INSTALL_PREFIX} ABSOLUTE)
ExternalProject_Add(glog
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/configure --prefix=${glog_absolute_install_dir}
CMAKE_GENERATOR 'Unix Makefiles'
BUILD_COMMAND ${MAKE}
INSTALL_DIR ${glog_absolute_install_dir}
INSTALL_COMMAND "${MAKE}")
endif()
will not install files to xxx and just build it to glog-prefix/src/glog-build/.
Ok, I have no idea how to make it work.. And how to
specify install dir
lib build type (static/shared)
configure type (Debug/Release) - not sure that now it works
On Windows, according to glog's documentation, for 2nd case I do next:
add_library(${lib_name} ${lib_type} ${src_files})
if(build_shared_lib)
add_definitions(-DLIBGLOG_EXPORTS)
else()
add_definitions(-DGOOGLE_GLOG_DLL_DECL=)
endif()
Thanks for any help
I will show you by example, the below is my project structure:
The file FindGLog.cmake in the directory cmake is used to find glog, it contents :
# - Try to find Glog
#
# The following variables are optionally searched for defaults
# GLOG_ROOT_DIR: Base directory where all GLOG components are found
#
# The following are set after configuration is done:
# GLOG_FOUND
# GLOG_INCLUDE_DIRS
# GLOG_LIBRARIES
include(FindPackageHandleStandardArgs)
if (NOT DEFINED GLOG_ROOT)
message("set GLOG_ROOT========================")
set (GLOG_ROOT /usr /usr/local /usr/include/)
endif (NOT DEFINED GLOG_ROOT)
#set(GLOG_ROOT_DIR "" CACHE PATH "Folder contains Google glog")
find_path(GLOG_INCLUDE_DIR glog/logging.h
PATHS
${GLOG_ROOT_DIR}
PATH_SUFFIXES
src)
find_library(GLOG_LIBRARY glog libglog
PATHS
${GLOG_ROOT_DIR}
PATH_SUFFIXES
.libs
lib
lib64)
find_package_handle_standard_args(GLOG DEFAULT_MSG
GLOG_INCLUDE_DIR GLOG_LIBRARY)
if(GLOG_FOUND)
set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR})
set(GLOG_LIBRARIES ${GLOG_LIBRARY})
message("GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIRS}===========")
message("GLOG_LIBRARY ${GLOG_LIBRARY}===========")
endif()
The main CMakeLists.txt use the above FindGLog.cmake to find glog:
cmake_minimum_required(VERSION 3.5)
project(my_caffe)
set(CMAKE_CXX_STANDARD 11)
# find glog
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
find_package(GLog REQUIRED)
set(SOURCE_FILES main.cpp)
add_executable(my_caffe_test ${SOURCE_FILES})
# link glog
target_link_libraries(my_caffe_test
${GLOG_LIBRARIES}
)
cited from:https://davidstutz.de/running-google-glog-on-travis-ci/
Nowadays (presumably this will be in glog release 0.3.5), there is a CMakeLists.txt included with glog, so no longer any need for ExternalProject.