0

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);
    }
}
gatherer
  • 43
  • 9
  • `It's pretty clear I don't know the true meaning of "undefined reference".` - If so, why do not read the question specifically about this error message: https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix? You lack of `target_link_libraries` which would link your test executable with a library which implements "undefined" function. – Tsyvarev Jul 08 '18 at 08:17
  • Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Tsyvarev Jul 08 '18 at 08:17
  • I read both of those. Tried different methods to fix the problem. Nothing worked either because it wasn't the right solution or I wasn't implementing properly. – gatherer Jul 08 '18 at 15:26
  • 1
    Your `OrderBook` library uses functions from `Strategy` one (the undefined function is one of them). So you should either link `OrderBook` with `Strategy` (`target_link_libraries`) or link `StrategyTests` executable with both of them in the **correct order**: `OrderBook` before `Strategy`. See [that answer](https://stackoverflow.com/a/24675715/3440745) to the referenced question about linking order. – Tsyvarev Jul 08 '18 at 16:43
  • Thank you for the comment and for directing me to the section. The problem is solved by linking in the correct order – gatherer Jul 09 '18 at 16:04

1 Answers1

0

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

Hack Saw
  • 2,741
  • 1
  • 18
  • 33
  • `add_dependencies` never helps against "undefined reference" error. Also, you use the command incorrectly: it accepts two arguments - **both sides** or a dependency relation - not a single one. – Tsyvarev Jul 08 '18 at 08:21
  • Oops, late night writing. – Hack Saw Jul 08 '18 at 16:24