We are experiencing Apple WatchOS build failures on Travis for a C++ library. Other configurations, like iPhone, iPhoneSimulator and AppleTV are OK.
The library compiles OK but it fails to link. A typical compile invocation is:
clang++ -DNDEBUG -g2 -O3 -fPIC -pipe -Wall -arch armv7 -stdlib=libc++ -isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.1.sdk \
-c cryptlib.cpp
clang++ -DNDEBUG -g2 -O3 -fPIC -pipe -Wall -arch armv7 -stdlib=libc++ -isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.1.sdk \
-c cpu.cpp
clang++ -DNDEBUG -g2 -O3 -fPIC -pipe -Wall -arch armv7 -stdlib=libc++ -isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.1.sdk \
-c integer.cpp
...
After compile there are lots of linker errors as shown below. We are not sure if these are false positives or if we missed a necessary option or library.
I've tried searching Apple Developer but I'm having trouble finding information specific to Watch builds. I found some similar questions like Undefined symbol compiling boost context for iphone but they are unanswered (and the wrong platform).
I have an older MacBook for testing, but it runs OS X 10.9 and has Xcode 6. Its too old to try and work this problem. For example, it does not have WatchOS and can't decode the missing symbol name:
$ echo __Unwind_SjLj_Register | c++filt
__Unwind_SjLj_Register
Are the linking errors expected when testing this configuration? If not, then is the architecture correct? Maybe, which option or libraries are we missing for Watch and TV?
I found this recently in Clang source code, ToolChain.cpp:
bool Darwin::UseSjLjExceptions(const ArgList &Args) const {
// Darwin uses SjLj exceptions on ARM.
if (getTriple().getArch() != llvm::Triple::arm &&
getTriple().getArch() != llvm::Triple::thumb)
return false;
// Only watchOS uses the new DWARF/Compact unwinding method.
llvm::Triple Triple(ComputeLLVMTriple(Args));
return !Triple.isWatchABI();
}
Here's what link looks like. We drive it through the compiler, and we use the same CXXFLAGS.
clang++ -o cryptest.exe -DNDEBUG -g2 -O3 -fPIC -pipe -Wall -arch armv7 -isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.1.sdk \
-stdlib=libc++ adhoc.o test.o bench1.o bench2.o validat0.o validat1.o validat2.o validat3.o \
datatest.o regtest1.o regtest2.o regtest3.o fipsalgt.o dlltest.o ./libcryptopp.a
Undefined symbols for architecture armv7:
"__Unwind_SjLj_Register", referenced from:
CryptoPP::CipherModeFinalTemplate_CipherHolder<CryptoPP::BlockCipherFinal<(CryptoPP::CipherDir)0, CryptoPP::Rijndael::Enc>, CryptoPP::ConcretePolicyHolder<CryptoPP::Empty, CryptoPP::AdditiveCipherTemplate<CryptoPP::AbstractPolicyHolder<CryptoPP::AdditiveCipherAbstractPolicy, CryptoPP::OFB_ModePolicy> >, CryptoPP::AdditiveCipherAbstractPolicy> >::~CipherModeFinalTemplate_CipherHolder() in test.o
CryptoPP::Test::scoped_main(int, char**) in test.o
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > CryptoPP::IntToString<long>(long, unsigned int) in test.o
std::__1::basic_istream<char, std::__1::char_traits<char> >& std::__1::operator>><char, std::__1::char_traits<char> >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, char*) in test.o
std::__1::basic_istream<char, std::__1::char_traits<char> >& std::__1::ws<char, std::__1::char_traits<char> >(std::__1::basic_istream<char, std::__1::char_traits<char> >&) in test.o
CryptoPP::Test::GenerateRSAKey(unsigned int, char const*, char const*, char const*) in test.o
CryptoPP::Test::RSASignFile(char const*, char const*, char const*) in test.o
...
"__Unwind_SjLj_Resume", referenced from:
CryptoPP::CipherModeFinalTemplate_CipherHolder<CryptoPP::BlockCipherFinal<(CryptoPP::CipherDir)0, CryptoPP::Rijndael::Enc>, CryptoPP::ConcretePolicyHolder<CryptoPP::Empty, CryptoPP::AdditiveCipherTemplate<CryptoPP::AbstractPolicyHolder<CryptoPP::AdditiveCipherAbstractPolicy, CryptoPP::OFB_ModePolicy> >, CryptoPP::AdditiveCipherAbstractPolicy> >::~CipherModeFinalTemplate_CipherHolder() in test.o
CryptoPP::Test::scoped_main(int, char**) in test.o
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > CryptoPP::IntToString<long>(long, unsigned int) in test.o
std::__1::basic_istream<char, std::__1::char_traits<char> >& std::__1::operator>><char, std::__1::char_traits<char> >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, char*) in test.o
std::__1::basic_istream<char, std::__1::char_traits<char> >& std::__1::ws<char, std::__1::char_traits<char> >(std::__1::basic_istream<char, std::__1::char_traits<char> >&) in test.o
CryptoPP::Test::GenerateRSAKey(unsigned int, char const*, char const*, char const*) in test.o
CryptoPP::Test::RSASignFile(char const*, char const*, char const*) in test.o
...