make: implicit rule to link c++ project
There supposed to be an implicit rule for prog or I am missing something?
There is no implicit rule. make
cannot know how to build prog
because it doesn’t know that prog
is supposed to be an executable. make
only uses the file name as a pattern to deduce the build rule. prog
is a generic file name without extension so make
doesn’t know how to treat it.
My answer (a neat solution): add
LDLIBS = -lstdc++
to the Makefile. According to the manual:
Libraries (
-lfoo
) should be added to theLDLIBS
variable instead.
LDFLAGS
are designed for library directory flags such as -L
. On my Linux (Ubuntu 14.04), LDFLAGS = -lstdc++
produces
cc -lstdc++ main.o -o main
which does not work, while LDLIBS = -lstdc++
produces
cc main.o -lstdc++ -o main
which works. I have no idea why the order matters, but it makes sense according to the roles of the two built-in variables. I do not like to alias CC
to CXX
which seems like hacking, as well as confusing for readers.
LDFLAGS v.s. LDLIBS
I just tried and found that this compiler does not work for LDFLAGS = -lstdc++
:
- GCC 4.8.5 on Ubuntu 14.04
but the following compilers accept LDFLAGS = -lstdc++
:
- Clang 3.4 on Ubuntu 14.04
- GCC 4.7.2 on Debian Wheezy
- Clang 7.3.0 (703.0.31) on OS X
So it works most of the time, but is not guaranteed. If you want your makefile to be more portable, use LDLIBS
which works on all the above environments.
Why not other solutions above?
Hasturkun: having
main.o
in the rulemain: main.o implementation.o
does not lead to an error. The
main.o
is not necessary, but it will still make.Simon Richter: the solution remove the need to track the header (which is really great), but OP wants an implicit rule. We can actually get the best of both:
VPATH = src include CPPFLAGS = -I include -MMD -MP CXXFLAGS = -g -W -Wall -Werror LDLIBS = -lstdc++ target = main lib = implementation.cpp objects = $(target:=.o) $(lib:.cpp=.o) $(target): $(objects) %.o: %.cpp %.d %.d: ; -include $(objects:.o=.d) clean:: $(RM) $(target) $(objects) $(objects:.o=.d)
which does what he did, as well as taking advantage of implicit rules. However, this complete solution should not be here, since it is not what the OP desire: OP just want to know why his Makefile does not work, and why. "Auto-Dependency Generation" is yet another huge topic deserving an entire tutorial (like this one). So I'm sorry, but his answer did not actually answer the question.
Jerome: I used to change
LINK.o
from$(CC) $(LDFLAGS) $(TARGET_ARCH)
to$(CXX) $(LDFLAGS) $(TARGET_ARCH)
and it worked, but I prefer editingLDLIBS
sinceLINK.o
is not documented (and possibly not part of the public API) and not future-proof. I would call that a hack.
How about this for a minimal Makefile:
SOURCES = src/main.cpp src/implementation.cpp
CXX = g++
CXXFLAGS = -g -W -Wall -Werror
LDFLAGS = -g
OBJECTS = $(SOURCES:.cpp=.o)
prog: $(OBJECTS)
$(CXX) $(LDFLAGS) -o $@ $^
clean::
$(RM) prog
.cpp.o:
$(CXX) -MD -MP $(CXXFLAGS) -o $@ -c $<
clean::
$(RM) src/*.o
DEPENDS = $(SOURCES:.cpp=.d)
-include $(DEPENDS)
%.d:
@touch $@
clean::
$(RM) src/*.d
This assumes GNU make and gcc, but it adds proper dependency tracking, so there is no need to explicitly list the header file dependencies.
According to the make manual, you can use the implicit linking rule with multiple objects if one of these matches the executable name, eg:
VPATH = src include
CPPFLAGS = -I include
main: implementation.o
main.o: header.hpp
implementation.o: header.hpp
This will build an executable named main from both main.o and implementation.o.
Note however that the builtin implicit rule uses the C compiler for linking, which will not link against the C++ std library by default, you will need to add the flag -lstdc++
to LDLIBS explicitly