linking shared libraries with cmake on ubuntu - linux

I am trying to link to shared object library (json-c) using cmake. I am a super beginner with cmake, and have tried the solutions in various SO posts to no avail.
I am following the directions laid out here
first step is to build the json-c library, which I did sucesfully.
Second step is linking to it. That's what I am having issues with. After following these instructions, my project directory structure looks like this:
Project Structure (before running make, build directory was empty)
base
|-json-c-master
|-libjson-c.so
|-libjson-c.a
|-json.h
:
:
:
|-CMakeLists.txt
|-Makefile
|-libjson-c.so
|-build
|-CMakeFiles
|-
:
:
|-Makefile.
|-src
|-main.c
|-project1.c
|-project1.h
The contents of my CMakeLists.txt in ~/base/project1/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(project1) set(CMAKE_CXX_STANDARD 14)
set(SOURCES src/main.c src/project1.h src/project1.c )
add_executable(project1 ${SOURCES})
find_package(json-c CONFIG)
target_link_libraries(${PROJECT_NAME} PRIVATE json-c::json-c)
then, I ran
cd build
cmake -DCMAKE_PREFIX_PATH=/home/<username>/base/project1/json-c-master ..
this populated the previously empty build directory.
then, I ran make
and I got the error that in project1.h, which #includes "json.h", the file "json.h" was not found.
How can I link json.h to project1.h?
I again appreciate your patience, I am a super noob with cmake and I've been pouring over their documentation and other SO posts to no avail.

Related

Shared Libraries not linking together after installation with CMake

I have run into a rather strange problem with Google Tests.
In my project, I am using externalProject_add in order to download google tests and add them into my project. In my function, I believe I am asking for the project to be built, and then installed into a specific directory:
ExternalProject_Add(gTest_download
URL ${GTEST_url}
URL_HASH ${GTEST_hash}
UPDATE_COMMAND ""
BUILD_COMMAND cmake --build . --target install
CMAKE_CACHE_ARGS
-DCMAKE_C_COMPILER:PATH=${Compiler_C}
-DCMAKE_CXX_COMPILER:PATH=${Compiler_CXX}
-DBUILD_SHARED_LIBS:BOOL=ON
-DCMAKE_INSTALL_PREFIX:PATH=<BINARY_DIR>/installation
)
I can then tell the program where all the source files are living with this:
ExternalProject_Get_Property(gTest_download BINARY_DIR)
set(gTest_LIBRARY_DIR ${BINARY_DIR}/installation/lib CACHE INTERNAL "Google Test Binary Dir")
set(gTest_INCLUDE_DIR ${BINARY_DIR}/installation/include CACHE INTERNAL "Google Test Include Dir")
However, when I try to run a cmake test with protobufs I get the run time error:
./Protobuf_test: error while loading shared libraries: libgmock.so.1.11.0: cannot open shared object file: No such file or directory
Which is super odd, because I know I specifically told the program where to find the libraries in the same externalProject_add file:
set(gTest_LIBRARIES
${gTest_LIBRARY_DIR}/${prefix}gmock${suffix}
${gTest_LIBRARY_DIR}/${prefix}gmock_main${suffix}
${gTest_LIBRARY_DIR}/${prefix}gtest${suffix}
${gTest_LIBRARY_DIR}/${prefix}gtest_main${suffix}
CACHE INTERNAL "Google Test Libraries"
)
Where ${prefix} is "lib" and ${suffix} is ".lib". And I make sure to link them in my CMakeLists.txt file properly by doing target_link_libraries(Protobuf_test ${gTest_LIBRARIES} ${protobuf_LIBRARIES}) ex:
CUSTOM_PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDS ${CMAKE_CURRENT_LIST_DIR} hello.proto)
include_directories(
${protoBuf_INCLUDE_DIR}
${gTest_INCLUDE_DIR}
${CMAKE_CURRENT_LIST_DIR}
)
add_executable(Protobuf_test protobuf_test.cc ${PROTO_SRCS} ${PROTO_HDS})
add_dependencies(Protobuf_test
gTest_download
protoBuf_download
)
target_link_libraries(Protobuf_test
${gTest_LIBRARIES}
${protoBuf_LIBRARIES}
)
add_test(NAME testing_protobuf COMMAND Protobuf_test)
So I went into the installation folder which is located in d/linuxBuild/lib/src/gTest_download-build/installation/lib and confirmed it exists there. I then ran ldd libgmock.so and got the following output:
libgtest.so.1.11.0 => not found
Which I thought was odd as well. gtest is in the same directory! How is that possible? So I ran ldd on gmock_main:
libgmock.so.1.11.0 => not found
libgtest.so.1.11.0 => not found
So now I have two libraries that are in the same directory however they cannot be found. Confused, I decide to go to where the libraries should have originally installed to and copied over from. So two folders up: d/linuxBuild/lib/src/gTest_download-build. I then go into that folders lib folder and verify the libraries are there. I then run the same ldd command on gmock:
libgtest.so.1.11.0 => /mnt/d/linuxBuild/lib/src/gTest_download-build/lib/libgtest.so.1.11.0 (0x00007fb651729000)
I'm confused by this and again, run it on gmock_main:
libgmock.so.1.11.0 => /mnt/d/linuxBuild/lib/src/gTest_download-build/lib/libgmock.so.1.11.0 (0x00007f58b0db3000)
libgtest.so.1.11.0 => /mnt/d/linuxBuild/lib/src/gTest_download-build/lib/libgtest.so.1.11.0 (0x00007f58b0c9c000)
I am sorry for the lengthy question, but I need to know what happened here? Why is it when I install the libraries the links break from each other and they don't know their locations compared to the ones in the original installation path? Did their symbolic links break? Did I do something incorrectly in the CMake build? I'm scratching my head on this problem since I have never encountered this before. Any advice would be greatly appreciated.
Forget about externalProject_add and use FetchContent / FetchContent_MakeAvailable, especially when dealing with CMake-ready projects:
See https://cmake.org/cmake/help/latest/module/FetchContent.html for details
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.11.0
)
FetchContent_MakeAvailable(googletest)
# ...
target_link_libraries(Protobuf_test
PRIVATE
gmock_main
${protoBuf_LIBRARIES}
)
This way, you are linking against the gmock_main target, which will set up your libraries, includes, and any indirect dependencies correctly like any cmake project added via add_subdirectory() or find_package().

