I’ve been trying to get used to c++ with cmake and gtest (google test).
I’m trying to understand why this setup yields the error
Undefined symbols for architecture x86_64:
"Project1::foo(int&)", referenced from:
Project1Test_MethodBarDoesAbc_Test::TestBody() in test_project1.cpp.o
ld: symbol(s) not found for architecture x86_64
when I run “make”.
When I implement methods in the .h file, things work fine; but when I only declare methods in the .h file and then implement it in the associated .cpp file, this error occurs.
My test file: test_project1.cpp
#include <iostream>
#include "gtest/gtest.h"
#include "project1.h"
// tests outside of the class
TEST(IndependentMethod, ResetsToZero2) {
int i = 0;
independentMethod(i);
EXPECT_EQ(0, i);
}
//...
// The fixture for testing the class
class Project1Test : public ::testing::Test {
protected:
// You can remove any or all of the following functions if its body
// is empty.
Project1Test() {
// nothing here
}
};
// Test case must be called the class above
TEST_F(Project1Test, MethodBarDoesAbc) {
Project1 p;
int i = 0;
p.foo(i); // WHY CAN'T Project1::foo(int&) be detected here?!
EXPECT_EQ(1, i);
}
Class definition: project1.h
#ifndef PROJECT1_H_
#define PROJECT1_H_
#include <iostream> // IO access
using namespace std;
class Project1 {
public:
// why only detected if implemented here?
// void foo(int &i) {
// i = 1;
// }
void foo(int &i);
};
void independentMethod(int &i) {
// From experience, should be implemented in the .h, not the .cpp.
// Otherwise, test can't find independentMethod, but WHY?
i = 0;
}
#endif /* PROJECT1_H_ */
Implementation of Project1 class: project1.cpp
#include <iostream>
#include "project1.h"
void Project1::foo(int &i) {
i = 1;
}
int main() {
// this works fine if I directly compile project1.cpp and run ./a.out
cout << "do stuff" << endl;
int x = 4;
cout << x << endl;
independentMethod(x);
cout << x << endl;
Project1 p;
p.foo(x);
cout << x << endl;
}
The procedure I go through to test is typical:
mkdir build
cd build
cmake ..
make
I don’t know if this is relevant, but here is my CMakeLists.txt file in the root of my project:
cmake_minimum_required(VERSION 2.8)
# Make PROJECT_SOURCE_DIR, PROJECT_BINARY_DIR, and PROJECT_NAME available
set(PROJECT_NAME MyProject)
project(${PROJECT_NAME})
set(CMAKE_CXX_FLAGS "-g -Wall")
#set(COMMON_INCLUDES ${PROJECT_SOURCE_DIR}/include) if you want your own include/ directory
# then you can do include_directories(${COMMON_INCLUDES}) in other cmakelists.txt files
################################
# Normal files
################################
add_executable(project1 project1.cpp)
################################
# GTest
################################
# This adds another subdirectory, which has project(gtest)
add_subdirectory(lib/gtest-1.6.0)
enable_testing()
# Include the gtest library
# gtest_SOURCE_DIR is available due to project(gtest) above
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
################################
# Unit Tests
################################
add_executable(runUnitTests test_project1.cpp)
target_link_libraries(runUnitTests gtest gtest_main)
add_test(NAME runUnitTests COMMAND runUnitTests)
I feel like the issue is due to some misunderstanding I have about implementing .cpp vs in .h. I know that templated functions must be implemented in .h, but I’m not templating anything. I just want to test.
Help appreciated.
You need to link to your runUnitTests executable with your own code in project1.cpp.
I’d favour making a library out out the guts of project1.cpp and move the main function into a separate file (e.g. main.cpp). Then you can do