Home > Blockchain >  How can I make my Makefile build to the obj/ folder, not the src/ folder?
How can I make my Makefile build to the obj/ folder, not the src/ folder?

Time:07-29

I am extending an old school project, and I have the Makefile the course staff made for us. I have reorganized the directory structure of the project like this.

 -----obj
|
 -----src
|     |
|      -Makefile
|      -allocator.h
|      -debug_break.h
|      -rbtree_clrs.c
|      -rbtree_linked.c
|      -rbtree_stack.c
|      -rbtree_topdown.c
|      -rbtree_unified.c
|      -segment.c
|      -segment.h
|      -test_harness.c
|      -my_optional_program.c
|
 ------scripts

The Makefile currently prepends the heap allocators I wrote (files starting with rbtree_) with either test_ or my_optional_program and puts them in the same directory as the Makefile. I can then run my different heap allocator implementations on the scripts in the scripts folder. Instead, I want this:

 -----obj
|      -my_optional_program_rbtree_clrs
|      -my_optional_program_rbtree_linked
|      -my_optional_program_rbtree_stack
|      -my_optional_program_rbtree_topdown
|      -my_optional_program_rbtree_unified
|      -test_rbtree_clrs
|      -test_rbtree_linked
|      -test_rbtree_stack
|      -test_rbtree_topdown
|      -test_rbtree_unified
|
 -----src
|     |
|      -Makefile
|      -allocator.h
|      -debug_break.h
|      -rbtree_clrs.c
|      -rbtree_linked.c
|      -rbtree_stack.c
|      -rbtree_topdown.c
|      -rbtree_unified.c
|      -segment.c
|      -segment.h
|      -test_harness.c
|      -my_optional_program.c
|     
 ------scripts

What do I need to add or change in the Makefile so that it will build to the obj/ folder?

# They had us try different optimization levels here (-O0, -O2, etc).
rbtree_clrs.o: CFLAGS  = -O0
rbtree_unified.o: CFLAGS  = -O0
rbtree_linked.o: CFLAGS  = -O0
rbtree_stack.o: CFLAGS  = -O0
rbtree_topdown.o: CFLAGS  = -O0

ALLOCATORS = rbtree_clrs rbtree_unified rbtree_stack rbtree_linked rbtree_topdown
PROGRAMS = $(ALLOCATORS:%=test_%)
MY_PROGRAMS = $(ALLOCATORS:%=my_optional_program_%)

all:: $(PROGRAMS) $(MY_PROGRAMS)

# I had to use gcc-11 on mac to be able to build this project.
UNAME := $(shell uname)
ifeq ($(UNAME),Darwin)
CC = gcc-11
else
CC = gcc
endif

CFLAGS = -g3 -std=gnu99 -Wall $$warnflags -fcf-protection=none -fno-pic -no-pie
export warnflags = -Wfloat-equal -Wtype-limits -Wpointer-arith -Wlogical-op -Wshadow -Winit-self -fno-diagnostics-show-option
LDFLAGS =
LDLIBS =

$(PROGRAMS): test_%:%.o segment.c test_harness.c
    $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(MY_PROGRAMS): my_optional_program_%:my_optional_program.c %.o segment.c
    $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

clean::
    rm -f $(PROGRAMS) $(MY_PROGRAMS) *.o callgrind.out.*

.PHONY: clean all

.INTERMEDIATE: $(ALLOCATORS:%=%.o)

Update: This Makefile has solved the issue. I took Renaud Pacalet's Makefile (thanks!) and adjusted the paths to achieve the desired result. It seems not going up one level in the directories was an issue. Then I had to add the path I wanted to the ALLOCATORS in the PROGRAMS variable. I have no idea if this is how it should be done but it worked. I can update this if there is a better way.

SRCDIR = ../src
OBJDIR = ../obj
SRC := $(wildcard $(SRCDIR)/*.c)
OBJ := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o,$(SRC))

# They had us try different optimization levels here (-O0, -O2, etc).
$(filter $(OBJDIR)/rbtree_%.o,$(OBJ)): CFLAGS  = -O0

ALLOCATORS = rbtree_clrs rbtree_unified rbtree_stack rbtree_linked rbtree_topdown
PROGRAMS = $(addprefix $(OBJDIR)/test_,$(ALLOCATORS))
MY_PROGRAMS = $(addprefix $(OBJDIR)/my_optional_program_,$(ALLOCATORS))

all:: $(PROGRAMS) $(MY_PROGRAMS)

# I had to use gcc-11 on mac to be able to build this project.
UNAME := $(shell uname)
ifeq ($(UNAME),Darwin)
CC = gcc-11
else
CC = gcc
endif

CFLAGS = -g3 -std=gnu99 -Wall $$warnflags -fcf-protection=none -fno-pic -no-pie
export warnflags = -Wfloat-equal -Wtype-limits -Wpointer-arith -Wlogical-op -Wshadow -Winit-self -fno-diagnostics-show-option
LDFLAGS =
LDLIBS =

$(OBJ): $(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(CC) $(CFLAGS) -c -o $@ $<

$(PROGRAMS): $(OBJDIR)/test_%: $(OBJDIR)/%.o segment.c test_harness.c
    $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(MY_PROGRAMS): $(OBJDIR)/my_optional_program_%: my_optional_program.c $(OBJDIR)/%.o segment.c
    $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

clean::
    rm -f $(PROGRAMS) $(MY_PROGRAMS) $(OBJ) callgrind.out.*

CodePudding user response:

You don't have a compilation rule so make uses its implicit rule for compilation which puts the object files in the same directory as the source files.

Simply add a rule of your own and rework a bit all references to object files:

SRC := $(wildcard src/*.c)
OBJ := $(patsubst src/%.c,obj/%.o,$(SRC))

# They had us try different optimization levels here (-O0, -O2, etc).
$(filter obj/rbtree_%.o,$(OBJ)): CFLAGS  = -O0

ALLOCATORS = rbtree_clrs rbtree_unified rbtree_stack rbtree_linked rbtree_topdown
PROGRAMS = $(ALLOCATORS:%=test_%)
MY_PROGRAMS = $(ALLOCATORS:%=my_optional_program_%)

all:: $(PROGRAMS) $(MY_PROGRAMS)

# I had to use gcc-11 on mac to be able to build this project.
UNAME := $(shell uname)
ifeq ($(UNAME),Darwin)
CC = gcc-11
else
CC = gcc
endif

CFLAGS = -g3 -std=gnu99 -Wall $$warnflags -fcf-protection=none -fno-pic -no-pie
export warnflags = -Wfloat-equal -Wtype-limits -Wpointer-arith -Wlogical-op -Wshadow -Winit-self -fno-diagnostics-show-option
LDFLAGS =
LDLIBS =

$(OBJ): obj/%.o: src/%.c
    $(CC) $(CFLAGS) -c -o '$@' '$<'

$(PROGRAMS): test_%: obj/%.o segment.c test_harness.c
    $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(MY_PROGRAMS): my_optional_program_%: my_optional_program.c obj/%.o segment.c
    $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

clean::
    rm -f $(PROGRAMS) $(MY_PROGRAMS) $(OBJ) callgrind.out.*

Note that you should also manage the dependencies between object and header files (which the above does not, just like the original version). If it's simple enough you'll easily modify the proposed Makefile. Else consider reading this very interesting post about Auto-Dependency Generation by the current GNU make main maintainer.

  • Related