"undefined reference" error from static lib of external parquet project

I want to link expernal 'parquet' project ( https://github.com/apache/arrow/tree/master/cpp ) as part of my current project on Linux.
For this purposes I ran cmake of parquet with such parameters
cd build_parquet
cmake -DCMAKE_BUILD_TYPE=Release -DARROW_PARQUET=ON \
-DBoost_NO_BOOST_CMAKE=TRUE -DBoost_NO_SYSTEM_PATHS=TRUE -DBOOST_ROOT=${BOOST_BUILD_DIR}/include -DBOOST_LIBRARYDIR=${BOOST_BUILD_DIR}/lib/boost -DARROW_BOOST_USE_SHARED=OFF -DBOOST_INCLUDEDIR=${BOOST_BUILD_DIR}/include/boost ..
cmake --build . --config Release
// There are a lot of dependencies except boost, but only boost required to be installed on system, since other could be downloaded and installed by cmake script
Project successfully compiled. I got executable which could launch, generated static libs libarrow.a, libparquet.a, shared libraries libarrow.so, libparquet.so
In my main project I want to use such libraries and I use such commands in cmake to find them
find_path(PARQUET_INCLUDE_DIR NAMES arrow/api.h PATHS ${PARQUET_DIR}/src)
find_library(PARQUET_LIBRARY_RELEASE NAMES parquet.a
PATHS build_parquet/release/Release/ )
find_library(ARROW_LIBRARY_RELEASE NAMES arrow.a
PATHS build_parquet/release/Release/ )
set(PARQUET_LIBRARIES_RELEASE ${PARQUET_LIBRARY_RELEASE} ${ARROW_LIBRARY_RELEASE} )
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Parquet DEFAULT_MSG PARQUET_INCLUDE_DIR
${PARQUET_LIBRARIES_RELEASE } )
That's work okay, libraries and includes are found.
Then I link this libraries to my project
target_link_libraries(${myExe} ${PARQUET_LIBRARIES_RELEASE} ${mySomeOtherLibraries} )
after this I got enormous amount of linker errors such that
libparquet.a(column_writer.cc.o): In function `apache::thrift::transport::TMemoryBuffer::~TMemoryBuffer()':
column_writer.cc:(.text._ZN6apache6thrift9transport13TMemoryBufferD0Ev[_ZN6apache6thrift9transport13TMemoryBufferD5Ev]+0x3): undefined reference to `vtable for apache::thrift::transport::TMemoryBuffer'
.....
so that's what I don't understand much, why lib compiled well in parquet project itself but has a lot of unresolved now, when I use it to link in my own project? Moreover I compiled project for windows and when I did the same things, but with arrow.lib and parquet.lib (instead of libparquet.a and libarrow.a ) things worked fine! I was needed only to put arrow.dll, parquet.dll to executables to run project. But in Linux I've already crashed my head
So, why it doesn't work, what I should do to finally link the project with library ?
Update
I found the problem, I had to link libraries with adding .so files (not only .a files) like this
find_library(PARQUET_LIBRARY_RELEASE NAMES parquet.so parquet.a
PATHS build_parquet/release/Release/ )
find_library(ARROW_LIBRARY_RELEASE NAMES arrow.so arrow.a
PATHS build_parquet/release/Release/ )
set(PARQUET_LIBRARIES_RELEASE ${PARQUET_LIBRARY_RELEASE} ${ARROW_LIBRARY_RELEASE} )
Project is builded. So now the question is, why I need to add .so files to linker (in Windows only static .lib are enough), is it always a case when I build project in Linux ? Is order of linkage important ( .so files first and .a files next ? )
As Uwe wrote in a comment, the https://github.com/apache/parquet-cpp repository is deprecated, and the Parquet C++ library is being developed as part of the Apache Arrow C++ codebase https://github.com/apache/arrow/tree/master/cpp. Can you try building based on that, and if you have trouble can you post on the dev#arrow.apache.org mailing list?
You have succeed to build the project when link with the shared (.so) libraries instead of the static (.a) ones.
(The command find_library actually looks for one library, which name is listed in NAMES option. In your case it found .so library because its name comes before the .a one).
Actually, both shared and static parquet libraries contain the same set of symbols, and both sets are insufficient for link. The difference is that the shared library contains information, where to find remaining symbols (in the thrift library in your case), but the static library doesn't.
For correctly link with the static libraries, you need to list dependent libraries manually.
On Windows .lib file may mean either a static library, or a import file for the shared (.dll) one. It seems that you link with the dynamic one (it has no lib prefix), which succeed like on Linux.

