Кросс-компиляция Python Greenlet и Gevent на Linux x86_64 для PowerPC

На моем хосте Linux x86_64 я пытаюсь кросс-компилировать некоторые дополнительные модули Python для моей цели PowerPC, в частности, greenlet, gevent и gevent-websockets. В настоящее время я застрял, просто пытаясь создать кросс-модуль greenlet.

Используя информацию с этого сайта:

http://randomsplat.com/id5-cross-compiling-python-for-embedded-linux.html

Я смог кросс-компилировать Python 2.7.2, используя эту настройку для моей среды сборки

# Undo variables for cross-compile environment
unset ROOT
unset SDKDIR
unset KLIBDIR
unset NFSDIR
unset CONFIG
unset CONFIGURED
unset ARCH
unset OS
unset TOOLCHAIN_BASE
unset TOOLCHAIN_BIN
unset CROSS_COMPILE
unset c
unset KERNEL_DIR
unset AS
unset LD
unset CC
unset AR
unset STRIP
unset SSTRIP
unset OBJCOPY
unset OBJDUMP
unset MAKE
unset CFLAGS

# Set cross-compile variables:
export TOOLCHAIN=/opt/freescale/usr/local/gcc-4.3.74-eglibc-2.8.74-dp-2/powerpc-none-linux-gnuspe/bin/powerpc-none-linux-gnuspe-
export CC=${TOOLCHAIN}gcc
export CXX=${TOOLCHAIN}g++
export AR=${TOOLCHAIN}ar
export RANLIB=${TOOLCHAIN}ranlib
export BLDSHARED="${TOOLCHAIN}gcc -shared"
export LDSHARED="${TOOLCHAIN}gcc -shared"
export RFS="../../ltib/rootfs"
export CFLAGS="-save-temps -Wall -I${RFS}/usr/include -I${RFS}/include/python2.7 -L${RFS}/usr/lib -L${RFS}/lib"
export LDFLAGS="-I${RFS}/usr/include -I${RFS}/include/python2.7 -L${RFS}/usr/lib -L${RFS}/lib"
export CROSS_COMPILE=ppc-linux
export CROSS_COMPILE_TARGET=yes
export HOSTARCH=ppc-linux
export BUILDARCH=x86_64-linux-gnu

Конфигурирование моей среды с помощью приведенного выше сценария и последующая попытка построить модуль greenlet дает:

$ python ./setup.py build
running build
running build_ext
building 'greenlet' extension
creating build
creating build/temp.linux-x86_64-2.7
/opt/freescale/usr/local/gcc-4.3.74-eglibc-2.8.74-dp-2/powerpc-none-linux-gnuspe/bin/powerpc-none-linux-gnuspe-gcc -I../../../ltib/rootfs/usr/include -L../../../ltib/rootfs/usr/lib -L../../../ltib/rootfs/lib -fPIC -I/usr/include/python2.7 -c greenlet.c -o build/temp.linux-x86_64-2.7/greenlet.o
In file included from /usr/include/python2.7/Python.h:58,
                 from greenlet.h:8,
                 from greenlet.c:5:
/usr/include/python2.7/pyport.h:849:2: error: #error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)."
error: command '/opt/freescale/usr/local/gcc-4.3.74-eglibc-2.8.74-dp-2/powerpc-none-linux-gnuspe/bin/powerpc-none-linux-gnuspe-gcc' failed with exit status 1

Почему setup.py тянет с /usr/include/python2.7 на моей хост-системе? Я не могу найти этот каталог на моей цели. Как я могу создать его для моей цели?

Какие-либо предложения?

Спасибо!

Тревор

ОБНОВЛЕНИЕ № 1:

Мои относительные ссылки на копию моего хоста rootfs цели были неверны. Исправление и повторное получение дает:

