Reputation: 154
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.
Upvotes: 2
Views: 593
Reputation: 94614
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.
Upvotes: 2
Reputation: 430
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
Upvotes: 0