Error in configuration process, Project files may be invalid

I'm new to CMake. I copied a small vtk example from the link http://www.vtk.org/Wiki/VTK/Examples/Cxx/IO/SimplePointsReader and used CMake to compile. And it gives me an error, " Error in configuration process, Project files may be invalid".
It shows me the errors,
CMake Error at CMakeLists.txt:5 (find_package): By not providing
"FindVTK.cmake" in CMAKE_MODULE_PATH this project has asked CMake to
find a package configuration file provided by "VTK", but CMake did
not find one.
Could not find a package configuration file provided by "VTK" with
any of the following names:
VTKConfig.cmake
vtk-config.cmake
Add the installation prefix of "VTK" to CMAKE_PREFIX_PATH or set
"VTK_DIR" to a directory containing one of the above files. If
"VTK" provides a separate development package or SDK, be sure it has
been installed.
I have already installed vtk in my pc and please help me with this problem.
CMakeLists.txt contains the following code
cmake_minimum_required(VERSION 2.8)
PROJECT(SimplePointsReader)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(SimplePointsReader MACOSX_BUNDLE SimplePointsReader)
if(VTK_LIBRARIES)
target_link_libraries(SimplePointsReader ${VTK_LIBRARIES})
else()
target_link_libraries(SimplePointsReader vtkHybrid vtkWidgets)
endif()
I've solved this problem by setting VTK_DIR=path_to_VTK/bin as an environment variable, because CMakeList.txt file's changing was not helpful.

