Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Makefile doesn't detect header file change

4,084 views
Skip to first unread message

lovecreatesbeauty

unread,
Mar 19, 2012, 10:18:28 PM3/19/12
to
My Makefile doesn't detect the change of header files.

This little makefile follows sec 2.6 of GNU make manual, and I
remember it worked before when header files changed.

Where am i wrong?

Thanks

$ touch b.h
$ make
make: `a.out' is up to date.
$

$ pwd
/home/ljh/temp/src
$ ls
a.c b.c b.h Makefile
$ cat Makefile
CC = gcc
CFLAGS = -ansi -pedantic -Wall -W
LDFLAGS =
OBJS = a.o b.o
OUT = a.out

$(OUT) : $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@

a.c b.c : b.h

.PHONY : clean

clean :
rm $(OUT) $(OBJS)

$ make
gcc -ansi -pedantic -Wall -W -c -o a.o a.c
a.c: In function ¡®main¡¯:
a.c:7: warning: implicit declaration of function ¡®b¡¯
gcc -ansi -pedantic -Wall -W -c -o b.o b.c
gcc a.o b.o -o a.out
$ touch b.c
$ make
gcc -ansi -pedantic -Wall -W -c -o b.o b.c
gcc a.o b.o -o a.out
$ make
make: `a.out' is up to date.
$ touch b.h
$ make
make: `a.out' is up to date.
$
$ make -v
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for i486-pc-linux-gnu
$ uname -a
Linux debian 2.6.32-5-686 #1 SMP Mon Jan 16 16:04:25 UTC 2012 i686 GNU/
Linux
$ cat /etc/debian_version
6.0.4
$

Ian Collins

unread,
Mar 19, 2012, 10:52:14 PM3/19/12
to
On 03/20/12 03:18 PM, lovecreatesbeauty wrote:
> My Makefile doesn't detect the change of header files.

Please don't multi-post,it wastes responder's time.

--
Ian Collins

lovecreatesbeauty

unread,
Mar 20, 2012, 2:09:34 AM3/20/12
to
Thank you.

Gordon Burditt

unread,
Mar 20, 2012, 5:08:13 AM3/20/12
to
> My Makefile doesn't detect the change of header files.
>
> This little makefile follows sec 2.6 of GNU make manual, and I
> remember it worked before when header files changed.

In sec 2.6 of the GNU make manual as it is online at www.gnu.org, there
are no .c file names on the left side of the colon. In your example,
there are.

> Where am i wrong?

When you change the header file b.h, you DO NOT need to rebuild the
source files a.c and b.c. You need to rebuild the object files a.o
and b.o .

> a.c b.c : b.h

a.o b.o: b.h

You might have .c file names on the left side of the colon if C
source files are being constructed (by, say, bison, yacc, flex,
lex, gperf, any number of scripts, etc.) but it is a little unusual
for simple programs.

I note that the BSD "mkdep" command creates a .depend file (which
can be included in a Makefile) which looks like this:
$ mkdep a.c b.c
$ cat .depend
# a.c b.c
a.o: a.c b.h
b.o: b.c b.h
$

lovecreatesbeauty

unread,
Mar 20, 2012, 9:06:39 AM3/20/12
to
On Mar 20, 5:08 pm, gordonb.y7...@burditt.org (Gordon Burditt) wrote:
> > My Makefile doesn't detect the change of header files.
>
> > This little makefile follows sec 2.6 of GNU make manual, and I
> > remember it worked before when header files changed.
>
> In sec 2.6 of the GNU make manual as it is online atwww.gnu.org, there
> are no .c file names on the left side of the colon.  In your example,
> there are.
>
> > Where am i wrong?
>
> When you change the header file b.h, you DO NOT need to rebuild the
> source files a.c and b.c.  You need to rebuild the object files a.o
> and b.o .
>
> > a.c b.c : b.h
>
> a.o b.o: b.h
>
> You might have .c file names on the left side of the colon if C
> source files are being constructed (by, say, bison, yacc, flex,
> lex, gperf, any number of scripts, etc.) but it is a little unusual
> for simple programs.
>
> I note that the BSD "mkdep" command creates a .depend file (which
> can be included in a Makefile) which looks like this:
> $ mkdep a.c b.c
> $ cat .depend
> # a.c b.c
> a.o: a.c b.h
> b.o: b.c b.h
> $
>

Thank you very much. I made that mistake and didn't know it.

I'm using Debian Linux. The gcc on it has -M and -MM options to
generate dependencies. Now I come up with this new version.

I still need to provide the source filenames in the Makefile script:
SRCS = a.c b.c
I used some wildcard expansion for the SRCS variable but got some
errors.

Some of the Windows Visual Studio programmer argued: Linux is better
than Windows because Linux programmers have the chance to write their
awful Makefile. I learnt some automake but the whole bundle of tools
are even more complex than the single Make.

How can I improve my Makefile to achieve the goal that I just put the
Makefile script there and the files compile like Windows programmer do
in Visual Studio.

How is my directory tree structure of the source code orgnization?



$ cat Makefile
CC = gcc
CFLAGS = -ansi -pedantic -Wall -W
CPPFLAGS = -I include
LDFLAGS =
SRCS = a.c b.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
OUT = a.out

vpath %.c src
vpath %.h include

$(OUT): $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@

include $(SRCS:.c=.d)

%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$

.PHONY : clean
clean:
rm *.d $(OBJS) $(OUT)

$
$ pwd
/home/ljh/temp
$
$ ls . ./src/ ./include/
.:
include Makefile src


./include/:
b.h


./src/:
a.c b.c
$

Johann Klammer

unread,
Mar 20, 2012, 3:07:20 PM3/20/12
to
lovecreatesbeauty wrote:
[snip]
>
> I still need to provide the source filenames in the Makefile script:
> SRCS = a.c b.c
> I used some wildcard expansion for the SRCS variable but got some
> errors.
>
[snip]

How did it fail? The following worked for me (gnu make, sources in same
dir):

sources = $(wildcard *.c)

lovecreatesbeauty

unread,
Mar 20, 2012, 10:07:14 PM3/20/12
to
On Mar 21, 3:07 am, Johann Klammer <klamm...@NOSPAM.a1.net> wrote:
>
> How did it fail? The following worked for me (gnu make, sources in same
> dir):
>
> sources = $(wildcard *.c)

Thank you.

If all ".c" source file and Makefile reside in same directory, it
works.

I got errors for source organization like this:

$ ls
include main.c Makefile foo_src foo2_src
$

Johann Klammer

unread,
Mar 21, 2012, 3:36:25 AM3/21/12
to
lovecreatesbeauty wrote:
[snip]
> If all ".c" source file and Makefile reside in same directory, it
> works.
>
> I got errors for source organization like this:
>
> $ ls
> include main.c Makefile foo_src foo2_src
> $
>

Tried

SRCS = main.c $(wildcard foo_src/*.c) $(wildcard foo2_src/*.c)

?

I think vpath just tells make where to search,
but gcc and any other program you invoke still has to know the
full filename(including path).
Keeping sources in a single directory would be the easy fix,
but may not be what you want.

Noob

unread,
Mar 21, 2012, 4:14:03 AM3/21/12
to
lovecreatesbeauty wrote:

> On Mar 20, 10:52 am, Ian Collins wrote:
>
>> On 03/20/12 03:18 PM, lovecreatesbeauty wrote:
>>
>>> My Makefile doesn't detect the change of header files.
>>
>> Please don't multi-post, it wastes responder's time.
>
> Thank you.

Thank you?

Nobody

unread,
Mar 21, 2012, 7:18:44 AM3/21/12
to
On Tue, 20 Mar 2012 20:07:20 +0100, Johann Klammer wrote:

> sources = $(wildcard *.c)

You should normally use := rather than = when the RHS involves system
calls (e.g. wildcard or shell functions).

:= forces the RHS to be evaluated, while = stores the RHS literally,
resulting in the expression being evaluated each time that it is used.
Apart from the inefficiency, it can also result in inconsistencies.

William Ahern

unread,
Mar 21, 2012, 3:47:36 PM3/21/12
to
Delayed evaluation is more efficient because the expression may only be used
with a target which isn't going to be built. Immediate evaluation may cause
useless directory scanning, or far worse in the case of $(shell). That's
extremely annoying when you have hundreds or thousands of targets. It could
mean the difference between waiting a fraction of a second to run make, or a
maddeningly long time. (Sure, it saved the asshat who wrote the rule 5
seconds of his day, but cumulatively costs me several hours!)

That said, I agree in this case it'd be prudent to force immediate
evaluation. Unless, perhaps, absolute paths could be used (e.g. when using
non-recursive-make-type rules).

lovecreatesbeauty

unread,
Mar 21, 2012, 8:35:11 PM3/21/12
to
On Mar 21, 3:36 pm, Johann Klammer <klamm...@NOSPAM.a1.net> wrote:
Thank you. This is what I get for now.

$ ls . bar/ include/
.:
bar foo.cpp include main.cpp Makefile

bar/:
bar.cpp bar.h

include/:
foo.h
$
$ cat Makefile
OUT = main.out
SRCS := $(wildcard *.cpp) $(wildcard bar/*.cpp)
OBJS := $(patsubst %.cpp,%.o,$(SRCS))

CXX = g++
CXXFLAGS = -ansi -pedantic -Wall -W
CPPFLAGS = -I ./include -I ../include -I bar
LDFLAGS =

$(OUT): $(OBJS)
$(CXX) $(LDFLAGS) $^ -o $@

include $(SRCS:.cpp=.d)

%.d: %.cpp
@set -e; rm -f $@; \
$(CXX) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$

.PHONY: clean
clean:
rm $(OBJS) $(OUT)

$

lovecreatesbeauty

unread,
Mar 22, 2012, 1:20:39 AM3/22/12
to
On Mar 21, 3:36 pm, Johann Klammer <klamm...@NOSPAM.a1.net> wrote:
If main.c is in the same directory with Makefile, it works.

If main.c is placed in sub-directory 'src', the header file change
can't be detected. Why?

Thank you!

$ pwd
/home/ljh/temp/myapp
$ ls . include/ src/
.:
include Makefile src

include/:
foobar.h

src/:
foobar.c main.c
$
$ cat Makefile
OUT = main.out
SRCS = $(wildcard *.c) $(wildcard src/*.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))
CC = gcc
CFLAGS = -ansi -pedantic -Wall -W
CPPFLAGS = -I include
LDFLAGS =

$(OUT): $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@

include $(SRCS:.c=.d)

%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$

.PHONY : clean
clean:
rm $(OBJS) $(OUT)

$
$ make
Makefile:12: src/foobar.d: No such file or directory
Makefile:12: src/main.d: No such file or directory
gcc -ansi -pedantic -Wall -W -I include -c -o src/foobar.o src/
foobar.c
gcc -ansi -pedantic -Wall -W -I include -c -o src/main.o src/
main.c
src/main.c: In function ‘main’:
src/main.c:7: warning: implicit declaration of function ‘foobar’
gcc src/foobar.o src/main.o -o main.out
$ touch include/foobar.h
$ make
make: `main.out' is up to date.
$


