How to link compiled cmph library in my project using CMake - c++

In order to use cmph, a perfect minimal hashing library, in my project organised using CMake, I installed cmph library in a ubuntu machine and tested it using a single c file called main.c.
If I try to compile this file using gcc 5.3.0 using the following command:
gcc main.c
I will get the following output
/tmp/ccSOH5ob.o: In function `main':
testperfect.c:(.text+0x63): undefined reference to `cmph_io_vector_adapter'
testperfect.c:(.text+0x73): undefined reference to `cmph_config_new'
testperfect.c:(.text+0x88): undefined reference to `cmph_config_set_algo'
testperfect.c:(.text+0x9b): undefined reference to `cmph_config_set_mphf_fd'
testperfect.c:(.text+0xa7): undefined reference to `cmph_new'
testperfect.c:(.text+0xb7): undefined reference to `cmph_config_destroy'
testperfect.c:(.text+0xca): undefined reference to `cmph_dump'
testperfect.c:(.text+0xd6): undefined reference to `cmph_destroy'
testperfect.c:(.text+0xe2): undefined reference to `cmph_load'
testperfect.c:(.text+0x118): undefined reference to `cmph_search'
testperfect.c:(.text+0x153): undefined reference to `cmph_destroy'
testperfect.c:(.text+0x15f): undefined reference to `cmph_io_vector_adapter_destroy'
But if I run this command:
gcc main.c $(pkg-config --libs cmph) -o main
It will be compiled and run normally.
Now I need to add a similar piece of code in my project and the CMakeList.txt is written like this:
set(PROJECT_EXECUTABLE ${PROJECT_NAME})
# Compiling flags.
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR
CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
endif()
# Inject project config.
configure_file(
${PROJECT_INCLUDE_DIR}/phsim/config.hpp.in
${PROJECT_INCLUDE_DIR}/phsim/config.hpp
)
include(FindPkgConfig)
find_package(PkgConfig REQUIRED)
pkg_search_module(CMPH REQUIRED cmph)
target_link_libraries(Phsim ${CMPH_LIBRARIES})
target_include_directories(Phsim PUBLIC ${CMPH_INCLUDE_DIRS})
target_compile_options(Phsim PUBLIC ${CMPH_CFLAGS_OTHER})
# Compile executable.
file(GLOB SOURCES ${PROJECT_SRC_DIR}/*.cpp)
add_executable(${PROJECT_EXECUTABLE} ${SOURCES})
set_target_properties(${PROJECT_EXECUTABLE} PROPERTIES
VERSION ${PHSIM_VERSION_LITER}
)
And then I try to run cmake . and make, but only get the error message:
CMake Error at src/CMakeLists.txt:20 (target_link_libraries):
Cannot specify link libraries for target "Phsim" which is not built by this
project.
But I won't get target executable file unless I compile the project. If I try to compile my project without those commands related to library linking, the compiler will give similar link errors provided in the beginning of my question.
I have checked the following questions:
Undefined reference to cmph functions even after installing cpmh library
And I tried instructions provided by these sites:
https://cmake.org/Wiki/CMake:How_To_Find_Libraries
https://cmake.org/cmake/help/v3.6/module/FindPkgConfig.html
Many thanks in advance.

Finally Solved.
cmake_minimum_required(VERSION 3.0.2)
project(TestGamma)
set(GAMMATEST_VERSION_MAJOR 1)
set(GAMMATEST_VERSION_MINOR 0)
set(CMPH_INCLUDE_DIR /usr/local/lib)
include(FindPkgConfig)
configure_file(
"${PROJECT_SOURCE_DIR}/TestGammaConfig.h.in"
"${PROJECT_BINARY_DIR}/TestGammaConfig.h"
)
include_directories(${PROJECT_BINARY_DIR})
set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
add_executable(testgamma ${SOURCE_FILES})
pkg_check_modules(CMPH REQUIRED cmph)
include_directories(${CMPH_INDLUDE_DIR})
link_directories(${CMPH_INCLUDE_DIR})
target_link_libraries(testgamma cmph ${CMPH_INCLUDE_DIR})
Make sure to include pkgconfig at first and add link operations after calling "add_executable"
#usr1234567 Thank you for your attention.

Related

CMake undefined reference to `pthread_create` in Github Action Ubuntu image

When I was using Github Action CI, I found that no matter what method I used to link, there was no way to link pthread_create
But this error only appears in the Ubuntu environment, Windows, macOS are no problem
I tried:
Not Working
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
add_executable(xxx xxx.c)
target_link_libraries(xxx PRIVATE Threads::Threads)
Not Working
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
You can view the compiled log here:
https://github.com/YuzukiTsuru/lessampler/runs/6640320037?check_suite_focus=true
If you read the build log carefully
/usr/bin/ld: CMakeFiles/GenerateAudioModelTest.dir/__/src/GenerateAudioModel.cpp.o: in function `GenerateAudioModel::GenerateModelFromFile()':
GenerateAudioModel.cpp:(.text+0x27aa): undefined reference to `pthread_create'
You notice the error has happened while linking the target GenerateAudioModelTest that is located in the directory test and CMakeLists.txt there does not have the compiler flags you shown. Just add -pthread in test/CMakeLists.txt.
This is a bad idea.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
Use
target_compile_options(GenerateAudioModelTest PRIVATE -pthread)
See What is the modern method for setting general compile flags in CMake?
Not Working
You did not link with Thread::Thread nor any library that the target links to.
https://github.com/YuzukiTsuru/lessampler/blob/a6bb7e7d7ac30b6b4043d4f717a2d4deb7fb7638/test/CMakeLists.txt#L22
Not Working
Flags have to be set before add_executable. Which means before all the add_subdirectories. And flags have directory scope. Use targe_compile_options.
https://github.com/YuzukiTsuru/lessampler/blob/master/src/CMakeLists.txt
Consider just making it one library, why so many, and so many CMakeLists.txt in every directory. If the tools are not so separate and you are never going to use them separately, just make it one library with one CMakeLists.txt that links with all the libraries.

Compiling boost::log with static linking doesn't work when including init_from_settings.hpp

I am able to successfully compile the below program.
#include <iostream>
#include "boost/log/trivial.hpp"
int main(int, char**)
{
BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
return EXIT_SUCCESS;
}
With the following CMakeFile.
cmake_minimum_required(VERSION 2.8)
project(boost_log CXX)
# we will use static libs
set(Boost_USE_STATIC_LIBS ON)
# Boost::log required Boost version >= 1.54.0
find_package(Boost 1.54.0 REQUIRED COMPONENTS log)
find_package(Threads)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
set(SRC_FILES
src/main.cpp)
add_executable(boost_log ${SRC_FILES})
target_link_libraries(boost_log ${Boost_LIBRARIES} Threads::Threads)
However, if I edit main.cpp and add the following snippet:
#include "boost/log/utility/setup.hpp"
#include "boost/log/utility/setup/from_settings.hpp"
void blah(void)
{
boost::log::settings setts;
boost::log::init_from_settings(setts);
}
Then I get linking errors:
/usr/bin/c++ -rdynamic CMakeFiles/boost_log.dir/src/main.cpp.o -o boost_log -Wl,-Bstatic -lboost_log -lboost_date_time -lboost_log_setup -lboost_system -lboost_filesystem -lboost_thread -lboost_regex -lboost_chrono -lboost_atomic -Wl,-Bdynamic -lpthread -lpthread
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libboost_log_setup.a(init_from_settings.o): In function `boost::log::v2s_mt_posix::(anonymous namespace)::default_syslog_sink_factory<char>::create_sink(boost::log::v2s_mt_posix::basic_settings_section<char> const&)':
(.text+0x27fa): undefined reference to `boost::log::v2s_mt_posix::sinks::syslog_backend::set_severity_mapper(boost::log::v2s_mt_posix::aux::light_function<boost::log::v2s_mt_posix::sinks::syslog::level (boost::log::v2s_mt_posix::record_view const&)> const&)'
(snipped, but the errors continue)
Why does including from_settings.hpp cause linking to fail? Is this not avaliable to link statically?
I have tried both on Fedora and Ubuntu with the same result.
You are missing the log_setup library!
Do:
find_package(Boost 1.54.0 REQUIRED COMPONENTS log_setup log)
I encountered the same link error these days and it turned out to be a static linking order issue which is a topic I'm not familiar enough to explain here but I found an article that may help: Library order in static linking.
I used the same C++ source code as you posted in the question but my CMakeLists.txt looks like the following:
cmake_minimum_required(VERSION 3.10)
include(CMakePrintHelpers)
project(boost_log CXX)
# Compile as C++17.
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# we will use static libs
set(Boost_USE_STATIC_LIBS ON)
find_package(Boost REQUIRED COMPONENTS
filesystem
log
log_setup
regex
system
)
find_package(Threads)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
set(SRC_FILES main.cpp)
message(STATUS "==========")
message(STATUS "Boost_LIBRARIES: ${Boost_LIBRARIES}")
message(STATUS "==========")
add_executable(boost_log_exec ${SRC_FILES}
)
target_link_libraries(boost_log_exec
# Unfortunately, in ${Boost_LIBRARIES}, `boost_log_setup` follows
# `boost_log` rather than precedes it, hence the link errors.
# ${Boost_LIBRARIES}
Boost::log_setup
Boost::log
Threads::Threads
)
The key point is the explicit use of Boost::log_setup and Boost::log in this particular order (i.e., Boost::log_setup must precede Boost::log) which are CMake targets that are explained here. With these two targets explicitly specified in target_link_libraries, you don't need the variable Boost_LIBRARIES at all.
The order of these two is important due to the static linking order issue I mentioned at the very beginning: one must put before the other in order to link correctly.
The reason that ${Boost_LIBRARIES} alone doesn't work is that the static libraries that Boost_LIBRARIES represents are listed in the following order (which is printed out by the message call in my CMakeLists.txt):
Boost_LIBRARIES: /usr/lib/x86_64-linux-gnu/libboost_filesystem.a;/usr/lib/x86_64-linux-gnu/libboost_log.a;/usr/lib/x86_64-linux-gnu/libboost_log_setup.a;/usr/lib/x86_64-linux-gnu/libboost_regex.a;/usr/lib/x86_64-linux-gnu/libboost_system.a;/usr/lib/x86_64-linux-gnu/libboost_date_time.a;/usr/lib/x86_64-linux-gnu/libboost_thread.a;-lpthread;/usr/lib/x86_64-linux-gnu/libboost_chrono.a;/usr/lib/x86_64-linux-gnu/libboost_atomic.a
(I'm not sure why -lpthread is also in the listing, by the way.)
The GCC command line that CMake generates uses the same order of the static libraries when ${Boost_LIBRARIES} was used. Therefore, the actual command was (see note [1] at the end):
/usr/bin/c++ CMakeFiles/boost_log_exec.dir/main.cpp.o -o boost_log_exec /usr/lib/x86_64-linux-gnu/libboost_filesystem.a /usr/lib/x86_64-linux-gnu/libboost_log.a /usr/lib/x86_64-linux-gnu/libboost_log_setup.a /usr/lib/x86_64-linux-gnu/libboost_regex.a /usr/lib/x86_64-linux-gnu/libboost_system.a /usr/lib/x86_64-linux-gnu/libboost_date_time.a /usr/lib/x86_64-linux-gnu/libboost_thread.a -lpthread /usr/lib/x86_64-linux-gnu/libboost_chrono.a /usr/lib/x86_64-linux-gnu/libboost_atomic.a -lpthread
The libboost_log.a and libboost_log_setup.a are listed in the inverse order that they should be, hence the link errors.
In addition, using the CMake target Boost::log itself doesn't solve the problem. In other words, the following code snippet doesn't work:
target_link_libraries(boost_log_exec
Boost::log
Threads::Threads
)
It doesn't work because the target Boost::log also lists libboost_log.a first and then libboost_log_setup.a, which is not the desired order. I found this by showing the underlying GCC command line as I mentioned in note [1].
Note [1]: FYI: After I ran cmake . to configure the build, I ran make VERBOSE=1 to build but also show the underlying GCC command line. New versions of CMake seem to support --verbose command line option directly. See this answer.

CMake Library Linking using two different compiler versions

I am facing some issues when trying to compile a shared library using CMake on Ubuntu (16.04) and linking it to an executable compiled with CMake on CentOS (6.8).
The first CMakeLists.txt to create the library looks like this:
cmake_minimum_required(VERSION 3.0)
project(MyLibrary)
file(GLOB ${SOURCES} SOURCES "src/*.cpp")
include_directories(${PROJECT_SRC_DIR}/include)
set(CMAKE_CXX_FLAGS "-std=c++11")
add_library(${PROJECT_NAME} SHARED ${SOURCES})
which will create libMyLibrary.so
The second CMakeLists.txt is:
cmake_minimum_required(VERSION 3.0)
project(MyApp)
set(MY_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../build)
include_directories(${MY_LIB_DIR}/include)
set(CMAKE_CXX_FLAGS "-std=c++98")
add_executable(${PROJECT_NAME} "main.cpp")
target_link_libraries(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/../build/libMyLibrary.so)
Note that the library was built in build directory, while the final executable MyApp is built in a different folder. On Ubuntu this combination works, while generating the library on Ubuntu and compiling only the second part on CentOS throws undefined reference for every function defined in C++11 and not defined in the C++98 standard. In fact, this was initially the reason why I did this: to build the library (containing C++11) with a more recent version of g++, and link it to the executable on CentOS, where an older version, not supporting the standard, is available (I have no root access on CentOS).
I would like to know if what I am trying to do is even possible, and, if yes, what am I missing.
EDIT After the answer of Matthieu Brucher, I added the flag -D_GLIBCXX_USE_CXX11_ABI=0 to the first CMakeLists.txt file, in addition to the -std=c++11 flag. This removed undefined reference errors, but stil keeps the following:
undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::basic_string<char,std::char_traits<char>,std::allocator<char> >&&)#GLIBCXX_3.4.14'
undefined reference to `std::basic_ios<char, std::char_traits<char>>::operator bool() const#GLIBCXX_3.4.21'
undefined reference to `std::random_device::_M_getval()#GLIBCXX_3.4.18'
undefined reference to `std::random_device::_M_fini()#GLIBCXX_3.4.18'
undefined reference to `std::random_device::_M_init(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)#GLIBCXX_3.4.18'
The main issue with this is that the c++11 version has a different abi. If you want to compile c++11 with the old abi, add the macro _GLIBCXX_USE_CXX11_ABI=0.
Then the undefined references should be solved.

Cmake undefined reference to `boost::gregorian::greg_month::as_short_string() const'

