Mac OSX 上的 _libiconv 或 _iconv 未定义符号

_libiconv or _iconv undefined symbol on Mac OSX

在 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:

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

我已经 运行 解决了这个问题多年 / Mac OSX 的升级。我已经仔细阅读了所有各种答案,其中有很多。这个答案是我开始这段旅程时希望得到的,所以我希望它能有所帮助。

发生了什么:

您安装了两个(可能是三个)版本的 iconv:

  1. 随 MacOSX in /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

无论您使用什么程序 compiling/running 都找不到它想要的程序。

发生这种情况的原因(至少)有 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",但链接器可能只会找到 Mac OSX 库在 /usr/lib(其中有符号“_iconv”、“_iconv_open”、“_iconv_close”),你会得到错误找不到“_libiconv”符号,即使你没有t 在任何地方安装了 iconv lib 的 GNU libiconv 版本。

怎么办:

你的工作是尽你所能 running/compiling 在其他人之前找到正确版本的 iconv。您可以通过几种方式执行此操作。

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

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

你要的是顺序。您希望您的 iconv 库目录在 "cc" 编译命令中显示在其他库目录之前,因此请检查 "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 lib 目录的路径在它之前。与此相同 -I include paths:

/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 路径 compiled/linked,那么找出一个详细的选项,这样它就会(对于配置我认为只是 运行 “export V=1”在命令行上,然后 运行 在相同的 shell window).
  • 中进行配置和制作
  • 你会认为将“--with-iconv=<path-to-iconv-dir>”指定为 ./configure 的参数会解决这个问题,但有时不能保证生成的 Makefile 会在另一个库路径之前包含你的 iconv 路径一些其他 iconv 文件,因此您可能需要编辑 Makefile 以真正强制它准确地查找您希望它首先查找的位置。
  • otool -L <executable/dylib> 将显示二进制链接到哪些库。
  • "file filename" 将向您展示一个库有哪些架构的符号。
  • 只需复制失败的 "cc" 命令(运行 Makefile 时的输出行之一)并添加或订购 par米,直到你找出一个有效的组合(即 -I、-L、-l、),然后从那里向后工作,让 Makefile 做同样的事情(或者再次 运行 "make" 让它继续编译和链接其他所有内容)。
  • 注意:有时,当您使用 Homebrew、MacPorts 等安装软件包时,会发生这样的情况:为解决非常具体的依赖关系而引入的 iconv 库现在潜伏在您的库中,包括路径和为依赖于正常 MacOSX 版本的其他东西而拾起——突然间你遇到一个不相关的程序的问题,即使你 "didn't change anything."
  • 注意:您会注意到 /usr/lib 中有一个 iconv 库,但 /usr/include 中没有相应的 header。事实上,根本就没有 /usr/include 目录。 Mac OSX 的最新版本将开发 header 与 OS 分开。开发 headers 和库由 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;dr:不要这样做。

为了让你的编译工作,你可能已经添加了一个新的路径到 DYLD_LIBRARY_PATH 或 LD_LIBRARY_PATH (在 ~/.bash_profile 或类似的)指向GNU iconv libs 以便 "help" 链接器找到东西。当与您现在正在做的事情完全无关的事情正在寻找 MacOSX iconv 库而不是拉入 GNU libiconv 库时,这将再次咬住您 time/day .因此,当涉及到 iconv 时,我不理会 DYLD_LIBRARY_PATH 和 LD_LIBRARY_PATH。对于我从源代码编译的其他项目,比如 OpenSSL,是的,我确实更改了 DYLD_LIBRARY_PATH 和 LD_LIBRARY_PATH,因为到目前为止 MacOSX 上没有任何冲突.

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

我在尝试安装时遇到了同样的问题 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

OS/161同学们:如果你在MacOSLion作为宿主编译gcc-4.8时遇到这个错误,

sudo port deactivate libiconv

帮我修好了。

避免出现此问题的方法之一是制定规则,确保您 building/installing 程序的所有 package/library 依赖项都是驻留的,并且立即 findable 在你的系统上。在 MacOS [以及其他基于 UNIX 的系统] 上,它们应该都在 /usr/local 或具有相关符号 link 的目录中。

我在 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= 选项中的所有 [除了几个] 选项都直接引用 libraries/packages,因为它们都安装在自定义目录中,并且相关符号 link已创建。

拿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;您可以选择任何您认为合适的目录。此外,为了避免必须 symlink,您可以使用 ./configure --prefix=/usr/local 并直接安装到 /usr/local,但使用自定义目录更安全。

安装 package/library 后,您可以直接引用它,例如./configure --with-libxml-dir=/usr/local/_utils/libxml2。另外,由于symlink的原因,如果不小心排除了这个选项,也很容易被找到。

为什么这是必要的?

我注意到,当我还没有安装这个包 [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 中已经有一个 link 到 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 中。

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

解决这个问题:

  1. 确保在配置过程中可以找到您 building/installing 的实际程序所需的 library/package 依赖项,即 ./configure ...。执行此操作时,搜索到的目录(如上面列出的目录 [/Library/... 等)将不会包含在 Makefile 中。
  2. 在 运行 configure 之后检查 Makefile。如果后缀为LDFLAGS的变量下有前缀/usr/local以外的目录,那么一定是少了一些library/package。找出它是什么并安装它。