Johann Klammer

unread,
Mar 22, 2012, 5:59:49 AM3/22/12
to
lovecreatesbeauty wrote:
[snip]
> If main.c is placed in sub-directory 'src', the header file change
> can't be detected. Why?
>
[snip]

Good morning,

Just tried something similar here
and it looks like the sed command does not match the filename anymore
Instead of:

src/main.o src/main.d: ....
I get
main.o: ....

(you really should have posted(or read) those .d files)

change your sed snippet to something like:

%.d : %.c
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($(*F)\)\.o[ :]*,$*.o $@\: ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$

and _that_ will work...

Of course you _will_ still run into problems with relative #include
paths and the like

Bye,
JK

Nobody

unread,
Mar 22, 2012, 9:37:45 AM3/22/12
to
On Wed, 21 Mar 2012 12:47:36 -0700, William Ahern wrote:

>> You should normally use := rather than = when the RHS involves system
>> calls (e.g. wildcard or shell functions).
>
>> := forces the RHS to be evaluated, while = stores the RHS literally,
>> resulting in the expression being evaluated each time that it is used.
>> Apart from the inefficiency, it can also result in inconsistencies.
>
> Delayed evaluation is more efficient because the expression may only be
> used with a target which isn't going to be built. Immediate evaluation may
> cause useless directory scanning, or far worse in the case of $(shell).

