CMAKE LINKING ERROR with a user-defined shared library - c++

I am a newcomer to the world of cmake. This question came up while I was experimenting with some basic cmake configurations in C++. To be precise, following is my directory structure :
/src----
|-> CMakeLists.txt
|-> main.cpp
|-> lib----
|-> libfsystem.so
|->filesystem----
|->CMakeLists.txt
|->listfiles.cpp
|->include-----
|->fsystem.h
Now, the /src/filesystem/CMakeLists.txt file is like this
cmake_minimum_required(VERSION 2.8)
project(fsystem)
set(CMAKE_BUILD_TYPE Release)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/build)
find_package(Boost REQUIRED system filesystem)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../lib)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(fsystem SHARED listfiles.cpp)
While, the /src/CMakeLists.txt file is like this
cmake_minimum_required(VERSION 2.8)
project(vessel_detect)
add_subdirectory(filesystem)
add_executable(main main.cpp)
set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
find_library(libpath fsystem)
MESSAGE(${libpath})
target_link_libraries(main ${libpath})
The library libfsystem.so is successfully created.
The library libfsystem.so is also successfully found by /src/CMakeLists.txt
However when the linking of main.cpp is done, then it gives me several undefined reference errors which should not have happened as everything has already been defined. For greater completeness, following is the content of main.cpp file
Main.cpp
#include<iostream>
#include"filesystem/include/fsystem.h"
using namespace std;
int main(void)
{
string path ("~");
vector<string>* output;
output = listfiles(path);
return 0;
}
The contents of listfiles.cpp are
listfiles.cpp
#include"fsystem.h"
using namespace boost::filesystem;
vector<string>* listfiles(int argc, char* argv[])
{
if (argc<2)
{
std::cout<<"No file name provided"<<std::endl;
}
else
{
path p(argv[1]);
vector<string>* output;
if (exists(p))
{
if(is_directory(p))
{
std::cout<<"You specified a directory"<<std::endl;
std::cout<<"Its contents are as follows :-"<<std::endl;
typedef std::vector<path> vec;
vec v;
copy(directory_iterator(p),directory_iterator(),back_inserter(v));
sort(v.begin(),v.end());
for(vec::const_iterator it(v.begin());it!=v.end();++it)
output->push_back(it->filename().string());
// std::cout<<it->filename()<<std::endl;
}
else if (is_regular_file(p))
{
std::cout<<argv[1]<<" "<<file_size(p)<<std::endl;
}
else
{
std::cout<<"The file is neither a directory nor a regular file"<<std::endl;
}
}
else
{
std::cout<<"The speicified path does not exist"<<std::endl;
}
}
}
And finally, the fsystem.h contents are :
fsystem.h
#ifndef _fsystem_h
#define _fsystem_h
#include<iostream>
#include<string>
#include<vector>
#include"boost/filesystem.hpp"
using namespace std;
vector<string>* listfiles(string);
#endif
Could someone provide me a reason for the undefined reference errors I am getting during the linking of main.cpp ? I would also be grateful if you could provide me with a resolution of this issue.
Thanks

Your not linking boost. you need to add target_link_libraries(fsystem ${Boost_LIBRARIES}) to the end of /src/filesystem/CMakeLists.txt and include_directories(${Boost_INCLUDE_DIRS}) between the find_package and add_library.
cmake_minimum_required(VERSION 2.8)
project(fsystem)
set(CMAKE_BUILD_TYPE Release)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/build)
find_package(Boost REQUIRED system filesystem)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../lib)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories(${Boost_INCLUDE_DIRS})
add_library(fsystem SHARED listfiles.cpp)
target_link_libraries(fsystem ${Boost_LIBRARIES})

(1) For TARGET_LINK_LIBRARIES you should put the name of the target, thus:
TARGET_LINK_LIBRARIES(main fsystem)
(2) You declare listfiles as vector<string>* listfiles(string) while you define it as vector<string>* listfiles(int,char**)
Additionally you need to link with Boost per the other reply.

Related

shared library error about "undefined symbol" when using `dlopen`

