Haskell связывается с динамическими библиотеками на Ubuntu

У меня возникают проблемы с ссылкой на библиотеку Haskell, которую мы написали. Это неправильно для Ubuntu, но не для Arch Linux. Ошибка в Ubuntu, которую мы получаем, такова:

/usr/bin/ld: warning: libHSdeepseq-1.3.0.0-ghc7.4.1.so, needed by /usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7.4.1.so, not found (try using -rpath or -rpath-link) /usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7.4.1.so: undefined reference to 'deepseqzm1zi3zi0zi0_ControlziDeepSeq_zdfNFDataArrayzuzdcrnf1_info'

Проблема, по-видимому, вызвана тем, что libHScontainers-0.4.2.1-ghc7.4.1.so неправильно связана, как видно из вывода ldd: ldd /usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7.4.1.so linux-vdso.so.1 => (0x00007fffe95a2000) libHSdeepseq-1.3.0.0-ghc7.4.1.so => not found libHSbase-4.5.0.0-ghc7.4.1.so => not found libHSghc-prim-0.2.0.0-ghc7.4.1.so => not found libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f89a5a59000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f89a569a000) /lib64/ld-linux-x86-64.so.2 (0x00007f89a5fd8000)

По-видимому, зависимые библиотеки не могут быть найдены. Они установлены. Однако, если я сделаю то же самое на Arch: ldd /usr/lib/ghc-7.8.3/deepseq-1.3.0.2/libHSdeepseq-1.3.0.2-ghc7.8.3.so linux-vdso.so.1 (0x00007fff09dfe000) libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007fb8d3e96000) libm.so.6 => /usr/lib/libm.so.6 (0x00007fb8d3b91000) librt.so.1 => /usr/lib/librt.so.1 (0x00007fb8d3988000) libdl.so.2 => /usr/lib/libdl.so.2 (0x00007fb8d3784000) libffi.so.6 => /usr/lib/libffi.so.6 (0x00007fb8d357b000) libHSarray-0.5.0.0-ghc7.8.3.so => /usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../array-0.5.0.0/libHSarray-0.5.0.0-ghc7.8.3.so (0x00007fb8d32e1000) libHSbase-4.7.0.1-ghc7.8.3.so => /usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../base-4.7.0.1/libHSbase-4.7.0.1-ghc7.8.3.so (0x00007fb8d2967000) libHSinteger-gmp-0.5.1.0-ghc7.8.3.so => /usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../integer-gmp-0.5.1.0/libHSinteger-gmp-0.5.1.0-ghc7.8.3.so (0x00007fb8d274c000) libHSghc-prim-0.3.1.0-ghc7.8.3.so => /usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../ghc-prim-0.3.1.0/libHSghc-prim-0.3.1.0-ghc7.8.3.so (0x00007fb8d24cf000) libc.so.6 => /usr/lib/libc.so.6 (0x00007fb8d212c000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fb8d1f10000) /usr/lib64/ld-linux-x86-64.so.2 (0x00007fb8d435f000)

Библиотеки найдены.

Как я уже сказал, я могу решить это на Ubuntu с помощью -rpath в приложении, которое мы пытаемся связать с библиотекой Haskell. Но это означает, что мы должны сделать это для каждого пакета Haskell, который кажется мне неправильным. Мы также можем исправить это, добавив строку в /etc/ld.so.conf.d/ghc.conf. Но это также должно быть сделано для каждого пакета и не является удобным для пользователя.

Несколько вопросов, которые у меня есть:

  • Каков правильный способ исправить это?
  • Почему пакеты в ghc-dynamic неправильно связаны?
  • Почему компоновщик может найти libHScontainers-0.4.2.1-ghc7.4.1.so, но не libHSdeepseq-1.3.0.0-ghc7.4.1.so?

Ответ 1

Я сильно подозреваю, что это потому, что библиотеки Haskell, установленные ghc, имеют местоположения их зависимостей (поле RPATH их заголовка ELF, вы можете проверить с помощью readelf -d), определенный в терминах $ORIGIN. Когда библиотека X зависит от библиотеки Y, библиотека X может указывать, что библиотека Y должна быть найдена в местоположении относительно своего местоположения, используя $ORIGIN. Это поддерживается динамическим компоновщиком, но не поддерживается статическим компоновщиком.

(Я размышляю здесь:) Ваша библиотека определит местоположение его прямых зависимостей (в вашем случае, я предполагаю, это включает containers) в терминах своего собственного RPATH, который не находится в членов $ORIGIN. Вот почему компоновщик может найти эти, но не свои транзитивные зависимости (опять же, я предполагаю, это включает deepseq в вашем случае).

Так почему разница между Arch Linux и Ubuntu? (Спекуляция дальше.) Это связано с тем, что в отличие от Arch Linux, компоновщик Ubunbu по умолчанию использует --as-needed. Понимаете, ghc свяжет вашу библиотеку со всеми ее зависимостями (включая транзитивные), но тогда компоновщик будет опускать некоторые из этих зависимостей, потому что он напрямую не зависит от них. Вы можете проверить это, перейдя на --no-as-needed.

Обратите внимание, что эти ошибки статическими компоновщиками действительно не являются ошибками, а предупреждениями: он пытается разрешить символы, но не может; но динамический компоновщик все равно сможет. Поэтому вы можете поручить компоновщику игнорировать эти ошибки (--unresolved-symbols=ignore-all), и все должно быть хорошо.

Я сражался с добавлением явной поддержки в Cabal для генерации библиотек Haskell для использования в программах на C и нашел ту же проблему. Подробнее см. https://github.com/haskell/cabal/pull/2540#issuecomment-95984067.