1
votes

In my projects, I have a project directory, and 4 subdirs: bin, inc, obj, and src. All source files are in "src", all header files are in "inc".

I am trying to make a makefile to compile all sources into same-name-new-extension objects into "obj" directory, and then link them all together into a final project.out in the "bin" directory. Here is what I have so far:

       C_FILES = $(wildcard src/*.c)
       OBJ_FILES = $(addprefix obj/,$(notdir $(C_FILES:.cpp=.o)))
       LD_FLAGS = 
       CC_FLAGS = -MMD -c -Wall -lm
       BINARY = bin/project.out

       all: $(BINARY)
       $(BINARY): $(OBJ_FILES)
           gcc $(LD_FLAGS) -o $@ $<

       OBJ_FILES = $(patsubst $(C_FILES),$(OBJ_FILES),$(SOURCES))
          $(CC) $(CC_FLAGS) $< -o $@

       -include $(OBJ_FILES:.o=.d)

I'm getting "Missing Separator on line 12" I am new to makefiles, so what are the mistakes I am making? I have tried the GNU makefile tutorial, and I am obviously missing something.

1
FYI: have you already looked at CMake? It could greatly simplify the creation of Makefiles, i.e. organizing your project structure. - yegorich

1 Answers

3
votes

You’re pretty close.

The “missing separator” error means that you’ve used spaces instead of a literal tab character at the start of a line. Make is unfortunately very picky about this. In vim you can hit CtrlV, Tab to enter a literal tab.

Apart from that, you only need to make two changes to get your Makefile to work. Here’s the diff:

--- Makefile
+++ Makefile
@@ -1,4 +1,4 @@
-C_FILES = $(wildcard src/*.c)
+C_FILES = $(wildcard src/*.cpp)
 OBJ_FILES = $(addprefix obj/,$(notdir $(C_FILES:.cpp=.o)))
 LD_FLAGS = 
 CC_FLAGS = -MMD -c -Wall -lm
@@ -8,7 +8,7 @@
 $(BINARY): $(OBJ_FILES)
         gcc $(LD_FLAGS) -o $@ $<

-OBJ_FILES = $(patsubst $(C_FILES),$(OBJ_FILES),$(SOURCES))
+obj/%.o: src/%.cpp
         $(CC) $(CC_FLAGS) $< -o $@

 -include $(OBJ_FILES:.o=.d)

The first change is that sometimes you refer to .c files and sometimes to .cpp files; you’ll need to make that consistent.

The second change is that you need to specify a rule for how Make can turn a src/foo.cpp file into an obj/foo.o file, using a pattern rule.

Here’s the updated Makefile:

C_FILES = $(wildcard src/*.cpp)
OBJ_FILES = $(addprefix obj/,$(notdir $(C_FILES:.cpp=.o)))
LD_FLAGS = 
CC_FLAGS = -MMD -c -Wall -lm
BINARY = bin/project.out

all: $(BINARY)
$(BINARY): $(OBJ_FILES)
        gcc $(LD_FLAGS) -o $@ $<

obj/%.o: src/%.cpp
        $(CC) $(CC_FLAGS) $< -o $@

-include $(OBJ_FILES:.o=.d)

Unfortunately you can’t just copy-and-paste this and expect it to work because the Tab characters get messed up. You’ll have to manually change the beginning of lines 9 and 12 to have literal Tab characters.