_libiconv or _iconv undefined symbol on Mac OSX
Asked Answered
T

6

34

When compiling some packages from source on Mac OSX, I get the following iconv error:

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

or I get:

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

Why does this happen and how can I get around this dependency or, more generally, figure out what is going on and how to fix it?

Tatianatatianas answered 31/8, 2019 at 0:47 Comment(0)
T
43

I have run into this problem over multiple years / upgrades of Mac OSX. I have thoroughly read through all the various answers, of which there are many. This answer is what I wish I had had when I started this journey, so I hope it helps.

What's happening:

You have two, possibly three, versions of iconv installed:

  1. One that comes installed with MacOSX in /usr/lib whose function call names are "iconv()", "iconv_open()", "iconv_close", etc.
  2. A GNU libiconv version for *nix systems whose function call names are "libiconv", "libiconv_open()", "libiconv_close()", etc.
  3. Possibly a version installed with Xcode here: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib

Whatever program you're compiling/running isn't finding the one it wants.

This can happen for (at least) 3 reasons:

  1. You have multiple versions of iconv installed on your system and the library search paths are finding another one first. This happens a lot with package managers that bring *nix packages onto MacOSX (like MacPorts, Homebrew, Fink, etc.). They not only bring in the GNU libiconv version but they usually modify the lib search path to hit their dir first (i.e., "_iconv" not found because the first lib it's hitting has the GNU libiconv's "_libiconv" defined instead).
  2. You are completely lacking the iconv version that your code is looking for, usually the GNU libiconv version. I've run across this when compiling PHP from source. It wants the GNU libiconv version (i.e., it calls "libiconv_open()", "libiconv_close()", etc.
  3. You have .h files that the compiler finds from one version but the library search path finds libs from another version first. For instance, if you find the GNU libiconv's iconv.h file first, it redefines "iconv" to "libiconv" but the linker may only be finding the Mac OSX lib in /usr/lib (which has symbols "_iconv", "_iconv_open", "_iconv_close") and you'll get the error can't find "_libiconv" symbols even if you haven't installed the GNU libiconv version of iconv lib anywhere.

What to do about it:

Your job is to get whatever you're running/compiling to find the right version of iconv before the others. You can do this in a couple of ways.

When compiling, you can try including a "--with-iconv=<dir>" and or "--with-iconv-dir=<dir>" or "--with-libiconv-prefix=<dir>" directive when running "configure" to point to the right version. If that doesn't work, you'll need to take a more direct approach like editing the Makefile directly.

My personal preference is to contain these kinds of changes just to the project having the problem so it doesn't have a cascading impact on unrelated projects later on. For me, that means editing the Makefile created by "configure" and including the iconv lib dir directly in an LDFLAGS entry (or similar) in the Makefile. When you pass "configure" a "--with-iconv=" directive, it's supposed to do that but I have found it doesn't always work because the Makefile will include some other lib dir before the one you want.

What you are after here is the ordering. You want your iconv lib dir to show up before other lib dirs in the "cc" compile command, so check the output when "make" is run (verbose mode). Also, you could just replace "-liconv" with the absolute path to the lib file itself (i.e., "path/to/iconv/lib/libiconv.dylib" with no -L, no -l).

In addition, if you see this in a lib path in the Makefile

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

then put it last in that list of library paths and make sure the path to the correct iconv lib dir is before it. Same for this one on the -I include paths:

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

Potentially, you could also just go in the unwanted iconv lib dirs and move them to another place (note: this won't work for the MacOSX versions because they're protected by the system).

