You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu20.04静态链接Python3.8嵌入C程序编译报-fPIE错误

问题背景

尝试编译运行Python官方文档《Embedding Python in Another Application》章节的高层嵌入示例时编译失败,运行环境为Ubuntu 20.04.2 LTS,使用系统预装的静态编译版本Python3.8,已安装libpython3-dev和libpython3.8-dev软件包。

官方高层嵌入示例文档地址:https://docs.python.org/3/extending/embedding.html#very-high-level-embedding


已尝试操作
  • 编写测试代码main.c,内容如下:
#define PY_SSIZE_T_CLEAN
#include <Python.h>

int
main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime\n"
                       "print('Today is', ctime(time()))\n");
    if (Py_FinalizeEx() < 0) {
        exit(120);
    }
    PyMem_RawFree(program);
    return 0;
}
  • 参照官方文档Unix类系统编译链接指引,通过python3-config获取gcc编译、链接参数,输出如下:

官方Unix编译指引地址:https://docs.python.org/3/extending/embedding.html#compiling-and-linking-under-unix-like-systems

tian@tian-B250M-Wind:~$ python3-config --cflags
-I/usr/include/python3.8 -I/usr/include/python3.8  -Wno-unused-result -Wsign-compare -g -fdebug-prefix-map=/build/python3.8-4wuY7n/python3.8-3.8.10=. -specs=/usr/share/dpkg/no-pie-compile.specs -fstack-protector -Wformat -Werror=format-security  -DNDEBUG -g -fwrapv -O3 -Wall
tian@tian-B250M-Wind:~$ python3-config --ldflags
-L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -L/usr/lib  -lcrypt -lpthread -ldl  -lutil -lm -lm

注:python3-config输出中存在重复值,并非输入笔误。

  • 拼接参数执行gcc编译命令,指定链接静态库/usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a,执行命令如下:
gcc -I/usr/include/python3.8 -I/usr/include/python3.8  -Wno-unused-result -Wsign-compare -g -fdebug-prefix-map=/build/python3.8-4wuY7n/python3.8-3.8.10=. -specs=/usr/share/dpkg/no-pie-compile.specs -fstack-protector -Wformat -Werror=format-security  -DNDEBUG -g -fwrapv -O3 -Wall -o main main.c /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -L/usr/lib  -lcrypt -lpthread -ldl  -lutil -lm -lm

编译时出现大量与-fPIE相关的链接错误,典型错误提示如下:

/usr/bin/ld: /tmp/ccdMZ2Yk.o: relocation R_X86_64_32 against `.rodata.str1.8' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(obmalloc.o): relocation R_X86_64_32 against `.text.hot' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(initconfig.o): relocation R_X86_64_32 against symbol `_PyRuntime' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(pathconfig.o): relocation R_X86_64_32 against symbol `_Py_path_config' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(preconfig.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(pylifecycle.o): relocation R_X86_64_32 against symbol `_PyRuntime' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(pystate.o): relocation R_X86_64_32 against `.rodata.str1.8' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(pythonrun.o): relocation R_X86_64_32 against symbol `_PyParser_Grammar' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a(pytime.o): relocation R_X86_64_32S against symbol `PyFloat_Type' can not be used when making a PIE object; recompile with -fPIE
.....

后续替换同目录下的libpython3.8-pic.a进行链接依然编译失败。


对照测试

在python:3.10.5-bullseyeDocker镜像中,使用动态编译版本的Python3.10进行测试,通过python3-config获取的参数如下:

root@tian-B250M-Wind:/# python3-config --cflags
-I/usr/local/include/python3.10 -I/usr/local/include/python3.10  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall
root@tian-B250M-Wind:/# python3-config --ldflags
 -L/usr/local/lib  -lcrypt -lpthread -ldl  -lutil -lm -lm

在链接参数末尾追加-lpython3.10后执行编译:

gcc -I/usr/local/include/python3.10 -I/usr/local/include/python3.10  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall -o main main.c -L/usr/local/lib  -lcrypt -lpthread -ldl  -lutil -lm -lm -lpython3.10

编译成功,执行./main可正常输出当前时间,运行结果符合预期:

root@tian-B250M-Wind:/# ./main
Today is Thu Jul 14 10:39:20 2022

问题解答

1. Ubuntu预装Python3.8静态链接失败的根本原因

本质是Ubuntu 20.04默认编译配置和系统自带静态Python库的编译属性不匹配:

  • Ubuntu 20.04版本的gcc默认启用-fPIE参数编译位置无关可执行文件,要求所有链接到最终程序的目标文件、静态库必须使用PIC(位置无关代码)格式编译,否则就会触发看到的R_X86_64_32重定位错误。
  • python3-config --cflags输出的-specs=/usr/share/dpkg/no-pie-compile.specs是Debian/Ubuntu打包Python时用的内部参数,作用是关闭PIE编译,但手动调用gcc时,全局默认的PIE配置优先级高于该specs规则,最终main.c按PIE格式编译,系统自带的libpython3.8.a是无PIC标记的非位置无关代码,libpython3.8-pic.a虽然命名带pic但打包时存在编译参数缺失,两者都无法满足PIE链接要求,最终报错。
  • Docker环境下动态链接成功的原因是动态库本身必须为PIC格式,链接时不存在静态库重定位冲突,因此可以正常编译运行。

2. 静态链接libpython的可行方案

方案1:直接在Ubuntu 20.04上修复编译参数(最快验证)

编译时手动加-no-pie参数关闭gcc默认的PIE编译,同时把no-pie的specs参数放在命令最前面保证生效,命令如下:

gcc -no-pie -specs=/usr/share/dpkg/no-pie-compile.specs $(python3-config --cflags) -o main main.c /usr/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a $(python3-config --ldflags) -lpython3.8

注意:该方案编译出的是非PIE可执行文件,部分强安全加固场景下可能不允许使用,仅做功能验证用。

方案2:自行编译静态版本Python(生产可用,无发行版打包问题)

全新环境下从源码编译带PIC支持的静态Python库,步骤如下:

  1. 安装编译依赖:
sudo apt update && sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev
  1. 下载对应版本Python源码(以3.8.10为例),解压后进入源码目录执行配置,开启静态编译+PIC支持:
./configure --prefix=/opt/python3.8-static --disable-shared --with-pic CFLAGS="-fPIC"
  1. 编译安装(-j后面跟CPU核心数加快编译速度):
make -j$(nproc) && sudo make install
  1. 用自行编译的静态Python的config工具获取参数编译即可,不需要额外加特殊参数:
gcc $(/opt/python3.8-static/bin/python3-config --cflags) -o main main.c /opt/python3.8-static/lib/libpython3.8.a $(/opt/python3.8-static/bin/python3-config --ldflags) -ldl -lpthread -lutil -lm

编译出来的可执行文件不依赖系统Python动态库,可以直接拷贝到同架构的其他Ubuntu 20.04机器上运行。


内容的提问来源于stack exchange,提问作者Rick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:39:16