【问题标题】:boost iOS linking errorboost iOS链接错误
【发布时间】:2015-02-17 19:13:53
【问题描述】:

我有一个 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 没有编译,它都是头文件,所以我不确定是什么导致了“错误的架构”错误。是否有另一个 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++ ios xcode boost linker


    【解决方案1】:

    首先确定:

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

    在 Apple LLVM 6.0 - 语言 - C++ 下进行以下更改

    C++ 语言方言到 C++11 [-std=c++11] C++ 标准库到 libc++(支持 C++11 的 LLVM C++ 标准库)

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

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

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

    【讨论】:

    • 感谢您的出色回答。我相信你是完全正确的。我应该提到我正在按照您的建议使用项目设置进行构建。 EOS 问题绝对是原因,并且确实错误报告建议我做的正是我所做的——注释掉portable_iarchive.hpp 和portable_oarchive.hpp 中的那些代码行。
    猜你喜欢
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多