How does CMake handle shared-library upgrades? - c++

I have a project where I link to boost; the CMakeLists.txt looks like this:
project(test VERSION 1.0)
set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall -Wextra -Wfloat-equal -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Woverloaded-virtual")
find_package(Boost COMPONENTS filesystem program_options log log_setup REQUIRED)
include_directories(
${Boost_INCLUDE_DIRS}
)
add_executable(test src/test.cpp)
target_link_libraries(test
LINK_PUBLIC
${Boost_LIBRARIES}
config++
)
install(TARGETS test DESTINATION /usr/bin)
Now I am stumped how the linking in CMake works under the hood. It compiles fine but after I upgraded Boost, I am getting the error
test: error while loading shared libraries: libboost_program_options.so.1.75.0: cannot open shared object file: No such file or directory
and I'd like to avoid having to recompile every time a library gets an update.
The CMake doc says that
The LINK_PUBLIC and LINK_PRIVATE modes can be used to specify both the link dependencies and the link interface in one command.
But I don't quite understand how or why CMake links to the specific version of Boost and not simply to /usr/lib/libboost_program_options.so which is just a symlink to the currently installed version.

Related

C++ cross compile WxWidgets with MXE using CMAKE

I am trying to make a CMAKE file that allows me to cross compile a WxWidgets application From Ubuntu For Windows.
My tools are all installed correctly, and I am able to run:
i686-w64-mingw32.static-gcc main.cpp $(i686-w64-mingw32.static-wx-config --cxxflags --libs) -o main.exe -std=c++11 -lstdc++
and produce a working output.
But I have been unsuccessful in finding a way to convert this into a CMAKE file. Does anyone have any resources or even examples of a working example?
Here is an example of my non-working file:
cmake_minimum_required(VERSION 3.11)
SET (PROJECT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
SET(PROJECT_NAME "WxWidgets")
SET(CMAKE_C_COMPILER i686-w64-mingw32.static)
project(
${PROJECT_NAME}
VERSION 1.0
LANGUAGES CXX)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} (i686-w64-mingw32.static-wx-config --cxxflags --libs) -L /home/kevin/wxWidgets/include/ -Wall -std=gnu++2a -static -g")
file(GLOB all_SRCS
"${PROJECT_SOURCE_DIR}/src/*.h"
"${PROJECT_SOURCE_DIR}/src/*.hpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
"${PROJECT_SOURCE_DIR}/src/*.cpp"
"${PROJECT_SOURCE_DIR}/src/**/*.c"
"${PROJECT_SOURCE_DIR}/src/**/*.cpp"
"${PROJECT_SOURCE_DIR}/src/**/*.hpp"
)
add_executable(${PROJECT_NAME} ${all_SRCS})
I am running the command:
i686-w64-mingw32.static-cmake ..
within my build directory.
By removing:
**(i686-w64-mingw32.static-wx-config --cxxflags --libs) -L /home/kevin/wxWidgets/include/**
...I am getting the error:
fatal error: wx/wxprec.h: No such file or directory
8 | #include "wx/wxprec.h"
I have this file I checked with locate:
$ locate wx/wxprec.h
/home/kevin/mxe/usr/i686-w64-mingw32.static/include/wx-3.1/wx/wxprec.h
/home/kevin/wxWidgets/include/wx/wxprec.h
/usr/local/include/wx-3.3/wx/wxprec.h
EDIT:
Thanks to #vre's comment, I have updated my CMakeLists.txt file and have moved closer, it seems now that I just need to link correctly Here is what I have:
cmake_minimum_required(VERSION 3.11)
SET (PROJECT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
SET(PROJECT_NAME "WxWidgets")
SET(CMAKE_C_COMPILER i686-w64-mingw32.static)
project(
${PROJECT_NAME}
VERSION 1.0)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=gnu++2a -static -g")
file(GLOB all_SRCS
"${PROJECT_SOURCE_DIR}/src/*.h"
"${PROJECT_SOURCE_DIR}/src/*.hpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
"${PROJECT_SOURCE_DIR}/src/*.cpp"
"${PROJECT_SOURCE_DIR}/src/**/*.c"
"${PROJECT_SOURCE_DIR}/src/**/*.cpp"
"${PROJECT_SOURCE_DIR}/src/**/*.hpp"
)
add_executable(${PROJECT_NAME} ${all_SRCS})
include( "${wxWidgets_USE_FILE}" )
find_package(wxWidgets REQUIRED)
target_include_directories(${PROJECT_NAME} PUBLIC /home/kevin/mxe/usr/i686-w64-mingw32.static/include/wx-3.1/ /home/kevin/mxe/usr/i686-w64-mingw32.static/lib/wx/include/i686-w64-mingw32.static-msw-unicode-static-3.1/)
target_link_directories(${PROJECT_NAME} PRIVATE /home/kevin/mxe/usr/i686-w64-mingw32.static/lib/)
But sadly, I have many linker errors such as:
undefined reference to `wxFrame::GetDefaultIcon() const'

How to fix: 'can not be used when making a shared object; recompile with -fPIC' using Cmake. Using plain g++ works

I get a message 'can not be used when making a shared object; recompile with -fPIC'
I have try other examples and the issue is the same.
I have try
changing from MODULE to SHARED
cmake .. -DCMAKE_CXX_FLAGS=-fPIC
and other variations
this works:
c++ -c -fPIC -I/usr/include/python3.6m ../account.cpp
c++ -shared -Wall -Werror -Wl,--export-dynamic account.o -L/usr/local/lib -lboost_python36 -o account.so
Here is the basic cmake
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(Test)
find_package(PythonInterp REQUIRED)
find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
find_package(Boost 1.70.0 COMPONENTS python REQUIRED)
add_library(account SHARED account.cpp)
target_link_libraries(account Boost::python)
target_include_directories(account PRIVATE ${PYTHON_INCLUDE_DIRS})
set_target_properties(account PROPERTIES PREFIX "")
Using: make VERBOSE=1 the output commands are:
c++ -DBOOST_ALL_NO_LIB -Daccount_EXPORTS -I/usr/include/python3.6m -isystem /usr/local/include -fPIC -o CMakeFiles/account.dir/account.cpp.o -c /src/boost_python_example/account.cpp
c++ -fPIC -shared -Wl,-soname,account.so -o account.so CMakeFiles/account.dir/account.cpp.o /usr/local/lib/libboost_python36.a
So the cmake is not getting the same paths and flags, I am learning cmake so Im trying to understand this problem. Clearly the problem is not on actual libs but telling cmake where to find the proper ones.
The solution was quite simple. Comparing both commands what was missing on the cmake command was: --export-dynamic
So I solved using option(BUILD_SHARED_LIBS "Build libraries as shared as opposed to static" ON) interesting enough the comment is needed.
Working solution:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(Test)
option(BUILD_SHARED_LIBS "Build libraries as shared as opposed to static" ON)
find_package(PythonInterp REQUIRED)
find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
find_package(Boost 1.70.0 COMPONENTS python REQUIRED)
add_library(account SHARED account.cpp)
target_link_libraries(account Boost::python)
target_include_directories(account PRIVATE ${PYTHON_INCLUDE_DIRS})
set_target_properties(account PROPERTIES PREFIX "")
Thanks everyone for the comments they lead me to a solution

Boost Dynamic Linking

I am aware this question was asked many times before, always ending with the same answer... add -DBOOST_LOG_DYN_LINK to your CMakeLists.txt file.
However, I've had this in my cmake for a long time and everything was linking without any problems. Now I decided to switch to Ubuntu 18.04 from 16.04 and update my projects one by one....
This is my cmake file:
cmake_minimum_required(VERSION 2.8.4)
project(FOO)
find_package(Boost REQUIRED COMPONENTS system timer filesystem log program_options unit_test_framework)
find_package(CGAL COMPONENTS Core)
find_library(OPEN_MESH_CORE_LIBRARY OpenMeshCore /usr/local/lib/OpenMesh REQUIRED)
find_library(YAML_CPP_LIBRARY yaml-cpp REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
find_package(PkgConfig REQUIRED)
pkg_check_modules(JSONCPP jsoncpp)
link_libraries(${JSONCPP_LIBRARIES})
include_directories(${JSONCPP_INCLUDE_DIRS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -fopenmp -msse2 -march=native -W -Wall -std=c++11")
add_definitions(-DBOOST_LOG_DYN_LINK=1)
add_definitions(-DUNIT_TEST_DATA="${CMAKE_SOURCE_DIR}/data")
include( ${CGAL_USE_FILE} )
include( CGAL_CreateSingleSourceCGALProgram )
set(SOURCE_FILES
Foo1.cpp
Foo2.cpp
Foo3.cpp)
add_executable(FOO main.cpp ${SOURCE_FILES})
target_include_directories(FOO PRIVATE ${JsonCpp_INCLUDE_DIRS})
target_link_libraries(FOO ${OPEN_MESH_CORE_LIBRARY} ${Boost_LIBRARIES} ${YAML_CPP_LIBRARY} ${JSONCPP_LIBRARIES})
add_library(foo SHARED ${SOURCE_FILES})
target_link_libraries(foo ${OPEN_MESH_CORE_LIBRARY} ${Boost_LIBRARIES} ${YAML_CPP_LIBRARY} ${JSONCPP_LIBRARIES})
add_executable(tests test.cpp ${SOURCE_FILES})
target_include_directories(FOO PRIVATE ${JsonCpp_INCLUDE_DIRS})
target_link_libraries(tests ${OPEN_MESH_CORE_LIBRARY} ${Boost_LIBRARIES} ${YAML_CPP_LIBRARY} ${JSONCPP_LIBRARIES})
When compiled, it fails with known long list of problems, all related ending with a message
undefined reference to boost::log::v2_mt_posix::...
I am not a cmake ninja and it is very likely that I am doing something wrong, however, I can not find out what it is.
EDIT:
I have successfully tried to build it on a clean Ubuntu 16.04 with gcc 5 and boost 1.58
I have unsuccessfully tried to build it on a clean 18.04 with gcc7.1
and boost 1.65
I have unsuccessfully tried to build it on a clean 18.04 with gcc 5.5
and self compiled boost 1.58
I have unsuccessfully tried to build it on a clean 18.04 with gcc 5.5
and self compiled boost 1.65
All attempts followed an exactly the same procedure.
Cause of this problem wasn't in Boost or CMakeLists.txt. It was actually a problem of CGAL calling find_package(Boost) again somewhere in their use protocol when include( ${CGAL_USE_FILE} ) was invoked, and ended up overriding Boost_LIBRARIES with links to it's own components, completely omitting what I've found previously.
Here is the reported issue
Solution is somewhat dirty as I'didn't patch CGAL up. All it took was changing the order when i call include( ${CGAL_USE_FILE} ) and placing it at the top.
find_package(CGAL COMPONENTS Core)
include( ${CGAL_USE_FILE} )
find_package(Boost REQUIRED COMPONENTS system timer filesystem log
program_options unit_test_framework)
Please NOTE that this is a quick fix and can result in further problems such as overriding Boost components required by CGAL!

Linking with thrift

I'm getting undefined reference to 'typeinfo for apache::thrift::transport::TTransportException' (and other symbols) when trying to link my executable with my library which uses thrift. I'm using GCC 7.3.0 on Ubuntu 18.04, building with CMake in CLion
I'm stuck after spending a day googling about this problem and after visiting this, that and this links.
The CMake command looks as following
For my shared object:
TARGET_LINK_LIBRARIES(server INTERFACE
etcdclient
TopologyProtocols
event
${THRIFT_LIBRARIES}
${Boost_LIBRARIES}
lzo2
sqlite3
zmq
${SPDK_LIBS}
${DPDK_LIBS}
grpc
grpc++
gtest
gmock
xml2
stdc++fs
bfd
-l:libisal.so.2
sgutils2
pthread
uuid
rt
)
The executable CMake command:
TARGET_LINK_LIBRARIES(kserver
server
${THRIFT_LIBRARIES}
)
Linker command generated by CMake:
cmake_link_script CMakeFiles/kserver.dir/link.txt --verbose=1
/usr/bin/c++ -O3 -DNDEBUG CMakeFiles/kserver.dir/main.cpp.o -o kserver -L/server/ext/spdk/build/lib -L/server/ext/spdk/dpdk/build/lib -L/server/ext/isal/lib -Wl,-rpath,/server/ext/spdk/build/lib:/server/ext/spdk/dpdk/build/lib:/server/ext/isal/lib:/server/cmake-build-release/lib/proj:/usr/local/lib:/server/cmake-build-release/ext/etcd:/server/cmake-build-release/protocols ../../lib/proj/libproj.so /usr/local/lib/libthrift.so /usr/local/lib/libthriftnb.so ../../ext/etcd/libetcdclient.so ../../protocols/libTopologyProtocols.so /home/user/vcpkg/installed/x64-linux/lib/libprotobuf.a -levent /usr/local/lib/libthrift.so /usr/local/lib/libthriftnb.so /home/user/vcpkg/installed/x64-linux/lib/libboost_system.a -llzo2 /home/user/vcpkg/installed/x64-linux/lib/libsqlite3.a -lpthread -ldl -lzmq -lspdk -ldpdk -lgrpc -lgrpc++ -lgtest -lgmock -lxml2 -lstdc++fs -lbfd -l:libisal.so.2 -lsgutils2 -lpthread -luuid -lrt
The command looks perfectly fine, it links with thrift, thriftnb and event
As of compiler and general projects settings, here a content of root CMakeList.txt in the source root
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
LIST(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/cmake")
SET(CMAKE_CXX_STANDARD 17)
#SET(ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/lib")
#SET(LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/lib")
#SET(RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/bin")
ADD_COMPILE_OPTIONS(
-include server.h
# -Wall
# -pedantic
-march=native
)
ADD_COMPILE_DEFINITIONS(
BOOST_COROUTINES_NO_DEPRECATION_WARNING
GTEST_LINKED_AS_SHARED_LIBRARY
)
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/lib/include/server
${CMAKE_SOURCE_DIR}/lib/include
)
LINK_DIRECTORIES(
${CMAKE_SOURCE_DIR}/ext/spdk/build/lib
${CMAKE_SOURCE_DIR}/ext/spdk/dpdk/build/lib
${CMAKE_SOURCE_DIR}/ext/isal/lib
)
FIND_PACKAGE(Boost REQUIRED COMPONENTS
system)
FIND_PACKAGE(Protobuf REQUIRED)
FIND_PACKAGE(GRPC REQUIRED)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/cmake/FindGRPC.cmake)
FIND_PACKAGE(LZO REQUIRED)
FIND_PACKAGE(sqlite3 REQUIRED)
FIND_PACKAGE(ZeroMQ CONFIG REQUIRED)
FIND_PACKAGE(GTest REQUIRED)
FIND_PACKAGE(Thrift REQUIRED)
ADD_SUBDIRECTORY(lib/server)
ADD_SUBDIRECTORY(ext/etcd)
ADD_SUBDIRECTORY(protocols)
ADD_SUBDIRECTORY(proc/kserver)
Sample compilation command
/usr/bin/c++ -DBOOST_COROUTINES_NO_DEPRECATION_WARNING -DGTEST_LINKED_AS_SHARED_LIBRARY -Dserver_EXPORTS -I/home/user/sourcelib/include/server -I/home/user/sourcelib/include -I/home/user/sourceext/spdk/include -I/home/user/sourcecmake-build-release/ext/etcd -I/home/user/sourcecmake-build-release/protocols -I/home/user/vcpkg/installed/x64-linux/include -O3 -DNDEBUG -fPIC -include server.h -march=native -std=gnu++1z -o CMakeFiles/server.dir/misc/ServerHost.cpp.o -c /home/user/sourcelib/server/misc/ServerHost.cpp
What I'm doing wrong?
It took two days to figure out that there was some esoteric version installed on my machine and the package manager was not aware of it, after removing it manually and using version provided by vcpkg everything linked as expected.

How to use FFTW library in cmake?

I have C++ code which uses FFTW 3.3.4. Ubuntu 16.04, cmake version 3.7.2
$ locate *fftw*.so
/usr/lib/libsfftw.so
/usr/lib/libsfftw_mpi.so
/usr/lib/libsfftw_threads.so
/usr/lib/libsrfftw.so
/usr/lib/libsrfftw_mpi.so
/usr/lib/libsrfftw_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3.so
/usr/lib/x86_64-linux-gnu/libfftw3_mpi.so
/usr/lib/x86_64-linux-gnu/libfftw3_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3f.so
/usr/lib/x86_64-linux-gnu/libfftw3f_mpi.so
/usr/lib/x86_64-linux-gnu/libfftw3f_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3f_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3l.so
/usr/lib/x86_64-linux-gnu/libfftw3l_mpi.so
/usr/lib/x86_64-linux-gnu/libfftw3l_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3l_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3q.so
/usr/lib/x86_64-linux-gnu/libfftw3q_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3q_threads.so
$ locate fftw3.h
/usr/include/fftw3.h
I can compile it in this way:
g++ main.cpp -o main -lfftw3
but I have a problem with cmake.
This is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.5.1)
project (main)
SET(CMAKE_C_COMPILER gcc)
SET(CMAKE_CXX_COMPILER g++)
file(GLOB SOURCES "*.cpp")
SET(CMAKE_CXX_FLAGS "-lm -lfftw3")
SET(CMAKE_C_FLAGS "-lm -lfftw3")
INCLUDE_DIRECTORIES(/usr/include)
LINK_DIRECTORIES(/usr/lib/x86_64-linux-gnu)
add_library(fftw3 STATIC IMPORTED)
set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
add_executable(main ${SOURCES})
cmake . && make
gives
undefined reference to `fftw_malloc'
and the same for the other fftw functions.
The command add_library will create a library in your project (CMake -
add_library). I assume that is not what you want.
The command: g++ main.cpp -o main -lfftw3 will link the executable to the fftw library. In CMake you can reproduce the linking with:
add_executable(main ${SOURCES})
target_link_libraries(main fftw3)
Docu: CMake - target_link_libraries
Notice: It is important that the add_executable command comes before the linking.
Have fun with FFTW :)
We delegate this to pkg-config:
find_package(PkgConfig REQUIRED)
pkg_search_module(FFTW REQUIRED fftw3 IMPORTED_TARGET)
include_directories(PkgConfig::FFTW)
link_libraries (PkgConfig::FFTW)
This works with cmake 3.11 (at least, it may work with earlier versions too).
NOTE: This doesn't work with fftw3_thread component because they don't have a separate .pc file. (see https://github.com/FFTW/fftw3/issues/180).
This may work to add the component (not tested, doesn't work in Macs --see comments--):
link_libraries (PkgConfig::FFTW -lfftw3_thread)
NOTE 2: I am pasting here #OlafWilkocx solution to get the thread component as well
cmake_minimum_required(VERSION 3.20)
...
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-math-errno -ffinite-math-only") # clang
find_package(OpenMP REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(FFTW IMPORTED_TARGET REQUIRED fftw3)
if( NOT FFTW_ROOT AND DEFINED ENV{FFTWDIR} )
set( FFTW_ROOT $ENV{FFTWDIR} )
endif()
find_library(
FFTW_DOUBLE_THREADS_LIB
NAMES "fftw3_threads"
PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
)
if (FFTW_DOUBLE_THREADS_LIB)
set(FFTW_DOUBLE_THREADS_LIB_FOUND TRUE)
set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_THREADS_LIB})
add_library(FFTW::DoubleThreads INTERFACE IMPORTED)
set_target_properties(FFTW::DoubleThreads
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_THREADS_LIB}"
)
else()
set(FFTW_DOUBLE_THREADS_LIB_FOUND FALSE)
endif()
include_directories(PkgConfig::FFTW)
add_executable(solver_step src/solver_step.cc)
target_link_libraries(solver_step PRIVATE OpenMP::OpenMP_CXX ${VTK_LIBRARIES} PkgConfig::FFTW ${FFTW_DOUBLE_THREADS_LIB})
NOTE 3
I am told that the line include_directories(PkgConfig::FFTW) is always incorrect and suggested to either only use link_libraries(PkgConfig::FFTW) or target_link_libraries(target_name PRIVATE PkgConfig::FFTW).
see here: Avoid bad include paths in CMake's pkg-config fallback