【问题标题】:_libiconv or _iconv undefined symbol on Mac OSXMac OSX 上的 _libiconv 或 _iconv 未定义符号
【发布时间】:2020-01-04 03:53:41
【问题描述】:

在 Mac OSX 上从源代码编译某些包时,我收到以下 iconv 错误:

Undefined symbols for architecture x86_64:
  "_iconv", referenced from:
  "_iconv_close", referenced from:
  "_iconv_open", referenced from:

或者我得到:

Undefined symbols for architecture x86_64:
"_libiconv", referenced from:
"_libiconv_open", referenced from:
"_libiconv_close", referenced from:

为什么会发生这种情况,我该如何解决这种依赖关系,或者更一般地说,弄清楚发生了什么以及如何解决它?

【问题讨论】:

    标签: iconv libiconv


    【解决方案1】:

    我多年来/升级 Mac OSX 时遇到过这个问题。我已经彻底阅读了所有各种答案,其中有很多。当我开始这段旅程时,我希望得到这个答案,所以我希望它有所帮助。

    发生了什么:

    您安装了两个,可能三个版本的 iconv:

    1. MacOSX 自带安装在 /usr/lib 中,其函数调用名称为“iconv()”、“iconv_open()”、“iconv_close”等。
    2. *nix 系统的 GNU libiconv 版本,其函数调用名称为“libiconv”、“libiconv_open()”、“libiconv_close()”等。
    3. 可能是安装了 Xcode 的版本:/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib

    无论您正在编译/运行的程序都找不到它想要的程序。

    发生这种情况(至少)有 3 个原因:

    1. 您的系统上安装了多个版本的 iconv,并且库搜索路径首先查找另一个版本。将 *nix 包引入 MacOSX 的包管理器(如 MacPorts、Homebrew、Fink 等)经常发生这种情况。他们不仅引入了 GNU libiconv 版本,而且通常会修改 lib 搜索路径以首先访问其目录(即,未找到“_iconv”,因为它访问的第一个 lib 定义了 GNU libiconv 的“_libiconv”)。
    2. 您完全缺少您的代码正在寻找的 iconv 版本,通常是 GNU libiconv 版本。我在从源代码编译 PHP 时遇到了这个问题。它需要 GNU libiconv 版本(即,它调用“libiconv_open()”、“libiconv_close()”等。
    3. 您有编译器从一个版本中找到的 .h 文件,但库搜索路径首先从另一个版本中找到库。例如,如果您首先找到 GNU libiconv 的 iconv.h 文件,它会将“iconv”重新定义为“libiconv”,但链接器可能只会在 /usr/lib 中找到 Mac OSX 库(其中包含符号“_iconv”、“_iconv_open ", "_iconv_close"),即使您没有在任何地方安装 GNU libiconv 版本的 iconv lib,您也会收到错误找不到“_libiconv”符号。

    怎么办:

    您的工作是获取您正在运行/编译的任何内容,以便在其他人之前找到正确版本的 iconv。你可以通过几种方式做到这一点。

    编译时,您可以尝试在运行“configure”时包含“--with-iconv=<dir>”和/或“--with-iconv-dir=<dir>”或“--with-libiconv-prefix=<dir>”指令以指向正确的版本。如果这不起作用,您将需要采取更直接的方法,例如直接编辑 Makefile。

    我个人的偏好是仅对有问题的项目进行此类更改,以免以后对不相关的项目产生级联影响。对我来说,这意味着编辑由“configure”创建的 Makefile,并将 iconv lib 目录直接包含在 Makefile 的 LDFLAGS 条目(或类似条目)中。当你传递“配置”一个“--with-iconv=”指令时,它应该这样做,但我发现它并不总是有效,因为 Makefile 会在你想要的之前包含一些其他的 lib 目录。

    您在这里追求的是订购。您希望您的 iconv lib 目录在“cc”编译命令中的其他 lib 目录之前显示,因此在运行“make”时检查输出(详细模式)。此外,您可以将“-liconv”替换为 lib 文件本身的绝对路径(即,“path/to/iconv/lib/libiconv.dylib”,不带 -L,不带 -l)。

    另外,如果你在 Makefile 的 lib 路径中看到这个

    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib

    然后将它放在库路径列表的最后,并确保正确 iconv 库目录的路径在它之前。与 -I 包含路径上的这个相同:

    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include

    您也可以直接进入不需要的 iconv lib 目录并将它们移动到另一个位置(注意:这不适用于 MacOSX 版本,因为它们受系统保护)。

    如何在您的系统上调试此问题:

    • find / -name iconv.*(或 libiconv.*,您可能需要 root 才能找到所有这些)
    • 如果你的编译器还没有显示每个编译/链接的东西的 -I 和 -L 路径,然后找出一个详细的选项,这样它就会(对于配置,我认为只需在命令上运行“export V=1”行,然后在同一个 shell 窗口中运行 configure 和 make)。
    • 您会认为将“--with-iconv=<path-to-iconv-dir>”指定为 ./configure 的参数可以解决此问题,但有时不能保证生成的 Makefile 会在另一个库路径之前包含您的 iconv 路径,该路径会选择其他一些 iconv 文件,因此您可能需要编辑 Makefile 以真正强制它查看您希望它首先查看的位置。
    • otool -L <executable/dylib> 将显示二进制文件链接到哪些库。
    • "file filename" 将向您展示库具有哪些架构的符号。
    • 只需复制失败的“cc”命令(运行 Makefile 时的输出行之一),然后随意添加或排序参数,直到找出可行的组合(即 -I、-L , -l, ),然后从那里向后工作以使 Makefile 执行相同的操作(或者再次运行“make”以使其继续编译和链接其他所有内容) .
    • 注意:有时,当您使用 Homebrew、MacPorts 等安装软件包时,为解决非常特定的依赖关系而引入的 iconv 库现在潜伏在您的库中,并包含路径并为其他依赖的东西拾取在正常的 MacOSX 版本上 - 突然之间,即使您“没有更改任何内容”,您也会遇到与无关程序有关的问题。
    • 注意:您会注意到 /usr/lib 中有一个 iconv 库,但 /usr/include 中没有相应的头文件。事实上,根本没有 /usr/include 目录。最新版本的 Mac OSX 将开发头文件从操作系统中分离出来。开发头文件和库由 Xcode 处理,您可以通过运行以下命令找到它们:“xcrun --show-sdk-path”,然后转到您将找到 /include 和 /lib 目录的目录。在这里解释:https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes#3035624

    DYLD_LIBRARY_PATH 和 LD_LIBRARY_PATH

    tl;博士:不要这样做。

    为了使您的编译工作,您可能已经添加了指向 GNU iconv 库的 DYLD_LIBRARY_PATH 或 LD_LIBRARY_PATH(在 ~/.bash_profile 或类似文件中)的新路径,以“帮助”链接器查找内容。当与您现在正在做的事情完全无关的事情正在寻找 MacOSX iconv 库而不是拉入 GNU libiconv 库时,这将在另一个时间/一天回来咬您。因此,当涉及到 iconv 时,我不理会 DYLD_LIBRARY_PATH 和 LD_LIBRARY_PATH。对于我从源代码编译的其他项目,例如 OpenSSL,是的,我确实更改了 DYLD_LIBRARY_PATH 和 LD_LIBRARY_PATH,因为到目前为止 MacOSX 上没有任何冲突。

    最后,这里有一个讨论这个问题的 MacPorts 支持线程,它非常说明为什么会存在这个问题:https://trac.macports.org/ticket/57821

    【讨论】:

    • 在 macOS 10.14 上编译 PHP 7.3.9 时,我还必须编辑 Makefile 的行 INCLUDES = 添加 -I/path/to/libiconv-build-directory/include 作为第二个元素。然后我就可以成功编译PHP了。
    【解决方案2】:

    我在尝试安装 cargo-tree 时遇到了同样的问题:

    cargo install cargo-tree
    <...>
    = note: Undefined symbols for architecture x86_64:
            "_iconv", referenced from:
                _git_path_iconv in liblibgit2_sys-966b1b327b8681d4.rlib(path.o)
               (maybe you meant: _git_path_iconv_clear, _git_path_iconv_init_precompose , _git_path_iconv )
            "_iconv_open", referenced from:
                _git_path_direach in liblibgit2_sys-966b1b327b8681d4.rlib(path.o)
    <...>
    

    我的解决方案不是从 MacPorts 禁用 libiconv

    sudo port deactivate libiconv
    

    然后安装成功。

    如果你们中的一些 Macports 应用程序无法正常工作,您可能需要重新激活 libiconv

    sudo port activate libiconv
    

    【讨论】:

      【解决方案3】:

      OS/161 学生:如果您在使用 Mac OS Lion 作为主机编译 gcc-4.8 时遇到此错误,

      sudo port deactivate libiconv

      帮我修好了。

      【讨论】:

        【解决方案4】:

        避免出现此问题的方法之一是制定规则,确保您正在构建/安装的程序的所有包/库依赖项都常驻并立即找到在您的系统上.在 MacOS [可能还有其他基于 UNIX 的系统] 上,它们都应该位于 /usr/local 或具有相关符号链接的目录中。

        我在尝试从 MacOS 上的源文件构建和安装 PHP 时遇到了这个问题。

        这是我的配置命令:

        ./configure --prefix=/usr/local/_utils/php/7.3.27 --enable-fpm --with-fpm-user=myusername --with-fpm-group=mygroupname --enable-bcmath --enable-cli --enable-exif --enable-ftp --enable-mbstring --enable-sockets --enable-zip --with-libzip=/usr/local/_utils/libzip --with-libxml-dir=/usr/local/_utils/libxml2 --with-mysqli --with-pdo-mysql=mysqlnd --with-iconv=/usr/local/_utils/iconv --with-iconv-dir=/usr/local/_utils/iconv --with-openssl=/usr/local/_utils/libressl --with-openssl-dir=/usr/local/_utils/libressl --with-zlib-dir=/usr/local/_utils/zlib --with-pcre-dir=/usr/local --with-pcre-regex=/usr/local --with-sodium=/usr/local/_utils/sodium
        

        如果您注意到所有 [除了几个] --with-pkg= 选项直接引用库/包,因为它们都已安装在自定义目录中,并创建了相关的符号链接。

        拿一个像libxml2这样的包。安装方法如下:

        # Create install directory
        sudo mkdir -p /usr/local/_utils/libxml2
        
        # Download and install
        wget -c ftp://xmlsoft.org/libxml2/libxml2-2.9.10.tar.gz
        tar -zxf libxml2-2.9.10.tar.gz
        cd libxml2-2.9.10
        ./configure --prefix=/usr/local/_utils/libxml2
        make
        sudo make install
        
        # Create symlinks for bin
        sudo ln -s /usr/local/_utils/libxml2/bin/xml2-config /usr/local/bin/
        sudo ln -s /usr/local/_utils/libxml2/bin/xmlcatalog /usr/local/bin/
        sudo ln -s /usr/local/_utils/libxml2/bin/xmllint /usr/local/bin/
        
        # Create symlinks for lib
        sudo ln -s /usr/local/_utils/libxml2/lib/libxml2.a /usr/local/lib/
        sudo ln -s /usr/local/_utils/libxml2/lib/libxml2.la /usr/local/lib/
        sudo ln -s /usr/local/_utils/libxml2/lib/libxml2.dylib /usr/local/lib/
        
        # Create symlinks for lib/pkgconfig
        sudo ln -s /usr/local/_utils/libxml2/lib/pkgconfig/libxml-2.0.pc /usr/local/lib/pkgconfig/
        
        # Create symlinks for include
        sudo ln -s /usr/local/_utils/libxml2/include/libxml2 /usr/local/include/
        
        

        注意:您不必使用_utils;您可以选择您认为合适的任何目录。此外,为了避免符号链接,您可以使用./configure --prefix=/usr/local 并直接安装到/usr/local,但使用自定义目录更安全。

        安装包/库后,您可以直接引用它,例如./configure --with-libxml-dir=/usr/local/_utils/libxml2。此外,由于符号链接的原因,如果您无意中排除了该选项,将很容易找到它。

        为什么需要这样做?

        我注意到,当我还没有安装这个包 [libxml2] 并且我没有指定 --with-libxml-dir 时,发生了以下情况:

        1. configure 操作进行了搜索以找到 libxml,因为 libxml 是必需的。
        2. 它在以下位置找到libxml/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib
        3. 然后它将此目录添加到特定变量下的 Makefile,特别是 EXTRA_LDFLAGSEXTRA_LDFLAGS_PROGRAM。然后,我最终得到了一个 Makefile,其相关部分如下所示:
        ...
        EXTRA_LDFLAGS = -L/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib -L/usr/local/_utils/libxml2/lib -L/usr/local/_utils/zlib/lib -L/usr/local/_utils/xz/lib -L/usr/local/_utils/libressl/lib -L/usr/local/lib -L/usr/local/_utils/iconv/lib -L/usr/local/_utils/sodium/lib -L/usr/local/_utils/libzip/lib
        EXTRA_LDFLAGS_PROGRAM = -L/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib -L/usr/local/_utils/libxml2/lib -L/usr/local/_utils/zlib/lib -L/usr/local/_utils/xz/lib -L/usr/local/_utils/libressl/lib -L/usr/local/lib -L/usr/local/_utils/iconv/lib -L/usr/local/_utils/sodium/lib -L/usr/local/_utils/libzip/lib
        ...
        
        1. 然后,当您运行make 命令时,将在构建包的过程中搜索上面列出的目录中的库。

        问题是在这些目录中搜索了所有库。所以,在我的例子中,你可以看到我已经在 Makefile 中有一个指向iconv 的链接:-L/usr/local/_utils/iconv/lib,但是首先搜索了/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib [因为它首先出现],并且在其中发现了一个不合适的版本iconv,然后用它代替了我指定的iconv。结果是错误。

        Undefined symbols for architecture x86_64:
        "_libiconv", referenced from:
        "_libiconv_open", referenced from:
        "_libiconv_close", referenced from:
        

        这很有趣,因为这个问题甚至与iconv 无关; libxml 的缺失导致搜索并随后将搜索到的目录 /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib 包含到 Makefile。

        John Q's answer 中,他建议将此引用移至列表末尾。这应该有效。但是,我会考虑编辑 Makefile 的不良做法并建议不要这样做。

        解决这个问题:

        1. 确保在配置期间可以找到您正在构建/安装的实际程序的所有必需库/包依赖项,即./configure ...。当您这样做时,上面列出的目录 [/Library/... 等] 将不会包含在 Makefile 中。
        2. 在运行configure 后检查 Makefile。如果在任何后缀为LDFLAGS 的变量下除了前缀为/usr/local 的目录之外还有其他目录,那么您一定缺少一些库/包。找出它是什么并安装它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-09-23
          • 2012-08-20
          • 2015-09-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-06-17
          • 2021-09-08
          相关资源
          最近更新 更多