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


92

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

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을 편집해야하는데, 이는 약간의 고통입니다. 헤더 파일 종속성을 자체적으로 파생 할 수있는 솔루션을 찾고 있는데, 다른 프로젝트에서 본 것이 상당히 확실합니다.

답변:


30

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

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

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


2
나는 착각 할 수 있지만 GCC는 실제로 그 sed 문제를 해결하기 위해 기능을 추가했다고 생각합니다. gcc.gnu.org/onlinedocs/gcc-4.3.1/gcc/Preprocessor-Options.html 특히 -MP를 확인하십시오 .
Eugene Marcotte 2013 년

예, -MP는 GCC 3부터 존재하고 clang 및 icc에 존재하며 sed에 대한 필요성을 무효화합니다. bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/…
hmijail은 사직자를 애도합니다.

답변의 최신 버전에는 GCC 플래그를 사용하는 예제가 포함되어 있습니다.
MadScientist

20

다른 사람들이 언급 한대로 '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.


18
이것은 나를 위해 작동하지 않았습니다. 예를 들어 makefile이 생성되고 실행되었습니다. g++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp 나는 main.d 파일을 얻었지만 main.o는 0 바이트였습니다. 그러나 -MMD 플래그는 필요한 작업을 정확히 수행하는 것 같습니다. 그래서 내 작업 메이크 파일 규칙은 다음과 같습니다.$(CC) -c $(CFLAGS) -MMD -o $@ $<
Darren Cook

17

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


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

depend: .depend

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

include .depend

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


4
SOURCES를 쓰지 않는 이유는 무엇입니까? 특히 더 많은 문자가 필요하지 않으며 약어처럼 보일 수있는 "SRCS"만큼 난독 화되지 않습니다.
HelloGoodbye

@HelloGoodbye 약간의 스타일. 난 항상 사용, 항상 볼, 한 SRCSOBJS. 나는 대부분의 시간에 동의하지만 모두가 그게 뭔지 알아야합니다.
sherrellbc

@sherrellbc 사람들이 "반드시"알아야하는 것과 사람들이 실제로 아는 것은 종종 두 가지 다른 것입니다. P
HelloGoodbye

7

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

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

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

4

기본적으로 헤더 파일이 변경 될 때 개체 파일을 다시 빌드하려면 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에.


2
(그 -MM 및 -MG 플래그가 새롭다는 것을 제외하고) 나는 이것을 이해합니다. 그래도 팀원들이 행복해지지는 않네요 ... ^ _ ^ 그래도 해보고 결과가 있는지 볼게요.
Nicholas Flynt

sed는 파일을 사용하지 않고도 텍스트 스트림을 수정할 수있는 "스트림 편집기"의 약자입니다. 표준 Unix 도구이며 더 작고 빠르기 때문에 awk 또는 perl보다 더 자주 사용됩니다.
Zan Lynx

아, 문제가 있습니다. Windows에서이 작업을하고 있습니다.
Nicholas Flynt

3

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


1

어떤 답변도 나를 위해 일하지 않았습니다. 예를 들어 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 파일을 컴파일합니다. 각 소스 파일에 대해 등등.


0

더 간단한 솔루션 : Makefile을 사용하여 .c에서 .o 로의 컴파일 규칙이 헤더 파일과 프로젝트에서 종속성으로 관련된 다른 모든 항목에 종속되도록하십시오.

예 : Makefile 어딘가에 :

DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv

::: (your other Makefile statements like rules 
:::  for constructing executables or libraries)

# Compile any .c to the corresponding .o file:
%.o: %.c $(DEPENDENCIES)
        $(CC) $(CFLAGS) -c -o $@ $<

-1

나는 mkdep명령이 당신이 원하는 것이라고 믿습니다 . 실제로 .c 파일에서 #include줄을 검색 하고 이에 대한 종속성 트리를 만듭니다. Automake / Autoconf 프로젝트는 기본적으로 이것을 사용한다고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.