_libiconv или _iconv неопределенный символ в 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:

Почему это происходит и как обойти эту зависимость или, в более общем плане, выяснить, что происходит и как это исправить?


person John Q    schedule 31.08.2019    source источник


Ответы (4)


Я столкнулся с этой проблемой в течение нескольких лет / обновлений Mac OSX. Я внимательно прочитал все различные ответы, которых много. Этот ответ — то, что я хотел бы иметь, когда начинал это путешествие, поэтому я надеюсь, что он поможет.

Что происходит:

У вас установлены две, возможно, три версии iconv:

  1. Тот, который устанавливается вместе с MacOSX в /usr/lib, именами вызовов функций которого являются «iconv()», «iconv_open()», «iconv_close» и т. д.
  2. Версия GNU libiconv для систем *nix с именами вызовов функций «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, которые компилятор находит из одной версии, но путь поиска библиотеки сначала находит библиотеки из другой версии. Например, если вы сначала найдете файл iconv.h GNU libiconv, он переопределит «iconv» в «libiconv», но компоновщик может найти только библиотеку Mac OSX в /usr/lib (которая имеет символы «_iconv», «_iconv_open ", "_iconv_close"), и вы получите сообщение об ошибке не можете найти символы "_libiconv", даже если вы нигде не установили GNU libiconv-версию iconv lib.

Что с этим делать:

Ваша задача — заставить все, что вы запускаете/компилируете, найти правильную версию iconv раньше других. Вы можете сделать это несколькими способами.

При компиляции вы можете попробовать включить директиву «--with-iconv=<dir>» и/или «--with-iconv-dir=<dir>» или «--with-libiconv-prefix=<dir>» при запуске «configure», чтобы указать на правильную версию. Если это не сработает, вам придется применить более прямой подход, например, напрямую отредактировать Makefile.

Я лично предпочитаю вносить такие изменения только в проект, в котором возникла проблема, чтобы впоследствии это не оказало каскадного влияния на несвязанные проекты. Для меня это означает редактирование Makefile, созданного с помощью «configure», и включение папки iconv lib непосредственно в запись LDFLAGS (или аналогичную) в Makefile. Когда вы передаете «настроить» директиву «--with-iconv=», она должна это делать, но я обнаружил, что это не всегда работает, потому что Makefile будет включать какой-то другой каталог lib перед тем, который вы хотите.

То, что вам нужно здесь, это заказ. Вы хотите, чтобы ваш каталог iconv lib отображался перед другими каталогами lib в команде компиляции «cc», поэтому проверьте вывод при запуске «make» (подробный режим). Кроме того, вы можете просто заменить «-liconv» на абсолютный путь к самому файлу lib (т. е. «path/to/iconv/lib/libiconv.dylib» без -L, без -l).

Кроме того, если вы видите это в пути к библиотеке в Makefile

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

затем поместите его последним в этот список путей к библиотекам и убедитесь, что путь к правильному каталогу iconv lib находится перед ним. То же самое для этого в пути -I include:

/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 для каждой скомпилированной/связанной вещи, тогда выясните подробный параметр, чтобы он был (для настройки, я думаю, просто запустите «export V=1» в командной строке, а затем запустите configure и сделать в той же оболочке окно).
  • Вы могли бы подумать, что указание «--with-iconv=<path-to-iconv-dir>» в качестве параметра для ./configure позаботится об этом, но иногда не гарантируется, что сгенерированный Makefile будет включать ваш путь iconv перед другим путем библиотеки, который подбирает некоторые другие файлы iconv, поэтому вам может понадобиться чтобы отредактировать Makefile, чтобы он действительно выглядел именно там, где вы хотите, чтобы он выглядел в первую очередь.
  • otool -L <executable/dylib> покажет вам, на какие библиотеки ссылается бинарный файл.
  • "file filename" покажет вам, для каких архитектур есть символы в библиотеке.
  • Просто скопируйте сбойную команду "cc" (одну из строк вывода при запуске Makefile) и возитесь с добавлением или упорядочением параметров, пока не найдете работающую комбинацию (т.е. -I, -L, -l , ‹абсолютный путь к файлу lib без предшествующего -l>), а затем действуйте в обратном направлении, чтобы заставить Makefile делать то же самое (или просто снова запустите «make», чтобы продолжить компиляцию и компоновку всего остального).
  • Примечание. Иногда при установке пакетов с помощью Homebrew, MacPorts и т. д. происходит то, что библиотека iconv, созданная для решения очень специфической зависимости, теперь скрывается в вашей библиотеке, включает пути и подбирается для других вещей, которые полагаются на обычный Версия 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/xcodexcrun --show-sdk-pathrelease_notes#3035624< /а>

DYLD_LIBRARY_PATH и LD_LIBRARY_PATH

Вкратце: не делай этого.

Чтобы заставить компиляцию работать, вы могли добавить новый путь к DYLD_LIBRARY_PATH или LD_LIBRARY_PATH (в ~/.bash_profile или подобном), указывающий на библиотеки iconv GNU, чтобы «помочь» компоновщику найти что-то. Это вернется, чтобы укусить вас в другое время / день, когда что-то совершенно не связанное с тем, что вы делаете сейчас, ищет библиотеки iconv MacOSX и вместо этого извлекает библиотеки GNU libiconv. Поэтому я оставляю DYLD_LIBRARY_PATH и LD_LIBRARY_PATH в покое, когда дело доходит до iconv. Для других проектов, которые я компилирую из исходников, таких как OpenSSL, да, я меняю DYLD_LIBRARY_PATH и LD_LIBRARY_PATH, потому что до сих пор не было никаких конфликтов в MacOSX.

Наконец, вот ветка поддержки MacPorts, обсуждающая эту проблему, которая очень хорошо объясняет, почему эта проблема вообще существует: https://trac.macports.org/ticket/57821

person John Q    schedule 31.08.2019
comment
При компиляции PHP 7.3.9 на macOS 10.14 мне также пришлось отредактировать строку Makefile INCLUDES =, добавив -I/path/to/libiconv-build-directory/include в качестве второго элемента. Затем я смог успешно скомпилировать PHP. - person Paolo; 06.09.2019

У меня была такая же проблема при попытке установить 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)
<...>

