Прежде всего, немного предыстории: скрипт определения платформы, который запускается во время сборки, использует утилиту uname(1)
(таким образом, uname(2)
системный вызов) для идентификации оборудования, на котором он работает:
root@6e4b69adfd4c:/gcc-4.8.5# grep 'uname -m' config.guess
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
На вашем 64-битном компьютере uname -m
возвращает x86_64
.Однако есть системный вызов, который позволяет переопределить этот результат: personality(2)
.Когда процесс вызывает personality(2)
, он и его последующие вилки (дочерние элементы) начинают видеть поддельные результаты при вызове uname(2)
.Таким образом, есть возможность попросить ядро предоставить ложную информацию об оборудовании в uname(2)
.
Используемый вами базовый образ (jnickborys/i386-ubuntu:12.04
) содержит 32-разрядные двоичные файлы и определяет точку входа /usr/bin/linux32
, который вызывает personality(PER_LINUX32)
, чтобы попросить ядро сделать вид, что оно работает на 32-разрядном оборудовании, и вернуть i686
в uname(2)
(это можно проверить, используя docker inspect
и strace
соответственно).Это позволяет сделать вид, что контейнерный процесс выполняется в 32-разрядной среде.
В чем разница между выполнением директивы build в RUN
и вручную в контейнере?
Когда вы выполняетесборка в RUN
, Docker не использует точку входа для запуска команд.Вместо этого он использует то, что указано в директиве SHELL
(по умолчанию /bin/sh -c
).Это означает, что индивидуальность оболочки, выполняющей сборку, не изменяется, и она (и дочерние процессы) видит реальную аппаратную информацию - x86_64
, таким образом, вы получаете x86_64-unknown-linux-gnu
тип системы сборки в 32-битной среде исборка завершается неудачей.
Когда вы запускаете сборку вручную в контейнере (например, после ее запуска с использованием docker run -it jnickborys/i386-ubuntu:12.04
и выполнения тех же шагов, что и в Dockerfile), точка входа вызывается, таким образом, изменяется личностьи ядро начинает сообщать, что оно работает на 32-разрядном оборудовании (i686
), поэтому вы получаете i686-pc-linux-gnu
тип системы сборки, и сборка выполняется правильно.
Как это исправить?Зависит от того, что вы хотите.Если ваша цель - создать gcc для 64-битной среды, просто используйте 64-битный базовый образ.Если вы хотите построить для 32-битной среды, один из ваших вариантов - изменить SHELL
, используемый для RUN
с до этих RUN
с:
SHELL ["/usr/bin/linux32", "/bin/sh", "-c"]
Это заставит Docker выполнитьRUN
с измененной индивидуальностью, поэтому тип системы сборки будет определен правильно (i686-pc-linux-gnu
), и сборка будет выполнена успешно.При необходимости вы можете изменить SHELL
обратно на /bin/sh -c
после сборки.