【问题标题】:cross-compile of Python's greenlet and gevent on Linux x86_64 for PowerPC在 Linux x86_64 for PowerPC 上交叉编译 Python 的 greenlet 和 gevent
【发布时间】:2012-07-20 05:15:46
【问题描述】:

在我的 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

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

【问题讨论】:

  • 鉴于该博客文章中的 cmets 似乎暗示人们甚至还没有获得目标 Python 来导入标准库模块,因此这些说明不适用于第三个也就不足为奇了-派对模块……
  • 不是那个问题(标题有问题?),我可能遗漏了一些东西,但你没有指定 PPC 而不是 ARM 工具链吗?
  • @TiloWiklund:很好。他复制的博客是关于ARM和PPC的交叉编译,他似乎复制了错误的。这实际上并不能解释他的问题,因为如果他改用 ARM 工具链,也会发生完全相同的事情。但这意味着在继续尝试为其构建扩展之前,他甚至没有尝试过最低限度地测试他构建的 Python。
  • @TiloWiklund:谢谢,这是一个错字。确实是 PPC。
  • @abarnet:根据我最初的问题,我已经可以交叉编译 Python 2.7.2。请原谅我的错字。

标签: python linux cross-compiling gevent greenlets


【解决方案1】:

也许你应该问一个新问题,因为这里确实(至少)有两个完全独立的问题。但是,看看你的第二个问题:

__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。所以,也许这就是它当时对每个人都有效的原因,而不是对你有效的原因。也许只是获得一个较旧的交叉编译器就可以解决您的问题。但我会先尝试修复代码。

【讨论】:

  • 谢谢!这就是问题所在。顺便说一句,如果我强制 -O2 编译器优化,编译器将正确汇编。 FWIW,我在这里从模块作者那里收到了类似的支持信息:link ... 感谢专家、详细和清晰的解释。我知道这花了一些时间,我非常感谢。 :)
  • 我可以相信 -O2 会导致它在寄存器中分配 stackref 而 -O0 将它留在堆栈中。但这并不是真正的修复,因为它恰好在您的机器上工作,而不是原始代码是正确的,因为它恰好在原始编码器的机器上工作......无论如何,希望你能让他们接受上游的 =r 修复(并对其进行测试,当然,而不是按照我对 gcc 内联汇编的回忆……)。
【解决方案2】:

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

不是。 /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: #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 扩展模块。如您所见,它并非完全微不足道,可能需要进行一些试验才能使其发挥作用,但看起来可行。

【讨论】:

  • 我如何告诉我的开发主机的 python 我正在构建一个超出我已经设置的 env-vars 的交叉编译模块?
  • @barnert:感谢您的更新和链接,但是在研究了该博客之后,我认为通过上述更新,我已经更接近于解决方案了,更不用说需要解开混乱的环境了那个食谱。还有其他想法吗? ...谢谢!
【解决方案3】:
python ./setup.py build

我们正在尝试交叉构建一个扩展,但系统使用了python-config 和错误的pyconfig.h。请参阅difference betweenx86_64armpyconfig。不要尝试使用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. 从容器中提取目标根文件夹并将其删除。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-18
    • 2022-01-03
    • 2017-05-24
    • 2021-01-21
    相关资源
    最近更新 更多