CMake Ubuntu set soname for shared object - linux

How to set the SONAME for a shared library with CMake in Ubuntu?
With help of How to add linker flag for libraries with CMake? I have created a CMakeLists.txt:
project(mylib VERSION 1.2.3)
set(src_files_mylib
Client.cpp
Server.cpp
)
set(hdr_files_mylib
Client.h
Server.h
)
add_library(mylib SHARED ${src_files_mylib} ${hdr_files_mylib})
set_target_properties(mylib PROPERTIES PREFIX "")
set_target_properties(mylib PROPERTIES SUFFIX "")
set_target_properties(mylib PROPERTIES OUTPUT_NAME "mylib.so.${PROJECT_VERSION}")
add_link_options("LINKER: -l,soname,mylib.so.${PROJECT_VERSION_MAJOR}")
Using CMake 3.16 and out of source build. It produces the library named mylib.so.1.2.3 but it does not seem to have an SONAME in it. When executing ldconfig -n . in the library dir, it does not produce a link.
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,soname,mylib.so.${PROJECT_VERSION_MAJOR}")
instead of
add_link_options("LINKER: -l,soname,mylib.so.${PROJECT_VERSION_MAJOR}")
behaves the same to me.
When writing the Makefile manually, the target is built correctly with this (going ldconfig -n . like above produces a link):
(...)
MYLIB_SO=mylib.so.$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)
MYLIB_SONAME=mylib.so.$(VERSION_MAJOR)
(...)
$(MYLIB_SO): $(OBJ_MYLIB)
$(CXX) $(SO_FLAGS) -Wl,-soname,$(MYLIB_SONAME) -o $(MYLIB_SO) $(DEBUGFLAGS) $(OBJ_MYLIB)

if libraries is called SoundTouch
project(SoundTouch VERSION 2.3.0 LANGUAGES CXX)
add_library(SoundTouch [SHARED]
sources/animation.cpp
sources/buffers.cpp
[...]
)
set_target_properties(SoundTouch PROPERTIES VERSION ${CMAKE_PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR} )

Related

CMake: How to use an imported .so.1.2.3 in transitive dependencies

I have to import a libft4222.so.1.2.3 into a CMake project on Linux. There are no symlinks without version information like a plain libmyimportedlibrary.so. I am writing a FindLibFT4222.cmake to make the library usable in my project.
In my project, a shared library uses libft4222 like this:
if (LIBFT4222_FOUND)
if (NOT TARGET LibFT4222::LibFT4222)
add_library(LibFT4222::LibFT4222 UNKNOWN IMPORTED)
set_target_properties(LibFT4222::LibFT4222
PROPERTIES IMPORTED_LOCATION ${LibFT4222_LIBS})
target_include_directories(LibFT4222::LibFT4222
INTERFACE
${LibFT4222_INCLUDE_DIR})
endif()
endif()
LibFT4222_LIBS points to the imported location of the libft4222.so.1.2.3:
/path/to/libft4222.so.1.2.3
I am adding this library as a dependency to a shared library A in my project.
Finally, I have an executable depending on A.
When I link the executable, the linker reports an error that it cannot find libft4222.so
When I add libft4222 directly to the executable, it works.
The error message I get:
/usr/lib/gcc-cross/arm-linux-gnueabihf/9/../../../../arm-linux-gnueabihf/bin/ld: warning: libft4222.so, needed by libSomeOtherLib.so, not found (try using -rpath or -rpath-link)
How do I tell CMake to correctly handle libft4222.so.1.2.3 and not to omit .1.2.3?
Update 1: I looked at the SONAME property of libft4222.so.1.2.3:
$ arm-linux-gnueabihf-objdump -p libft4222.so.1.4.4.44 | grep SONAME
SONAME libft4222.so
So I guess creating the symlinks is unavoidable.

How do I write the cmake script for clion to include glfw?