How to debug this problem on your system:

  • find / -name iconv.* (or libiconv.* and you may need to be root to find all of them)
  • If your compile isn't already showing you the -I and -L paths for each thing compiled/linked, then figure out a verbose option so it will (for configure I think just run "export V=1" on the command line and then run configure and make in that same shell window).
  • You would think that specifying "--with-iconv=<path-to-iconv-dir>" as a param for ./configure would take care of this but sometimes it's not guaranteed that the generated Makefile will include you iconv path before another library path that picks up some other iconv files, so you might need to edit the Makefile to really force it to look exactly where you want it to look first.
  • otool -L <executable/dylib> will show you what libraries a binary is linking to.
  • "file filename" will show you what architectures a library has symbols for.
  • Just copy the "cc" command that's failing (one of the lines of output when you run the Makefile) and screw around with adding or ordering the parameters until you figure out a combo that works (i.e., -I, -L, -l, <absolute path to lib file with no preceding -l>) and then work backwards from there to get the Makefile to do the same thing (or just run "make" again to let it continue compiling and linking everything else).
  • Note: Sometimes what happens when you install packages using Homebrew, MacPorts, etc. is that the iconv lib brought in to solve a very specific dependency is now lurking there in your lib and include paths and picked up for other things that rely on the normal MacOSX version -- and all of a sudden you get problems with an unrelated program even though you "didn't change anything."
  • Note: You'll notice there is an iconv lib in /usr/lib but no corresponding header in /usr/include. In fact, there's no /usr/include directory at all. The latest versions of Mac OSX separate out the development headers from the OS. The development headers and libs are handled by Xcode and you can find them by running this: "xcrun --show-sdk-path" and then going to that directory where you will find /include and /lib directories. Explained here: https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes#3035624

DYLD_LIBRARY_PATH and LD_LIBRARY_PATH

tl;dr: don't do it.

In an effort to get your compile to work, you might have added a new path to DYLD_LIBRARY_PATH or LD_LIBRARY_PATH (in ~/.bash_profile or similar) pointing to the GNU iconv libs in order to "help" the linker find things. This will come back to bite you at another time/day when something completely unrelated to what you're doing now is looking for the MacOSX iconv libs and instead pulls in the GNU libiconv libs. So I leave DYLD_LIBRARY_PATH and LD_LIBRARY_PATH alone when it comes to iconv. For other projects that I compile from source, like OpenSSL, yes, I do change DYLD_LIBRARY_PATH and LD_LIBRARY_PATH because so far there haven't been any conflicts on MacOSX.

Finally, here is a MacPorts support thread discussing this issue that is very illuminating about why this problem exists at all: https://trac.macports.org/ticket/57821

Tatianatatianas answered 31/8, 2019 at 0:47 Comment(3)
While compiling PHP 7.3.9 on macOS 10.14 I also had to edit the Makefile's line INCLUDES = adding -I/path/to/libiconv-build-directory/include as second element. Then I was able to compile PHP successfully.Pepito
Thanks for linking to the macports ticket as I was in the same situation as the bug reporter there (using Haskell) . For posterity, the bug reporter provided a cabal invocation (modified for my environment) that helped the ghc compiler find the proper iconv lib: 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" followed by cabal v2-build in my case to build it without issues.Unchartered
Nice. Glad it helped. I thought the discussion there was really interesting.Tatianatatianas
H
16

I had the same problem whilst trying to install 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)
<...>

My solution was to disable libiconv from MacPorts:

sudo port deactivate libiconv

Then the installation succeeded.

You may need to reactivate libiconv if some of your Macports applications are not working:

sudo port activate libiconv
Honesty answered 3/11, 2019 at 18:32 Comment(1)
I so hoped this would work for me. Unfortunately, my libgit2 (also from MacPorts) needed that version of libiconv, and the cargo install still bailed out with histdyld[520]: Symbol not found: (_libiconv).Strongwilled
S
8

Same Issue

Xcode compile failed at linking step:

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)

Final Worked

  • use Xcode to add referenced framework: libiconv

    • Xcode->select correct project Targets -> Build Phases -> Link Binary With Libraries-> click + -> search libiconv -> select found libiconv.tbd

    • enter image description here

    • enter image description here

  • some internal details

here Xcode's iPhoneOS15.2 SDK contains related (above search out) libiconv lib:

➜  ~ 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

  • Note:
    • should NOT added to wrong Xcode project's target
      • just like me before: added to wrong target Aweme, cause still fail, then change to correct target here: AwemeDylib, then work.
Saari answered 7/6, 2022 at 9:19 Comment(0)
W
1

My solution

brew install libiconv

Better: Don't depend on the GNU implementation!

Whelk answered 11/7, 2023 at 20:36 Comment(0)
S
0

OS/161 students: if you hit this error while compiling gcc-4.8 with Mac OS Lion as the host,

sudo port deactivate libiconv

fixed it for me.

Swansdown answered 27/3, 2021 at 6:21 Comment(0)
S
0

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:

  1. The configure operation did a search to find libxml, because libxml is required.
  2. It found libxml at a location: /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib
  3. 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
...
  1. 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:

  1. 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.
  2. 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.
Saturday answered 21/4, 2021 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.