[dependencies] Makefile, 헤더 종속성

규칙이있는 메이크 파일이 있다고 가정 해 보겠습니다.

%.o: %.c
 gcc -Wall -Iinclude ...

헤더 파일이 변경 될 때마다 * .o가 다시 작성되기를 원합니다. 종속성 목록을 작성하는 대신 헤더 파일이 /include변경 될 때마다 dir의 모든 개체를 다시 빌드해야합니다.

나는 이것을 수용하기 위해 규칙을 변경하는 좋은 방법을 생각할 수 없다. 나는 제안에 개방적이다. 헤더 목록을 하드 코딩 할 필요가없는 경우 보너스 포인트



답변

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

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ -MF  ./.depend;

include .depend

또는

depend: .depend

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

include .depend

여기서는 SRCS소스 파일의 전체 목록을 가리키는 변수입니다.

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


답변

대부분의 답변은 놀랍도록 복잡하거나 오류가 있습니다. 그러나 간단하고 강력한 예제는 [ codereview ] 다른 곳에 게시되었습니다 . 확실히 gnu 전처리 기가 제공하는 옵션은 약간 혼란 스럽습니다. 그러나 빌드 대상에서 모든 디렉토리를 제거하는 -MM것은 문서화되어 있으며 버그 [ gpp ]가 아닙니다 .

기본적으로 CPP는 기본 입력 파일의 이름을 사용하고 모든
디렉토리 구성 요소 및 ‘.c’와 같은 파일 접미사를 삭제 하고 플랫폼의 일반적인 개체 접미사를 추가합니다.

(다소 더 새로운) -MMD옵션은 아마도 당신이 원하는 것입니다. 완전성을 위해 여러 src 디렉토리를 지원하고 일부 주석으로 디렉토리를 빌드하는 메이크 파일의 예입니다. 빌드 디렉토리가없는 간단한 버전은 [ codereview ]를 참조하십시오 .

CXX = clang++
CXX_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow

# Final binary
BIN = mybin
# Put all auto generated stuff to this build dir.
BUILD_DIR = ./build

# List of all .cpp source files.
CPP = main.cpp $(wildcard dir1/*.cpp) $(wildcard dir2/*.cpp)

# All .o files go to build dir.
OBJ = $(CPP:%.cpp=$(BUILD_DIR)/%.o)
# Gcc/Clang will create these .d files containing dependencies.
DEP = $(OBJ:%.o=%.d)

# Default target named after the binary.
$(BIN) : $(BUILD_DIR)/$(BIN)

# Actual target of the binary - depends on all .o files.
$(BUILD_DIR)/$(BIN) : $(OBJ)
    # Create build directories - same structure as sources.
    mkdir -p $(@D)
    # Just link all the object files.
    $(CXX) $(CXX_FLAGS) $^ -o $@

# Include all .d files
-include $(DEP)

# Build target for every single object file.
# The potential dependency on header files is covered
# by calling `-include $(DEP)`.
$(BUILD_DIR)/%.o : %.cpp
    mkdir -p $(@D)
    # The -MMD flags additionaly creates a .d file with
    # the same name as the .o file.
    $(CXX) $(CXX_FLAGS) -MMD -c $< -o $@

.PHONY : clean
clean :
    # This should remove all generated files.
    -rm $(BUILD_DIR)/$(BIN) $(OBJ) $(DEP)

이 방법은 단일 대상에 대해 여러 종속성 라인이있는 경우 종속성이 단순히 결합되기 때문에 작동합니다. 예 :

a.o: a.h
a.o: a.c
    ./cmd

다음과 같습니다.

a.o: a.c a.h
    ./cmd

언급했듯이 : Makefile 단일 대상에 대한 여러 종속성 줄?


답변

내가 여기에 게시했듯이 gcc는 종속성을 생성하고 동시에 컴파일 할 수 있습니다.

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

-include $(DEPS)

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

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

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

-o 옵션과 관련하여 gcc에 버그가있는 것 같습니다. 객체 파일 이름을 obj / _file__c.o로 설정하면 생성 된 파일 .d에는 여전히 obj / _file__c.o가 아닌 .o 파일 이 포함 됩니다 .


답변

다음과 같은 것은 어떻습니까?

includes = $(wildcard include/*.h)

%.o: %.c ${includes}
    gcc -Wall -Iinclude ...

와일드 카드를 직접 사용할 수도 있지만 여러 곳에서 필요한 경우가 많습니다.

이것은 모든 개체 파일이 모든 헤더 파일에 의존한다고 가정하기 때문에 소규모 프로젝트에서만 잘 작동합니다.


답변

위의 Martin의 솔루션은 훌륭하게 작동하지만 하위 디렉토리에있는 .o 파일을 처리하지 않습니다. Godric은 -MT 플래그가 해당 문제를 처리하지만 동시에 .o 파일이 올바르게 작성되는 것을 방지한다고 지적합니다. 다음은 이러한 문제를 모두 처리합니다.

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

-include $(DEPS)

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


답변

이것은 작업을 잘 수행하고 지정된 하위 디렉토리도 처리합니다.

    $(CC) $(CFLAGS) -MD -o $@ $<

gcc 4.8.3으로 테스트했습니다.


답변

다음은 두 줄짜리입니다.

CPPFLAGS = -MMD
-include $(OBJS:.c=.d)

에 모든 개체 파일 목록이있는 한 기본 make 레시피에서 작동합니다 OBJS.