Makefile은 변경되지 않은 파일을 컴파일합니다.

Makefile은 변경되지 않은 파일을 컴파일합니다.

소스 디렉터리 트리를 반영하는 다른 디렉터리에서 대상 파일을 얻으려고 노력합니다. 잘 작동하지만 해당 줄에 일부가 누락되어 $(OBJ):(맞습니까?) 소스 코드 변경 여부에 관계없이 다시 컴파일됩니다. 구경하다.

SRC_PATH=../src/
CC=g++
CFLAGS=-c -Wall
LDFLAGS=-lSDL -lSDL_gfx
INCL=-I $(SRC_PATH)include/
EXE=run

SRC=$(wildcard $(SRC_PATH)*.cpp $(SRC_PATH)game/*.cpp $(SRC_PATH)player/*.cpp)
OBJ=$(subst ../src, ../obj, $(SRC:.cpp=))
OBJ_O=$(addsuffix .o, $(OBJ))

all: $(SRC) $(EXE)

$(EXE): $(OBJ)
    $(CC) $(LDFLAGS) $(OBJ_O) -o $@

$(OBJ):
    $(CC) $(CFLAGS) $(INCL) -o $(addsuffix .o, $@) $(subst ../obj, ../src, $@).cpp

clean:
    rm -rf run $(OBJ_O)

편집하다

이는 예상대로 작동합니다. 다시 컴파일하지 않습니다. 또한 복잡한 앞뒤 접미사가 없어 읽기가 더 쉽습니다. 아래 답변과 의견을 참조하세요.

SRC_PATH=../src/
CC=g++
CFLAGS=-c -Wall
LDFLAGS=-lSDL -lSDL_gfx
INCL=-I $(SRC_PATH)include/
EXE=run

SRC=$(wildcard $(SRC_PATH)*.cpp $(SRC_PATH)game/*.cpp $(SRC_PATH)player/*.cpp)
OBJ=$(subst ../src, ../obj, $(SRC:.cpp=.o))

all: $(SRC) $(EXE)

$(EXE): $(OBJ)
    $(CC) $(LDFLAGS) $(OBJ) -o $@

../obj/%.o: ../src/%.cpp
    $(CC) $(CFLAGS) $(INCL) -o $@ $<

clean:
    rm -rf run $(OBJ)

답변1

몇 가지 질문이 있습니다:

첫째, OBJ 변수는 빌드된 파일 목록을 참조하지 않습니다. 예를 들어 소스 파일 src/a.cpp 및 src/b.cpp가 있는 경우 OBJ에는 obj/a 및 obj/b가 포함됩니다. 따라서 OBJ 대신 OBJ_O를 사용하세요.

둘째, OBJ 파일을 빌드하는 대상은 .cpp와 .o 파일 간의 종속성을 제공하지 않습니다. .o 파일을 생성하기 위한 규칙을 이런 방식으로 작성하는 것은 해당 행에 종속성 정보를 제공할 수 없기 때문에 문제가 됩니다. .o 파일 생성 규칙을 완전히 다시 작성하겠습니다.

../obj/%.o: ../src/%.cpp
    $(CC) $(CFLAGS) $(INCL) -o "$@" "$<"

이는 각 .o 파일을 개별적으로 빌드하고 각 .o 파일은 해당 .cpp 파일에 따라 달라집니다.

../obj/**.o이는 일치하는 각 파일에서 파일을 생성하는 규칙입니다 ../src/**.cpp.

답변2

더 명확하게 설명하려면:

가장 큰 문제는 라인이다.$(OBJ):

문제는 ../src/a.cpp변수 OBJ에 소스 파일이 포함되어 ../obj/a있고 규칙이 $(OBJ):"파일을 작성하려면 다음 레시피를 사용하십시오 ../obj/a"를 의미하는 경우입니다. 하지만 레시피는 그렇지 않습니다! (대신 파일을 생성합니다 ../obj/a.o.)

../obj/a그 파일 이름이 종속성으로 나열되어 있기 때문에 긴급하게 해당 파일을 생성해야 하기 때문에 make가 항상 해당 레시피를 실행하는 이유입니다.$(EXE): $(OBJ)

관련 정보