How can I make fat execuatable file in CMAKE? - c++

I am newbie on CMAKE. I am trying to make "fat executable file".
The term, fat executeable file, I mentioned, is a executable binary file which contains all shared libraries and can be just run in another environment.
Example (Trouble Situation)
There is ComputerA which is a computer that I used for developing. There is GCC, Boost libraries, librados etc.
And there is ComputerB which is a computer that I wanted to execute the binary that I built.
* Of course, Both Computer A and B have some conditions. Same Intel CPU Arch. (i7), Same CentOS.
I built binary file in ComputerA using CMAKE with this command, cmake .. && make. And I copied this file to ComputerB and executed.
When I execute the copied binary file in Computer B, it said like below.
[root#ComputerB ~]# ./binaryFile 123.123.123.123
./binaryFile: error while loading shared libraries: libboost_json.so.1.80.0: cannot open shared object file: No such file or directory
I understand what this error message say. There is no shared library which it needed. So, what I want to ask in this community is, What is CMAKE Command for containing shared libraries.
Similar thing :: fat JAR
The reason, why I called "fat executable file", is that there is a word "fat JAR" in Java. I am not familiar with Java. But it is commonly used word in Java community.
My CMAKE File
It contains some libraries like Boost, Rados, RBD etc. (There will be more according to progress of developing)
cmake_minimum_required(VERSION 3.2.0)
project(BinaryHelper VERSION 0.1.0)
find_package(Boost REQUIRED COMPONENTS json)
include_directories(${Boost_INCLUDE_DIR})
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lrados -std=c++17")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
add_executable(
${PROJECT_NAME}
main.cpp
utils/binary.cpp
utils/message.cpp
utils/header.cpp
)
target_link_libraries (
${PROJECT_NAME}
${Boost_LIBRARIES}
rados
rbd
Threads::Threads
)

Thanks to #HolyBlackCat, I solved the problem with static link.
Modified CMAKE
cmake_minimum_required(VERSION 3.2.0)
project(BinaryHelper VERSION 0.1.0)
find_package(Boost REQUIRED COMPONENTS json)
include_directories(${Boost_INCLUDE_DIR})
set(Boost_USE_STATIC_LIBS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lrados -std=c++17")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
add_library(
boost_json
STATIC
IMPORTED
)
set_target_properties(
boost_json
PROPERTIES
IMPORTED_LOCATION /usr/local/lib/libboost_json.a
)
add_executable(
${PROJECT_NAME}
main.cpp
utils/binary.cpp
utils/message.cpp
utils/header.cpp
)
# target_link_libraries (
# ${PROJECT_NAME}
# ${Boost_LIBRARIES}
# rados
# rbd
# Threads::Threads
# )
target_link_libraries(
${PROJECT_NAME}
boost_json
rados
rbd
Threads::Threads
)
There is additional(modified) keywords, add_library, set_target_properties, target_link_libraries.

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.

Build Application using libpam0g-dev with cmake

I'm trying to build a C++ application which uses the library libpamg0-dev.
I installed it with the following command on my elementaryOS VM.
apt-get install libpam0g-dev
When I try to compile the application, the compiler spits out the following errors:
undefined reference to `pam_start`
undefined reference to `pam_authenticate`
undefined reference to `pam_end`
My CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.10)
project(application)
set(CMAKE_CXX_STANDARD 11)
INCLUDE_DIRECTORIES(/home/dnagl/dev/libs/restbed/distribution/include /usr/include/security)
LINK_DIRECTORIES(/home/dnagl/dev/libs/restbed/distribution/library /usr/lib/x86_64-linux-gnu)
add_executable(application main.cpp Utils/Json/Json.cpp Utils/Json/Json.h Utils/Stringhelper/Stringhelper.cpp Utils/Stringhelper/Stringhelper.h Utils/File/Filehelper.cpp Utils/File/Filehelper.h Utils/System/SystemHelper.cpp Utils/System/SystemHelper.h Controller/Info/InfoController.cpp Controller/Info/InfoController.h Rest/ResourceHandler/ResourceHandler.cpp Rest/ResourceHandler/ResourceHandler.h Controller/System/SystemController.cpp Controller/System/SystemController.h Rest/Log/RequestLogger.cpp Rest/Log/RequestLogger.h Controller/Authentication/AuthenticationController.cpp Controller/Authentication/AuthenticationController.h Controller/Log/LogController.cpp Controller/Log/LogController.h)
target_link_libraries(application restbed)
Maybe one of you knows how to link the library in the right way.
I have found a nice solution with find_package option from CMake. CMake provides a way to find packages/libraries with specified FindModule.cmake file.
A really good news is that there are a lot of existing module files. You can use this version to find PAM package on Linux. Put it to cmake/modules/ in your project folder and update your CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(restbed)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Notify CMake that we have module files to find packages/libs.
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
find_package(PAM REQUIRED)
# Check if we found PAM.
if (NOT PAM_FOUND)
message(FATAL_ERROR "PAM library was not found.")
endif ()
# Source configuration.
include_directories(
${PAM_INCLUDE_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
set(EXECUTABLE_NAME "application")
# Add sources to this project's executable.
add_executable(${EXECUTABLE_NAME}
"main.cpp"
"Utils/Json/Json.cpp"
"Utils/Json/Json.h"
"Utils/Stringhelper/Stringhelper.cpp"
"Utils/Stringhelper/Stringhelper.h"
"Utils/File/Filehelper.cpp"
"Utils/File/Filehelper.h"
"Utils/System/SystemHelper.cpp"
"Utils/System/SystemHelper.h"
"Controller/Info/InfoController.cpp"
"Controller/Info/InfoController.h"
"Rest/ResourceHandler/ResourceHandler.cpp"
"Rest/ResourceHandler/ResourceHandler.h"
"Controller/System/SystemController.cpp"
"Controller/System/SystemController.h"
"Rest/Log/RequestLogger.cpp"
"Rest/Log/RequestLogger.h"
"Controller/Authentication/AuthenticationController.cpp"
"Controller/Authentication/AuthenticationController.h"
"Controller/Log/LogController.cpp"
"Controller/Log/LogController.h"
)
target_link_libraries(${EXECUTABLE_NAME}
${PAM_LIBRARIES}
)
set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINKER_LANGUAGE CXX)
Hope this helps!

C++ How to link boost libraries with my shared library to work on the target machine?

I try to make jni shared library.
I use boost library in the code of this library.
I successfuly make shared library on the development machine and test's done.
I make boost lib folder which have libboost_*.so files in on target machine and add it to LD_LIBRARY_PATH.
So, I try to test on the target machine (same OS platform with development machine) but target machine cannot link it.
So, my java program find my .so (libsample.so) but libsample.so can't find boost library and throw message ( undefined symbol: _ZTIN5boost6detail16thread_data_baseE)
How can I solve this problem?
I want to pack the boost libaries on my shared library
or I want to dynamically linking with boost library with my shared libarary.
my project's CMakeLists.txt following
cmake_minimum_required(VERSION 3.0)
### This CMakeLists.txt : Root CMake of this project
################## complie settings of this project ##################
set(ARTIFACT_NAME "sample-plugin")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread ")
add_definitions("-Wno-deprecated-declarations")
add_definitions("-Wno-write-strings")
################## Boost Settings ##################
set(Boost_NO_SYSTEM_PATH ON)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME ON)
set(BOOST_INCLUDE_DIR "${BOOST_ROOT}/boost")
include_directories(${BOOST_INCLUDE_DIR})
link_directories(${BOOST_INCLUDE_DIR})
link_directories(${BOOST_LIBRARY_DIR})
find_package(Boost 1.58.0 REQUIRED)
include_directories("$ENV{JAVA_HOME}/include")
if (WIN32)
include_directories("$ENV{JAVA_HOME}/include/win32")
else ()
include_directories("$ENV{JAVA_HOME}/include/linux")
endif ()
add_library(${ARTIFACT_NAME} SHARED ${SOURCES} )
target_link_libraries(${ARTIFACT_NAME} ${Boost_LIBRARIES})
Thanks, Martin Bonner.
I solve this problem.
Here is my edited CMakeLists.txt
################## complie settings of this project ##################
set(ARTIFACT_NAME "sample-plugin")
#set(CMAKE_CXX_STANDARD 11) # 아래에 -std=c++11 옵션과 중복
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -shared -fPIC -std=c++11 -pthread ")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_definitions("-Wno-deprecated-declarations")
add_definitions("-Wno-write-strings")
################## Boost Settings ##################
set(Boost_NO_SYSTEM_PATH ON)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME ON)
set(BOOST_INCLUDE_DIR "${BOOST_ROOT}/boost")
include_directories(${BOOST_INCLUDE_DIR})
link_directories(${BOOST_INCLUDE_DIR})
link_directories(${BOOST_LIBRARY_DIR})
unset(Boost_INCLUDE_DIR CACHE)
unset(Boost_LIBRARY_DIRS CACHE)
find_package(Boost 1.58.0 REQUIRED COMPONENTS thread date_time filesystem system program_options )
################## Target Settings ##################
add_library(${ARTIFACT_NAME} SHARED ${SOURCES})
set_target_properties(${ARTIFACT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${ARTIFACT_NAME} ${Boost_LIBRARIES})
Before this cmake run, I recompile boost libraries with -cxxflags=-fPIC because of this issue
I successfuly make .so library including boost libraries as static in it.

Creation of a cmake module for using a library

I am new to C++ and have just started to use Cmake for linking the libraries to my project. I need to use a library:
https://github.com/Gnimuc/FastPD
Fortunately, I managed to build the library using Cmake (in my build there is no *.lib file at all), but I don't know how to link it to my project. I mean that I don't know how to add it to my cmakelists.txt :
(PS. I'm also using two other libraries ITK and VTK; but I can't link the above mentioned library to my project or main.cpp.)
################################################
cmake_minimum_required(VERSION 2.8)
project(My_project)
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
if (ITKVtkGlue_LOADED)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
else()
find_package(ItkVtkGlue REQUIRED)
include(${ItkVtkGlue_USE_FILE})
set(Glue ItkVtkGlue)
endif()
add_executable(My_project MACOSX_BUNDLE main.cpp)
target_link_libraries(My_project
${Glue} ${VTK_LIBRARIES} ${ITK_LIBRARIES})
################################################
Thanks in advance for your helps,
Assuming you installed the library and its header files, you can then search for the header files using find_path, and add the found path to the include directories. Then you can search for the library by using find_library, and add the library with the target_link_libraries command.
I tried both shared and static types for creation of the library. In the case of shared, no *.lib file was created, and in the case of static, my project couldn't link to the library. Therefore, in my project's CmakeLists.txt, I decided to add all the *.cpp and headers as libraries and then link them together (as I didn't know the dependency among them!!!), and finally, I linked them to my project. Perhaps it does not make sense but it works; hope it helps you:
CmakeLists.txt
##############################################
cmake_minimum_required(VERSION 2.6)
set(PROJ_NAME PROJECT46)
PROJECT(${PROJ_NAME})
# Prevent compilation in-source
if( ${CMAKE_BINARY_DIR} STREQUAL ${PROJECT_SOURCE_DIR} )
Message( " " )
Message( FATAL_ERROR "Source and build directories are the same.
Create an empty build directory,
change into it and re-invoke cmake")
endif()
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support.
Please use a different C++ compiler.")
endif()
##############################################
## External libraries
##############################################
list( APPEND CMAKE_MODULE_PATH
${PROJECT_SOURCE_DIR}/cmake
)
# Blitz
find_package( Blitz++ REQUIRED )
list( APPEND PROJ_INCLUDE_DIRS
${Blitz++_INCLUDE_DIR}
)
list( APPEND
PROJ_LIB
${Blitz++_LIBRARIES}
)
# ITK and VTK
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
if (ITKVtkGlue_LOADED)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
else()
find_package(ItkVtkGlue REQUIRED)
include(${ItkVtkGlue_USE_FILE})
set(Glue ItkVtkGlue)
endif()
##############################################
# FASTPD
add_library(FASTPD Fast_PD.cpp Fast_PD.h common.h block.h)
add_library(GRAPH graph.h graph.cpp)
add_library(linked LinkedBlockList.h LinkedBlockList.cpp)
add_library(MAXFLOW maxflow.cpp)
include_directories(${PROJ_INCLUDE_DIRS})
add_executable(${PROJ_NAME} main.cpp)
target_link_libraries(linked MAXFLOW)
target_link_libraries(GRAPH linked)
target_link_libraries(FASTPD GRAPH)
target_link_libraries(${PROJ_NAME} FASTPD)
target_link_libraries(${PROJ_NAME}
${PROJ_LIB} ${Glue} ${VTK_LIBRARIES} ${ITK_LIBRARIES}
)

Compiling a static executable with CMake

for a project I need to create an executable that includes all the libraries that I used (opencv, cgal) in order to execute it on a computer that has not those libraries. Currently, this is my CMakeLists.txt (I use linux).
cmake_minimum_required(VERSION 2.8)
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall -O2")
project( labeling )
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
add_library(OpenCV STATIC IMPORTED)
add_library(CGAL STATIC IMPORTED COMPONENTS Core)
add_library(GMP STATIC IMPORTED)
find_package(OpenCV REQUIRED)
find_package(CGAL QUIET COMPONENTS Core )
find_library(GMP_LIBRARY gmp /usr/lib)
include(src)
include( ${CGAL_USE_FILE} )
include( CGAL_CreateSingleSourceCGALProgram )
set(EXECUTABLE_OUTPUT_PATH ../bin)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
include_directories( src )
include_directories( ${OpenCV_INCLUDE_DIRS} )
file(GLOB_RECURSE nei_SRC "src/*.cpp")
add_executable( nei_segmentation ${nei_SRC})
target_link_libraries( nei_segmentation ${OpenCV_LIBS} ${GMP_LIBRARY})
In such a way only GMP and some other c++ libraries are included in my executable. My question is: How can I create a makefile in order to automatically including all the libraries in a static manner and creating only a "big" executable that contains all the libraries? Can you help me?
As global CMake settings, add these lines before add_executable, valid for gcc/clang:
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "-static")
On Modern CMake (3.x+ - target_link_libraries doc), you can apply the flag to specific targets, in this way:
target_link_libraries(your_target_name -static)
If you're using MSVC, you have to set the compiler and linker flags:
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
target_compile_options(your_target_name [PUBLIC|PRIVATE] /MT)
target_link_options(your_target_name [PUBLIC|PRIVATE] /INCREMENTAL:NO /NODEFAULTLIB:MSVCRT)
or alternatively also:
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
and if you are using MFC, you need to specify the flag to 1 see here:
set(CMAKE_MFC_FLAG 1)
Add these lines after add_executable(MyExec "main.c") (for example) :
target_link_libraries(MyExec PUBLIC "-static")
or before: link_libraries("-static")