GNU-Make does not recompile when a header file changed

偶尔善良 提交于 2020-01-23 08:58:21

问题


GNU-Make does not recompile when hdr.h file changed. As below printed lines, it did not try to recompile even main.d file is generated. Can you guide me why it happend?

hdr.h

#ifndef __HDR_H__  

#define LOOP_CNT 1000  

#endif /* __HDR_H__ */  

main.c

#include <stdio.h>  
#include "hdr.h"  

int main(void)  
{  
    int i, sum = 0;  
    for (i = 0; i < LOOP_CNT; i++) sum += i;  
    (void)printf("sum = %d\n", sum);  
    return 0;  
}  

Makefile

SUFFIXES += .d

.PHONY: clean  

OBJECTS = $(patsubst %.c,%.o,$(wildcard *.c))  
CC = armcc  
LD = armcc  
CFLAGS += 

# Default target  
all: sum  

sum : $(OBJECTS)  
    $(CC) $(CFLAGS) -o $@ $^  

$(OBJECTS) : %.o : %.c   
    $(CC) $(CFLAGS) -o $@ -c $<  

# Generating dependency files  
%.d : %.c  
    @$(CC) -M $< > $@  

# Include dependency file to have gcc recompile necessary sources  
include $(patsubst %.c,%.d,$(wildcard *.c))  
#$(info $(patsubst %.c,%.d,$(wildcard *.c)))

clean:  
    rm -f *.o *.d core $(EXEC_NAME)  

Here is printed line in second.

C:\project\dep>make all
Makefile:24: main.d: No such file or directory
armcc    -o main.o -c main.c
armcc    -o sum main.o

C:\project\dep>make all
make: Nothing to be done for `all'. 

main.d file is generated as below.

__image.axf: main.c
__image.axf: C:\Program Files\ARM\RVCT\Data\4.1\713\include\windows\stdio.h
__image.axf: hdr.h

回答1:


As a quick and dirty Makefile fix for rebuilding if headers change I just list all my header files and then add $(HEADERS) as a dependency in the part that builds the object files from the C src files. Its not as efficient as it could be but I find it to be good enough, i.e.

HEADERS = \
    my_header.h \
    my_other_header.h

$(BUILD_DIR)/%.o: %.c $(HEADERS)
    $(LINK.c) $< -c -o $@



回答2:


Generally speaking, if a source file needs to be compiled to create an object file, then its dependency file also needs to be rebuilt.

So, instead of having a separate target for the .d files, simple regenerate it when compiling. To achieve this, a simple approach is to replace

$(OBJECTS) : %.o : %.c   
    $(CC) $(CFLAGS) -o $@ -c $<  

# Generating dependency files  
%.d : %.c  
    @$(CC) -M $< > $@  

with

$(OBJECTS) : %.o : %.c   
    $(CC) $(CFLAGS) -o $@ -c $<  
    @$(CC) -M $< > $@  

Note that the dependency file will only be regnerated if compilation succeeds. If compilation fails, the object file will be deleted, so recompilation would be forced regardless of whether the dependency file is up to date.




回答3:


Have you tried make clean before you build. Clean and build should work




回答4:


To get it to rebuild your dependency files if the header files change you could change the build rule for them to something like this:

%.d : %.c
        $(CC) -M $< > $@
        @$(CC) -M $< -MT $*.d >> $@  

as that'll also append on dependency rules that say that the .d file is built from the .c and .h files.

As for how to get them to (re)build in the first place - if your version of make is too really old and doesn't (re)build them automatically you could either have something like this:

all: depend subs

depend: $(patsubst %.c,%.d,$(wildcard *.c))

(As an aside, I think it'd look cleaner if that were in a variable BTW and also be more efficient)

Or add a dependency to the object building like so:

$(OBJECTS) : %.o : %.c %.d
    $(CC) $(CFLAGS) -o $@ -c $<  

But both solutions will require you to run make twice as it won't include the changes otherwise




回答5:


The problem with the Makefile is this:

Incorrect:

$(OBJECTS) : %.o : %.c
    $(CC) $(CFLAGS) -o $@ -c $<

Correct (notice the added %.d dependency, %.c cannot be elimin):

$(OBJECTS) : %.o : %.c %.d
    $(CC) $(CFLAGS) -o $@ -c $<

The dependency chain is like this:

all
+->sum
   +->x.o
      +->x.c
---------------------------------
x.d
+->x.c
[generate rule: "x.d: x.c x.h"]

after include:
x.d
+->x.c
+->x.h

In the original version, the %.d rules are do triggered, I guess the include directives are responsible (without that, the %.d-s won't be built). But even though they are triggered, nothing connects them to the %.o files. Thus, even if they are rebuilt, because of the changed %.h files, there is no dependency chain to the %.o files.

Connecting the dependency chains fixes this problem.


Note that running the corrected Makefile after a clean will generate error messages like this one:

Makefile:123: x.d: No such file or directory

As explained in the make docs, when include cannot find a Makefile, it emits an error message, but at this point it does not consider this a fatal error and tries to find a rule that would create the missing files.

Adding

$(info $(shell ls))

to the object file creation / linking recipe can confirm that the rules are indeed there, at that time.



来源:https://stackoverflow.com/questions/44020890/gnu-make-does-not-recompile-when-a-header-file-changed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!