First thing first, here's my minimum reproducible program:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.17)
project(untitled4)
set(CMAKE_CXX_STANDARD 17)
add_library(lib1 SHARED lib1.cpp)
add_executable(untitled4 main.cpp)
target_link_libraries(untitled4 PRIVATE dl)
main.cpp:
#include "iostream"
#include <dlfcn.h>
int Test() {
return 123456;
}
int main() {
auto* handler = dlopen("/home/liu/source/untitled4/cmake-build-debug/liblib1.so", RTLD_LAZY|RTLD_GLOBAL);
if (!handler) {
std::cerr << dlerror();
exit(1);
}
}
and lib1.cpp:
#include "iostream"
extern int Test();
class Foo {
public:
Foo() {
std::cout << Test() << std::endl;
}
};
Foo foo;
now let me explain:
As you can see I defined a function called Test in main.cpp, and I want to the shared library liblib1.so call it when it is loaded.
But when I run the main() function, there's an error log said:
/home/liu/source/untitled4/cmake-build-debug/liblib1.so: undefined symbol: _Z4Testv
I check the symbol by using nm untitled4 |grep Test and the symbol seems exist:
0000000000000b87 t _GLOBAL__sub_I__Z4Testv
0000000000000aea T _Z4Testv
So what did I do wrong? How to fix this?
An important thing to be notice is that in the real case, the build of lib1 and the build of main.cpp are totally separated, the two build don't know each other. But I can make them into one build (very difficult) if this can fix the problem(if there's no other way).
P.S. I tried using extern "C" to wrap around the Test() in both files, but not working, seems not the C/C++ function naming problem.
With the addition of the linker option -rdynamic your code does not fail with "undefined symbol".
You can set that with set_target_properties(untitled4 PROPERTIES ENABLE_EXPORTS 1) or target_link_options(untitled4 BEFORE PRIVATE "-rdynamic").
Example:
cmake_minimum_required(VERSION 3.17)
project(untitled4)
set(CMAKE_CXX_STANDARD 17)
add_library(lib1 SHARED lib1.cpp)
add_executable(untitled4 main.cpp)
set_target_properties(untitled4 PROPERTIES ENABLE_EXPORTS 1)
target_link_libraries(untitled4 PRIVATE dl)

Getting "undefined reference to"

