I've been using the BDD framework Cucumber-cpp for a little while now without much issues, but extending the feature set of a module proved to raise some linker errors.
Setup:
- Linux
- Cucumber-cpp
- makefile
If I start with the following:
# ./test1.feature
Feature: test with a single cpp file
Scenario:
Given I'm a test
When a trig happens
Then light should be ON
and
// ./step_definitions/f1.cpp
#include <boost/test/unit_test.hpp>
#include <cucumber-cpp/defs.hpp>
#include <iostream>
using namespace std;
GIVEN("I'm a test")
{
cerr << "Given..." << endl;
}
WHEN("a trig happens")
{
cerr << "Trig!" << endl;
}
THEN("light should be on")
{
cerr << "light ON..." << endl;
}
When I build this with make, it generates the test binary no problem and execution via cucumber works as expected.
But if I add another feature file (which describes another feature to test)
# ./test2.feature
Feature: another set of feature to impl.
Scenario: extra code
Given I'm another test code
When a trig happens
Then light should be OFF
with the associated test file,
// ./step_definitions/f2.cpp
#include <boost/test/unit_test.hpp>
#include <cucumber-cpp/defs.hpp>
#include <iostream>
using namespace std;
GIVEN("I'm another test")
{
cerr << "Given ANOTHER..." << endl;
}
compiling those 2 files now give the following linker error:
$ make build
mkdir -p ./objs
mkdir -p ./build
compiling step_definitions/f1.cpp
gcc -c -g -O0 -DDEBUG -Wall -Werror -DBOOST_ALL_DYN_LINK -I/usr/local/include -o objs/f1.o -c step_definitions/f1.cpp
compiling step_definitions/f2.cpp
gcc -c -g -O0 -DDEBUG -Wall -Werror -DBOOST_ALL_DYN_LINK -I/usr/local/include -o objs/f2.o -c step_definitions/f2.cpp
building feature-test...
gcc -DBOOST_ALL_DYN_LINK -I/usr/local/include -L/usr/local/lib -o feature-test objs/f1.o objs/f2.o -lcucumber-cpp -lboost_regex -lboost_system -lboost_thread -lboost_unit_test_framework -lboost_date_time
objs/f2.o: In function `toSourceString':
/usr/local/include/cucumber-cpp/internal/step/StepManager.hpp:161: multiple definition of `CukeObject0::cukeRegId'
objs/f1.o:/usr/local/include/cucumber-cpp/internal/step/StepManager.hpp:161: first defined here
objs/f2.o: In function `CukeObject0::body()':
/home/fred/dev/cuketest/step_definitions/f2.cpp:16: multiple definition of `CukeObject0::body()'
objs/f1.o:/home/fred/dev/cuketest/step_definitions/f1.cpp:15: first defined here
collect2: ld returned 1 exit status
make: *** [build] Error 1
Looking at the generated obj files, gives this:
$ nm objs/f2.o | grep "cukeRegId"
0000000000000395 t _GLOBAL__sub_I__ZN11CukeObject09cukeRegIdE
0000000000000000 B _ZN11CukeObject09cukeRegIdE
$ nm objs/f1.o | grep "cukeRegId"
000000000000069e t _GLOBAL__sub_I__ZN11CukeObject09cukeRegIdE
0000000000000000 B _ZN11CukeObject09cukeRegIdE
0000000000000004 B _ZN11CukeObject19cukeRegIdE
0000000000000008 B _ZN11CukeObject29cukeRegIdE
Problem looks like the cukeRegId functions have exactly the same decorated name in the 2 obj files, causing linker error. Now, I'm stuck as to how I can prevent this.
digging up the internet on this, I found a bug entry related to that specific issue. It turned out that in each cpp file, we must declare a unique define value for CUKE_OBJECT_PREFIX in order to avoid object naming clash at linker time.