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

33

在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:
为什么会发生这种情况,我该如何避免这种依赖,或者更普遍地说,如何找出问题所在并修复它?

为什么会发生这种情况,我该如何避免这种依赖,或者更普遍地说,如何找出问题所在并修复它?

6个回答

41

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

发生了什么:

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

  1. 一个位于/usr/lib的MacOSX预装的版本,其函数调用名称为“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版本,而且通常会修改库搜索路径,以先命中它们的目录(例如,找不到“_iconv”,因为它首先遇到的第一个库具有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库,您也会收到错误无法找到"_libiconv"符号。

怎么办:

您的任务是让您运行/编译的内容先找到正确的iconv版本。您可以通过几种方式实现这一点。

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

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

您在这里想要的是顺序,您希望在“cc”编译命令中优先显示iconv lib目录,因此在运行“make”(详细模式)时检查输出。另外,您可以只用lib文件本身的绝对路径替换“-liconv”(即,“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包含路径中的以下内容也是如此:

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

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

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

  • 查找 / -name iconv.* (或者 libiconv.* 并且您可能需要以 root 权限找到它们所有的文件)
  • 如果您的编译没有显示每个编译/链接的 -I 和 -L 路径,请找到一个详细的选项,使其可以显示(对于 configure,我认为只需在命令行中运行 "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,没有 -l 前缀的 lib 文件的绝对路径),然后从那里开始向后工作以使 Makefile 执行相同的操作(或者只需再次运行 "make" 命令以让它继续编译和链接其他所有东西)。
  • 注意:有时在使用 Homebrew、MacPorts 等安装包时会发生这种情况:引入了 iconv 库以解决某个特定依赖关系,现在它潜伏在您的 lib 和 include 路径中,并在需要使用正常 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;dr:不要这么做。

为了使编译工作,您可能已经将 DYLD_LIBRARY_PATH 或 LD_LIBRARY_PATH(在 ~/.bash_profile 或类似位置中)添加了新路径,指向 GNU iconv 库,以“帮助”链接器查找文件。这会在另一个时间/日期回来咬你一口,当与您现在所做的完全无关的事情正在寻找 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


2
在 macOS 10.14 上编译 PHP 7.3.9 时,我还必须编辑 Makefile 的行 INCLUDES =,将 -I/path/to/libiconv-build-directory/include 添加为第二个元素。然后我才能成功编译 PHP。 - Paolo
1
感谢您链接到MacPorts工单,因为我和那里的错误报告者一样处于同样的情况(使用Haskell)。为了后人,该错误报告者提供了一个Cabal调用(针对我的环境进行了修改),帮助ghc编译器找到正确的iconv库:cabal v2-configure --with-ghc ~/.ghcup/bin/ghc --with-gcc /usr/bin/clang --with-ld /usr/bin/clang --ld-option "/usr/lib/libiconv.dylib" --ghc-option "/usr/lib/libiconv.dylib"。在我的情况下,执行cabal v2-build来构建它而没有问题。 - Joe
很好。很高兴能帮到你。我觉得那里的讨论非常有趣。 - John Q

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

我非常希望这对我起作用。不幸的是,我的libgit2(也来自MacPorts)需要那个版本的libiconv,而cargo install仍然因为histdyld[520]: Symbol not found: (_libiconv)而失败了。 - undefined

8

同样的问题

Xcode编译在链接步骤时失败:

Showing All Messages
Ld /Users/crifan/Library/Developer/Xcode/DerivedData/Aweme-fswcidjoxbkibsdwekuzlsfcdqls/Build/Products/Debug-iphoneos/libAwemeDylib.dylib normal (in target 'AwemeDylib' from project 'Aweme')
...
Undefined symbols for architecture arm64:
  "_iconv_open", referenced from:
      +[CrifanLibiOS removeInvalidUtf8Nsdata:] in CrifanLibiOS.o
  "_iconvctl", referenced from:
      +[CrifanLibiOS removeInvalidUtf8Nsdata:] in CrifanLibiOS.o
  "_iconv", referenced from:
      +[CrifanLibiOS removeInvalidUtf8Nsdata:] in CrifanLibiOS.o
  "_iconv_close", referenced from:
      +[CrifanLibiOS removeInvalidUtf8Nsdata:] in CrifanLibiOS.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

最终方案

  • 使用Xcode添加引用框架:libiconv

    • Xcode->选择正确的项目Targets->Build Phases->Link Binary With Libraries->点击+->搜索libiconv->选择找到的libiconv.tbd

    • enter image description here

    • enter image description here

  • 一些内部细节

在这里,Xcode的iPhoneOS15.2SDK包含相关(上面搜索到的)libiconv库:

➜  ~ ll /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/lib/
total 5648
...
lrwxr-xr-x    1 crifan  staff    14B  4 15 15:37 libiconv.2.4.0.tbd -> libiconv.2.tbd
-r--r--r--    1 crifan  staff   1.2K 11 19  2021 libiconv.2.tbd
lrwxr-xr-x    1 crifan  staff    18B  4 15 15:37 libiconv.tbd -> libiconv.2.4.0.tbd

  • 注意:
    • 不应该添加到错误的Xcode项目目标中
      • 就像我之前一样: 添加到错误的目标Aweme,因为仍然失败,然后在这里更改为正确的目标:AwemeDylib,然后工作。

1
我的解决方案
brew安装libiconv
更好的方法:不要依赖GNU的实现!

0

针对使用 Mac OS Lion 作为主机编译 gcc-4.8 时遇到此错误的 OS/161 学生:

sudo port deactivate libiconv

对我来说解决了这个问题。


0

避免出现这种问题的一种方法是培养确保正在构建/安装的程序的所有包/库依赖项都驻留在您的系统上并且可以立即找到的纪律。在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的回答中,他建议将此引用移动到列表末尾。这应该可以解决问题。然而,我认为编辑Makefile是一个不好的习惯,并且建议避免这样做。

要解决此问题:

  1. 确保在配置期间找到正在构建/安装的实际程序的所有必需库/软件包依赖项,即./configure ...。这样做时,像上面列出的那个目录[/Library/...等]的搜索目录将不会包含在Makefile中。
  2. 在运行configure后检查Makefile。如果存在除具有前缀/usr/local的任何变量之外的任何目录,则您必须缺少某些库/软件包。找出它是什么并安装它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接