It *may* be more efficient. Immediate evaluation is performed exactly
once. Delayed evaluation may be performed any number of times (where the
number may be zero).

If the variable is used as a target or prerequisite, it will be expanded
when the rule is parsed, regardless of whether or not the target is
eventually built. Variables used in commands will only be expanded if the
commands are executed.

When $(wildcard ...) is used to determine targets or prerequisites, it's
almost certain that the expansion will occur regardless of which targets
are to be made.

OTOH, something like:

CFLAGS = $(shell pkg-config --cflags ...)

will only be expanded if compilation commands are actually run, but in
the case of a clean (or substantially out-of-date) source tree it will
be expanded many times.

lovecreatesbeauty

unread,
Mar 22, 2012, 10:37:27 AM3/22/12
to
On Mar 22, 5:59 pm, Johann Klammer <klamm...@NOSPAM.a1.net> wrote:
> src/main.o src/main.d: ....
> I get
> main.o: ....
>
> (you really should have posted(or read) those .d files)
>
> change your sed snippet to something like:
>
> %.d : %.c
>         $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
> sed 's,\($(*F)\)\.o[ :]*,$*.o $@\: ,g' < $@.$$$$ > $@; \
> rm -f $@.$$$$
>

Thank you.

The list of generated .d files added. You won't need the content of
those .d files, right?

