如何在Conan 2.0中构建GCC交叉编译器的依赖模型?
问题描述
我希望为GCC交叉编译器制作一个Conan包。从头构建GCC交叉工具链需执行以下步骤:
- 使用
--without-headers参数构建GCC版本,生成的编译器无法创建普通二进制文件,但足以构建glibc; - 使用该受限GCC构建glibc;
- 通过
--sysroot=参数指定glibc安装路径,构建完整GCC。
我希望将整个构建过程建模为Conan依赖图。目前实现的情况:
conan install cc --build=missing可正常运行,会构建一个目标平台与运行平台一致的常规编译器;conan install cc --build=missing pr:macos-x86_64 -o os_target=Linux -o arch_target=x86_64无法运行,报错ConanException: Tried to define 'os' setting inside recipe。
请问是否有办法让cc包依赖于为完全不同的profile构建的libc包?
相关代码
cc/conanfile.py
import os from typing import Any from conan import ConanFile class CompilerConanfile(ConanFile): name : Any = "cc" version : Any = "1.0" description : Any = "c compiler" license : Any = "TBD" homepage : Any = "TBD" options : Any = { "os_target": ["Windows", "Linux", "Macos"], "arch_target": ["x86", "x86_64"], "libc":[True, False]} default_options : Any = {"libc": True, "os_target": "Macos", "arch_target": "x86_64"} build_requires: Any requires: Any def configure(self): # record target information in options if settings_target := getattr(self, "settings_target", None): self.options.os_target = self.options.os_target or settings_target.os self.options.arch_target = self.options.arch_target or settings_target.os def requirements(self): if self.options.libc: self.requires("sysroot/1.0", options={ "os_target": self.options.os_target, "arch_target": self.options.arch_target, }) def generate(self): if self.options.libc: sysroot = self.dependencies.get('sysroot').conf_info.get('user.sysroot.root') self.output.highlight(f"sysroot is at {sysroot}")
sysroot/conanfile.py
import os from typing import Any from conan import ConanFile class SysrootConanfile(ConanFile): name : Any = "sysroot" version : Any = "1.0" description : Any = "sysroot files for a cross compiler" license : Any = "TBD" homepage : Any = "TBD" options : Any = { "os_target": ["Windows", "Linux", "Macos"], "arch_target": ["x86", "x86_64"] } default_options : Any = {"os_target": "Macos", "arch_target": "x86_64"} settings : Any = ("os", "arch") build_requires: Any requires: Any conf_info: Any def configure(self): if self.settings.os != self.options.os_target: self.settings.os = self.options.os_target if self.settings.arch != self.options.arch_target: self.settings.arch = self.options.arch_target def requirements(self): self.requires('libc/1.0', visible=True) def package_info(self): sysroot = self.dependencies["libc"].package_folder self.output.highlight(f"sysroot exporting path at {sysroot}") self.conf_info.define("user.sysroot.root", sysroot)
libc/conanfile.py
import os from typing import Any from conan import ConanFile class RuntimeConanfile(ConanFile): name : Any = "libc" version : Any = "1.0" description : Any = "c runtime library" license : Any = "TBD" homepage : Any = "TBD" settings : Any = ("os", "arch") tool_requires : Any def build_requirements(self): # require the version of the compiler that does not have a libc baked in, # since this recipe is for building libc self.tool_requires("cc/1.0", options={"libc": False})
解决方案
报错原因是sysroot/conanfile.py的configure方法中直接修改了self.settings——Conan不允许在配方内部修改settings,settings由profile或命令行参数决定,属于只读属性。
要实现交叉编译场景下的依赖管理,需利用Conan的交叉编译profile机制,通过settings_target区分构建主机和目标平台,调整方案如下:
1. 重构sysroot包
去掉修改settings的逻辑,改用settings_target同步目标平台,同时指定libc依赖使用目标平台构建:
import os from typing import Any from conan import ConanFile class SysrootConanfile(ConanFile): name : Any = "sysroot" version : Any = "1.0" description : Any = "sysroot files for a cross compiler" license : Any = "TBD" homepage : Any = "TBD" options : Any = { "os_target": ["Windows", "Linux", "Macos"], "arch_target": ["x86", "x86_64"] } default_options : Any = {"os_target": "Macos", "arch_target": "x86_64"} settings : Any = ("os", "arch") # 声明使用settings_target处理交叉编译 settings_target : Any = ("os", "arch") build_requires: Any requires: Any conf_info: Any def configure(self): # 用settings_target同步目标平台选项 if self.settings_target: self.options.os_target = self.settings_target.os self.options.arch_target = self.settings_target.arch def requirements(self): # 强制libc使用目标平台的settings构建 self.requires("libc/1.0", target=self.settings_target) def package_info(self): sysroot = self.dependencies["libc"].package_folder self.output.highlight(f"sysroot exporting path at {sysroot}") self.conf_info.define("user.sysroot.root", sysroot)
2. 修正cc包的configure方法
修复原代码中settings_target赋值错误(误将settings_target.os赋值给arch_target):
def configure(self): # record target information in options if settings_target := getattr(self, "settings_target", None): self.options.os_target = self.options.os_target or settings_target.os self.options.arch_target = self.options.arch_target or settings_target.arch
3. 使用交叉编译profile调用
创建交叉编译profile文件(例如cross-linux-x86_64):
[settings] os=Macos arch=x86_64 [settings_target] os=Linux arch=x86_64
执行命令:
conan install cc --build=missing --profile:build=macos-x86_64 --profile:host=cross-linux-x86_64
关键原理
- Conan的
settings_target(或--profile:host)专门用于交叉编译,区分构建主机和目标平台; - 依赖声明时使用
target=self.settings_target,可强制依赖包使用目标平台的settings构建; - 绝对不要在配方内部修改
self.settings,所有settings调整需通过profile或命令行参数传递。
内容的提问来源于stack exchange,提问作者Lawrence D'Anna
相关产品推荐
相关产品推荐

