16

I am working my way through a make tutorial. Very simple test projects I am trying to build has only 3 files: ./src/main.cpp ./src/implementation.cpp and ./include/header.hpp This is the make file.

VPATH = src include
CPPFLAGS = -I include

main: main.o implementation.o
main.o: header.hpp
implementation.o: header.hpp

When called without any arguments make builds only object files, but doesn't link the executable file. There supposed to be an implicit rule for prog or I am missing something? I really need someone to point me into right direction.

Thanks.

I made the first target name the same as the prefix of the source file. Now make calls cc to link object files.

g++  -I include  -c -o main.o src/main.cpp    
g++  -I include  -c -o implementation.o src/implementation.cpp
cc   main.o implementation.o   -o main

For some reason linking with g++ works, but linking with cc doesn't.

I could specify the rule explicitly, but want to learn how to use implicit rules.

pic11
  • 14,267
  • 21
  • 83
  • 119
  • I am assuming you were reading the book - Managing projects with GNU Make 3e and were experimenting with implicit and pattern rules in make. I got stuck at the same place and thanks to this SO question I got it resolved in no time. – rgk Jan 02 '15 at 17:21
  • 1
    You could set target specific CC variable to alias CXX. `main: CC=$(CXX)` make sure that CC is only set to be CXX for compiling and linking main and it dependencies. Of course that isn't good solution if main is mixing C and C++ code requiring C compiler for some objects. – Pauli Nieminen Apr 01 '15 at 15:49

7 Answers7

15

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

Teharez
  • 501
  • 8
  • 25
