正如 Carl Norum 在他们的 answer 中指出的那样(也可以在 How do I use a conditional in nmake 中查看我的评论),!IF 在 makefile 被解析时使用,而 $@ 只有意思是当makefile在被解析之后运行。
一种解决方案是以下makefile:
all: foo.obj bar.obj
.c.obj:
@cmd /c if $(@B)==foo ( \
echo clang will be used to create $@ from $** \
) else ( \
echo cl will be used create $@ from $** \
)
给出:
clang will be used to create foo.obj from foo.c
cl will be used create bar.obj from bar.c
更新:更好、更具可扩展性的解决方案是以下 makefile:
CLANG_SOURCES = foo1.c foo2.c
CL_SOURCES = bar1.c bar2.c
CLANG_OBJECTS = $(CLANG_SOURCES:.c=.obj)
CL_OBJECTS = $(CL_SOURCES:.c=.obj)
all: $(CLANG_OBJECTS) $(CL_OBJECTS)
$(CLANG_OBJECTS):
@echo using clang to create $@ from $?
$(CL_OBJECTS):
@echo using cl to create $@ from $?
然后nmake -nologo 将给出(假设*.c 文件存在):
using clang to create foo1.obj from foo1.c
using clang to create foo2.obj from foo2.c
using cl to create bar1.obj from bar1.c
using cl to create bar2.obj from bar2.c
更新 2: 一个完整的工作示例。生成文件:
CLANG_SOURCES = foo1.c foo2.c
CL_SOURCES = bar1.c bar2.c
CLANG_OBJECTS = $(CLANG_SOURCES:.c=.obj)
CL_OBJECTS = $(CL_SOURCES:.c=.obj)
OBJECTS = $(CLANG_OBJECTS) $(CL_OBJECTS)
CFLAGS = -nologo
CLANG_CL = C:\Progra~2\LLVM32\bin\clang-cl
all: $(OBJECTS)
$(OBJECTS): some_header.h
$(CLANG_OBJECTS):
$(CLANG_CL) $(CFLAGS) -c $*.c
clean:
del $(OBJECTS) 2>NUL
给,nmake -nologo:
C:\Progra~2\LLVM32\bin\clang-cl -nologo -c foo1.c
C:\Progra~2\LLVM32\bin\clang-cl -nologo -c foo2.c
cl -nologo /c bar1.c bar2.c
bar1.c
bar2.c
Generating Code...
这里为方便起见,我们使用 nmake 的预定义推理规则来生成 $(CL_OBJECTS)。
注意 nmake 不允许在这里使用 $<,some_header.h 会导致 $? 和 $** 出现问题。我之前的建议是错误的。
另外请注意,尽管在上面不明显,nmake 保留了目标文件对相应源文件的隐式依赖,即使添加了 clang 规则。例如:
C:\Users\Joe>nmake -nologo
C:\Users\Joe>copy /b foo1.c +,,
1 file(s) copied.
C:\Users\Joe>nmake -nologo
C:\Progra~2\LLVM32\bin\clang-cl -nologo -c foo1.c
C:\Users\Joe>copy /b bar1.c +,,
1 file(s) copied.
C:\Users\Joe>nmake -nologo
cl -nologo /c bar1.c
bar1.c
(这里copy 命令用作“触摸”:参见https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/copy/ 的示例。)