避免出现这种问题的一种方法是培养确保正在构建/安装的程序的所有包/库依赖项都驻留在您的系统上并且可以立即找到的纪律。在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 这样的包为例。以下是安装方法:
sudo mkdir -p /usr/local/_utils/libxml2
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
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/
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/
sudo ln -s /usr/local/_utils/libxml2/lib/pkgconfig/libxml-2.0.pc /usr/local/lib/pkgconfig/
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
时,会发生以下情况:
configure
操作进行了搜索以找到 libxml
,因为 libxml
是必需的。
- 它在以下位置找到了
libxml
:/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib
- 然后将此目录添加到 Makefile 中的特定变量下,特别是
EXTRA_LDFLAGS
和 EXTRA_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
...
- 在运行
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是一个不好的习惯,并且建议避免这样做。
要解决此问题:
- 确保在配置期间找到正在构建/安装的实际程序的所有必需库/软件包依赖项,即
./configure ...
。这样做时,像上面列出的那个目录[/Library/...
等]的搜索目录将不会包含在Makefile中。
- 在运行
configure
后检查Makefile。如果存在除具有前缀/usr/local
的任何变量之外的任何目录,则您必须缺少某些库/软件包。找出它是什么并安装它。
INCLUDES =
,将-I/path/to/libiconv-build-directory/include
添加为第二个元素。然后我才能成功编译 PHP。 - Paolo