在我的Linux x86_64主机上,我正试图为我的PowerPC目标交叉编译一些额外的Python模块,特别是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
中提取?我在目标上找不到那个目录。我如何为我的目标创建它?
有什么建议吗?
谢谢!
Trevor
更新#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, %0n"
"add 1, 1, 11n"
"add 30, 30, 11n"
: /* no outputs */
: "g" (stsizediff)
: "11"
);
SLP_RESTORE_STATE();
}
__asm__ volatile ("" : : : REGS_TO_SAVE);
return 0;
}
#endif
我开始怀疑这是否是编译器中的一个错误,因为宏似乎足够简单!有什么建议吗。。。谢谢
也许你应该问一个新问题,因为这里确实(至少)有两个完全独立的问题。但是,看看你的第二个问题:
__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上开发的,十年前(由主要是Mac开发人员的人)移植到AIX,然后逐字逐句地从AIX复制到linux(甚至留下了"PowerPC上的AIX端口"的描述),从那以后就没有什么变化了。当时OSX和AIX都只有gcc3。所以,也许这就是当时它对每个人都有效,但对你不起作用的原因。也许只需要一个旧的交叉编译器就能解决你的问题。但我会先尝试修复代码。
为什么setup.py在我的主机系统上从/usr/include/python2.7中提取?
事实并非如此。/usr/include/python2.7/pyport.h:849
指的是用于构建主机Python的源代码,该源代码可能实际存在于您的系统中,也可能不存在于系统中。
我在目标上找不到那个目录。我如何为我的目标创建它?
我不确定你想不想。我想你是在转移注意力。
这是你的问题的关键:
$ python ./setup.py build
您正在使用主机的原生Python来构建扩展,并且您没有做任何事情来告诉它您想要交叉编译扩展。因此,据它所知,您正试图为它构建greenlet,而不是为其他Python构建greenlet。因此,事情是这样的:
创建内部版本/临时版本linux-x86_64-2.7
但当然,你给它提供了ARM交叉编译器,它将无法为x86_64主机python编译扩展,因此:
/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
创建虚拟env。但有一种100%可靠的方法,没有任何扩展。
- 创建
amd64
容器并安装基本系统(buildah或docker) - 将目标工具链安装到此容器中(crossdev)
- 使用目标工具链在目标根文件夹中安装除python扩展之外的所有必需软件
- 为容器的python添加补丁,强制
python-config
返回目标include和库路径并重建容器的python - 使用目标工具链将所有必需的python扩展安装到目标根文件夹中
- 从容器中提取目标根文件夹并将其删除