Undefined symbols for architecture arm64: "CryptoPP::BufferedTransformation::ChannelFlush(std::string const&, bool, int, bool)", referenced from:
vtable for CryptoPP::SimpleProxyFilter in MYCLASSBBB.o
vtable for CryptoPP::Bufferless<CryptoPP::Filter> in MYCLASSBBB.o
I think you are not using libc++
, which is LLVM's C++ standard library. I think that because I don't see a -stdlib=libc++
(but I don't recall if that's passed to ld
directly).
The symbol is defined in the github's prebuilt cryptopp (that's my github, btw). Here's how to verify.
First, extract the arm64 library from the fat library:
$ xcrun -sdk iphoneos lipo libcryptopp.a -thin arm64 -output libcryptopp-arm64.a
$ ls
libcryptopp-arm64.a libcryptopp.a
Next, use nm
to dump global symbols, and use c++filt
to demangle:
$ nm -g libcryptopp-arm64.a | c++filt | grep BufferedTransformation::ChannelFlush | grep " T "
0000000000002110 T CryptoPP::BufferedTransformation::ChannelFlush(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool, int, bool)
The capitol T
means you are searching for symbols that are defined and exported. Lower t
means its defined but not exported - i.e., private. Capitol U
means its undefined.
The __1
is what libc++
(LLVM) uses to differentiate from libstdc++
(GNU). std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
is a string
, so that could be rewritten as:
CryptoPP::BufferedTransformation::ChannelFlush(std::__1::string const&, bool, int, bool)
If this library was built against libstdc++
(GNU), then the symbol from the library would be:
CryptoPP::BufferedTransformation::ChannelFlush(std:::string const&, bool, int, bool)
We can repeat for the second problem child, and it follows the same pattern (libc++
, and not libstdc++
):
$ nm -g libcryptopp-arm64.a | c++filt | grep CryptoPP::Filter::CopyRangeTo2 | grep " T "
00000000000001c4 T CryptoPP::Filter::CopyRangeTo2(CryptoPP::BufferedTransformation&, unsigned long long&, unsigned long long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool) const
This can be rewritten as:
CryptoPP::Filter::CopyRangeTo2(CryptoPP::BufferedTransformation&, unsigned long long&, unsigned long long, std::__1::string const&, bool) const
-----
IF you need GNU's libstdc++
, then you can build it yourself. Here are the steps:
- Download and unpack Crypto++ from the website
- Download and unpack
cryptopp-mobile.zip
. Unpack it right over top the Crypto++ source files
- Open the new
GNUmakefile
, find the iOS rule by searching for the block that begins with IS_IOS
- Change this line in the
IS_IOS
block: CXXFLAGS += -stdlib=libc++
. Change it to CXXFLAGS += -stdlib=libstdc++
- Do the cross compile...
-----
I downloaded Cocos2D-x and tried to look at its configuration (I'm not a Cmake guy, so I could be wrong with what follows). It has the following in CmakeList.txt
:
if(MSVC)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS
-wd4251 -wd4244 -wd4334 -wd4005 -wd4820 -wd4710
-wd4514 -wd4056 -wd4996 -wd4099)
else()
set(CMAKE_C_FLAGS_DEBUG "-g -Wall -DCOCOS2D_DEBUG=1")
set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-exceptions -std=c99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -std=c++11 -Wno-deprecated-declarations -Wno-reorder")
if(CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
endif(MSVC)
If Cmake is doing what I suspect, then its using LLVM's libc++
. But its also using -std=c++11
, and the GitHub project is not using it. But I'm not sure -std=c++11
makes a difference here.
Just bike shedding, but this is a bad sign: _SCL_SECURE_NO_WARNINGS
. If they are blatantly doing that, then they probably have various degrees of of badness and brokenness. (Just my experience with auditing software).
If interested, the __1
is an inline namespace used for versioning. See What are inline namespaces for? and Where does the __1 symbol come from when using LLVM's libc++?.