cmake_minimum_required(VERSION 3.15)
project(hello)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
set(CMAKE_CXX_STANDARD 11)
add_executable(hello main.cpp)
INCLUDE_DIRECTORIES(${GLFW_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(hello ${GLFW_STATIC_LIBRARIES})
It tells me
CMake Error at /home/user/.local/share/JetBrains/Toolbox/apps/CLion/ch-0/193.5233.144/bin/cmake/linux/share/cmake-3.15/Modules/FindPkgConfig.cmake:696 (message):
None of the required 'glfw3' found
when I try to build it. My glfw folder is located at /usr/local/include/GLFW.
AFAIK, glfw3 is using CMake as the build system,
(src: packages.debian.org/fr/sid/amd64/libglfw3-dev/filelist)
which uses modern CMake, so you don't need GLFW_INCLUDE_DIRS etc...
Inside this file /usr/lib/cmake/glfw3/glfw3Targets.cmake (loaded by /usr/lib/cmake/glfw3/glfw3Config.cmake), you'll see:
...
# Create imported target glfw
add_library(glfw SHARED IMPORTED)
set_target_properties(glfw PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "GLFW_DLL"
INTERFACE_INCLUDE_DIRECTORIES "/usr/include"
)
...
So you can simply use:
find_package(glfw3 REQUIRED)
...
target_link_libraries(Foo glfw)
ps: same as my previous comment

Understanding `Makevars` for linking to external C library in R package

I am working on a package which includes C code from third-party library (SUNDIALS). The package compiles and works (i.e., is able to solve a test ODE) with the following Makevars file performing static linking
CXX=clang++
PKG_CPPFLAGS = -I../inst/include
PKG_LDFLAGS = /usr/local/lib
PKG_LIBS= $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(PKG_LDFLAGS)/libsundials_cvode.a $(PKG_LDFLAGS)/libsundials_nvecserial.a
However, a slightly modified version (based on the example in R-Exts, i.e. -
PKG_LIBS = -L$(XML_DIR)/lib -lxml2) of Makevars (below) fails
CXX=clang++
PKG_CPPFLAGS = -I../inst/include
PKG_LDFLAGS = /usr/local/lib
PKG_LIBS= $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -L$(PKG_LDFLAGS) -lsundials_cvode -lsundials_nvecserial -lm
fails with the following error message.
Error: package or namespace load failed for ‘Rcppsbmod’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod/libs/Rcppsbmod.so':
dlopen(/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod/libs/Rcppsbmod.so, 6): Library not loaded: libsundials_cvode.3.dylib
Referenced from: /Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod/libs/Rcppsbmod.so
Reason: image not found
Error: loading failed
Execution halted
ERROR: loading failed
* removing ‘/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod’
* restoring previous ‘/Library/Frameworks/R.framework/Versions/3.4/Resources/library/Rcppsbmod’
Exited with status 1.
I am not sure why it is looking for the libraries in another location when I am specifying PKG_LDFLAGS as /usr/local/lib.
As an aside, the test example which comes which the SUNDIALS package compiles and works with the following command
gcc -Wall cvRoberts_dns.c -o cvRoberts_dns.exe -I/usr/local/include -L/usr/local/lib/ -lsundials_cvode -lsundials_nvecserial -lm
So, I know that the library is installed properly and correct files (for linking) are available at /usr/local/lib location.
The entire package source code can be found at - https://github.com/sn248/Rcppsbmod
Any help or guidance will be highly appreciated!
System-wide dynamic linking, as in your second use case which fails, requires the cooperation of the dynamic linker on your system.
That means after build and copyring the libraries to /usr/local/lib you must typically run sudo ldconfig to update the linker cache.
You can check if the libraries are know by grep'ing through the output of ldconfig -p. On my system, no sundials:
edd#rob:~$ ldconfig -p | grep sundials
edd#rob:~$
Relatedly you can (locally) use different directories by declaring them in
/etc/ld.so.conf.d/somefile.conf -- but that is of course not portable and would not help you with a package designated for CRAN.
The use of static libraries you build as part of your package as in your first example would work as it does not require any system assistance. It just takes longer the build the libraries each time.
I am fighting with similar issues, c.f. Runtime linking R-extension on MacOS. My current workaround is to set the rpath at compile time. In your case that would mean:
CXX=clang++
PKG_CPPFLAGS = -I../inst/include
PKG_LDFLAGS = /usr/local/lib
PKG_LIBS= $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -L$(PKG_LDFLAGS) -lsundials_cvode -lsundials_nvecserial -lm -Wl,-rpath,$(PKG_LDFLAGS)
However, this does not fix your problems. Comparing the error messages I see one difference: In your case the library libsundials_cvode.3.dylib is not found, while in my case it is #rpath/libaf.3.dylib. This means that the library you installed identifies itself as libsundials_cvode.3.dylib. You can check this with
$ otool -L /usr/local/lib/libsundials_cvode.3.dylib
/usr/local/lib/libsundials_cvode.3.dylib:
/usr/local/opt/sundials/lib/libsundials_cvode.3.dylib (compatibility version 3.0.0, current version 3.1.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
In your case the second output line should not contain an absolute path but only the basename of the library. My installation uses brew, which typically uses absolute paths as library names. In some trivial tests I had no problem with linking an R extension with these libraries.
I see several possibilities:
Try SUNDIAL from brew.
Adjust the library path in your installed libraries with
install_name_tool -id /usr/local/lib/libsundials_cvode.3.dylib /usr/local/lib/libsundials_cvode.3.dylib
to use absolute paths.
Adjust the library path in your installed libraries with
install_name_tool -id '#rpath/libsundials_cvode.3.dylib' /usr/local/lib/libsundials_cvode.3.dylib
and set rpath as above.
Adjust the name of the library your R extension is looking for with this addition to Makevars
all: $(SHLIB)
#if command -v install_name_tool; then install_name_tool -change libsundials_cvode.3.dylib /usr/local/lib/libsundials_cvode.3.dylib $(SHLIB); fi

Using CMake to find symbols in libraries

I am trying to use CMake to find if an external library depends on another library.
Example: the HDF5 library can be optionally linked with zlib
In Linux, this can be found with
readelf -Ws /usr/local/lib/libhdf5.so | grep inflateEnd
54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND inflateEnd
With CMake it seems this can be found with CheckLibraryExists
https://cmake.org/cmake/help/v3.0/module/CheckLibraryExists.html
In Cmake script
set(CMAKE_REQUIRED_LIBRARIES ${HDF5_LIBRARY})
check_library_exists(${HDF5_LIBRARY} inflateEnd "" NEED_ZLIB)
message(${NEED_ZLIB})
if (NEED_ZLIB)
message("-- ZLIB library is needed...")
else()
message("-- ZLIB library is not needed...")
endif()
output is not found
-- Looking for inflateEnd in /usr/local/lib/libhdf5.so - not found
-- ZLIB library is not needed...
because of this I did the Cmake version of using readelf, that finds the symbol
but, still would like to know why the above Cmake script fails :-)
the working version is
set(have_read_symbols "no")
find_program(read_symbols_prg readelf)
if (${read_symbols_prg} MATCHES "readelf")
set(have_read_symbols "yes")
message("-- Readelf program found: " ${read_symbols_prg})
execute_process(COMMAND ${read_symbols_prg} -Ws ${HDF5_LIBRARY} OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/symbols.txt)
endif()
if (${have_read_symbols} MATCHES "yes")
message("-- Detecting if HDF5 library ${HDF5_LIBRARY} needs the ZLIB library...")
file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/symbols.txt NEED_ZLIB REGEX "inflateEnd")
if (NEED_ZLIB)
message("${color_blue}-- ZLIB library is needed...${color_reset}")
else()
message("-- ZLIB library is not needed...")
endif(NEED_ZLIB)
endif()
that finds the symbol
-- Detecting if HDF5 library /usr/local/lib/libhdf5.so needs the ZLIB library...
-- ZLIB library is needed...
Ok, The Cmake documentation for checkLibraryExists() is short on details on how this is accomplished, they just say "Check if the function exists".
checkLibraryExists() tries to link a test program, and depending on success or not, the output variable parameter is set to value 1 or empty.
In this case, the symbol to look must be one that is defined in libhdf5.so only with using the zlib library. There is one and only one symbol for this case, a structure named "H5Z_DEFLATE" that is added to the library depending on a #ifdef for the zlib case.
So, this does the trick
check_library_exists(${HDF5_LIBRARY} H5Z_DEFLATE "" NEED_ZLIB)
However for the Windows case using Visual Studio this is error prone, because for check_library_exists() to detect it, Visual Studio must set an option as additional dependencies the zlib library, and this is not a requirement for the library to build successfully. So, if this option is set, check_library_exists detects the dependency, if not set, it does not.

How to list target_link_libraries available on a system?

I'm trying to link with the Curl library in my CMakeLists.txt and I know that I should require the package add executable and link the library but I don't know how the variables names are called and where should I look for them, do you know where should I be looking for? Is there a way to list all the libraries in the system that I could be able to add in my project?
Here it's my CMakeLists (silly) attempt:
cmake_minimum_required(VERSION 3.3)
project(RadekClientRecon)
find_package(OpenCV REQUIRED)
find_package(CURL REQUIRED)
link_directories(/usr/lib/)
set(SOURCE_FILES main.cpp HttpManager.cpp)
add_executable(RadekClientRecon ${SOURCE_FILES})
target_link_libraries(RadekClientRecon ${OpenCV_LIBS} ${CURL_LIBRARIES})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
I've searched all "curl" named files in my computer if helps, I'm also using CLion if there's an automated way.
rinaldi#rinaldi-home:~/Projects/radekrecon$ sudo find / -name "*curl*" 2> /dev/null
/home/rinaldi/.atom/packages/atom-beautify/node_modules/jscs/lib/rules/disallow-curly-braces.js
/home/rinaldi/.atom/packages/atom-beautify/node_modules/jscs/lib/rules/require-curly-braces.js
/var/lib/dpkg/info/libcurl3:amd64.list
/var/lib/dpkg/info/python3-pycurl.md5sums
/var/lib/dpkg/info/libcurl3-gnutls:amd64.shlibs
/var/lib/dpkg/info/curl.md5sums
/var/lib/dpkg/info/libcurl3:amd64.postrm
/var/lib/dpkg/info/libcurl3:amd64.md5sums
/var/lib/dpkg/info/python3-pycurl.list
/var/lib/dpkg/info/libcurl3-gnutls:amd64.symbols
/var/lib/dpkg/info/libcurl3-gnutls:amd64.postrm
/var/lib/dpkg/info/libcurl3:amd64.symbols
/var/lib/dpkg/info/libcurl3-gnutls:amd64.md5sums
/var/lib/dpkg/info/libcurl3:amd64.postinst
/var/lib/dpkg/info/libcurl3:amd64.shlibs
/var/lib/dpkg/info/python3-pycurl.postinst
/var/lib/dpkg/info/curl.list
/var/lib/dpkg/info/python3-pycurl.prerm
/var/lib/dpkg/info/libcurl3-gnutls:amd64.postinst
/var/lib/dpkg/info/libcurl3-gnutls:amd64.list
/opt/clion-1.2.4/bin/cmake/doc/cmake-3.3/cmcurl
/opt/clion-1.2.4/bin/gdb/lib/python2.7/macurl2path.py
/usr/lib/python2.7/macurl2path.py
/usr/lib/python3.5/macurl2path.py
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
/usr/lib/x86_64-linux-gnu/libcurl.so.4
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.3
/usr/lib/x86_64-linux-gnu/libcurl.so.3
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4.3.0
/usr/lib/x86_64-linux-gnu/gstreamer-0.10/libgstcurl.so
/usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0
/usr/lib/python3/dist-packages/pycurl.cpython-35m-x86_64-linux-gnu.so
/usr/lib/python3/dist-packages/curl
/usr/lib/python3/dist-packages/pycurl-7.19.5.1.egg-info
/usr/lib/python3/dist-packages/pycurl.cpython-34m-x86_64-linux-gnu.so
/usr/lib/python3.4/macurl2path.py
/usr/lib/gnupg/gpgkeys_curl
/usr/bin/curl
/usr/share/man/man1/curl.1.gz
/usr/share/lintian/overrides/libcurl3
/usr/share/lintian/overrides/libcurl3-gnutls
/usr/share/doc/libcurl3
/usr/share/doc/python3-pycurl
/usr/share/doc/libcurl3-gnutls
/usr/share/doc/curl
/usr/share/bash-completion/completions/curl
Apparently I needed to install some packages other than curl.
* libcurl4-gnutls-dev
* libcurl4-nss-dev
* libcurl4-openssl-dev
Those variables are named after their modules that can be found here.
My CMakeList.txt now it's creating the proper make file and looks like this:
cmake_minimum_required(VERSION 3.3)
project(RadekClientRecon)
find_package(OpenCV REQUIRED)
find_package(CURL REQUIRED)
link_directories(/usr/lib/)
link_directories(CURL_INCLUDE_DIRS)
set(SOURCE_FILES main.cpp HttpManager.cpp)
add_executable(RadekClientRecon ${SOURCE_FILES})
target_link_libraries(RadekClientRecon ${OpenCV_LIBS} ${CURL_LIBRARIES})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
After verifying the installation of curl, this is my CMakeLists.txt, which is running well on ubuntu 17.10
cmake_minimum_required(VERSION 2.8)
set(CURL_MIN_VERSION "7.55.1")
project(Downloader)
find_package(CURL REQUIRED)
link_directories(/usr/lib/x86_64-linux-gnu/)
add_executable(Downloader HTTPDownloaderExample.cpp HTTPDownloader.cpp)
target_link_libraries(Downloader curl)

Resources