提升 iOS 链接错误

boost iOS linking error

我有一个 C++ 库,它在很大程度上依赖于我正在尝试为 iOS8 编译的 boost。我使用 Daniel Rosser 的脚本为 iOS 编译了 boost-1.57.0: https://github.com/danoli3/ofxiOSBoost

我修改了脚本,它也构建了 boost 的 serialization 库,一切看起来都很好。

但是,当我在 XCode 中编译我的库时,我得到:

Undefined symbols for architecture x86_64:
  "boost::archive::detail::shared_ptr_helper::shared_ptr_helper()", referenced from:
      eos::portable_iarchive::portable_iarchive(std::__1::basic_istream<char, std::__1::char_traits<char> >&, unsigned int) in data_receiver.o
      eos::portable_oarchive::portable_oarchive(std::__1::basic_streambuf<char, std::__1::char_traits<char> >&, unsigned int) in tcp_server.o
  "boost::archive::detail::shared_ptr_helper::~shared_ptr_helper()", referenced from:
      eos::portable_iarchive::portable_iarchive(std::__1::basic_istream<char, std::__1::char_traits<char> >&, unsigned int) in data_receiver.o
      eos::portable_iarchive::~portable_iarchive() in data_receiver.o
      eos::portable_oarchive::portable_oarchive(std::__1::basic_streambuf<char, std::__1::char_traits<char> >&, unsigned int) in tcp_server.o
      eos::portable_oarchive::~portable_oarchive() in tcp_server.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

它似乎坚持 boost::archive 库中的 shared_ptr_helper() 函数。我有点困惑,因为我认为这部分 boost 没有编译,它都是头文件,所以我不确定是什么导致了 'wrong architecture' 错误。是否有另一个 boost 库实际定义了我没有编译的这个方法?

稍后...这里是 eos::portable_iarchive 构造函数代码(这似乎是错误的来源——oarchive 代码几乎相同)

namespace eos {

    // forward declaration
    class portable_iarchive;

    typedef boost::archive::basic_binary_iprimitive<
            portable_iarchive
    #if BOOST_VERSION < 103400
            , std::istream
    #else
            , std::istream::char_type
            , std::istream::traits_type
    #endif
    > portable_iprimitive;

    /**
     * \brief Portable binary input archive using little endian format.
     *
     * This archive addresses integer size, endianness and floating point types so
     * that data can be transferred across different systems. There may still be
     * constraints as to what systems are compatible and the user will have to take
     * care that e.g. a very large int being saved on a 64 bit machine will result
     * in a portable_archive_exception if loaded into an int on a 32 bit system.
     * A possible workaround to this would be to use fixed types like
     * boost::uint64_t in your serialization structures.
     *
     * \note The class is based on the portable binary example by Robert Ramey and
     *           uses Beman Dawes endian library plus fp_utilities by Johan Rade.
     */
    class portable_iarchive : public portable_iprimitive

            // the example derives from common_oarchive but that lacks the
            // load_override functions so we chose to stay one level higher
            , public boost::archive::basic_binary_iarchive<portable_iarchive>

    #if BOOST_VERSION >= 103500
            // mix-in helper class for serializing shared_ptr
            , public boost::archive::detail::shared_ptr_helper
    #endif
    {
            // only needed for Robert's hack in basic_binary_iarchive::init
            friend class boost::archive::basic_binary_iarchive<portable_iarchive>;

            // workaround for gcc: use a dummy struct
            // as additional argument type for overloading
            template <int> struct dummy { dummy(int) {}};

            // loads directly from stream
            inline signed char load_signed_char()
            {
                    signed char c;
                    portable_iprimitive::load(c);
                    return c;
            }

            // archive initialization
            void init(unsigned flags)
            {
                    using namespace boost::archive;
                    archive_version_type input_library_version(3);

                    // it is vital to have version information!
                    // if we don't have any we assume boost 1.33
                    if (flags & no_header)
                            set_library_version(input_library_version);

                    // extract and check the magic eos byte
                    else if (load_signed_char() != magic_byte)
                            throw archive_exception(archive_exception::invalid_signature);

                    else
                    {
                            // extract version information
                            operator>>(input_library_version);

                            // throw if file version is newer than we are
                            if (input_library_version > archive_version)
                                    throw archive_exception(archive_exception::unsupported_version);

                            // else set the library version accordingly
                            else set_library_version(input_library_version);
                    }
            }
public:
        /**
         * \brief Constructor on a stream using ios::binary mode!
         *
         * We cannot call basic_binary_iprimitive::init which tries to detect
         * if the binary archive stems from a different platform by examining
         * type sizes.
         *
         * We could have called basic_binary_iarchive::init which would create
         * the boost::serialization standard archive header containing also the
         * library version. Due to efficiency we stick with our own.
         */
        portable_iarchive(std::istream& is, unsigned flags = 0)
        #if BOOST_VERSION < 103400
                : portable_iprimitive(is, flags & boost::archive::no_codecvt)
        #else
                : portable_iprimitive(*is.rdbuf(), flags & boost::archive::no_codecvt)
        #endif
                , boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
        {
                init(flags);
        }

#if BOOST_VERSION >= 103400
        portable_iarchive(std::streambuf& sb, unsigned flags = 0)
                : portable_iprimitive(sb, flags & boost::archive::no_codecvt)
                , boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
        {
                init(flags);
        }
#endif

        //! Load narrow strings.
        void load(std::string& s)
        {
                portable_iprimitive::load(s);
        }

#ifndef BOOST_NO_STD_WSTRING
        /**
         * \brief Load wide strings.
         *
         * This is rather tricky to get right for true portability as there
         * are so many different character encodings around. However, wide
         * strings that are encoded in one of the Unicode schemes only need
         * to be _transcoded_ which is a lot easier actually.
         *
         * We generate the output string to be encoded in the system's native
         * format, ie. UTF-16 on Windows and UTF-32 on Linux machines. Don't
         * know about Mac here so I can't really say about that.
         */
        void load(std::wstring& s)
        {
                std::string utf8;
                load(utf8);
                s = boost::from_utf8(utf8);
        }

等等

这些行特别有趣:

#if BOOST_VERSION >= 103500
        // mix-in helper class for serializing shared_ptr
        , public boost::archive::detail::shared_ptr_helper
#endif

将它们注释掉使我的构建成功,但我仍然对无法使用 shared_ptr_helper() 感到不高兴。

首先确定:

  • 您必须将项目或目标构建设置更改为 c++11

Under Apple LLVM 6.0 - Language - C++ make the following changes

C++ Language Dialect to C++11 [-std=c++11] C++ Standard Library to libc++ (LLVM C++ standard library with C++11 support)

否则我认为这可能与以下链接的 EOS - Boost Bug (Boost >= 1.56.0)

问题:https://epa.codeplex.com/workitem/2456

我还快速查看了构建脚本,以确保它肯定会为每个架构将 Boost 序列化库添加到 lipo boost 存档中,是的,它肯定在那里。