[gcc] Makefile이 수정 된 헤더 파일을 포함하는 소스 파일을 자동으로 다시 빌드하도록하려면 어떻게해야합니까? (C / C ++에서)

작업중인 프로그램 (실제로 커널)을 빌드하는 데 사용하는 다음 메이크 파일이 있습니다. 처음부터 프로세스에 대해 배우고 있으므로 완벽하지는 않지만이 시점에서 메이크 파일 작성 경험 수준에 비해 충분히 강력하다고 생각합니다.

AS  =   nasm
CC  =   gcc
LD  =   ld

TARGET      =   core
BUILD       =   build
SOURCES     =   source
INCLUDE     =   include
ASM         =   assembly

VPATH = $(SOURCES)

CFLAGS  =   -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
            -nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS =   -f elf

#CFILES     =   core.c consoleio.c system.c
CFILES      =   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES      =   assembly/start.asm

SOBJS   =   $(SFILES:.asm=.o)
COBJS   =   $(CFILES:.c=.o)
OBJS    =   $(SOBJS) $(COBJS)

build : $(TARGET).img

$(TARGET).img : $(TARGET).elf
    c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img

$(TARGET).elf : $(OBJS)
    $(LD) -T link.ld -o $@ $^

$(SOBJS) : $(SFILES)
    $(AS) $(ASFLAGS) $< -o $@

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

#Clean Script - Should clear out all .o files everywhere and all that.
clean:
    -del *.img
    -del *.o
    -del assembly\*.o
    -del core.elf

이 메이크 파일의 주요 문제는 하나 이상의 C 파일이 포함 된 헤더 파일을 수정할 때 C 파일이 다시 빌드되지 않는다는 것입니다. 내 모든 헤더 파일이 내 모든 C 파일에 대한 종속성이되도록함으로써이 문제를 아주 쉽게 해결할 수 있지만, 헤더 파일을 변경 / 추가 할 때마다 프로젝트를 완전히 재 빌드 할 수 있습니다.

내가 원하는 것은 내가 변경 한 헤더 파일 을 포함 하는 C 파일 만 다시 빌드하고 전체 프로젝트를 다시 링크하는 것입니다. 모든 헤더 파일을 대상의 종속성으로 설정하여 연결을 수행 할 수 있지만 포함 된 헤더 파일이 더 최신 일 때 C 파일을 무효화하는 방법을 알 수 없습니다.

GCC에이를 가능하게하는 몇 가지 명령이 있다고 들었지만 (메이크 파일이 어떤 파일을 재 빌드해야하는지 알아낼 수 있음) 실제 구현 예제를 볼 수는 없습니다. 누군가 메이크 파일에서이 동작을 가능하게하는 솔루션을 게시 할 수 있습니까?

편집 : 명확해야합니다. 개별 대상을 넣고 각 target.o에 헤더 파일이 필요하다는 개념에 익숙합니다. 어딘가에 헤더 파일을 포함 할 때마다 makefile을 편집해야하는데, 이는 약간의 고통입니다. 헤더 파일 종속성을 자체적으로 파생 할 수있는 솔루션을 찾고 있는데, 다른 프로젝트에서 본 것이 상당히 확실합니다.



답변

이 사이트의 다른 곳에서 이미 지적했듯이 다음 페이지를 참조하십시오.
자동 종속성 생성

간단히 말해 gcc는 컴파일 한 .c 파일의 종속성을 포함하는 미니 메이크 파일 조각 인 .d 종속성 파일을 자동으로 생성 할 수 있습니다. .c 파일을 변경하고 컴파일 할 때마다 .d 파일이 업데이트됩니다.

-M 플래그를 gcc에 추가하는 것 외에도 메이크 파일에 .d 파일을 포함해야합니다 (위에서 Chris가 작성한 것처럼). 페이지에는 sed를 사용하여 해결되는 좀 더 복잡한 문제가 있지만 더 이상 존재하지 않는 헤더 파일을 빌드 할 수 없다는 불만이있을 때마다이를 무시하고 “make clean”을 수행하여 .d 파일을 지울 수 있습니다. .


답변

