模仿GNU make -C功能在子目录运行NMake,解决uuid.lib链接错误
问题
希望在VS 2022开发者PowerShell中实现类似GNU make -C的功能:在根目录Makefile的test目标里调用子目录(test/)的NMake构建测试套件,但调用时出现致命错误:
LINK : fatal error LNK1104: cannot open file 'uuid.lib' NMAKE : fatal error U1077: ...
补充信息:
- 直接进入
test目录调用Makefile.win可正常完成构建 - 在VS2019和VS2022中均出现此问题
- 根目录
Makefile.win内容:
NODEBUG=1 INCS = -I. OPTS = /O2 /D_CRT_SECURE_NO_WARNINGS LIB = myio.lib DLL = myio.dll OBJS = myread.obj mywrite.obj all: lib lib: $(OBJS) link.exe /lib /nologo /out:$(LIB) $(OBJS) dll: $(OBJS) link.exe /dll /nologo /out:$(DLL) $(OBJS) .c.obj: $(CC) /nologo $(CFLAGS) $(INCS) $(OPTS) /c $< # Run test suite test: lib pushd $@ && $(MAKE) /NOLOGO /f Makefile.win /$(MAKEFLAGS) & popd
test\Makefile.win内容:
NODEBUG=1 INCS = -I. -I.. LIBS = ..\myio.lib OPTS = /O2 /D_CRT_SECURE_NO_WARNINGS /nologo TEST_RUNNER = test-runner.exe test: $(TEST_RUNNER) $(TEST_RUNNER) $(TEST_RUNNER): test-*.c $(CC) $(CFLAGS) $(INCS) $(OPTS) $** $(LIBS) /Fe: $@
完整运行日志:
> nmake -f Makefile.win test Microsoft (R) Program Maintenance Utility Version 14.36.32532.0 Copyright (C) Microsoft Corporation. All rights reserved. cl /nologo -I. /O2 /D_CRT_SECURE_NO_WARNINGS /c myread.c myread.c cl /nologo -I. /O2 /D_CRT_SECURE_NO_WARNINGS /c mywrite.c mywrite.c link.exe /lib /nologo /out:myio.lib myread.obj mywrite.obj pushd test && "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.36.32532\bin\HostX86\x86\nmake.exe" /NOLOGO /f Makefile.win / & popd cl -I. -I.. /O2 /D_CRT_SECURE_NO_WARNINGS /nologo test-read.c test-write.c ..\myio.lib /Fe: test-runner.exe test-read.c test-write.c Generating Code... LINK : fatal error LNK1104: cannot open file 'uuid.lib' NMAKE : fatal error U1077: 'cl -I. -I.. /O2 /D_CRT_SECURE_NO_WARNINGS /nologo test-read.c test-write.c ..\myio.lib /Fe: test-runner.exe' : return code '0x2' Stop.
解决方案
问题根源是根目录Makefile中定义的LIB = myio.lib覆盖了系统环境变量LIB——这个环境变量是VS开发者shell预设的,用来指定链接器搜索系统库(比如uuid.lib)的路径。当子NMake进程启动时,会继承被修改后的LIB变量,导致链接器无法找到依赖的系统库。
解决步骤:
- 修改根目录
Makefile.win中的变量名,避免覆盖系统环境变量:
将LIB = myio.lib改为TARGET_LIB = myio.lib(或其他不冲突的名称,比如MYIO_LIB) - 更新根目录Makefile中所有引用该变量的地方:
lib: $(OBJS)目标中的link.exe /lib /nologo /out:$(LIB) $(OBJS)改为link.exe /lib /nologo /out:$(TARGET_LIB) $(OBJS)- 若有其他地方用到
$(LIB),一并替换为新变量名
修改后的根目录Makefile.win关键部分示例:
NODEBUG=1 INCS = -I. OPTS = /O2 /D_CRT_SECURE_NO_WARNINGS TARGET_LIB = myio.lib # 改名避免覆盖系统LIB环境变量 DLL = myio.dll OBJS = myread.obj mywrite.obj all: lib lib: $(OBJS) link.exe /lib /nologo /out:$(TARGET_LIB) $(OBJS) # 使用新变量名
修改后,系统环境变量LIB会被正常传递给子NMake进程,链接器就能找到uuid.lib,测试套件的构建即可正常完成。
内容的提问来源于stack exchange,提问作者terse
相关产品推荐
相关产品推荐

