28

I have the following makefile:

CC=g++
INC_DIR = ../StdCUtil
CFLAGS=-c -Wall -I$(INC_DIR)
DEPS = split.h

all: Lock.o DBC.o Trace.o

%.o: %.cpp $(DEPS)
    $(CC) -o $@ $< $(CFLAGS)

clean:
    rm -rf *o all

This makefile and all three source files Lock.cpp, DBC.cpp, Trace.cpp are located in the current directory called Core. One of the source file Trace.cpp contains a line that includes a header file outside the current directory:

//in Trace.cpp
#include "StdCUtil/split.h"

The header file split.h is located at one level above the current directory and then in the subdirectory called StdCUtil. So that's why I added INC_DIR = ../StdCUtil in the makefile. The overall directory structure looks like the following:

root
  |___Core
  |     |
  |     |____Makefile
  |     |____DBC.cpp
  |     |____Lock.cpp
  |     |____Trace.cpp
  |
  |___StdCUtil
        |___split.h

But when I make it, it gives me the error:

Trace.cpp:8:28: fatal error: StdCUtil/split.h: No such file or directory
 #include "StdCUtil/split.h"
                            ^
compilation terminated.
<builtin>: recipe for target 'Trace.o' failed

Why this doesn't find the header file split.h even if I specify the INC_DIR in the makefile? How to correct this?

tonga
  • 11,749
  • 25
  • 75
  • 96

4 Answers4

37

These lines in your makefile,

INC_DIR = ../StdCUtil
CFLAGS=-c -Wall -I$(INC_DIR)
DEPS = split.h

and this line in your .cpp file,

#include "StdCUtil/split.h"

are in conflict.

With your makefile in your source directory and with that -I option you should be using #include "split.h" in your source file, and your dependency should be ../StdCUtil/split.h.

Another option:

INC_DIR = ../StdCUtil
CFLAGS=-c -Wall -I$(INC_DIR)/..  # Ugly!
DEPS = $(INC_DIR)/split.h

With this your #include directive would remain as #include "StdCUtil/split.h".

Yet another option is to place your makefile in the parent directory:

root
  |____Makefile
  |
  |___Core
  |     |____DBC.cpp
  |     |____Lock.cpp
  |     |____Trace.cpp
  |
  |___StdCUtil
        |___split.h

With this layout it is common to put the object files (and possibly the executable) in a subdirectory that is parallel to your Core and StdCUtil directories. Object, for example. With this, your makefile becomes:

INC_DIR = StdCUtil
SRC_DIR = Core
OBJ_DIR = Object
CFLAGS  = -c -Wall -I.
SRCS = $(SRC_DIR)/Lock.cpp $(SRC_DIR)/DBC.cpp $(SRC_DIR)/Trace.cpp
OBJS = $(OBJ_DIR)/Lock.o $(OBJ_DIR)/DBC.o $(OBJ_DIR)/Trace.o
# Note: The above will soon get unwieldy.
# The wildcard and patsubt commands will come to your rescue.

DEPS = $(INC_DIR)/split.h
# Note: The above will soon get unwieldy.
# You will soon want to use an automatic dependency generator.


all: $(OBJS)

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
  $(CC) $(CFLAGS) -c $< -o $@

$(OBJ_DIR)/Trace.o: $(DEPS)
Enlico
  • 23,259
  • 6
  • 48
  • 102
David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • Thanks David. The second approach you marked as "ugly" actually works! I also tried the first approach in which I just use `#include "split.h"` in `Trace.cpp` but I still get the same error. Don't know why the first approach doesn't work. I haven't had time to try the third way yet. Will report back after I try it. – tonga Mar 20 '14 at 21:55
  • 1
    It turns out that both the first and third option work. I found out that I need to change the dependency variable to be `DEPS = $(INC_DIR)/StdCUtil/split.h` and this way I don't need to modify the source code include and it remains as `#include "StdCUtil/split.h"`. Thanks for all the suggestions. – tonga Mar 21 '14 at 14:15
  • Does the "." immediately after "-I" refer to the current directory? The syntax seems somehow awkward, like I'd expect a space or an "=" between them. Is that just me? – Alex Jansen Mar 01 '17 at 01:42
  • 2
    @AlexJohnson -- That's exactly what it means. The gcc documentation says that the `-I` option is specified as `-Idir`, where `dir` is the name of the directory to be added to the include path. `-I=dir` would add the directory `=dir` to the include path. (But `-I dir` with a space between the `-I` and the path to the directory does seem to work.) – David Hammen Mar 01 '17 at 21:32
4

The preprocessor is looking for StdCUtil/split.h in

and in

  • $INC_DIR (i.e. ../StdCUtil/ = /root/Core/../StdCUtil/ = /root/StdCUtil/). So ../StdCUtil/ + StdCUtil/split.h = ../StdCUtil/StdCUtil/split.h and the file is missing

You can fix the error changing the $INC_DIR variable (best solution):

$INC_DIR = ../

or the include directive:

#include "split.h"

but in this way you lost the "path syntax" that makes it very clear what namespace or module the header file belongs to.

Reference:

EDIT/UPDATE

It should also be

CXX = g++
CXXFLAGS = -c -Wall -I$(INC_DIR)

...

%.o: %.cpp $(DEPS)
    $(CXX) -o $@ $< $(CXXFLAGS)
Community
  • 1
  • 1
manlio
  • 18,345
  • 14
  • 76
  • 126
  • Thanks manilo. Actually I tried using `INC_DIR = ../` but it gives me the same error information. I also feel strange on this error. – tonga Mar 20 '14 at 21:28
  • You are right, we must change also CC with CXX=g++ and CFLAGS=... with CXXFLAGS=... – manlio Mar 20 '14 at 21:52
0

This is not a question about make, it is a question about the semantic of the #include directive.

The problem is, that there is no file at the path "../StdCUtil/StdCUtil/split.h". This is the path that results when the compiler combines the include path "../StdCUtil" with the relative path from the #include directive "StdCUtil/split.h".

To fix this, just use -I.. instead of -I../StdCUtil.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
0

Try INC_DIR=../ ../StdCUtil.

Then, set CCFLAGS=-c -Wall $(addprefix -I,$(INC_DIR))

EDIT: Also, modify your #include to be #include <StdCUtil/split.h> so that the compiler knows to use -I rather than local path of the .cpp using the #include.

Bill Perkins
  • 194
  • 4
  • 1
    I feel silly too. Just realized that you are using reserved words in make - namely `CC` and `CFLAGS`. `CC` should be `CXX` and `CFLAGS` should be `CXXFLAGS`. Then, your command for your %.o target is `$(CXX) -o $@ $<` – Bill Perkins Mar 20 '14 at 21:45
  • 1
    In general, it's not a good idea to switch from `#include "foo/bar.h"` to `#include `. The standard is not at all clear on the difference between the two; it's implementation-defined. In practice, unless you use some rather advanced flags, the difference between the two forms on most compilers oftentimes is amazingly small. `#include "foo/bar.h"` first searches in the directory that contains the file being compiled and then reverts to `#include `. Amongst programmers, `#include ` typically means "`foo/bar.h` is something my team didn't write". – David Hammen Mar 20 '14 at 23:16
  • @DavidHammen: Agreed on this. – tonga Mar 21 '14 at 14:17