2017-05-12 4 views
0

나는 다음 메이크 파일이 있습니다연기 평가

CC ?= gcc 
LD := gcc 

CFLAGS := -Wall -Wextra -Werror -Wfatal-errors 
LDFLAGS := 
LIBRARIES := m c 
INCLUDEDIRS := . 
LIBS = $(addprefix -l,$(LIBRARIES)) 
INCLUDES = $(addprefix -I,$(INCLUDEDIRS)) 

SRC := $(wildcard *.c) 
TARGET = $(TARGETDIR)/test 
OBJDIR = $(TARGETDIR)/obj/ 
OBJ = $(addprefix $(OBJDIR),$(SRC:%.c=%.c.o)) 

.SUFFIXES: 
.SUFFIXES: .c.o 

.PHONY: all debug i7avx i7avx-debug 

all: TARGETDIR := generic 
all: CFLAGS += -O3 
all: LDFLAGS += -s 
all: $(TARGET) 

debug: CFLAGS += -Og 
debug: TARGETDIR := generic/dbg 
debug: $(TARGET) 


$(OBJDIR): 
    @mkdir -p $(OBJDIR) 

$(OBJ): | $(OBJDIR) 

$(OBJDIR)%.c.o : %.c 
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o [email protected] 

$(TARGET) : $(OBJ) 
    $(LD) $(LDFLAGS) -o [email protected] $^ $(LIBS) 

여기에 특별한 것은 출력 디렉토리는 대상에 따라 달라집니다 것입니다. 현재 all 및 debug 만 정의되어 있지만 개념은 전체 아키텍처를 지원하고 대상마다 출력 디렉토리를 정의하는 것입니다.

문제 : 이것은 작동하지 않습니다. 나는 이것을 실행하면, 내가 얻을 :

cc -Wall -Wextra -Werror -Wfatal-errors -O3 -I. -c main.c -o /obj/main.c.o 
Assembler messages: 
Fatal error: can't create /obj/main.c.o: No such file or directory 
make: *** [Makefile:37: /obj/main.c.o] Error 1 

TARGETDIR 변수가 너무 늦게 확대 된 것을 의미한다. 내가 진짜 변수와 자동 변수를 교체하는 경우,이 작업을 수행합니다

$(OBJ): | $(OBJDIR) 

$(OBJDIR)%.c.o : %.c 
    $(CC) $(CFLAGS) $(INCLUDES) -c $(SRC) -o $(OBJ) 

$(TARGET) : $(OBJ) 
    $(LD) $(LDFLAGS) -o $(TARGET) $(OBJ) $(LIBS) 

이 실행 : SOOO

cc -Wall -Wextra -Werror -Wfatal-errors -O3 -I. -c main.c -o generic/obj/main.c.o 
gcc -s -o generic/test generic/obj/main.c.o -lm -lc 

가 나는 autmatic 변수를 확장 할 수있는 방법을 TARGETDIR가

정의 된 후에는?

+1

이 메이크 파일에는 크고 작은 문제가 있으므로 철저한 대답이 길어질 수 있습니다. 자동 변수를 작동 시키려고하는지, 또는 예상대로 작동하지 않는 이유를 이해하고 있습니까? (그들은 다른 목표입니다.) – Beta

+0

글쎄, 내 Makefile에 대한 비판을 기꺼이 쓰고 싶다면, 나는 그것에 대해 완전히 열려있을 것이다.이상적인 대답은 실제 문제에 대한 해결책이 될 것입니다. 하나의 Makefile을 사용하여 여러 개의 서로 다른 폴더에서 여러 다른 아키텍처로 컴파일 할 수 있기를 바랍니다. 나는 이것이 작동하지 않는 이유를 알아 냈다. (목표와 의존성은 즉시 평가된다. 그래서 $ ^, $ @ etceta는 TARGETDIR이 설정되기 전에 설정된다.) 현재 Bash가 TARGETDIR 변수를 설정 한 다음 make를 호출하는 Make/Bash 솔루션에 기대고 있습니다. – Cheiron

답변

0

Make는 와일드 카드를 매우 능숙하게 처리합니다. 그렇지 않으면 훨씬 쉬운 문제가됩니다.

그대로, 최선의 해결책은 recursive Make을 사용하는 것입니다. 이것에

all: $(TARGET) 

debug: $(TARGET) 

: 그냥이 변경

all debug:          
    $(MAKE) $(TARGET) TARGETDIR=$(TARGETDIR) CFLAGS+='$(CFLAGS)' LDFLAGS=$(LDFLAGS) 
0

첫째, 작동하지 않는 이유 : 당신은 대상별 변수를 사용하고 있지만 사람들은에서만 사용할 수 있습니다

규칙을 평가하는 동안이 아니라 대상 레서피의 컨텍스트 (여기에서 설명서를 인용) : Make가 먼저 Makefile을 읽고, $(OBJDIR)$(TARGET) 규칙을 평가합니다 (이 시점에서 $(TARGETDIR)은 아직 정의되지 않았습니다). 암탉은 all을 업데이트하려고 시도합니다.이 시점에서 $(TARGETDIR)을 대상 지정 값 all으로 설정합니다 (두 번째 예제 작업의 이유를 설명하지만 매번 다시 작성해야 함).

나는 (내가 실제로 곧 비슷한 일을 계획하고있어) 당신이 뭘 하려는지 달성하기위한 몇 가지 힌트가있을 수 있습니다 :

각 빌드에 대해 하나 개의 규칙을 생성하기 위해 eval 함수를 사용할 수 있습니다/이 같은 ARCHI :

#define TARGET_RULE 
$(TARGET) : $(OBJ) 
    $$(RECIPE) 
#endif 
$(foreach TARGETDIR, $(BUILD_LIST), $(eval $(TARGET_RULE)) 

또한 당신이 목표에 대해서만 규칙 또는 규칙을 정의 할 수 있어야한다

($$이 조리법에 필요한이 규칙을 평가하는 동안 확장되지 않도록하기 위해) 현재 건물 (n 확실한 퍼프 차이를 만들 수 있는지 확인하십시오).