Makefiles: specific 'no input files', automatic variables

586 views Asked by At

I'm new to makefiles, and they puzzle me. I have the following folder hierarchy:

A folder named lib contains tow folders: include (with file mylib.h) and src (with file mylib.cpp). It also contains a Makefile, which, for some reason, gives me an error.

The full makefile is:

CFLAGS = -Wall -fPIC
OBJECTS = mylib.o

all: libmine.so

libmine.so: $(OBJECTS)
            g++ -shared $(CFLAGS) \
            -o libmine.so \
            $(OBJECTS)

%.o:        src/%.cpp include/%.h
            g++ $(CFLAGS) \
            -I include \
            -o %.o \
            -c src/%.cpp

clean:
            rm src/*.o
            rm libmine.so

The error is

mr209@Quantum:~/Desktop/hw1/lib$ make
g++ -Wall -fPIC \
            -I include \
            -o %.o \
            -c src/%.cpp
g++: error: src/%.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
make: *** [mylib.o] Error 4

But the file is present. Thus, make is doing weird things, causing it not to be able to find the .cpp file.

In order to make libmine.so, g++ will have to do something with mylib.o, and for a generic .o file I have written some lines of code.

Here is what I was thinking: in order to make libmine.so, g++ will have to do something with mylib.o. Thus, in lib, a file named mylib.o has to appear. Using the generic %.0 rule, this file is made from mylib.cpp in src and mylib.h in include (hence the first line of the %.o rule). The file is made using g++, which has to look in include for additional headers, produces mylib.o as output, and compiles src/mylib.cpp, but -c guarantees that a .o file is produced.

Obviously, something goes wrong, and I am unable to figure out what. Only 2 days ago have I learned what Makefiles are and why one should learn how to deal with them, so I'm not that much of an expert.

2

There are 2 answers

0
E. Spiroux On

You must do a variable before put it in g++ like :

FT_C= $(src/%.cpp) FT_O=$(FT_C:.c=.o)

and

g++ $(CFLAGS) -I include -o $(FT_O) -c $(FT_C)

and don't put your .h in compilation '-I' are here for it.

Look this example if you want understand what i mean:

https://github.com/emericspiroux/wolf3d/blob/master/libft/Makefile

0
Anya Shenanigans On

Your build target %.o is miswritten. You can't use the % in the command section, so the names of the destination file and dependent file won't ever match.

The proper change is to do the following:

%.o: src/%.cpp include/%.h
    g++ $(CFLAGS) \
    -I include \
    -o $@ \
    -c src/$(@:%.o=%.cpp)

Just to explain the changes, the -o needs the target file, which is pretty much always written as $@ in Makefiles, as that's the name of the target.

Secondly, the source file needs to be defined in terms of the target, the operator in question is a pattern replacement operator $(@:%.o=%.cpp), so what that does is take the target - which will match a filename of <blah>.o, then it pattern match replaces .o with .cpp.

So in the case of the target mylib.o, the variable $@ is mylib.o, and the result of doing $(@:%.o=%.cpp) is to turn mylib.o into mylib.cpp. As a result it is the expected file that is being compiled, and the expected target is build.

Rules using a % pattern in them are what are referred to as implicit rules, and are used to reduce the complexity of the code being written - if you had a pile of files that shared the target pattern: blah.o: src/blah.cpp src/blah.h, then you use the implicit rule to only have to write the target once, then you need to write the commands in terms of the target.