다른 사람들이 언급 한대로 ‘make dependent’명령을 추가 할 수 있지만 gcc를 사용하여 종속성을 만들고 동시에 컴파일하지 않는 이유는 무엇입니까?

DEPS := $(COBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<

‘-MF’매개 변수는 종속성을 저장할 파일을 지정합니다.

‘-include’시작 부분의 대시는 Make가 .d 파일이 존재하지 않을 때 (예 : 첫 번째 컴파일시) 계속하도록 지시합니다.

-o 옵션과 관련하여 gcc에 버그가있는 것 같습니다. 당신은 말을 오브젝트 파일 이름을 설정하면 obj/_file__c.o다음 생성 _file_.d아직 포함 _file_.o하지 obj/_file_c.o.


답변

이것은 Chris Dodd의 대답 과 동일하지만 다른 명명 규칙을 사용합니다 (우연히 sed마법이 필요하지 않습니다 . 나중에 복제 된 .


GNU 컴파일러를 사용하는 경우 컴파일러가 종속성 목록을 조합 할 수 있습니다. Makefile 조각 :

depend: .depend

.depend: $(SOURCES)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^>>./.depend;

include .depend

도구도 makedepend있지만 나는 그것을만큼 좋아하지 않았습니다.gcc -MM


답변

각 C 파일에 대해 개별 대상을 만든 다음 헤더 파일을 종속성으로 나열해야합니다. 일반 대상을 계속 사용할 수 있으며 .h다음과 같이 나중에 종속성을 배치 할 수 있습니다 .

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

foo.c: bar.h
# And so on...


답변

기본적으로 헤더 파일이 변경 될 때 개체 파일을 다시 빌드하려면 makefile 규칙을 동적으로 만들어야합니다. gcc와 gnumake를 사용한다면 이것은 매우 쉽습니다. 다음과 같이 입력하십시오.

$(OBJDIR)/%.d: %.c
        $(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@

ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif

당신의 makefile에.


답변

@mipadi가 말한 것 이상으로 ‘ -M‘옵션을 사용하여 종속성 레코드를 생성하는 방법을 탐색 할 수도 있습니다 . 이를 별도의 파일 (예 : ‘depend.mk’)로 생성 한 다음 makefile에 포함 할 수도 있습니다. 또는 make depend올바른 종속성으로 메이크 파일을 편집 하는 ‘ ‘규칙을 찾을 수 있습니다 (Google 용어 : “이 줄을 제거하지 마십시오”및 종속성).


답변

어떤 답변도 나를 위해 일하지 않았습니다. 예를 들어 Martin Fido의 대답은 gcc가 종속성 파일을 만들 수 있다고 제안하지만 경고 나 오류없이 빈 (0 바이트) 개체 파일을 생성하려고 시도했습니다. gcc 버그 일 수 있습니다. 나는

$ gcc –version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)

그래서 여기 저에게 맞는 완전한 Makefile이 있습니다. 솔루션 + 다른 사람이 언급하지 않은 것의 조합입니다 (예 : .cc.o :로 지정된 “접미사 대체 규칙”) :

CC = g++
CFLAGS = -Wall -g -std=c++0x
INCLUDES = -I./includes/

# LFLAGS = -L../lib
# LIBS = -lmylib -lm

# List of all source files
SRCS = main.cc cache.cc

# Object files defined from source files
OBJS = $(SRCS:.cc=.o)

# # define the executable file 
MAIN = cache_test

#List of non-file based targets:
.PHONY: depend clean all

##  .DEFAULT_GOAL := all

# List of dependencies defined from list of object files
DEPS := $(OBJS:.o=.d)

all: $(MAIN)

-include $(DEPS)

$(MAIN): $(OBJS)
    $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)

#suffix replacement rule for building .o's from .cc's
#build dependency files first, second line actually compiles into .o
.cc.o:
    $(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

clean:
    $(RM) *.o *~ $(MAIN) *.d

.cc ..를 사용했습니다. 위의 Makefile은 .c 파일에 대해 쉽게 조정할 수 있습니다.

또한 다음 두 줄의 중요성에 유의하십시오.

$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

따라서 gcc를 한 번 호출하여 먼저 종속성 파일을 빌드 한 다음 실제로 .cc 파일을 컴파일합니다. 각 소스 파일에 대해 등등.