We encounter some new problems with a code that includes the latest version of Catch during build. One of the recent code changes triggers spurious linker errors. Interesting enough some executables are built, other not, but their code differs only slightly.
A bisection shows that the error does not occur up to revision
commit f5910f38ef38ac2cca9f3830804abf6d9a8d40bf
Author: Martin Ho艡e艌ovsk媒 <[email protected]>
Date: Wed Jan 10 13:44:08 2018 +0100
Copy reporters to single_include during releases
but is introduced via changes in
commit cd76f5730c9a3afa19f3b9c83608d9c7ab325a19
Author: Martin Ho艡e艌ovsk媒 <[email protected]>
Date: Wed Jan 10 13:53:04 2018 +0100
v2.1.0
for 2 versions of gcc and clang-6.0. This gives me some headache, because I do not see what could have triggered it.
Unfortunately no small example can be provided yet. The error messages are:
cd /home/markus/PROJECT/lib-lshape-detection/build/test-catch && /usr/bin/cmake -E cmake_link_script CMakeFiles/generate_report.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/generate_report.dir/generate_report.cpp.o CMakeFiles/generate_report.dir/test_main.cpp.o -o generate_report -rdynamic ../liblshape-detection.a -lboost_system -lboost_filesystem -ldl
CMakeFiles/generate_report.dir/generate_report.cpp.o: In function `____C_A_T_C_H____T_E_S_T____0()':
generate_report.cpp:(.text+0x3780): undefined reference to `Catch::AssertionHandler::handleExpr(Catch::ITransientExpression const&)'
generate_report.cpp:(.text+0x379e): undefined reference to `Catch::AssertionHandler::complete()'
generate_report.cpp:(.text+0x39d6): undefined reference to `Catch::AssertionHandler::handleUnexpectedInflightException()'
CMakeFiles/generate_report.dir/generate_report.cpp.o: In function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > Catch::Detail::stringify<int>(int const&)':
generate_report.cpp:(.text._ZN5Catch6Detail9stringifyIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_[_ZN5Catch6Detail9stringifyIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_]+0x2f): undefined reference to `Catch::StringMaker<int, void>::convert[abi:cxx11](int)'
collect2: error: ld returned 1 exit status
test-catch/CMakeFiles/generate_report.dir/build.make:124: recipe for target 'test-catch/generate_report' failed
make[3]: *** [test-catch/generate_report] Error 1
make[3]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
CMakeFiles/Makefile2:1216: recipe for target 'test-catch/CMakeFiles/generate_report.dir/all' failed
make[2]: *** [test-catch/CMakeFiles/generate_report.dir/all] Error 2
make[2]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
CMakeFiles/Makefile2:1228: recipe for target 'test-catch/CMakeFiles/generate_report.dir/rule' failed
make[1]: *** [test-catch/CMakeFiles/generate_report.dir/rule] Error 2
make[1]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
Makefile:605: recipe for target 'generate_report' failed
make: *** [generate_report] Error 2
and with g++-7
/usr/bin/g++-7 CMakeFiles/generate_report.dir/generate_report.cpp.o CMakeFiles/generate_report.dir/test_main.cpp.o -o generate_report -rdynamic ../liblshape-detection.a -lboost_system -lboost_filesystem -ldl
CMakeFiles/generate_report.dir/generate_report.cpp.o: In function `____C_A_T_C_H____T_E_S_T____0()':
generate_report.cpp:(.text+0x3461): undefined reference to `Catch::AssertionHandler::handleExpr(Catch::ITransientExpression const&)'
generate_report.cpp:(.text+0x347f): undefined reference to `Catch::AssertionHandler::complete()'
generate_report.cpp:(.text+0x36b7): undefined reference to `Catch::AssertionHandler::handleUnexpectedInflightException()'
CMakeFiles/generate_report.dir/generate_report.cpp.o: In function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > Catch::Detail::stringify<int>(int const&)':
generate_report.cpp:(.text._ZN5Catch6Detail9stringifyIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_[_ZN5Catch6Detail9stringifyIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_]+0x2f): undefined reference to `Catch::StringMaker<int, void>::convert[abi:cxx11](int)'
collect2: error: ld returned 1 exit status
test-catch/CMakeFiles/generate_report.dir/build.make:124: recipe for target 'test-catch/generate_report' failed
make[3]: *** [test-catch/generate_report] Error 1
make[3]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
CMakeFiles/Makefile2:1216: recipe for target 'test-catch/CMakeFiles/generate_report.dir/all' failed
make[2]: *** [test-catch/CMakeFiles/generate_report.dir/all] Error 2
make[2]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
CMakeFiles/Makefile2:1228: recipe for target 'test-catch/CMakeFiles/generate_report.dir/rule' failed
make[1]: *** [test-catch/CMakeFiles/generate_report.dir/rule] Error 2
make[1]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
Makefile:605: recipe for target 'generate_report' failed
make: *** [generate_report] Error 2
and with clang++--6.0
/usr/bin/clang++-6.0 CMakeFiles/generate_report.dir/generate_report.cpp.o CMakeFiles/generate_report.dir/test_main.cpp.o -o generate_report -rdynamic ../liblshape-detection.a -lboost_system -lboost_filesystem -ldl
CMakeFiles/generate_report.dir/generate_report.cpp.o: In function `____C_A_T_C_H____T_E_S_T____0()':
generate_report.cpp:(.text+0x1a3f): undefined reference to `Catch::AssertionHandler::handleExpr(Catch::ITransientExpression const&)'
generate_report.cpp:(.text+0x1acf): undefined reference to `Catch::AssertionHandler::handleUnexpectedInflightException()'
generate_report.cpp:(.text+0x1aef): undefined reference to `Catch::AssertionHandler::complete()'
CMakeFiles/generate_report.dir/generate_report.cpp.o: In function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > Catch::Detail::stringify<int>(int const&)':
generate_report.cpp:(.text._ZN5Catch6Detail9stringifyIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_[_ZN5Catch6Detail9stringifyIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_]+0x1a): undefined reference to `Catch::StringMaker<int, void>::convert[abi:cxx11](int)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
test-catch/CMakeFiles/generate_report.dir/build.make:124: recipe for target 'test-catch/generate_report' failed
make[3]: *** [test-catch/generate_report] Error 1
make[3]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
CMakeFiles/Makefile2:1216: recipe for target 'test-catch/CMakeFiles/generate_report.dir/all' failed
make[2]: *** [test-catch/CMakeFiles/generate_report.dir/all] Error 2
make[2]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
CMakeFiles/Makefile2:1228: recipe for target 'test-catch/CMakeFiles/generate_report.dir/rule' failed
make[1]: *** [test-catch/CMakeFiles/generate_report.dir/rule] Error 2
make[1]: Leaving directory '/home/markus/PROJECT/lib-lshape-detection/build'
Makefile:605: recipe for target 'generate_report' failed
make: *** [generate_report] Error 2
I am happy to announce that I found a code snippet that triggers the linker error:
#include <catch.hpp>
TEST_CASE("Spurious behavior", "[report]")
{
REQUIRE(1 == 1);
}
Just making sure: The short provided code fails to link when using g++5.4, single header version of Catch and when CATCH_CONFIG_MAIN is defined?
I'm brand-new to Catch, so this might be newbie failure / something different, but I am also getting linker errors. When I try to build the Catch2 factorial example...
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
unsigned int Factorial( unsigned int number ) {
return number <= 1 ? number : Factorial(number-1)*number;
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}
This is what I get:
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/c++/4.2.1
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$ g++ -std=c++14 test/main.cpp -I./Catch2/include
Undefined symbols for architecture x86_64:
"Catch::NameAndTags::NameAndTags(Catch::StringRef, Catch::StringRef)", referenced from:
___cxx_global_var_init.1 in main-bf9b39.o
"Catch::StringMaker<int, void>::convert(int)", referenced from:
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Catch::Detail::stringify<int>(int const&) in main-bf9b39.o
"Catch::StringMaker<unsigned int, void>::convert(unsigned int)", referenced from:
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > Catch::Detail::stringify<unsigned int>(unsigned int const&) in main-bf9b39.o
"Catch::LeakDetector::LeakDetector()", referenced from:
___cxx_global_var_init in main-bf9b39.o
"Catch::makeTestInvoker(void (*)())", referenced from:
___cxx_global_var_init.1 in main-bf9b39.o
"Catch::AssertionHandler::handleExpr(Catch::ITransientExpression const&)", referenced from:
____C_A_T_C_H____T_E_S_T____0() in main-bf9b39.o
"Catch::AssertionHandler::handleUnexpectedInflightException()", referenced from:
____C_A_T_C_H____T_E_S_T____0() in main-bf9b39.o
"Catch::AssertionHandler::complete()", referenced from:
____C_A_T_C_H____T_E_S_T____0() in main-bf9b39.o
"Catch::AssertionHandler::AssertionHandler(Catch::StringRef, Catch::SourceLineInfo const&, Catch::StringRef, Catch::ResultDisposition::Flags)", referenced from:
____C_A_T_C_H____T_E_S_T____0() in main-bf9b39.o
"Catch::ITransientExpression::~ITransientExpression()", referenced from:
Catch::BinaryExpr<unsigned int const&, int const&>::~BinaryExpr() in main-bf9b39.o
"Catch::formatReconstructedExpression(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, Catch::StringRef, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
Catch::BinaryExpr<unsigned int const&, int const&>::streamReconstructedExpression(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const in main-bf9b39.o
"Catch::AutoReg::AutoReg(Catch::ITestInvoker*, Catch::SourceLineInfo const&, Catch::StringRef, Catch::NameAndTags const&)", referenced from:
___cxx_global_var_init.1 in main-bf9b39.o
"Catch::AutoReg::~AutoReg()", referenced from:
___cxx_global_var_init.1 in main-bf9b39.o
"Catch::Session::run(int, char**)", referenced from:
_main in main-bf9b39.o
"Catch::Session::Session()", referenced from:
_main in main-bf9b39.o
"Catch::Session::~Session()", referenced from:
_main in main-bf9b39.o
"Catch::StringRef::StringRef(char const*)", referenced from:
____C_A_T_C_H____T_E_S_T____0() in main-bf9b39.o
Catch::BinaryExpr<unsigned int const&, int const&> const Catch::ExprLhs<unsigned int const&>::operator==<int>(int const&) in main-bf9b39.o
___cxx_global_var_init.1 in main-bf9b39.o
"typeinfo for Catch::ITransientExpression", referenced from:
typeinfo for Catch::BinaryExpr<unsigned int const&, int const&> in main-bf9b39.o
"vtable for Catch::ITransientExpression", referenced from:
Catch::ITransientExpression::ITransientExpression(bool, bool) in main-bf9b39.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
On the other hand, the single-include version works for me, no linker errors.
I will try to create a fully working example.
@bifurcation You are supposed to use the single-include version.
It is possible to use the headers in include/, but then you have to also compile and link the implementation files in there and you are not provided with any guarantees vis-a-vis stability and functionality.
I have this problem too, basically the same errors with a test as simple as this
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
TEST_CASE("Failing test", "[failing]") {
REQUIRE(0 == 1);
}
I am on macOS El Capitan 10.11.6, clang 5.0.1 and cloned the latest Catch2 from git
Taking the hint from above I changed -I.../include to -I.../single_include and the linker errors went away. (clang++ on MacOS).
I was able to solve my issue. I am using meson and precompiled headers. Excluding the catch include from the list of precompiled headers solve my problem.
In this regard, how should I use catch with precompiled headers?
Since Catch 2.0.0, using include/catch.hpp directly is unsupported. If you properly compile and link all implementation files from include/ tree, it should still work, but we recommend to use single_include/catch.hpp instead.
PCHs are somewhat supported (AFAIK it works, but we haven't had many users), see our documentation.
As I often do, I didn't pay enough attention to the documentation. Now everything is smooth with meson building my library with the precompiled headers and testing it as it should. Thanx a lot.
Most helpful comment
Since Catch 2.0.0, using
include/catch.hppdirectly is unsupported. If you properly compile and link all implementation files frominclude/tree, it should still work, but we recommend to usesingle_include/catch.hppinstead.PCHs are somewhat supported (AFAIK it works, but we haven't had many users), see our documentation.