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

生成嵌入Python脚本的FMU:无Ubuntu权限安装Python环境的解决方案咨询

解决无管理员权限Ubuntu系统下嵌入Python脚本的FMU生成问题

方案1:修改PythonFMU的CMake脚本,嵌入独立Python环境

步骤1:编译独立的Python解释器(无管理员权限)

在Ubuntu20.04环境(或同版本Docker容器)中,从源码编译仅用户权限的独立Python版本:

# 下载兼容Ubuntu20.04的Python源码(以3.8为例)
wget https://www.python.org/ftp/python/3.8.18/Python-3.8.18.tgz
tar xzf Python-3.8.18.tgz
cd Python-3.8.18
# 指定安装到用户目录,编译为静态链接版本
./configure --prefix=$HOME/my_python --enable-shared=no --enable-static=yes
make -j$(nproc)
make install

编译完成后,$HOME/my_python目录包含完整的独立Python环境,包括解释器、标准库和pip。

步骤2:安装依赖到独立环境

用独立pip安装脚本所需依赖:

$HOME/my_python/bin/pip install numpy pandas  # 替换为你的实际依赖

步骤3:修改PythonFMU的CMake配置

找到PythonFMU项目的CMakeLists.txt,做以下调整:

  1. 指定独立Python路径:替换系统Python查找逻辑,直接指向你的独立环境:
set(Python_ROOT_DIR "$ENV{HOME}/my_python")
set(Python_INCLUDE_DIR "${Python_ROOT_DIR}/include/python3.8")
set(Python_LIBRARY "${Python_ROOT_DIR}/lib/libpython3.8.a")
  1. 嵌入Python环境到FMU:添加规则,将独立Python的核心目录复制到FMU的resources文件夹:
# 复制Python解释器
add_custom_command(TARGET your_fmu_target POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${Python_ROOT_DIR}/bin"
        "${FMU_OUTPUT_DIR}/resources/python/bin"
)
# 复制Python标准库与依赖包
add_custom_command(TARGET your_fmu_target POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${Python_ROOT_DIR}/lib/python3.8"
        "${FMU_OUTPUT_DIR}/resources/python/lib/python3.8"
)
  1. 调整FMU初始化逻辑:在PythonFMU的C++ wrapper代码中,设置Python环境变量指向内部路径:
// 获取FMU资源路径
const char* resourcePath = fmi2GetResourcePath(instance);
std::string pythonBinPath = std::string(resourcePath) + "/python/bin/python3.8";
std::string pythonLibPath = std::string(resourcePath) + "/python/lib/python3.8";

// 设置PYTHONPATH
setenv("PYTHONPATH", pythonLibPath.c_str(), 1);

// 初始化Python解释器时指定内部路径
Py_SetProgramName((wchar_t*)pythonBinPath.c_str());
Py_Initialize();

方案2:用PyInstaller打包Python脚本为独立二进制,再封装成FMU

此方案无需修改PythonFMU核心CMake,实现更简单:

步骤1:打包Python脚本为独立二进制

在Ubuntu20.04环境下,用PyInstaller生成不依赖系统Python的单文件二进制:

pip install pyinstaller
pyinstaller --onefile --target-platform linux-x86_64 your_script.py

生成的dist/your_script为独立可执行文件。

步骤2:封装成FMU

  1. 基于PythonFMU编写简单wrapper,在doStep函数中调用二进制传递数据:
from pythonfmu import FmuBuilder, Fmu2Slave

class MySlave(Fmu2Slave):
    def __init__(self, instanceName, fmuGUID, fmuResourceLocation, mimeType, visible, logLevel):
        super().__init__(instanceName, fmuGUID, fmuResourceLocation, mimeType, visible, logLevel)
        self.input_val = 0.0
        self.output_val = 0.0
        self.script_path = f"{fmuResourceLocation}/your_script"

    def doStep(self, currentTime, stepSize):
        import subprocess
        result = subprocess.run([self.script_path, str(self.input_val)], capture_output=True, text=True)
        self.output_val = float(result.stdout.strip())
        return fmi2Status.ok

if __name__ == "__main__":
    FmuBuilder.build_FMU(MySlave, "MyPythonFMU", "1.0", "me", resources=["dist/your_script"])
  1. 打包时通过resources参数将二进制加入FMU的resources目录。

方案3:用Nuitka编译Python脚本为C++代码,静态链接到FMU

此方案将Python代码直接编译为机器码,完全消除对Python解释器的依赖:

步骤1:用Nuitka编译Python脚本

pip install nuitka
nuitka --standalone --static-libpython=yes --output-dir=compiled your_script.py

编译后compiled/your_script.dist目录包含静态链接的可执行文件。

步骤2:与FMU wrapper静态编译

用FMU SDK编写C++ wrapper,直接调用编译后的Python代码导出函数,再将wrapper与Nuitka生成的目标文件一起编译为FMU二进制模块,最终打包成FMU。该方式生成的FMU体积更小、运行效率更高。

关键注意事项

  • 所有打包操作必须在Ubuntu20.04环境下完成,确保二进制与目标系统兼容。
  • 测试时在目标系统直接加载FMU,不要设置任何Python相关环境变量,验证运行状态。
  • 对于依赖C扩展的Python库(如numpy),需确认打包工具(PyInstaller/Nuitka)已自动包含对应编译产物,必要时手动补充。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:40:21