0
votes

I have the following structure for a project and I am just starting to introduce a Makefile to build the software:

├── Makefile
├── README.md
├── cg
│   └── cg.c
└── utilities
   ├── utilities.c
   └── utilities.h

I am trying to put object files in a directory called obj yet I can't seem to get it working.

My makefile looks like:

CC=mpicc
CFLAGS=-O3 -std=c99
LIBS=
MKDIR_P = mkdir -p

make_build_dir:
    @mkdir -p obj/

utilities.o: utilities/utilities.c
    $(CC) $(CFLAGS) -o ./obj/$@ -c $<

cg.o: cg/cg.c
    $(CC) $(CFLAGS) -o ./obj/$@ -c $<

.PHONY: make_build_dir

cg.exe: make_build_dir utilities.o cg.o 
    $(CC) $(CFLAGS) -o $@ $<

clean:
    rm -fr obj
    rm cg.exe

Yet this generates the following error:

a@a:b/b ‹master*›$ make cg.exe
mpicc -O3 -std=c99 -o ./obj/utilities.o -c utilities/utilities.c
mpicc -O3 -std=c99 -o ./obj/cg.o -c cg/cg.c
cg/cg.c:133:3: warning: implicit declaration of function 'decompose' is invalid in C99
      [-Wimplicit-function-declaration]
  decompose(num_chunks, chunks_per_rank,me, &settings); 
  ^
1 warning generated.
mpicc -O3 -std=c99 -o cg.exe make_build_dir
clang: error: no such file or directory: 'make_build_dir'
make: *** [cg.exe] Error 1

How can I get it to generate the object files in the obj directory and then an executable in the top-level directory?

2
The target make_build_dir is accompanied by the rule mkdir -p obj, you might want to quickly fix that?lubgr
@lubgr How do you mean? Don't I need a rule to create the obj directory?Dean
Sorry, I misunderstood the snippet, forget about that. From the error message it seems that make_build_dir is passed to $(CC) somewhere, though. Does this happen during object creation or linking?lubgr
I'll append the full output.Dean

2 Answers

1
votes

This linking part of the makefile

cg.exe: make_build_dir utilities.o cg.o 
    $(CC) $(CFLAGS) -o $@ $<

has two issues. First, $< refers to the first prerequesite of the target cg.exe, and that is make_build_dir. Declaring it as .PHONY doesn't help here, it's simply passed to $(CC). Second, utilities.o cg.o both don't exist at this location. You can change the rule to

cg.exe: obj/utilities.o obj/cg.o 
    $(CC) $(CFLAGS) -o $@ $^

Note the automatic variable $^ which refers to all prerequisites. Additionally, the object file targets should be

obj/cg.o: cg/cg.c
    $(CC) $(CFLAGS) -o $@ -c $<

(identical for utilities.o).

0
votes

First of all, you need to make_build_dir before making any *.o or make won't have a place to put them.

And you can make the Makefile more generic.

.PHONY: all clean info
.DEFAULT_GOAL := all

SRC_DIRS = cg utilities
OBJ_DIR  = obj
EXE      = cg.exe

SOURCES = $(foreach path, $(SRC_DIRS), $(wildcard $(path)/*.c))
OBJECTS = $(addprefix $(OBJ_DIR)/, $(notdir $(SOURCES:%.c=%.o)))

$(OBJ_DIR)/%.o: */%.c
    $(CC) $(CFLAGS) -o $@ -c $<

all: make_build_dir $(EXE)

info:
    $(info SOURCES=$(SOURCES))
    $(info OBJECTS=$(OBJECTS))

make_build_dir:
    @mkdir -p $(OBJ_DIR)

$(EXE): $(OBJECTS)
    $(CC) $(CFLAGS) -o $@ $^

With this Makefile, you can add more source directories to SRC_DIRS and it will automatically compile sources in them.

What does it do? Run make with the -n option to see:

$ make -n
mkdir -p obj
cc  -o obj/cg.o -c cg/cg.c
cc  -o obj/utilities.o -c utilities/utilities.c
cc  -o cg.exe obj/cg.o obj/utilities.o

You can also display the info on the variables by:

$ make info
SOURCES= cg/cg.c  utilities/utilities.c
OBJECTS=obj/cg.o obj/utilities.o