0
votes

This is my absolute first time ever making a makefile, and I'm really trying to understand the process.

I'm trying to create a very simple makefile for a C++ project whose structure is as follows:

root folder
    makefile
    readme
src folder
    ...source files all here...
include folder
    ...header files for external libraries here...
lib folder
    ...external lib files all here...
bin folder
    ...output directory for built executable...
    obj folder
    ...object files all here...

I followed the tutorial here.

Here's my makefile:

IDIR=include .
CC=g++
CFLAGS=-I$(IDIR)
ODIR=bin/obj
LDIR=lib
LIBS=none
SRC=src


_DEPS=hello.h
DEPS=$(patsubst %,$(IDIR)/,%(_DEPS))
_OBJ=file1.o file2.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))

$(ODIR)/%.o: $(SRC)/%.cpp $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS) # $(LIBS)

test_proj: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS)

.PHONY: clean

clean:
    rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~

When I run make on this, I get the following error:

g++      -o .o
g++: fatal error: no input files
compilation terminated.
<builtin>: recipe for target '.o' failed
mingw32-make.exe: *** [.o] Error 1

I'm using GNU Make 3.82.90 built for i686-pc-mingw32, if that matters at all.

Can anyone point out whatever ridiculous error I'm making?

2
Why such a complex file tree structure for a small project?Basile Starynkevitch
Honestly, I agree it's overkill and I've scaled this down to a working and simpler makefile. Part of my goal with this project was to decouple myself for Windows / Visual Studio and gain confidence in the GNU toolchain and workflow. The project will likely grow, but I wanted to make sure I could build a makefile that would work on a project with a more complicated structure, so I started with this for my simple project. So yeah, overkill :)8bitcartridge
Your overall goal might be satisfied by switching to Linux and develop under Linux.Basile Starynkevitch
Working on it :) Working on Windows = a temporary condition; I just really wanted to get started on this.8bitcartridge

2 Answers

1
votes
IDIR=include .

is the first problem. Replace it by:

IDIR=include

With your code CFLAGS is expanded as:

-Iinclude .

It does not make sense, I'm afraid. The second problem is:

DEPS=$(patsubst %,$(IDIR)/,%(_DEPS))

which should probably be:

DEPS=$(patsubst %,$(IDIR)/%,$(_DEPS))

and would expand as:

DEPS=include/hello.h

if you fix the first problem, else as:

DEPS=include ./hello.h

which does not make sense neither. The cumulated effect of these two errors are strange recipes (I didn't try to expand them by hand) that probably trigger a make implicit rule with wrong parameters.

1
votes
IDIR=include .
CC=g++
CFLAGS=-I$(IDIR)

This is wrong. First, for C++ code, use CXX not CC and CXXFLAGS not CFLAGS. Run make -p to understand the builtin rules of your make.

Then -I$(IDIR) does not "distribute" the -I, and IDIR is never used elsewhere. So I suggest to start your Makefile with:

CXX=g++
MY_CXX_LANG_FLAGS= -std=c++11
MY_CXX_WARN_FLAGS= -Wall -Wextra
MY_CXX_INCL_FLAGS= -I.  -Iinclude
MY_CXX_MACRO_FLAGS= -DMYFOO=32
### replace with -O2 for a release build below
MY_CXX_OPTIM_FLAGS= -g 
CXXFLAGS= $(MY_CXX_LANG_FLAGS) $(MY_CXX_WARN_FLAGS) \
          $(MY_CXX_INCL_FLAGS) $(MY_CXX_MACRO_FLAGS)

I won't improve your Makefile, but I do suggest to upgrade to GNU make version 4 if possible (and compiling make 4.1 from its source code is worthwhile in 2015) for that purpose. If possible enable GUILE scripting in it.

If you are forced to use make 3.82 debug your Makefile using remake (with -x); if you can afford a make version 4 use its --trace option

BTW, you might consider using automatic dependencies, that is generating dependencies by passing -M or -MG (etc) flags of g++, see that.

At last, a simple project for a small program (less than a hundred thousands of source lines) might just put all (a few dozens of) its files in the current directory (then the Makefile could be simpler); your proposed directory structure might be arcane for a simple project (but could worth the pain if you have millions of C++ source lines of code). I've given several simple examples of Makefile, e.g. this & that. And GNU make source code itself has a less complex file tree that what you want.

BTW, I strongly disagree with the opinions of that answer (which I did upvote, since it is helpful). I don't feel that GNU make is senile, but I regret that, instead of using recent features available on recent versions (4.x) of make, many people prefer to use complex and arcane Makefile generators (like cmake) instead of coding a clever Makefile (for make version 4 specifically).

At last, you could use other builders, e.g. omake, icmake, ....