在Linux x86_64上为PowerPC交叉编译Python的greenlet和gevent

时间:2012-07-20 22:13:51

标签: python linux cross-compiling gevent greenlets

在我的Linux x86_64主机上,我正在尝试为我的PowerPC目标交叉编译一些其他Python模块,特别是greenletgeventgevent-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

我开始怀疑这是否是编译器中的错误,因为宏看起来很简单!有什么建议? ......谢谢!

3 个答案:

答案 0 :(得分: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(甚至留下描述“Port for PowerPC上的AIX“),并没有明显触及。 OS X和AIX当时只有gcc 3。所以,也许这就是当时每个人都有效的原因,并不适合你。也许只是获得一个较旧的交叉编译器将解决您的问题。但我会先尝试修复代码。

答案 1 :(得分:1)

  

为什么在我的主机系统上从/usr/include/python2.7中提取setup.py?

不是。 /usr/include/python2.7/pyport.h:849指的是用于构建主机Python的源代码,它可能实际上也可能不在您的系统上。

  

我无法找到目标上的目录。如何为目标创建它?

我不确定你是否愿意。我想你已经离开了红鲱鱼。

这是您问题的关键:

$ python ./setup.py build

您正在使用主机的本机Python来构建扩展,并且您没有做任何事情来告诉它您希望扩展交叉编译。所以,据他所知,你正在尝试为它构建greenlet,而不是为其他Python构建。因此这样的事情:

  

创建build / temp.linux-x86_64-2.7

但是当然你给它的ARM交叉编译器,它不能为你的x86_64主机python编译扩展,因此:

  

/usr/include/python2.7/pyport.h:849:2:错误:#error“LONG_BIT定义对于平台来说是错误的(糟糕的gcc / glibc配置?)。”

您的主机Python是使用为64位LP系统设置的LONG_BIT构建的,但它正在尝试使用32位系统的编译器构建代码。

博文http://kynesim.blogspot.co.uk/2012/06/cross-compiling-python-for-arm-with.html(从您引用的那篇链接)显示了如何构建第三方C扩展模块。正如你所看到的,它并不是完全无关紧要的,可能需要一些实验来使它工作,但看起来它是可行的。

答案 2 :(得分:0)

python ./setup.py build

我们正在尝试交叉构建扩展,但是系统使用python-config和错误的pyconfig.h。请参见difference between x86_64arm pyconfig。不要尝试使用i686容器来修复LONG_BIT问题,这是错误的方法,以后您会收到更复杂的问题。

有多个python扩展可以为python-config创建虚拟环境。但是有一种100%可靠的方法,无需进行任何扩展。

  1. 创建amd64容器并安装基本系统(buildah或docker)。
  2. 将目标工具链安装到此容器中(crossdev)。
  3. 使用目标工具链在目标根文件夹内安装除python扩展名以外的所有必需软件。
  4. 为容器的python添加补丁,以强制python-config返回目标include and library pathes并重建容器的python。
  5. 使用目标工具链将所有必需的python扩展安装到目标根文件夹中。
  6. 从容器中提取目标根文件夹并将其删除。