I spend whole day trying to link the data_time library to my c++ cmake project.
So I am using cmake 3.4 and boost 1.61.0.
I have the class where is a function which is taking local time:
void TestClass::getTime() {
this->endDate = boost::posix_time::second_clock::local_time();
}
Then I want to return the value of endDate by function returning string:
string testCalss::Info() {
return to_simple_string(this->beginningDate);
}
I need to convert the type of endDate variable to string, because function is string type.
I am getting error messages while program is linking:
In function boost::date_time::month_formatter<boost::gregorian::greg_month, boost::date_time::simple_format<char>, char>::format_month(boost::gregorian::greg_month const&, std::ostream&)':
/usr/include/boost/date_time/date_formatting.hpp:44: undefined reference to `boost::gregorian::greg_month::as_short_string() const'
/usr/include/boost/date_time/date_formatting.hpp:49: undefined reference to `boost::gregorian::greg_month::as_long_string() const'
I have read that data_time is not only header-only library and I should build and add it to my project.
I have tried this command gcc myapp.cpp -omyapp -lboost_date_time, and it's does not work because I am using g++ in cmake project and I haven't find nothing for g++.
I also tried this:
c++ -I path/to/boost_1_61_0 example.cpp -o example \
~/boost/stage/lib/libboost_regex-gcc34-mt-d-1_36.a
Its example from official boost docs how to link libraries.
In cmake project I have few cpp files. Should I run this command using file where is my converting command?
Is there any easier way to fix this error?
I found out how to solve the problem. The way I choose is simple. First of all I have used the locate */boost/date_time* command to find where is my boost and date_time libraries installed. I did not know what version of boost library I am using, so I used locate command again to find boost/version.hpp file. After that I added few lines to my CmakeLists.txt:
find_package( Boost 1.60.0 COMPONENTS date_time)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries( Program ${Boost_DATE_TIME_LIBRARY} )
endif()
Thats all.
cmake_minimum_required(VERSION 3.17)
project(boost_ptime)
set(CMAKE_CXX_STANDARD 17)
set(SOURCE_FILES main.cpp)
add_executable(boost_ptime ${SOURCE_FILES})
find_package( Boost 1.73 COMPONENTS date_time)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries( boost_ptime ${Boost_DATE_TIME_LIBRARY} )
endif()
Thanks to Warszawski Koks, I was able to compile my program in this way. Above is the full CMakeLists.txt file.

