Reputation: 1021
At the moment I am using this makefile:
CFLAGS=-g -Wall
SRCS=foo.c bar.c main.c
OBJS=$(subst .c,.o,$(SRCS))
linux: CC=gcc
linux: OUTPUT=a.out
windows: CC=x86_64-w64-mingw32-gcc
windows: OUTPUT=a.exe
%.o: %.c
$(CC) $(CFLAGS) -c $<
linux: $(OBJS)
$(CC) $(OBJS) -o $(OUTPUT)
windows: $(OBJS)
$(CC) $(OBJS) -o $(OUTPUT)
clean:
${RM} a.out a.exe *.o
I can use it to build the program with make windows
or make linux
.
But since all the objects files are created in the same directory I cannot build the windows version and then the linux version without having to make clean
the directory.
So I would like to build the windows objects in a sub-directory and the linux objects in another sub-directory. I have tried to modify the makefile as shown below but I cannot get it to work.
$ make linux
gcc obj/linux/foo.o obj/linux/bar.o obj/linux/main.o -o a.out
gcc: error: obj/linux/foo.o: No such file or directory
gcc: error: obj/linux/bar.o: No such file or directory
gcc: error: obj/linux/main.o: No such file or directory
gcc: fatal error: no input files
compilation terminated.
make: *** [Makefile:19: linux] Error 1
CFLAGS=-g -Wall
SRCS=foo.c bar.c main.c
OBJS=$(subst .c,.o,$(SRCS))
DIR=obj/subdir/
OBJSDIR:=$(addprefix $(DIR), $(OBJS))
linux: CC=gcc
linux: OUTPUT=a.out
linux: OBJECTS=$(subst subdir,linux,$(OBJSDIR))
windows: CC=x86_64-w64-mingw32-gcc
windows: OUTPUT=a.exe
windows: OBJECTS=$(subst subdir,windows,$(OBJSDIR))
%.o: %.c
$(CC) $(CFLAGS) -c $<
linux: $(OBJECTS)
$(CC) $(OBJECTS) -o $(OUTPUT)
windows: $(OBJECTS)
$(CC) $(OBJECTS) -o $(OUTPUT)
clean:
${RM} a.out a.exe *.o
Upvotes: 0
Views: 264
Reputation: 100936
There's a lot that won't work here.
First, after your change the pattern %.o : %.c
doesn't match any more, because the stem is now obj/subdir/foo
and there's no obj/subdir/foo.c
. And, this recipe doesn't tell the compiler where to put the output file so it will use the default location. So, this pattern needs to be:
$(DIR)%.o : %.c
$(CC) $(CFLAGS) -c -o $@ $<
But this still won't work because you have missed a critical restriction in the documentation of target-specific variables: they ONLY take effect inside recipes. You are trying to change the prerequisites of a target using a target-specific variable; that won't work.
There are a number of ways this can be handled but the simplest one is to use recursion, like this:
...
DIR = obj/$(SUBDIR)/
...
linux:
$(MAKE) a.out CC=gcc OUTPUT=a.out SUBDIR=linux
windows:
$(MAKE) a.exe CC=x86_64-w64-mingw32-gcc OUTPUT=a.exe SUBDIR=windows
$(OUTPUT): $(OBJECTS)
$(CC) $^ -o $@
Upvotes: 2