Reputation: 318
I want to do a simple thing, if target name is "enclose_io_memfs.obj" - build it with clang, if its another target - build it with common cl. So I have next code in Makefile:
.c.obj:
$(ECHO) target $@
$(ECHO) target $(@)
!if "$@" == "enclose_io_memfs.obj"
clang-cl -c enclose_io_memfs.c
$(ECHO) clang used
!else
cl -nologo -c enclose_io_memfs.c
$(ECHO) cl used
!endif
but the output is:
./win32/Makefile.sub(1162) : warning U4006: special macro undefined : '$@"'
target enclose_io_memfs.obj
target enclose_io_memfs.obj
cl -nologo -c enclose_io_memfs.c
enclose_io_memfs.c
cl used
compiling repu1sion_02 enclose_io_memfs.c
Few questions:
Upvotes: 1
Views: 561
Reputation: 9972
As Carl Norum notes in their answer (and also see my comment in How do I use a conditional in nmake), the !IF
is used when the makefile is parsed, while the $@
only has meaning when the makefile run after being parsed.
One solution is the following 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 $** \
)
which gives:
clang will be used to create foo.obj from foo.c
cl will be used create bar.obj from bar.c
Update: A better, more scalable, solution is the following 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 $?
Then nmake -nologo
will give (assuming the *.c
files exist):
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
Update 2: A complete working example. The 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)
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
gives, with 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...
Here for convenience we are using nmake's predefined inference rule for generating $(CL_OBJECTS)
.
Note nmake doesn't allow $<
here, and some_header.h
causes problems for $?
and $**
. My previous suggestions are wrong concerning this.
Also note, while not apparent in the above, nmake preserves the implicit dependency of the object file to the corresponding source file, even with the added rule for clang. For example:
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
(Here the copy
command is used as a "touch": see the example at https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/copy/.)
Upvotes: 0
Reputation: 225032
That !if/!then
stuff is done as the makefile is read, not when your target gets invoked. You're trying to do the equivalent of using a variable in a preprocessor conditional statement in C.
Make your if/then
in whatever way the shell environment your makefile executes files in. I'm not an nmake/dos shell expert, but for bash it would be something like:
.c.obj:
$(ECHO) target $@
if [[ "$@" == "enclose_io_memfs.obj" ]] ;\
then \
clang-cl -c $(@:.obj=.c) ;\
$(ECHO) clang used ;\
else \
cl -nologo -c $(@:.obj=.c) ;\
$(ECHO) cl used ;\
fi
Upvotes: 2