Ray
Ray

Reputation: 1021

Configure make to build objects for different systems in different directories

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

Answers (1)

MadScientist
MadScientist

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

Related Questions