NSIS中!insertmacro与偏移量+2结合失效,被迫用标签求原因分析
NSIS中IfFileExists偏移量跳转失效的原因分析
嗨,这个问题的核心其实是NSIS预处理器和运行时指令的执行时机差异导致的,我给你掰扯清楚:
首先得明确NSIS里两类指令的区别:
- 预处理器指令:就是那些带
!前缀的(比如!insertmacro、!define),它们是在编译阶段就会被处理的,会直接把宏展开成具体的运行时代码,不会留到安装程序运行时执行。 - 运行时指令:像
IfFileExists、Section这类不带!的,是安装程序运行的时候才会逐条执行的。
接下来看你的两种写法:
有效带标签写法的逻辑
IfFileExists "$INSTDIR\XX\*.*" XX_Found 0 !insertmacro UnselectSection ${Section_XX} XX_Found:
编译的时候,!insertmacro会先被展开成UnselectSection宏对应的所有运行时代码。而IfFileExists的标签跳转是编译时就确定好位置的——不管宏展开成多少行代码,只要文件存在,就会直接跳到XX_Found标签处,完美跳过整个宏的代码;如果文件不存在,就执行宏展开后的代码,逻辑完全正确。
失效偏移量写法的问题
IfFileExists "$INSTDIR\XX\*.*" +2 0 !insertmacro UnselectSection ${Section_XX}
这里的+2是运行时跳转的偏移量,它指的是「跳过当前指令之后的2条运行时代码」。但问题在于,你写的!insertmacro在编译时会被展开成多条运行时代码(比如UnselectSection宏大概率会展开成Push、Call、Pop这类多条指令)。
举个实际的例子,假设UnselectSection宏展开后是:
Push ${Section_XX} Call un.SelectSection Pop $0
那你写的偏移量代码编译后就变成:
IfFileExists "$INSTDIR\XX\*.*" +2 0 Push ${Section_XX} Call un.SelectSection Pop $0
此时+2的跳转只会跳到Call un.SelectSection这一行,根本跳不过整个宏的代码——哪怕文件存在,还是会执行后续的Call和Pop操作,自然就导致你的逻辑失效了。
总结
+n这类偏移量跳转是基于编译后的运行时代码指令数量来计算的,但预处理器宏会改变实际的指令行数,你手动写的+2和实际需要跳过的指令数不匹配,所以出错。- 标签跳转是编译时就解析好位置的,不管宏展开多少行,都能精准跳转到目标位置,所以逻辑稳定可靠。
内容的提问来源于stack exchange,提问作者Erik Šťastný
相关产品推荐
相关产品推荐