linking against library using VS and CMake on windows

I'm new to the world of cmake and linking to libaries. Now for a project I need to include a third party library in the current application. However I'm having problems linking to the library.
Here is what I have:
The library is build in the location D:/qwt-6.1.2, which contains:
the folder /src with the header and source files
the folder /lib which contains (qwt.dll, qwt.ext, qwt.lib, qwtd.dll, qwtd.ext, qwtd.ilk, qwtd.lib and qwtd.pdb.
I have tried to add the following to the cmake file:
add_executable(Demo main.cpp mainwindow.cpp mainwindow.h )
include_directories(D:/qwt-6.1.2/src)
link_directories(D:/qwt-6.1.2/lib)
target_link_libraries(Demo qwt)
The including goes fine since the intellisense of visual studio can the includes that I do, however when I build I get the error:
Error 1 error LNK1104: cannot open file 'qwt.lib'
Does anybody have an idea what I'm doing wrong? I don't care at the moment if it is statically or dynamically linked.

Linux opencv independent installation : not found in CMake

I am creating an object tracking program which rely on OpenCV. Thus I want to be able to test it with different versions of OpenCV but I have linking errors.
I installed the last version of OpenCV (a69b435c928f422fb5f99c02cf2dcae57dcf820a) in the following folder : /usr/local/opencv/opencv-trunk instead of the usual /usr/local.
Then I followed also the official tutorial to use OpenCV with CMake in Linux, but I had the following "normal" error :
CMake Error at CMakeLists.txt:11 (find_package):
By not providing "FindOpenCV.cmake" in CMAKE_MODULE_PATH this project has asked CMake to find a package configuration file provided by "OpenCV", but CMake did not find one.
Could not find a package configuration file provided by "OpenCV" with any of the following names:
OpenCVConfig.cmake
opencv-config.cmake
Add the installation prefix of "OpenCV" to CMAKE_PREFIX_PATH or set "OpenCV_DIR" to a directory containing one of the above files. If "OpenCV" provides a separate development package or SDK, be sure it has been installed.
-- Configuring incomplete, errors occurred!
So I did what was suggested and added the following line in my CMakeLists.txt :
# Find independently installed OpenCV libraries
set(OpenCV_DIR "/usr/local/opencv/opencv-trunk/share/OpenCV")
This is the complete CMakeLists.txt file :
# Find independently installed OpenCV libraries
set(OpenCV_DIR "/usr/local/opencv/opencv-trunk/share/OpenCV")
cmake_minimum_required(VERSION 2.8)
project( DisplayImage )
add_executable( DisplayImage DisplayImage.cpp )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
target_link_libraries( DisplayImage ${OpenCV_LIBS} )
Now I have the following error and I don't find how to deal with it.
CMake Error at CMakeLists.txt:12 (find_package):
Found package configuration file:
/usr/local/opencv/opencv-trunk/share/OpenCV/OpenCVConfig.cmake
but it set OpenCV_FOUND to FALSE so package "OpenCV" is considered to be NOT FOUND.
-- Configuring incomplete, errors occurred!
If you have already faced that issue in such context your solutions are welcomed ;)
If you are running IntelliJ or any other IDE, just try re-building CMake cache (or just remove your build directory and run cmake utility again).
I believe this is not the best practice - to set the configuration variable like OpenCV_DIR hard-coded in the CMakeLists.txt. Try setting it manually, as an environment variable to the cmake utility:
OpenCV_DIR=/usr/local/Cellar/opencv3/3.1.0_2/share/OpenCV/ cmake ..
or set your IDE to make this for you:

Resources