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 the LDLIBS 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?

  1. Hasturkun: having main.o in the rule

    main: main.o implementation.o
    

    does not lead to an error. The main.o is not necessary, but it will still make.

  2. 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.

  3. Jerome: I used to change LINK.o from $(CC) $(LDFLAGS) $(TARGET_ARCH) to $(CXX) $(LDFLAGS) $(TARGET_ARCH) and it worked, but I prefer editing LDLIBS since LINK.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

Tags:

C++

Makefile