EDIT: I'm not the only one having this issue, maybe it's VS https://github.com/google/googletest/issues/2628
I'm having trouble getting GMock setup correctly. I'm using Windows and CMake, and adding GMock to my existing project.
The code that I'm trying to run is:
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using ::testing::AnyNumber;
namespace ifac
{
class Foo
{
public:
virtual ~Foo() = default;
virtual void Bar(int i) = 0;
};
class FooMock : public Foo
{
public:
MOCK_METHOD1(Bar, void(int));
};
TEST(FooTest, BarCalled)
{
FooMock m;
EXPECT_CALL(m, Bar(1)).Times(AnyNumber());
m.Bar(1);
}
}
When it runs I get an error saying:
Exception thrown: read access violation. this was 0xFFFFFFFFFFFFFFFB.
The error is in the void Mutex::ThreadSafeLazyInit() of gtest-port.cc.
This seems to only happen if I set CMAKE_CXX_STANDARD to 17 too. I'm not really sure where to start with this, since I don't know a lot about C++, CMake or gtest/gmock.
Here's a stripped down version of the CMakeLists.txt files I have.
cmake_minimum_required (VERSION 3.8)
project ("TestingDemo")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
enable_testing()
add_subdirectory("googletest")
add_executable(Tests
"Main.cpp"
"Tests.cpp")
target_link_libraries(Tests PUBLIC gtest gtest_main gmock gmock_main)
add_test(RunTests Tests)
Related
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)
I'm trying to integrate a normal compilation and a unit-test with gtest into one cmake file, but I don't know how to achieve this. Here is my project:
|---include
| |---Student.h
|
|---src
| |---Student.cpp
| |---main.cpp
|
|---unittest
| |---TestStudent.cpp
|
|---CMakeLists.txt # how to write this file?
So, Student.h, Student.cpp and main.cpp is the source code, TestStudent.cpp is the test code, which includes gtest/gtest.h and a main function, here it is:
#include "gtest/gtest.h"
#include "Student.h"
class TestStudent : public ::testing::Test
{
protected:
Student *ps;
void SetUp() override
{
ps = new Student(2, "toto");
}
void TearDown() override
{
delete ps;
}
};
TEST_F(TestStudent, ID)
{
EXPECT_TRUE(ps->GetID() == 2);
EXPECT_TRUE(ps->GetName() == "toto");
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Now, if I want to compile the source code, I need to run g++ -std=c++11 Student.cpp main.cpp -o a.out, whereas if I want to compile the test code, I need to run g++ -std=c++11 TestStudent.cpp Student.cpp -lgtest -lpthread -o test.out.
So, how could I write the CMakeLists.txt to allow me to compile the different targets, such as cmake NORMAL and cmake TEST?
As already pointed out in the comments use multiple targets via add_executable. The following CMakeLists.txt will produce two targets generating the executables student and student-test.
The last three lines can be omitted if you don't care about CTest.
cmake_minimum_required(VERSION 3.9)
project(Student CXX)
set(CMAKE_CXX_STANDARD 11)
set(SOURCES src/Student.cpp)
set(INCLUDES include)
find_package(GTest REQUIRED)
add_executable(student src/main.cpp ${SOURCES})
target_include_directories(student PRIVATE ${INCLUDES})
add_executable(student-test unittest/TestStudent.cpp ${SOURCES})
target_include_directories(student-test PRIVATE ${INCLUDES})
target_link_libraries(student-test GTest::GTest GTest::Main)
enable_testing()
include(GoogleTest)
gtest_add_tests(TARGET student-test AUTO)
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
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.
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.