One of the ways to avoid having this issue is to develop the discipline of ensuring that all the package/library dependencies of the program you're building/installing are resident and instantly findable on your system. On MacOS [and perhaps other UNIX-based systems], they should all be in /usr/local
, or directories with relevant symlinks to.
I had this issue when trying to build and install PHP from source files on MacOS.
Here is my configure command:
./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
If you notice all [but a couple] of the --with-pkg=
options reference the libraries/packages directly as they've all been installed in a custom directory, and relevant symlinks created.
Take a package like libxml2. Here's how to install it:
# 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/
Note: You don't have to use _utils
; you can whatever directory you deem fit. Also, to avoid having to symlink, you can use ./configure --prefix=/usr/local
and install directly to /usr/local
, but using a custom directory is safer.
After you install the package/library, you can then reference it directly e.g. ./configure --with-libxml-dir=/usr/local/_utils/libxml2
. Also, on account of the symlinks, it will be found easily if you exclude the option inadvertently.
Why is this necessary?
What I noticed was that when I hadn't installed this package [libxml2] yet and I had not specified --with-libxml-dir
, the following happened:
- The
configure
operation did a search to find libxml
, because libxml
is required.
- It found
libxml
at a location: /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib
- It then added this directory to the Makefile under specific variables, notably
EXTRA_LDFLAGS
and EXTRA_LDFLAGS_PROGRAM
. I then ended up with a Makefile with the relevant section notated below:
...
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
...
- The listed directories above will then be searched for libraries in the process of building the package when you run the
make
command.
The problem is that all the libraries are searched in these directories. So, in my case, you can see that I already have a link to iconv
in the Makefile: -L/usr/local/_utils/iconv/lib
, but /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib
was searched first [since it appears first], and in it was found an unsuitable version of iconv
, which was then used instead of the iconv
I specified. The result was the error.
Undefined symbols for architecture x86_64:
"_libiconv", referenced from:
"_libiconv_open", referenced from:
"_libiconv_close", referenced from:
This is funny, because the problem wasn't even iconv
related; it was the absence of libxml
which caused a search and subsequent inclusion of the searched directory /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib
to the Makefile.
In John Q's answer, he advises to move this reference to the end of the list. This should work. However, I would consider editing a Makefile bad practice and advise against it.
To solve this issue:
- Ensure that all the required library/package dependencies of the actual program you are building/installing can be found during configuration i.e.
./configure ...
. When you do this, searched directories like the one listed above [/Library/...
, etc.] will not be included in the Makefile.
- Check the Makefile after you run
configure
. If there are any directories other than those with prefix /usr/local
under any variables with suffix LDFLAGS
, then you must be missing some library/package. Find out what it is and install it.
INCLUDES =
adding-I/path/to/libiconv-build-directory/include
as second element. Then I was able to compile PHP successfully. – Pepito