The problem with my ./Makefile is: If ./bar/bar.h is touched its
corresponding source file ./bar/bar.c will not be re-compiled; Only
the ./main.c is re-compiled. (Followed by the linking process)

For files in sub-directories eg. ./bar/bar.c, ./bar/bar.h, the my ./
Makefile in upper level directory doesn't work with them properly.

If ./include/foo.h touched, the corresponding source file ./foo.c
and ./main.c are all re-compiled. (in the mentioned ./bar/bar.h
case, ./bar/bar.c not re-compiled). (Followed by the linking)

It seems that it will work if all my .c source files are placed in the
current ./Makefile directory.

$
$ pwd
/home/jhl/tmp/c/myapp
$ ls . bar include/
.:
bar foo.c include main.c Makefile

bar:
bar.c bar.h

include/:
foo.h
$ cat Makefile
OUT = main.out
SRCS := $(wildcard *.c) $(wildcard bar/*.c)
OBJS := $(patsubst %.c,%.o,$(SRCS))

CC = gcc
CFLAGS = -ansi -pedantic -Wall -W
CPPFLAGS = -I ./include -I ../include -I bar
LDFLAGS =

$(OUT): $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@

include $(SRCS:.c=.d)

%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$

.PHONY: clean
clean:
rm $(OBJS) $(OUT)

$ make
Makefile:13: foo.d: No such file or directory
Makefile:13: main.d: No such file or directory
Makefile:13: bar/bar.d: No such file or directory
gcc -ansi -pedantic -Wall -W -I ./include -I ../include -I bar -c -o
foo.o
foo.
c
gcc -ansi -pedantic -Wall -W -I ./include -I ../include -I bar -c -o
main.o
mai
n.c
gcc -ansi -pedantic -Wall -W -I ./include -I ../include -I bar -c -o
bar/
bar.o
bar/bar.c
gcc foo.o main.o bar/bar.o -o main.out
$ make
make: `main.out' is up to date.
$ ls . bar include/
.:
bar foo.c foo.d foo.o include main.c main.d main.o main.out
Makefile

bar:
bar.c bar.d bar.h bar.o

include/:
foo.h
$ touch include/foo.h
$ make
gcc -ansi -pedantic -Wall -W -I ./include -I ../include -I bar -c -o
foo.o
foo.
c
gcc -ansi -pedantic -Wall -W -I ./include -I ../include -I bar -c -o
main.o
mai
n.c
gcc foo.o main.o bar/bar.o -o main.out
$ touch bar/bar.h
$ make
gcc -ansi -pedantic -Wall -W -I ./include -I ../include -I bar -c -o
main.o
mai
n.c
gcc foo.o main.o bar/bar.o -o main.out
$
$

William Ahern

unread,
Mar 22, 2012, 6:20:46 PM3/22/12
to
Nobody <nob...@nowhere.com> wrote:
> On Wed, 21 Mar 2012 12:47:36 -0700, William Ahern wrote:

> >> You should normally use := rather than = when the RHS involves system
> >> calls (e.g. wildcard or shell functions).
> >
> >> := forces the RHS to be evaluated, while = stores the RHS literally,
> >> resulting in the expression being evaluated each time that it is used.
> >> Apart from the inefficiency, it can also result in inconsistencies.
> >
> > Delayed evaluation is more efficient because the expression may only be
> > used with a target which isn't going to be built. Immediate evaluation may
> > cause useless directory scanning, or far worse in the case of $(shell).

> It *may* be more efficient. Immediate evaluation is performed exactly
> once. Delayed evaluation may be performed any number of times (where the
> number may be zero).

Good point.

What would be nice is true lazy evaluation--delayed but memoized. I'll put
that on my list of features to add to my fantasy Make implementation.

William Ahern

unread,
Mar 22, 2012, 7:01:03 PM3/22/12
to
Alas, once again this is something gmake can do, but only by holding one's
nose: http://cakoose.com/wiki/gnu_make_thunks

FWIW, the example didn't work as-is for me. GNU Make 3.81 (OS X Lion) choked
unless I separated the two macros in the thunk with a space.

Gordon Burditt

unread,
Mar 22, 2012, 8:47:32 PM3/22/12
to
> How is my directory tree structure of the source code orgnization?
>
...
> $ ls . ./src/ ./include/
> .:
> include Makefile src

What is the purpose of such an organization, other than confusing
make and/or making Makefiles harder to read?

I can see the point if your program has 9 different modules (database,
UI, graphics, command line parsing, new mail check, save configuration,
restore configuration, common support routines, and zombies) with
9 source directories and 1 directory for *public* includes.

For a single program, it just seems to make finding stuff in the
source code more difficult.

lovecreatesbeauty

unread,
Mar 22, 2012, 9:22:13 PM3/22/12
to
Thank you.

The Managing Projects with GNU Make (3rd) calls this organization
"traditional source tree layout".

For a too simple program, I can just write every individual explicit
rule for those several files.

--quote: Managing Projects with GNU Make (3rd)--
In a traditional source tree layout the header files are placed in an
include directory
and the source is placed in a src directory. We’ll do this and put our
makefile in the
parent directory.
--quote ends--

lovecreatesbeauty

unread,
Mar 22, 2012, 9:23:51 PM3/22/12
to
On Mar 22, 5:59 pm, Johann Klammer <klamm...@NOSPAM.a1.net> wrote:

I found this: edam’s general-purpose makefile! < http://ed.am/dev/make/edam-mk
>

How do you think about it?

Johann Klammer

unread,
Mar 23, 2012, 2:53:43 AM3/23/12
to
I suspect that in a later chapter they will suggest you put a makefile
in each subdirectory and use some recursive make thingy...

But then you may want to read this:
http://evbergen.home.xs4all.nl/nonrecursive-make.html

BTW, most of the old geezers around here seem to killfile posts from
google groups, so you may get more answers using some real newsreader
(like thunderbird).

lovecreatesbeauty

unread,
Mar 23, 2012, 3:18:22 AM3/23/12
to
On Mar 23, 2:53 pm, Johann Klammer <klamm...@NOSPAM.a1.net> wrote:
>
> > --quote: Managing Projects with GNU Make (3rd)--
>
> I suspect that in a later chapter they will suggest you put a makefile
> in each subdirectory and use some recursive make thingy...
>
> But then you may want to read this:http://evbergen.home.xs4all.nl/nonrecursive-make.html
>
> BTW, most of the old geezers around here seem to killfile posts from
> google groups, so you may get more answers using some real newsreader
> (like thunderbird).
>

Thank you.

If I don't use wildcard in variable SRCS, this version even woks for
all the following layout:

Layout 1:

$ ls . include/ src/ mod_a/
.:
include Makefile mod_a src

include/:
bar.h foo.h

mod_a/:
mod_a.c mod_a.h

src/:
bar.c foo.c main.c
$

Layout 2:

$ ls . include/ src/ mod_a/
.:
include main.c Makefile mod_a src

include/:
bar.h foo.h

mod_a/:
mod_a.c mod_a.h

src/:
bar.c foo.c
$

The inconvenient is that I need to specify all the names and
directories of source files. I can stay peace with it though.

I haven't tried your new sed snippet. With you suggestion of the
wildcard in variable SRCS, there's no need to do that. But the ./src/
Makefile and all source files should be put in one same directory eg ./
src/ and header files in ./header. If I can fix it, I'll get my
general Makefile and it will be great.


$ cat Makefile
OUT = main.out
SRCS = main.c foo.c bar.c \
mod_a.c
OBJS = $(patsubst %.c,%.o,$(SRCS))

CC = gcc
CXX = g++
CFLAGS = -ansi -pedantic -Wall -W
CXXFLAGS = -ansi -pedantic -Wall -W
CPPFLAGS = -I include -I mod_a
LDFLAGS =

vpath %.c src mod_a

# use CXX instead of CC for C++ source file
$(OUT): $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@

include $(SRCS:.c=.d)

# use CXX instead of CC for C++ source file
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$

.PHONY : clean
clean:
rm *.d $(OBJS) $(OUT)

$
$ make
Makefile:19: main.d: No such file or directory
Makefile:19: foo.d: No such file or directory
Makefile:19: bar.d: No such file or directory
Makefile:19: mod_a.d: No such file or directory
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o main.o main.c
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o foo.o src/
foo.c
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o bar.o src/
bar.c
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o mod_a.o mod_a/
mod_a.c
gcc main.o foo.o bar.o mod_a.o -o main.out
$ make
make: `main.out' is up to date.
$ touch include/foo.h
$ make
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o main.o main.c
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o foo.o src/
foo.c
gcc main.o foo.o bar.o mod_a.o -o main.out
$ make
make: `main.out' is up to date.
$ touch mod_a/mod_a.h
$ make
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o main.o main.c
gcc -ansi -pedantic -Wall -W -I include -I mod_a -c -o mod_a.o mod_a/
mod_a.c
gcc main.o foo.o bar.o mod_a.o -o main.out
$ make
make: `main.out' is up to date.
$ ./main.out
main.c:8:main
src/foo.c:6:foo
src/bar.c:6:bar
mod_a/mod_a.c:6:mod_a
$

0 new messages