$ python ./setup.py build
running build
running build_ext
building 'greenlet' extension
creating build
creating build/temp.linux-x86_64-2.7
/opt/freescale/usr/local/gcc-4.3.74-eglibc-2.8.74-dp-2/powerpc-none-linux-gnuspe/bin/powerpc-none-linux-gnuspe-gcc -save-temps -Wall -I../../ltib/rootfs/usr/include -I../../ltib/rootfs/include/python2.7 -L../../ltib/rootfs/usr/lib -L../../ltib/rootfs/lib -fPIC -I/usr/include/python2.7 -c greenlet.c -o build/temp.linux-x86_64-2.7/greenlet.o
greenlet.s: Assembler messages:
greenlet.s:832: Error: syntax error; found `(' but expected `,'
greenlet.s:832: Error: junk at end of line: `(31),1'
error: command '/opt/freescale/usr/local/gcc-4.3.74-eglibc-2.8.74-dp-2/powerpc-none-linux-gnuspe/bin/powerpc-none-linux-gnuspe-gcc' failed with exit status 1

По крайней мере, он находит больше библиотек включения моей цели, но теперь я действительно в замешательстве!:(

Есть еще предложения?

Спасибо!

ОБНОВЛЕНИЕ № 2:

Добавляя -save-temps флаг компилятору (обновленная ошибка выше), я смог сохранить и изучить промежуточный код ассемблера, который упоминался в приведенном выше сообщении об ошибке. Пунктирные линии:

#APP
 # 52 "platform/switch_ppc_linux.h" 1
    mr 8(31), 1
 # 0 "" 2

Операция MR (регистр перемещения) довольно проста, принимая только 2 аргумента (mr to-reg, from-reg). Я не знаю, как были добавлены скобки с дополнительным номером регистра. FWIW, здесь приведенный макрос в указанном выше заголовочном файле:

#define STACK_REFPLUS 1

#ifdef SLP_EVAL

#define STACK_MAGIC 3

/* !!!!WARNING!!!! need to add "r31" in the next line if this header file
 * is meant to be compiled non-dynamically!
 */
#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \
       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \
       "cr2", "cr3", "cr4"
static int
slp_switch(void)
{
    register int *stackref, stsizediff;
    __asm__ volatile ("" : : : REGS_TO_SAVE);
    __asm__ ("mr %0, 1" : "=g" (stackref) : );
    {
        SLP_SAVE_STATE(stackref, stsizediff);
        __asm__ volatile (
            "mr 11, %0\n"
            "add 1, 1, 11\n"
            "add 30, 30, 11\n"
            : /* no outputs */
            : "g" (stsizediff)
            : "11"
            );
        SLP_RESTORE_STATE();
    }
    __asm__ volatile ("" : : : REGS_TO_SAVE);
    return 0;
}

#endif

Я начинаю задаваться вопросом, является ли это ошибкой в ​​компиляторе, потому что макрос кажется достаточно простым! Какие-либо предложения? ... Спасибо!

2 ответа

Решение

Возможно, вам следовало задать новый вопрос, потому что здесь действительно есть (по крайней мере) две совершенно независимые проблемы. Но, глядя на вашу вторую проблему:

__asm__ ("mr %0, 1" : "=g" (stackref) : );

Это не верно. Я объясню почему ниже, но сначала, следующее изменение, вероятно, исправит это:

__asm__ ("mr %0, 1" : "=r" (stackref) : );

Вам также может понадобиться изменить "g" (stsizediff) ниже до "r" (stsizediff),

Итак, что не так с существующей версией? Сначала посмотрим, как определяется stackref:

register int *stackref, stsizediff;

register является подсказкой для компилятора, говоря, что вы думаете, что он может сделать вещи быстрее или лучше, если он выделит регистр для stackref вместо использования расположения в стеке, не является обязательным требованием. Если stackref заканчивается в R12, отлично; если это заканчивается 8 байтами в стеке стека, это тоже хорошо. Любой из них является совершенно законным, если он не нарушает никаких ограничений.

Итак, какие ограничения существуют на stackref? Единственный находится в этом блоке asm, указанном выше. У тебя есть "=g" (stackref) в качестве выходного операнда. = означает, что это ограничение только для записи, и g означает, что он должен быть в регистре, ячейке памяти или непосредственном значении.

Так что компилятор не делает ничего плохого. Он выделяет stackref 8 байт стека, что соответствует ограничению (это место в памяти), а затем подставляет это значение в "%0"и вы получите:

mr 8(31), 1

В этом нет ничего плохого - пока вы не попытаетесь собрать его, и ассемблер не заметит, что вы пытаетесь использовать 8(31) с кодом операции, который принимает только регистры. Но проблема не в компиляторе или ассемблере, а в коде. Вы попросили его использовать stackref в качестве операнда для mrи не заставлял stackref быть регистром, чтобы вы получили то, что просили.

Во всяком случае, изменение "=g" в "=r" изменяет ограничение с "любой регистр, ячейка памяти или непосредственное значение" на "любой регистр общего назначения". Это означает, что компилятор должен поставить stackref в общем реестре. Или, если он не может по какой-то причине, он потерпит неудачу и скажет вам, почему, вместо генерации сборки, которая не будет собираться.

Итак, почему это работает для оригинального автора? Ну, ему, наверное, повезло, и stackref был выделен, скажем, R12, вместо 8 байтов в кадре стека, поэтому он закончил с mr 12, 1, который собирает просто отлично.

Или еще одна возможность. Глядя на дерево git, похоже, что код был разработан на Mac OS X, затем перенесен в AIX (людьми, в основном разработчиками Mac) десять лет назад, а затем дословно скопировал из AIX в linux (даже оставив описание "Порт для AIX на PowerPC"), и не тронут значительно, так как Тогда и OS X, и AIX имели только gcc 3. Так что, возможно, именно поэтому он работал для всех в то время, и не работает для вас. И, возможно, просто получить старый кросс-компилятор решит вашу проблему. Но я бы попробовал исправить код первым.

Почему файл setup.py извлекается из /usr/include/python2.7 в моей хост-системе?

Это не. /usr/include/python2.7/pyport.h:849 относится к источнику, используемому для сборки вашего хоста Python, который может быть, а может и не быть в вашей системе.

Я не могу найти этот каталог на моей цели. Как я могу создать его для моей цели?

Я не уверен, что ты хочешь. Я думаю, что вы на красной сельди.

Вот ключ к вашей проблеме:

$ python ./setup.py build

Вы используете собственный Python своего хоста для создания расширения и ничего не делаете, чтобы сказать, что хотите, чтобы расширение было кросс-скомпилировано. Итак, насколько он знает, вы пытаетесь построить гринлет для него, а не для другого Python. Отсюда и такие вещи:

создание build/temp.linux-x86_64-2.7

Но, конечно, вы даете ему кросс-компилятор ARM, который не сможет скомпилировать расширения для вашего питона x86_64, следовательно, это:

/usr/include/python2.7/pyport.h:849:2: error: #error "Определение LONG_BIT неверно для платформы (неверный конфиг gcc / glibc?)."

Ваш хост Python был собран с LONG_BIT, установленным для 64-битной системы LP, но он пытается собрать код с компилятором для 32-битной системы.

В блоге http://kynesim.blogspot.co.uk/2012/06/cross-compiling-python-for-arm-with.html (ссылка на который вы указали) показано, как создавать сторонние модули расширения C, Как видите, это не совсем тривиально, и, возможно, потребуется немного экспериментировать, чтобы заставить его работать, но похоже, что это выполнимо.

python ./setup.py build

Мы пытаемся создать расширение, но система использует python-config и неправильно pyconfig.h. Увидеть разницу между x86_64 а также arm pyconfig. Не пытайтесь использоватьi686 контейнер для фиксации LONG_BIT проблема, это неправильный путь, позже вы получите более сложные вопросы.

Существует несколько расширений Python, которые создают виртуальную среду для python-config. Но есть один 100% надежный способ без всяких продлений.

  1. Создайте amd64 контейнер и установить базовую систему (билд или докер).
  2. Установите целевой набор инструментов в этот контейнер (crossdev).
  3. Установите все необходимое программное обеспечение, кроме расширений Python, в целевую корневую папку, используя целевую цепочку инструментов.
  4. Добавить патч для контейнерного питона, который заставляет python-configдля возврата целевого включения и пути к библиотеке и пересборки контейнера python.
  5. Установите все необходимые расширения Python с помощью целевой цепочки инструментов в целевую корневую папку.
  6. Извлеките целевую корневую папку из контейнера и удалите ее.
Другие вопросы по тегам