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.
Related
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.
I have a folder structure that is as follows:
|-CMakeLists.txt
|-main.cpp
|-network
---------- CMakeLists.txt
---------- network.h
---------- network.cpp
Where network is a folder containing the last 3 items.
I'm struggling to build this in CMake because the documentation is very strange to me. In my root CMakeLists.txt, it's as follows:
cmake_minimum_required(VERSION 3.11.0)
project(Test)
set(CMAKE_CXX_STANDARD 11)
include_directories ("${PROJECT_SOURCE_DIR}/network")
add_subdirectory (${PROJECT_SOURCE_DIR}/network)
add_executable(server main.cpp)
target_link_libraries (network)
find_package(Boost 1.67 REQUIRED COMPONENTS thread)
# Check for libray, if found print message, include dirs and link libraries.
if(Boost_FOUND)
message("Boost Found")
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(server ${Boost_LIBRARIES})
target_link_libraries(server Boost::thread)
elseif(NOT Boost_FOUND)
error("Boost Not Found")
endif()
In the CMakeLists.txt in the network folder it's as follows:
cmake_minimum_required(VERSION 3.11.0)
project(Test)
set(CMAKE_CXX_STANDARD 11)
install(FILES ${MY_HEADER_FILES} DESTINATION ./)
add_executable(network network.cpp)
I made that by myself playing around to see if I can get CMake to add the files in that folder into the root project. Obviously, this is all just failing because I'm struggling to understand CMake from the documentation. My apologies. I get an error due to the implementation in "network.cpp" not being recognized:
main.cpp:(.text+0x409): undefined reference to `Socket::GetThis()'
I'm certain there's nothing wrong with the implementation because it's worked using another round about method but I want to build my project using the previous structure but I can't get my head around how to make the root CMakeLists and the network CMakeLists so that they work together.
How do I design the CMakeLists so that the network header and implementation are included in the root project. Also, the network library will be using Boost as well. Should I find the package in there too?
target_link_libraries (network)
You want to link "server" executable with "network" library. It's like this:
target_link_libraries(server PUBLIC network)
The PUBLIC can be omitted, but I like to specify it everywhere.
Also:
add_executable(network network.cpp)
should network.spp really be an executable? I guess there is no main in network.cpp`. You should:
add_library(network network.cpp)
And I guess the network include path is integral to the network library. So I would inside network/CMakeLists.txt do:
target_include_directories(network PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Also note the target_compile_feature is preferred over set(CMAKE_CXX_STANDARD 11).
Also, there is no error() function. There is message(FATAL_ERROR).
All in all, I would write it like this:
# root/CMakeLists.txt
cmake_minimum_required(VERSION 3.11.0)
project(Test)
# this tells cmake that all c++ files that are in this file
# and all in add_subdirectory projects
# will compile with C++11 (by default)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(network)
add_executable(server main.cpp)
# tell cmake to link server with network library
# ie. server executable uses network library
target_link_libraries(server PUBLIC network)
find_package(Boost 1.67 REQUIRED COMPONENTS thread)
# Check for libray, if found print message, include dirs and link libraries.
if(Boost_FOUND)
message(STATUS "Boost Found")
target_include_directories(server PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(server PUBLIC ${Boost_LIBRARIES} Boost::thread)
elseif(NOT Boost_FOUND)
message(FATAL_ERROR "Boost Not Found")
endif()
and:
# network/CMakeLists.txt
add_libraries(network network.cpp)
# tell cmake, that all targets that link with network library
# will have include path added
target_include_directories(network PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
I link only server executable with boost. I have no idea if your network library needs to link with boost too, if so, move the boost info netowrk/CMakeLists.txt and target_link_libraries(network PUBLIC ${Boost_LIBRARIES})
I think you have to change line
add_executable(server main.cpp)
to
add_executable(server main.cpp network.cpp)
P.S I personally prefer to use this construction:
SET(PROJECT_NAME "MyProject")
...
file(GLOB SRC_FILES *.cpp)
...
add_executable("${PROJECT_NAME}" "${SRC_FILES}")
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!
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}
)
My program uses giblib and Imlib2 library and it is built with cmake.
It works perfectly in my computer but not in other's.
I guess the reason is I installed every library what my program needs but other's doesn't.
My goal is making standalone program. (don't need to install any other library addtionally)
What should I add in cmake file?
projectDef.cmake source code
file (GLOB PLATFORM RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
X11/[^.]*.cpp
X11/[^.]*.h
X11/[^.]*.cmake
)
SOURCE_GROUP(X11 FILES ${PLATFORM})
add_definitions(
)
set (SOURCES
${SOURCES}
${PLATFORM}
)
add_x11_plugin(${PROJECT_NAME} SOURCES)
target_link_libraries(${PROJECT_NAME}
${PLUGIN_INTERNAL_DEPS}
)
include_directories(/usr/include/giblib)
include_directories(/usr/include/X11)
target_link_libraries(MyProject X11)
target_link_libraries(MyProject Imlib2)
target_link_libraries(MyProject giblib)
CMakeList.txt source code
cmake_minimum_required (VERSION 2.6)
set (CMAKE_BACKWARDS_COMPATIBILITY 2.6)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "-static")
Project(${PLUGIN_NAME})
file (GLOB GENERAL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
[^.]*.cpp
[^.]*.h
[^.]*.cmake
)
include_directories(${PLUGIN_INCLUDE_DIRS})
SET_SOURCE_FILES_PROPERTIES(
${GENERATED}
PROPERTIES
GENERATED 1
)
SOURCE_GROUP(Generated FILES
${GENERATED}
)
SET( SOURCES
${GENERAL}
${GENERATED}
)
include_platform()
Try starting with this options in your root CMakeLists.txt:
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
BUILD_SHARED_LIBS is only needed if your project has its own libraries (add_library).
With the -static linker flag, you need static libs for ALL your additional libraries too! One common problem when static linking is to avoid circular dependencies.