Windows下使用GNU Make如何配置可继承的永久shell环境?
问题核心原因
GNU Make 在Windows下执行每一行规则时都会默认启动独立的cmd进程,单独进程内执行vcvarsall.bat配置的环境变量无法跨进程共享,因此你现在的写法每次编译单个文件都会重复执行环境初始化步骤,产生大量不必要的开销。
解决方案
方案1:前置配置环境(推荐,性能最优)
这是改动最小、性能最高的方案,完全避免重复执行vcvars的开销,也兼容并行编译逻辑:
- 编译时直接打开Visual Studio对应架构的开发者命令提示符,该窗口默认已经完成vcvars环境配置,直接在窗口内执行make命令即可
- 也可以自己编写启动脚本
build.bat,后续直接运行该脚本即可启动编译,脚本示例如下:
@echo off :: 路径根据自己的VS版本、安装路径和目标架构调整 call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 make -j%NUMBER_OF_PROCESSORS%
对应修改makefile的编译规则,移除每次执行的vcvars调用即可:
# C object file generation rule ../int/$(PROJECT)/%.o: ../%.c ifeq ($(OS),Windows_NT) @cl $(CFLAGS) -c $(subst /,\,$<) else @gcc $(CFLAGS) -c $< endif
方案2:Make内部自举初始化(适合需要直接执行make的场景)
如果要求用户直接输入make就能启动编译,不需要提前手动配置环境,可以在makefile开头增加环境检测逻辑,如果检测到VS环境未初始化,就执行vcvars后重新调用make:
ifeq ($(OS),Windows_NT # 检测是否已经初始化过VS环境,以VSINSTALLDIR作为标记变量 ifndef VSINSTALLDIR # 临时规则:初始化环境后重新调用make all: @vcvarsall.bat x86 ^&^& make $(MAKECMDGOALS) # 阻止当前make实例继续执行后续规则 .RECIPEPREFIX = > > @exit /b 0 endif endif # 后续保留修改后的编译规则即可,无需再调用vcvars ../int/$(PROJECT)/%.o: ../%.c ifeq ($(OS),Windows_NT) @cl $(CFLAGS) -c $(subst /,\,$<) else @gcc $(CFLAGS) -c $< endif
该方案vcvarsall.bat仅会在最开始执行一次,后续所有编译命令都继承初始化后的环境,不会重复执行。
补充提示
如果需要同时支持32/64位编译,可以把架构参数做成make变量,根据传入的编译参数动态切换vcvars的调用参数即可。
内容的提问来源于stack exchange,提问作者Tomatin
相关产品推荐
相关产品推荐