Hasturkun
  • 35,395
  • 6
  • 71
  • 104
  • 1
    It works if defined CC = g++. Linking with cc instead of g++ doesn't work. – pic11 Mar 29 '11 at 16:21
  • 8
    This fixed it: **LDFLAGS = -lstdc++**. Btw, why not just set CC=g++? Would it cause any problems if my project had C source files or linked to C libs? – pic11 Mar 29 '11 at 16:32
  • 2
    @PavelŠimerda: From the manual: "This rule does the right thing for a simple program with only one source file. It will also do the right thing if there are multiple object files (presumably coming from various other source files), one of which has a name matching that of the executable file" – Hasturkun Oct 20 '13 at 12:15
  • @Hasturkun I just realized that it works for *any* name if you have at least one `*.c` source file instead of `*.cpp`. That sounds like a bug in `make`, actually. – Pavel Šimerda Oct 20 '13 at 12:19
  • @Hasturkun: With C programs, the citation from the manual seems to actually only applies if you don't write down the dependency list for that target at all. – Pavel Šimerda Oct 20 '13 at 12:20
  • @Hasturkun My bad, sorry for the confusion, I mixed the test results with the same name and with a different name. – Pavel Šimerda Oct 20 '13 at 12:23
  • @PavelŠimerda: Not a bug, IMHO. more like useful shorthand. Not everything has to be compiled by the C compiler (You can still use it to link though). Anyhow, I don't see an obvious was of clarifying my answer (I could direct the link at "Linking a single object file", but that might break), so I'll take the downvote. – Hasturkun Oct 20 '13 at 13:06
  • 3
    Although `LDFLAGS` technically works, [the documentation says](https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html#Implicit-Variables) `LDLIBS` (formerly known as `LOADLIBES`) is where `-l` options like `-lstdc++` belong. – Rob Kennedy Dec 29 '15 at 23:54
  • @RobKennedy Exactly. As I mentioned below. – Franklin Yu Jun 15 '16 at 02:04
5

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.

Franklin Yu
  • 8,920
  • 6
  • 43
  • 57
5

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.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • What is the fix? How to trigger the implicit rule to build the executable? – pic11 Mar 29 '11 at 15:12
  • @pic11 I don’t think there is one, as soon as you name it. It only exists for executables that have the same base name as their source file (.cpp or .o). – Konrad Rudolph Mar 29 '11 at 15:14
  • Replaced prog with main (since there is main.cpp), but make calls cc to link. – pic11 Mar 29 '11 at 15:18
  • @pic11 `make` always calls `cc` to link, that’s normal (and shouldn’t cause any problems). – Konrad Rudolph Mar 29 '11 at 15:20
  • 1
    It doesn't link. Says: main.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0' – pic11 Mar 29 '11 at 15:34
  • Not true. When I run `touch qwer.cpp && make qwer`, it triggers an implicit rule for C++ to make the executable called `qwer`. – Pavel Šimerda Oct 20 '13 at 11:37
  • Simply false. There's an implicit rule for building an executable file from object files. – Pavel Šimerda Oct 20 '13 at 12:02
  • Or at least it's used when you explicitly write the object files as dependencies but without commands. – Pavel Šimerda Oct 20 '13 at 12:21
  • @Pavel Read the question and my answer again. OP is trying to build a program named `prog` and there is no corresponding source file for `prog`. Your test case is completely different because the base name is the same for the source and target file. Implicit rules are done via filename matching, as my answer says. – Konrad Rudolph Oct 20 '13 at 21:19
  • @Pavel I invite you to look at the authorship dates then. My answer was posted **before** that. So “already covered elsewhere” applies to *that* answer not to mine, if at all. – Konrad Rudolph Oct 21 '13 at 22:49
  • @KonradRudolph: It actually applies to the answer I would give you if I haven't already commented elsewhere. – Pavel Šimerda Oct 22 '13 at 22:53
5

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.

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • 2
    It is OK, but I am trying to learn how to use implicit rules. – pic11 Mar 29 '11 at 16:11
  • Implicit rules will not get you very far. :) – Simon Richter Mar 29 '11 at 16:25
  • Implicit rules work pretty well but I recommend you to very soon switch to *autotools*. It's a bit more work for the beginning, but not that bad and allows very easily do much more than with plain makefiles. – Pavel Šimerda Oct 20 '13 at 11:39
  • By the way, this doesn't answer the question nor does it provide a reason for that. – Pavel Šimerda Oct 20 '13 at 12:04
  • Implicit rules will not get you far (e.g. when you are _hacking_), but it does work for this situation. The OP simply needs one more line. – Franklin Yu Jun 15 '16 at 02:11
  • Without dependency tracking, you will get curious and interesting bugs if you change a header file. – Simon Richter Aug 12 '16 at 22:12
  • @SimonRichter Sorry to reply to an old comment. Yes dependency is very useful, but they don't conflict with implicit rule. Why not having implicit rule *and* dependency tracking? – Franklin Yu Oct 01 '19 at 02:53
  • @FranklinYu, the savings isn't worth it usually. In my example, only the `.cpp.o` rule can be implicit, and you still need to specify `-MD -MP` somewhere, so you can only shorten that to `CXXFLAGS+=-MD -MP`. The linker rule in my example can't be implicit as soon as there are multiple source files, and both the `clean` rules and the rule to generate the initial empty dependency files need to be made explicit as well. So you are saving one line in a twenty line file, for unclear benefit. – Simon Richter Oct 01 '19 at 12:16
  • @SimonRichter First, it's OP who wants implicit rule, as well as future users coming from Google. You are trying to argue against implicit rule to all of them, and I doubt this is the right place instead of writing a blog "*implicit rule considered harmful*". Or at least you should first teach them implicit rule *before* arguing against it. This makes Stack Overflow more useful. Second, the linking line can also be implicit. When GNU make sees `prog: main.o lib.o` it will link it with GCC correctly (actually not always GCC but that's beside the point). – Franklin Yu Oct 02 '19 at 04:55
2

If you want to link c++ object files you can specify LINK.o to be LINK.cc at the top

LINK.o := $(LINK.cc)

You should then see c++ instead of cc in your make output

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
1

The implicit rule for linking object files is:

$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

But $(LINK.o) uses $(CC), which is not quite correct for compiling C++ programs, so the easiest fix is:

CC = $(CXX)
Jerome
  • 2,350
  • 14
  • 25
0

Hmm...

CXX = g++               # Just an example
CXXFLAGS = -Wall -O2    # Just an example

prog: main.o implementation.o
    $(CXX) $(CXXFLAGS) $^ -o $@

main.o: header.hpp
implementation.o: header.hpp

should do the job. Why your variant isn't working is explained in Konrad Rudolph answer

maverik
  • 5,508
  • 3
  • 35
  • 55
  • You shouldn't need `$(CXXFLAGS)` in the linker rule, instead, `$(LDFLAGS)` is commonly used. You shouldn't need to write down the linker command at all, as it's implicit. – Pavel Šimerda Oct 20 '13 at 11:42
  • Sorry, you need the linker command to get it right with different filenames, only the first part applies. – Pavel Šimerda Oct 20 '13 at 12:25