How to correct CMAKE error: package 'opencv' not found

OK, I know that opencv linking has been discussed before, but I can't see an error and I don't understand the corrective action. I'm trying to link DBoW2 library, which requires opencv. I'm getting undefined reference errors.
$ mingw32-make
Linking CXX shared library ..\lib\libDBoW2.dll
CMakeFiles\DBoW2.dir/objects.a(FORB.cpp.obj):FORB.cpp:(.text+0x124): undefined reference to `cv::Mat::zeros(int, int, int)'
CMakeFiles\DBoW2.dir/objects.a(FORB.cpp.obj):FORB.cpp:(.text+0x1db): undefined reference to `cv::fastFree(void*)'
CMakeFiles\DBoW2.dir/objects.a(FORB.cpp.obj):FORB.cpp:(.text+0x394): undefined reference to `cv::Mat::deallocate()'
CMakeFiles\DBoW2.dir/objects.a(FORB.cpp.obj):FORB.cpp:(.text+0x46a): undefined reference to `cv::Mat::copyTo(cv::_OutputArray const&) const'
CMakeFiles\DBoW2.dir/objects.a(FORB.cpp.obj):FORB.cpp:(.text+0x503): undefined reference to `cv::Mat::copySize(cv::Mat const&)'
CMakeFiles\DBoW2.dir/objects.a(FORB.cpp.obj):FORB.cpp:(.text+0x93f): undefined reference to `cv::Mat::create(int, int const*, int)'
collect2.exe: error: ld returned 1 exit status
Here's the CMakeLists.txt file
cmake_minimum_required(VERSION 2.8)
project(DBoW2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -march=native ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native")
set(HDRS_DBOW2
DBoW2/BowVector.h
DBoW2/FORB.h
DBoW2/FClass.h
DBoW2/FeatureVector.h
DBoW2/ScoringObject.h
DBoW2/TemplatedVocabulary.h)
set(SRCS_DBOW2
DBoW2/BowVector.cpp
DBoW2/FORB.cpp
DBoW2/FeatureVector.cpp
DBoW2/ScoringObject.cpp)
set(HDRS_DUTILS
DUtils/Random.h
DUtils/Timestamp.h)
set(SRCS_DUTILS
DUtils/Random.cpp
DUtils/Timestamp.cpp)
find_package(OpenCV REQUIRED)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
include_directories(${OpenCV_INCLUDE_DIRS})
add_library(DBoW2 SHARED ${SRCS_DBOW2} ${SRCS_DUTILS})
target_link_libraries(DBoW2 ${OpenCV_LIBS})
I'm using the gui interface, and the parameter OpenCV_DIR automatically sets to C:/OpenCV/minwg_64. Under that directory there is a directory lib containing library files like "libopencv_videostab300.dll.a"
The CMakeCache.txt file contains the lines
//Dependencies for the target
DBoW2_LIB_DEPENDS:STATIC=general;opencv_videostab;general;opencv_videoio;general;opencv_video;general;opencv_superres;general;opencv_stitching;general;opencv_shape;general;opencv_photo;general;opencv_objdetect;general;opencv_ml;general;opencv_imgproc;general;opencv_imgcodecs;general;opencv_highgui;general;opencv_hal;general;opencv_flann;general;opencv_features2d;general;opencv_core;general;opencv_calib3d;
From what I've read, the following lines should be sufficient, but I'm getting the linker errors.
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(DBoW2 ${OpenCV_LIBS})
Edit 1:
In response to Chris Maes
added the pkg check
pkg_check_modules (OPENCV REQUIRED opencv)
Now the configure causes an error, which is progress, but I'm still at a loss. I must have an error in the opencv installation / build. I do have a second copy on an external drive, that was built recently (and easily) using something like cmake .. . But setting OpenCV_DIR to the external build produces the same error.
Found PkgConfig: C:/msys64/usr/bin/pkg-config.exe (found version "0.28")
checking for module 'opencv'
package 'opencv' not found
Edit 2:
Here are the settings that CMake automatically generates when I start a new cache and press generate twice (first time it only generates the make, sh).
CMAKE_BUILD_TYPE (BLANK)
CMAKE_GNUtoMS (UNCHECKED)
CMAKE_INSTALL_PREFIX C:/Program Files (x86)/DBoW2
CMAKE_MAKE_PROGRAM C:/msys64/mingw64/bin/mingw32-make.exe
CMAKE_SH C:/msys64/usr/bin/sh.exe
OpenCV_DIR C:/OpenCV/minwg_64
The directory C:/OpenCV/minwg_64 contains the opencv library built from mingw gcc 64, and cmake files including OpenCVConfig.cmake and directories bin and lib. I wonder if I need directory staticlib?
For windows environment, I have
OPENCV_DIR = C:\OpenCV\minwg_64 (where built bin and lib are located)
OPENCV_VER = 300
PATH includes C:\OpenCV\minwg_64\bin
On linux I use pkg_check_modules plugin for cmake:
find_package( OpenCV REQUIRED )
find_package( PkgConfig REQUIRED )
pkg_check_modules (OPENCV REQUIRED opencv)
include_directories(/usr/include/opencv2)
target_link_libraries(DBoW2 ${OPENCV_LDFLAGS})
note: I don't remember why I used hardcoded /usr/include/opencv2, but I guess OPENCV_INCLUDE_DIRS wasn't any good when I tried. There might be a more clean way :)