如何在IAR的.icf链接器文件中引入C语言#define定义?
方案1:通过预处理器生成链接器脚本片段
核心思路是维护一份纯C宏定义的内存映射文件,用IAR的C预处理器把它转换成链接器脚本能识别的格式,再引入到主.icf文件中。
第一步:拆分现有
mmap.h,把纯宏定义部分抽出来放到mmap_common.h里,比如:#define FLASH_BOOT_START 0x08000000 #define FLASH_BOOT_SIZE 0x00010000 #define FLASH_APP_START 0x08010000 #define FLASH_APP_SIZE 0x00070000 #define FLASH_STORAGE_START 0x08080000 #define FLASH_STORAGE_SIZE 0x00080000原
mmap.h可以直接包含mmap_common.h,保持原有模块调用逻辑不变。第二步:创建链接器脚本模板文件
mmap_icf.tpl,内容如下:#include "mmap_common.h" define symbol FLASH_BOOT_START = FLASH_BOOT_START; define symbol FLASH_BOOT_SIZE = FLASH_BOOT_SIZE; define symbol FLASH_APP_START = FLASH_APP_START; define symbol FLASH_APP_SIZE = FLASH_APP_SIZE; define symbol FLASH_STORAGE_START = FLASH_STORAGE_START; define symbol FLASH_STORAGE_SIZE = FLASH_STORAGE_SIZE;第三步:添加预构建步骤,用IAR的C预处理器把模板转成可用的.icf片段。在项目(或工作区)的
Options > Build Actions > Pre-build command line中添加命令:"$TOOLKIT_DIR$\bin\iccarm" -E -D__ICF_TEMPLATE__ -o "$PROJ_DIR$\mmap_icf.icf" "$PROJ_DIR$\mmap_icf.tpl"这个命令会预处理模板文件,生成包含链接器符号定义的
mmap_icf.icf。第四步:在主链接器脚本
xxx.icf中引入生成的文件:include "mmap_icf.icf"; // 接下来就可以用这些符号定义内存区域了 define region FLASH_BOOT_region = mem:[from FLASH_BOOT_START to FLASH_BOOT_START + FLASH_BOOT_SIZE - 1]; define region FLASH_APP_region = mem:[from FLASH_APP_START to FLASH_APP_START + FLASH_APP_SIZE - 1];
这样只需要维护mmap_common.h这一份文件,C代码和链接器脚本的内存映射就自动同步了。
方案2:工作区级别全局定义宏(避免逐个项目配置)
如果不想用预构建步骤,可以直接在工作区层面统一定义内存映射宏,让C编译器和链接器都能读取:
第一步:打开IAR工作区的
Workspace > Options(注意是工作区选项,不是单个项目的)。第二步:在
C/C++ Compiler > Preprocessor > Defined symbols中添加所有内存映射宏,比如:FLASH_BOOT_START=0x08000000,FLASH_BOOT_SIZE=0x00010000,FLASH_APP_START=0x08010000,...第三步:切换到
Linker > Config > Additional options,添加参数把这些宏传递给链接器:--define_symbol FLASH_BOOT_START=$FLASH_BOOT_START --define_symbol FLASH_BOOT_SIZE=$FLASH_BOOT_SIZE --define_symbol FLASH_APP_START=$FLASH_APP_START ...这里
$XXX是引用工作区预定义的宏变量。第四步:在C代码中直接使用这些宏(不需要额外头文件,或者在
mmap.h里声明后使用),在链接器脚本xxx.icf中用这些符号:define region FLASH_BOOT_region = mem:[from FLASH_BOOT_START to FLASH_BOOT_START + FLASH_BOOT_SIZE - 1];
这个方案的优势是不用额外的文件或构建步骤,所有定义集中在工作区配置里,工作区下的所有项目自动继承这些配置,不用逐个设置。
方案3:从链接器脚本反向传递宏给C代码
如果更习惯在链接器脚本里维护内存映射,可以反过来把链接器里的符号传递给C代码:
第一步:在主
xxx.icf中定义所有内存区域符号:define symbol FLASH_BOOT_START = 0x08000000; define symbol FLASH_BOOT_SIZE = 0x00010000; define symbol FLASH_APP_START = 0x08010000; define symbol FLASH_APP_SIZE = 0x00070000; define region FLASH_BOOT_region = mem:[from FLASH_BOOT_START to FLASH_BOOT_START + FLASH_BOOT_SIZE - 1];第二步:在链接器选项
Linker > Config > Additional options中添加参数,把这些符号定义成C预处理器宏:--define_symbol FLASH_BOOT_START=FLASH_BOOT_START --define_symbol FLASH_BOOT_SIZE=FLASH_BOOT_SIZE ...第三步:在C代码的
mmap.h中直接使用这些宏,比如:// 直接用链接器传递过来的宏 #define FLASH_BOOT_ADDR FLASH_BOOT_START #define FLASH_BOOT_LEN FLASH_BOOT_SIZE
这个方案适合更熟悉链接器脚本语法的开发者,所有内存映射的维护都在.icf文件里,C代码直接复用这些定义。
内容的提问来源于stack exchange,提问作者morfl