Мое решение заключалось в том, чтобы отключить libiconv из MacPorts:

sudo port deactivate libiconv

Тогда установка прошла успешно.

Возможно, вам придется снова активировать libiconv, если некоторые из ваших приложений Macports не работают:

sudo port activate libiconv
person Artem Skoretskiy    schedule 03.11.2019

Студенты OS/161: если вы столкнулись с этой ошибкой при компиляции gcc-4.8 с Mac OS Lion в качестве хоста,

sudo port deactivate libiconv

исправил это для меня.

person Darbin Reyes    schedule 27.03.2021

Один из способов избежать этой проблемы — выработать дисциплину, гарантирующую, что все зависимости пакетов/библиотек программы, которую вы создаете/устанавливаете, являются резидентными и мгновенно находимыми в вашей системе. В MacOS [и, возможно, в других системах на базе UNIX] все они должны находиться в /usr/local или каталогах с соответствующими символическими ссылками на них.

У меня возникла эта проблема при попытке собрать и установить PHP из исходных файлов в MacOS.

Вот моя команда настройки:

./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_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
...
  1. Перечисленные выше каталоги затем будут искать библиотеки в процессе сборки пакета, когда вы запускаете команду make.

Проблема в том, что все библиотеки ищутся в этих каталогах. Итак, в моем случае вы можете видеть, что у меня уже есть ссылка на iconv в Makefile: -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 answer он советует переместить эту ссылку в конец списка. Это должно работать. Тем не менее, я бы рассмотрел плохую практику редактирования Makefile и посоветовал бы не делать этого.

Чтобы решить эту проблему:

  1. Убедитесь, что все необходимые зависимости библиотек/пакетов для реальной программы, которую вы создаете/устанавливаете, могут быть найдены во время настройки, т. е. ./configure .... Когда вы сделаете это, искомые каталоги, такие как перечисленные выше [/Library/..., и т.д.], не будут включены в Makefile.
  2. Проверьте Makefile после запуска configure. Если в каких-либо переменных с суффиксом LDFLAGS есть какие-либо каталоги, отличные от тех, что имеют префикс /usr/local, значит вам не хватает какой-то библиотеки/пакета. Узнайте, что это такое, и установите его.
person BannerMan    schedule 21.04.2021