%.o: Fast/**/%.cpp $(FAST_HEADERS)
g++ $@ -o $<
This never applies due to **
. You also reversed $@
and $<
. You could use
Fast/tests/%.o: Fast/tests/%.cpp | $(FAST_HEADERS)
Fast/src/%.o: Fast/src/%.cpp | $(FAST_HEADERS)
%.o: %.cpp
g++ -o $@ $<
The Real Problem
That said, let's find out what the problem is with the linker messages. To be honest, I spent way more time than I'm comfortable admitting here to "accidentally" find it. First I, obviously per-used the documentation, mainly:
And also several mailing list/SO posts:
Honestly the only tangible thing I learned was that
However, the other documented flags BOOST_TEST_DYN_LINK
and BOOST_TEST_NO_MAIN
had zero effect. After some trial and error and preprocessor #error
debugging I found out that those symbols are all just undef
-ined after inclusion of
#include <boost/test/included/unit_test.hpp>
I didn't immediately recognize the /included/
part. On a whim I thought to change to:
#include <boost/test/unit_test.hpp>
That worked, but now main
was undefined. So, I came up with a the following refactored makefile and an extra Fast/tests/module.cpp
to define the main. No doubt this is all still not completely optimal. E.g. I think, since you're linking the dynamic library, BOOST_TEST_DYN_LINK ought to be defined, but it appears to work fine without that ¯\(ツ)/¯.
So part of the Makefile shown here is for inspiration on how to achieve particular advanced tasks in case you need them.
test: # make default target
FAST_HEADERS := $(wildcard Fast/**/*.h)
FAST_TEST_SOURCES := $(filter-out Fast/src/main.cpp, $(wildcard Fast/src/*.cpp Fast/tests/*.cpp))
FAST_TEST_OBJECTS := ${FAST_TEST_SOURCES:.cpp=.o}
CPPFLAGS+= $(INCLUDES)
CPPFLAGS+= -D BOOST_TEST_DYN_LINK
CXXFLAGS+= -std=c++11 $(CPPFLAGS)
LDFLAGS+= -lboost_unit_test_framework
Fast/tests/test_%.o: CPPFLAGS+=-DBOOST_TEST_NO_MAIN
Fast/tests/%.o: Fast/tests/%.cpp | $(FAST_HEADERS)
Fast/src/%.o: Fast/src/%.cpp | $(FAST_HEADERS)
%.o: %.cpp
g++ $(CXXFLAGS) -o $@ -c $<
fast_test: $(FAST_TEST_OBJECTS)
g++ $(CXXFLAGS) $^ $(LDFLAGS) -o $@
test: fast_test
./$<
.PHONY: test
Testing with make -Bsn
shows how the flags combine:
g++ -std=c++11 -D BOOST_TEST_DYN_LINK -o Fast/src/size.o -c Fast/src/size.cpp
g++ -std=c++11 -D BOOST_TEST_DYN_LINK -o Fast/src/repeats.o -c Fast/src/repeats.cpp
g++ -std=c++11 -D BOOST_TEST_DYN_LINK -DBOOST_TEST_NO_MAIN -o Fast/tests/test_size.o -c Fast/tests/test_size.cpp
g++ -std=c++11 -D BOOST_TEST_DYN_LINK -DBOOST_TEST_NO_MAIN -o Fast/tests/test_repeats.o -c Fast/tests/test_repeats.cpp
g++ -std=c++11 -D BOOST_TEST_DYN_LINK -o Fast/tests/module.o -c Fast/tests/module.cpp
g++ -std=c++11 -D BOOST_TEST_DYN_LINK Fast/src/size.o Fast/src/repeats.o Fast/tests/test_size.o Fast/tests/test_repeats.o Fast/tests/module.o
-lboost_unit_test_framework -o fast_test
./fast_test
The output of e.g. ./fast_test -l all
:
Running 2 test cases...
Entering test module "Fast_Tests"
Fast/tests/test_size.cpp(3): Entering test case "test_size"
Fast/tests/test_size.cpp(8): info: check sz.n == n && sz.m == m has passed
Fast/tests/test_size.cpp(3): Leaving test case "test_size"; testing time: 136us
Fast/tests/test_repeats.cpp(3): Entering test case "test_repeats"
Fast/tests/test_repeats.cpp(7): info: check r.rep == n has passed
Fast/tests/test_repeats.cpp(3): Leaving test case "test_repeats"; testing time: 125us
Leaving test module "Fast_Tests"; testing time: 311us
*** No errors detected
Loose Ends
I kept the "test-driven" implementations for Size
/Repeats
header-only. You need to link the dependent objects if you change that for your real code.
For the GNU Make features I didn't explain, see https://www.gnu.org/software/make/manual/
Code Dump:
File Makefile
test: # make default target
FAST_HEADERS := $(wildcard Fast/**/*.h)
FAST_TEST_SOURCES := $(filter-out Fast/src/main.cpp, $(wildcard Fast/src/*.cpp Fast/tests/*.cpp))
FAST_TEST_OBJECTS := ${FAST_TEST_SOURCES:.cpp=.o}
CPPFLAGS+= $(INCLUDES)
CPPFLAGS+= -D BOOST_TEST_DYN_LINK
CXXFLAGS+= -std=c++11 $(CPPFLAGS)
LDFLAGS+= -lboost_unit_test_framework
Fast/tests/test_%.o: CPPFLAGS+=-DBOOST_TEST_NO_MAIN
Fast/tests/%.o: Fast/tests/%.cpp | $(FAST_HEADERS)
Fast/src/%.o: Fast/src/%.cpp | $(FAST_HEADERS)
%.o: %.cpp
g++ $(CXXFLAGS) -o $@ -c $<
fast_test: $(FAST_TEST_OBJECTS)
g++ $(CXXFLAGS) $^ $(LDFLAGS) -o $@
test: fast_test
./$<
.PHONY: test
File Fast/include/repeats.h
#pragma once
struct Repeats {
explicit Repeats(int n) : rep(n){}
int const rep;
};
File Fast/include/size.h
#pragma once
struct Size {
explicit Size(int n, int m)
: n(n)
, m(m)
{
}
int const n, m;
};
File Fast/include/test_config.h
#include <boost/test/unit_test.hpp>
#include "../include/size.h"
#include "../include/repeats.h"
File Fast/src/main.cpp
File Fast/src/repeats.cpp
File Fast/src/size.cpp
File Fast/tests/module.cpp
#define BOOST_TEST_MODULE Fast_Tests
#include <boost/test/included/unit_test.hpp>
File Fast/tests/test_repeats.cpp
#include "../include/test_config.h"
BOOST_AUTO_TEST_CASE(test_repeats)
{
int n = 30;
Repeats r = Repeats(n);
BOOST_REQUIRE(r.rep == n);
}
File Fast/tests/test_size.cpp
#include "../include/test_config.h"
BOOST_AUTO_TEST_CASE(test_size)
{
int n = 20;
int m = 30;
Size sz = Size(n, m);
BOOST_REQUIRE(sz.n == n && sz.m == m);
}