I tried several things to resolve this issue, but I just can't get my head around CMake apparently...
The following is basically the entire project:
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── main.cpp
├── SubwordEncoder.cpp
└── SubwordEncoder.h
The first (./CMakeLists.txt) contains:
cmake_minimum_required(VERSION 3.5)
project(xlib)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(./src)
add_executable(main src/main.cpp)
and the second (src/MakeLists.txt)
file(GLOB_RECURSE xlib_SOURCES "*.cpp")
file(GLOB_RECURSE xlib_SURCES "*.h")
main.cpp only contains this:
#include <string>
#include <iostream>
#include <stdio.h>
#include "SubwordEncoder.h"
int main() {
std::cout << "Hello World!" << std::endl;
auto encoder = new SubwordEncoder();
auto encoded = encoder->encode("Hello World!");
for (auto i : encoded) {
std::cout << i << std::endl;
}
return 0;
}
SubwordEncoder.h
#ifndef XLIB_SUBWORDENCODER_H
#define XLIB_SUBWORDENCODER_H
#include <string>
#include <vector>
class SubwordEncoder {
public:
std::vector<int> encode(std::string decoded);
};
#endif //XLIB_SUBWORDENCODER_H
and SubwordEncoder.cpp
#include "SubwordEncoder.h"
std::vector<int> SubwordEncoder::encode(std::string decoded) {
std::vector<int> vect;
vect.push_back(10);
vect.push_back(20);
vect.push_back(30);
return vect;
}
Yet I keep getting this error:
/tmp/tmp.KYl9HEcObN/src/main.cpp:13: undefined reference to `SubwordEncoder::encode(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
What am I doing wrong?
Note:
I know I could do this:
add_executable(main src/main.cpp src/SubwordEncoder.cpp src/SubwordEncoder.h)
but I don't want to add every single file here. I want all files in src/ to be used for the compilation.
When you call add_executable(), you are only including main.cpp and not the others, so SubwordEncoder::encode is undefined when you try to use it in main(). Try changing your CMake files to something like this:
./CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(xlib)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(src)
./src/CMakeLists.txt
file(GLOB_RECURSE xlib_SOURCES "*.cpp")
file(GLOB_RECURSE xlib_HEADERS "*.h")
add_executable(main ${xlib_SOURCES} ${xlib_HEADERS})
# Include the current folder for including headers.
target_include_directories(main PRIVATE ${CMAKE_CURRENT_LIST_DIR})
The only line in either of your CMake files that actually causes files to be compiled is add_executable(main src/main.cpp) and the only file it adds is main.cpp. There is nothing in either CMake file that actually tells it to compile the other source files.
These lines
file(GLOB_RECURSE xlib_SOURCES "*.cpp")
file(GLOB_RECURSE xlib_HEADERS "*.h")
only set up variables containing lists of file names. There is nothing that then includes those files in any compilation. Your options are either add those files to your compilation of the main target as in squareskittles answer, or compile them as a separate library and then link it into main:
src/CMakeLists.txt:
add_library(SubwordEncoder ${xlib_SOURCES})
./CMakeLists.txt:
target_link_libraries(main SubwordEncoder)

C++ modularized project linking issues and undefined reference error

I am having trouble figuring out how to build out a modularized c++ app and getting everything to link up properly. Specifically, I can't get some tests to build because ultimately I get an undefined reference error based on a class method. (I am new to c++ and CMake so I'm probably doing a lot wrong, but I'm learning!) I have gone through other posts and all I can glean is that I'm potentially not linking properly.
Both OrderBook and Strategy build just fine. However, when I go to build StrategyTests and OrderBookTests I get an error:
[ 83%] Linking CXX executable StrategyTests.exe
../../OrderBook/libOrderBook.a(OrderBook.cpp.o): In function `orderbook::OrderBook::notify_strategies(std::shared_ptr<orderbook::Order> const&, bool)':
/cygdrive/d/Dropbox/My Documents/Programming/CLionProjects/TradingSystem/OrderBook/OrderBook.cpp:220: undefined reference to `HYSTRAT::Strategy::onBookUpdate(std::shared_ptr<Events::TOB> const&, std::shared_ptr<Events::OrderBookEvent> const&, bool)'
/cygdrive/d/Dropbox/My Documents/Programming/CLionProjects/TradingSystem/OrderBook/OrderBook.cpp:220:(.text+0x11c4): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `HYSTRAT::Strategy::onBookUpdate(std::shared_ptr<Events::TOB> const&, std::shared_ptr<Events::OrderBookEvent> const&, bool)'
collect2: error: ld returned 1 exit status
I've tried a number of different things including fiddling with CMakeLists and headers, but none seem to work. It's pretty clear I don't know the true meaning of "undefined reference". I suspect this is an easy fix, but I posted the project setup below in case it's not.
Here's my setup:
Clion and Cygwin on Windows 10
Project Tree
TradingSystem
|-CMakeLists.txt
|\OrderBook
|-|-CMakeLists.txt
|-|-OrderBook.h
|-|-OrderBook.cpp
|\Strategy
|-|-CMakeLists.txt
|-|-Strategy.h
|-|-Strategy.cpp
|\Tests
|-|-CMakeLists.txt
|-|\OrderBookTests
|-|-|-CMakeLists.txt
|-|-|\BoostTests
|-|-|-|-CMakeLists.txt
|-|-|-|-OrderBookBoostTests.cpp
|-|\StrategyTests
|-|-|-CMakeLists.txt
|-|-|-StrategyBoostTests.cpp
CMakes
#TradingSystem/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(TradingSystem)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
add_executable(TradingSystem ${SOURCE_FILES} ${HEADER_FILES})
include_directories(OrderBook Strategy Events)
add_subdirectory(OrderBook)
add_subdirectory(Strategy)
add_subdirectory(Events)
add_subdirectory(Tests/OrderBookTests)
add_subdirectory(Tests/StrategyTests)
target_link_libraries(TradingSystem OrderBook Strategy)
-
#TradingSystem/OrderBook/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(OrderBook)
include_directories(/cygdrive/c/Program Files/boost/boost_1_66_0)
set(CMAKE_CXX_STANDARD 11)
set(HEADER_FILES OrderBook.h)
set(SOURCE_FILES OrderBook.cpp)
add_library(OrderBook STATIC ${SOURCE_FILES} ${HEADER_FILES})
-
#TradingSystem/Strategy/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(Strategy)
include_directories(/cygdrive/c/Program Files/boost/boost_1_66_0)
set(CMAKE_CXX_STANDARD 11)
set(HEADER_FILES Strategy.h)
set(SOURCE_FILES Strategy.cpp)
add_library(Strategy STATIC ${SOURCE_FILES} ${HEADER_FILES})
-
#TradingSystem/Tests/CMakeLists.txt
project(Tests)
add_subdirectory(OrderBookTests)
add_subdirectory(StrategyTests)
-
#TradingSystem/Tests/OrderBookTests/CMakeLists.txt
project(OrderBookTests)
add_subdirectory(BoostTests)
[EDIT]
#TradingSystem/Tests/OrderBookTests/BoostTests/CMakeLists.txt
add_executable(BoostTests OrderBookBoostTests.cpp)
enable_testing()
include_directories(/cygdrive/c/Program Files/boost_1_66_0)
set(BOOST_ROOT "C:/Program Files/boost_1_66_0/")
set(BOOST_LIBRARYDIR "C:/Program Files/boost_1_66_0/")
find_package(Boost 1.66.0)
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
include_directories(${BOOSTROOT})
link_directories("${BOOSTROOT}")
target_include_directories(OrderBook PRIVATE ${BOOST_INCLUDE_DIRS})
# Original:
# target_link_libraries(BoostTests OrderBook)
# Changed to:
target_link_libraries(BoostTests Orderbook Strategy)
if(NOT Boost_FOUND)
message(FATAL_ERROR "Could not find boost!")
endif()
[EDIT]
#TradingSystem/Tests/StrategyTests/CMakeLists.txt
project(StrategyTests)
add_executable(StrategyTests StrategyBoostTests.cpp)
enable_testing()
include_directories(/cygdrive/c/Program Files/boost_1_66_0)
set(BOOST_ROOT "C:/Program Files/boost_1_66_0/")
set(BOOST_LIBRARYDIR "C:/Program Files/boost_1_66_0/")
find_package(Boost 1.66.0)
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
include_directories(${BOOSTROOT})
link_directories("${BOOSTROOT}")
target_include_directories(Strategy PRIVATE ${BOOST_INCLUDE_DIRS})
# Original:
# target_link_libraries(StrategyTests Strategy OrderBook)
# Change to:
target_link_libraries(StrategyTests Orderbook Strategy)
if(NOT Boost_FOUND)
message(FATAL_ERROR "Could not find boost!")
endif()
The Src Files
#TradingSystem/OrderBook/OrderBook.h
#fndef TRADINGSYSTEM_ORDERBOOK_H
#define TRADINGSYSTEM_ORDERBOOK_H
#include <vector>
using std::vector;
#include "Strategy.h"
#include "Events.h"
namespace orderbook {
/////////////////////
// HIDDEN CODE
/////////////////////
class OrderBook {
private:
vector<HYSTRAT::Strategy> strategies_;
bool notify_strategies(const order_ptr& o, bool add_flag);;
Events::order_book_event_ptr create_order_book_event(const order_ptr& order);;
public:
/////////////////////////////
// CONSTRUTORS; DESTRUCTORS
/////////////////////////////
inline bool subscribe(HYSTRAT::Strategy& s) {
strategies_.push_back(s);
}
#endif //TRADINGSYSTEM_ORDERBOOK_H
-
#TradingSystem/OrderBook/OrderBook.cpp
#include "OrderBook.h"
#include "Events.h"
#include "Strategy.h"
using orderbook::OrderBook;
using HYSTRAT::Strategy;
bool orderbook::OrderBook::notify_strategies(const order_ptr& o, bool add_flag) {
try {
Events::order_book_event_ptr event = create_order_book_event(o);
Events::topOfBook_ptr tob = get_top_of_book();
for (HYSTRAT::Strategy& strategy : strategies_) {
strategy.onBookUpdate(tob, event, add_flag);
}
return true;
} catch (const std::exception& e) {
return false;
}
}
-
#TradingSystem/Strategy/Strategy.h
#ifndef TRADINGSYSTEM_STRATEGY_H
#define TRADINGSYSTEM_STRATEGY_H
#include "Events.h"
namespace HYSTRAT {
class Strategy {
public:
void onBookUpdate(const Events::topOfBook_ptr& tob, const Events::order_book_event_ptr& e, bool event_flag);;
};
}
#endif //TRADINGSYSTEM_STRATEGY_H
-
#TradingSystem/Strategy/Strategy.cpp
#include "OrderBook.h"
#include "Strategy.h"
#include "Events.h"
using namespace HYSTRAT;
void Strategy::onBookUpdate(const Events::topOfBook_ptr &tob, const Events::order_book_event_ptr &e, bool event_flag) {
if (tob->bidP >= tob->offerP) {
quantity_t order_size = std::min(tob->offerQ, tob->bidQ);
order_ptr buy_order(new Order(tob->offerP, order_size, BUY));
order_ptr sell_order(new Order(tob->bidP, order_size, SELL));
send_order(buy_order);
send_order(sell_order);
}
}
I think you are missing a few calls to "add_dependencies" in your CMakeLists.txt files. I think this particular problem might be solved by adding
add_dependencies(OrderBook Strategy)
to your Orderbooks CMakelists.txt

Error while linking libconfig with c++ using cmake?

Here is the cmake file that i am using
cmake_minimum_required (VERSION 3.0)
project (midasd)
set (midas VERSION_MAJOR 0)
set (midas VERSION_MINOR 0)
set (midas VERSION_REVISION 1)
find_library(libconfig libconfig)
add_executable(midasd src/main.cpp)
target_link_libraries(midasd "${libconfig_LIBS}")
The problem i am facing is undefined reference for config_init. The main function is as follows
#include <libconfig.h>
int main(int argc, char *argv[])
{
midas::midasCtx *container = new midas::midasCtx(argc,argv);
config_t cfg;
config_init(&cfg);
return 0;
}
Where am i going wrong with CMAKE ?
Actually the libconfig is recognized as simply -lconfig not -llibconfigin linking argument. The CMakeLists.txt should contain
target_link_libraries(my_project config)
Source
This manual(https://hyperrealm.github.io/libconfig/libconfig_manual.html) says " To link with the library, specify ‘-lconfig++’ as an argument to the linker. "
So I fixed like following code and build was completed.
target_link_libraries(my_project config++)

Creating cmake install macro for a library

This my project structure:
main
|
--src
|
--feed.h
--feed.cc
--other files
--CMakeLists2.txt
--test
|
--test.cpp
--CMakeLists3.txt
CMakeLists1.txt
CMakeLists1.txt
cmake_minimum_required (VERSION 2.8.11)
project (Feedparser)
set(CMAKE_MODULE_PATH cmake)
find_package(PTHREAD REQUIRED)
find_package(CURL REQUIRED)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++14" 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++14 ")
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()
add_subdirectory (src)
add_subdirectory (test)
CMakeLists2.txt
cmake_minimum_required (VERSION 2.8.11)
add_library (Feedparser news.h xml2json.hpp jsonxx.cc curler.cc feed.cc )
target_link_libraries(Feedparser pthread)
target_link_libraries(Feedparser curl)
install(TARGETS Feedparser
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION /usr/lib)
install(FILES "feed.h" DESTINATION /usr/include )
target_include_directories (Feedparser PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
CMakeLists3.txt
cmake_minimum_required (VERSION 2.8.11)
add_executable(Feedtest test.cc)
target_link_libraries (Feedtest LINK_PUBLIC Feedparser)
Here is my Header file.
feed.h
#include "news.h"
#include "curler.cc"
#include "jsonxx.h"
#include "jsonxx.cc"
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <thread>
#include <stdio.h>
using namespace std;
using namespace jsonxx;
class feed{
map <string,string> info;
std::map<int, Object> items;
string url;
news News;
Object *item;
void strip_items();
public:
Object json;
feed(string url);
void create(string url){
this->url = url;
}
feed(){}
string get_topic(){
return info["title"];
}
bool fetch();
bool fetch_data();
bool parse();
string get_url(){
return url;
}
string get_item_title(int index){
return News.title[index];
}
string get_item_img(int index){
return News.image[index];
}
string get_item_link(int index){
return News.link[index];
}
int get_total(){
return News.num_item;
}
struct news get_news(){
return News;
}
};
Should I include feed.h in feed.cc and compile and how does the compiler directly link .h files with the .cxx files in archives?
How do i write a cmake script for installing this library?
Where is my mistake?
C++'s building process consists of 2 stages:
Compilation: The compiler runs on every source (.cc) file, generating an intermidiate binary.
Linking: The linker runs on every intermidiate binary, matching declarations with definitions.
Finally, it combines all of them to make the final binary.
With this in mind, you need to make sure the compiler doesn't come across something that it doesn't know about. That's why you include headers (.h).
The linker should be fed with everything the compiler creates.