Развертывание Yesod в Heroku, не может строить статически
Я очень новичок в Йесод и у меня проблемы со сборкой Йесод статически, поэтому я могу развернуться в Хероку.
Я изменил файл.cabal по умолчанию, чтобы отразить статическую компиляцию
if flag(production)
cpp-options: -DPRODUCTION
ghc-options: -Wall -threaded -O2 -static -optl-static
else
ghc-options: -Wall -threaded -O0
И это больше не строит. Я получаю целую кучу предупреждений, а затем множество неопределенных ссылок, таких как:
Linking dist/build/personal-website/personal-website ...
/usr/lib/ghc-7.0.3/libHSrts_thr.a(Linker.thr_o): In function
`internal_dlopen':
Linker.c:(.text+0x407): warning: Using 'dlopen' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/unix-2.4.2.0/libHSunix-2.4.2.0.a(HsUnix.o): In
function `__hsunix_getpwent':
HsUnix.c:(.text+0xa1): warning: Using 'getpwent' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/unix-2.4.2.0/libHSunix-2.4.2.0.a(HsUnix.o): In
function `__hsunix_getpwnam_r':
HsUnix.c:(.text+0xb1): warning: Using 'getpwnam_r' in statically
linked applications requires at runtime the shared libraries from the
glibc version used for linking
/usr/lib/libpq.a(thread.o): In function `pqGetpwuid':
(.text+0x15): warning: Using 'getpwuid_r' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/libpq.a(ip.o): In function `pg_getaddrinfo_all':
(.text+0x31): warning: Using 'getaddrinfo' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__63.o): In function `sD3z_info':
(.text+0xe4): warning: Using 'gethostbyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__164.o): In function `sFKc_info':
(.text+0x12d): warning: Using 'getprotobyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__155.o): In function `sFDs_info':
(.text+0x4c): warning: Using 'getservbyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/libpq.a(fe-misc.o): In function `pqSocketCheck':
(.text+0xa2d): undefined reference to `SSL_pending'
/usr/lib/libpq.a(fe-secure.o): In function `SSLerrmessage':
(.text+0x31): undefined reference to `ERR_get_error'
/usr/lib/libpq.a(fe-secure.o): In function `SSLerrmessage':
(.text+0x41): undefined reference to `ERR_reason_error_string'
/usr/lib/libpq.a(fe-secure.o): In function `initialize_SSL':
(.text+0x2f8): undefined reference to `SSL_check_private_key'
/usr/lib/libpq.a(fe-secure.o): In function `initialize_SSL':
(.text+0x3c0): undefined reference to `SSL_CTX_load_verify_locations'
(... snip ...)
Если я просто скомпилирую просто -static
и без -optl-static
все строится нормально, но приложение вылетает при попытке запуска на Heroku.
2011-12-28T01:20:51+00:00 heroku[web.1]: Starting process with command
`./dist/build/personal-website/personal-website -p 41083`
2011-12-28T01:20:51+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: error while loading shared libraries: libgmp.so.10:
cannot open shared object file: No such file or directory
2011-12-28T01:20:52+00:00 heroku[web.1]: State changed from starting
to crashed
Я попытался добавить libgmp.so.10 в LD_LIBRARY_PATH, как предложено здесь, а затем получил следующую ошибку:
2011-12-28T01:31:23+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: /lib/libc.so.6: version `GLIBC_2.14' not found
(required by ./dist/build/personal-website/personal-website)
2011-12-28T01:31:23+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: /lib/libc.so.6: version `GLIBC_2.14' not found
(required by /app/dist/build/personal-website/libgmp.so.10)
2011-12-28T01:31:25+00:00 heroku[web.1]: State changed from starting
to crashed
2011-12-28T01:31:25+00:00 heroku[web.1]: Process exited
Кажется, что версия libc, которую я собираю, отличается. Я также попытался добавить libc в пакет библиотек так же, как и для libgmp, но это привело к ошибке сегментации при запуске приложения на стороне Heroku.
Все отлично работает на моем ПК. Я использую 64-битную версию archlinux с ghc 7.0.3. Сообщение в блоге на официальном блоге Yesod выглядело довольно легко, но я в этом тупике. У кого-нибудь есть идеи? Если есть способ заставить эту штуку работать без статического строительства, я тоже открыт для этого.
РЕДАКТИРОВАТЬ
в Employed Russians
Ответ Я сделал следующее, чтобы исправить это.
Сначала создали новый каталог lib
под каталогом проекта и скопировал недостающие общие библиотеки в него. Вы можете получить эту информацию, запустив ldd path/to/executable
а также heroku run ldd path/to/executable
и сравнивая результат.
Я тогда сделал heroku config:add LD_LIBRARY_PATH=./lib
поэтому при запуске приложения динамический компоновщик будет искать библиотеки в новом каталоге lib.
Наконец, я создал виртуальную машину Ubuntu 11.10, а затем собрал и развернул ее в Heroku, у нее достаточно старый glibc, чтобы он работал на хосте Heroku.
Изменить: с тех пор я написал учебник на вики Yesod
4 ответа
Я понятия не имею, что такое Yesod, но я точно знаю, что означает каждая из ваших других ошибок.
Во-первых, вы не должны пытаться связывать статически. Полученное предупреждение совершенно верно: если вы статически связываетесь и используете одну из подпрограмм, для которых вы получаете предупреждение, вы должны организовать работу в системе сточно такой же версией libc.so.6, что и Вы использовали во время сборки.
Вопреки распространенному мнению, статическое связывание создаетменьше, а не больше переносимых исполняемых файлов в Linux.
Ваши другие (статические) ошибки ссылки вызваны отсутствиемlibopenssl.a
во время ссылки.
Но давайте предположим, что вы идете по "вменяемому" маршруту и используете динамическое связывание.
Для динамического связывания Linux (и большинство других UNIX) поддерживают обратную совместимость: старый двоичный код продолжает работать на более новых системах. Но они не поддерживают прямую совместимость (двоичный файл, построенный на более новой системе, обычноне работает на более старой).
Но это то, что вы пытаетесь сделать: вы собрали систему с glibc-2.14 (или новее), и вы работаете в системе с glibc-2.13 (или старше).
Еще одна вещь, которую вам нужно знать, это то, что glibc состоит из более чем 200 двоичных файлов, которые должны точно совпадать. Два ключевых двоичных файла /lib/ld-linux.so
а также /lib/libc.so.6
(но есть еще много: libpthread.so.0
, libnsl.so.1
и тд и тп). Если некоторые из этих двоичных файлов пришли из разных версий glibc, вы обычно получаете сбой. И это именно то, что вы получили, когда пытались разместить свой glibc-2.14 libc.so.6
наLD_LIBRARY_PATH
- больше не соответствует системе/lib/ld-linux
,
Итак, каковы решения? Есть несколько возможностей (в возрастающей сложности):
Вы могли бы скопировать
ld-2.14.so
(цель/lib/ld-linux
символическая ссылка) на целевую систему и вызовите ее явно:/path/to/ld-2.14.so --library-path <whatever> /path/to/your/executable
Это обычно работает, но может запутать приложение, которое смотрит на
argv[0]
и перерывы для приложений, которые повторно выполняют себя.Вы можете использовать более старую систему.
Вы могли бы использовать
appgcc
(эта опция исчезла, см. описание того, что было раньше).Вы можете настроить окружение chroot, соответствующее целевой системе, и создать внутри этого chroot.
Вы можете создать собственный кросс-компилятор Linux-to-Linux
У вас есть несколько вопросов.
Вы не должны создавать производственные двоичные файлы на передовых дистрибутивах. Библиотеки в производственной системе не будут напрямую совместимы.
Вы не должны связывать glibc статически - он всегда будет пытаться загрузить дополнительные библиотеки во время выполнения. Например сборка на основе процессора. Вот о чем ваши первые предупреждения.
Последние ошибки компоновщика выглядят так, как будто они связаны с отсутствующей библиотекой openssl в командной строке.
Но в целом - понизьте ваш дистрибутив.
У меня были похожие проблемы с запуском Heroku (который использует glibc-2.11), где у меня было приложение, которое требовало glibc-2.14, но у меня не было доступа к источнику, и я не мог пересобрать его. Я перепробовал много вещей, но ничего не получалось.
Мой обходной путь состоял в том, чтобы запустить сервис на Amazon Elastic Beanstalk и просто предоставить интерфейс API.
Я также нашел предоставленную информацию полезной, я думаю, что в различных описаниях отсутствует критическая проблема, с которой я также столкнулся, заставляя обновленную версию Vagrant снова начать работать.
Это внутренние ссылки на что-то вроде сложных установок, таких как Yesod для Heroku. Эти межстрановые ссылки должны быть сохранены.
Вот сценарий, который я написал, чтобы проблемы исчезли (по крайней мере, надеюсь, ненадолго):
#!/bin/bash
cd $HOME/
GLIBC_VERSION="2.17"
GLIBC_PREFIX="/usr/glibc/"
VAGRANT_VERSION="2.2.19"
# Install the basic build system utilities.
yum groupinstall -y "Development tools"
yum install -y curl patchelf
# Grab the tarball with the GNU libc source code.
curl -Lfo glibc-${GLIBC_VERSION}.tar.gz "https://ftp.gnu.org/gnu/glibc/glibc-${GLIBC_VERSION}.tar.gz"
echo "a3b2086d5414e602b4b3d5a8792213feb3be664ffc1efe783a829818d3fca37a glibc-${GLIBC_VERSION}.tar.gz" | sha256sum -c || exit 1
# Extract the secrets and get ready to rumble.
tar xzvf glibc-${GLIBC_VERSION}.tar.gz
# The configure script requrires an independent build directory.
mkdir -p glibc-build && cd glibc-build
# Configure glibc with a GLIBC_PREFIX so it doesn't conflict with distro libc files..
../glibc-${GLIBC_VERSION}/configure --prefix="${GLIBC_PREFIX}" --libdir="${GLIBC_PREFIX}/lib" \
--libexecdir="${GLIBC_PREFIX}/lib" --enable-multi-arch
# Compile and then install GNU libc.
make -j8 && make install
# Download and install Vagrant.
curl -Lfo vagrant_${VAGRANT_VERSION}_x86_64.rpm "https://releases.hashicorp.com/vagrant/${VAGRANT_VERSION}/vagrant_${VAGRANT_VERSION}_x86_64.rpm"
echo "990e8d2159032915f21c0f1ccdcbca1a394f7937e06e43dc1dabe605d208dc20 vagrant_${VAGRANT_VERSION}_x86_64.rpm" | sha256sum -c || exit 1
yum install -y vagrant_${VAGRANT_VERSION}_x86_64.rpm
# Patch the binaries and shared libraries inside the Vagrant directory, so they use the new version of GNU libc.
(find /opt/vagrant/ -type f -exec file {} \; )| grep "dynamically linked" | awk -F':' '{print $1}' | while read FILE ; do
patchelf --set-rpath /opt/vagrant/embedded/lib:/opt/vagrant/embedded/lib64:/usr/glibc/lib:/usr/lib64:/lib64:/lib --set-interpreter /usr/glibc/lib/ld-linux-x86-64.so.2 "${FILE}"
done
Сценарий должен быть довольно простым для понимания и легко адаптироваться к любому MacGuffin , который вы хотите заставить работать, при условии, что вы его понимаете.
Единственная сложная часть - это
rpath
вы переходите к
patchelf
. Upi должен убедиться, что вы сохранили пути поиска и приоритет, требуемый вашим программным обеспечением. Или вы решаете одну проблему только для того, чтобы создать еще одно не менее неприятное препятствие.
PS Не забудьте обновить хеши для любого файла, который вы удалили. В частности, вам нужно скомпилировать/установить другую версию GNU libc, вам нужно будет обновить этот хэш, чтобы он соответствовал версии, которую вы хотите использовать.