Systems/Unix / Linux2012.07.03 13:04

Makefile을 작성할 때에도 if, else 등의 조건식을 사용할 수 있긴 합니다. GNU make 메뉴얼에 실린 예제를 보시면... 


libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
        $(CC) -o foo $(objects) $(libs_for_gcc)
else
        $(CC) -o foo $(objects) $(normal_libs)
endif

이렇게 하면 $(CC)의 값이 gcc냐 아니냐에 따라서 선택적으로 컴파일 옵션을 바꿀 수 있는데요. 문제는 Stackoverflow에 실린 글타래에도 나와 있듯이, 아래와 같은 작업을 하려고 하면 잘 안됩니다. 


.c.o .cpp.o .cc.o:

ifeq ($(*D),mySpecialDirectory)  
   @echo "I'm in mySpecialDirectory! \o/"
   $(CC) $(DEBUG_FLAGS) $(MYSPECIALFLAGS) -c $< -o $@
else  
   @echo "Failed! I'm in $(*D)"
   $(CC) $(DEBUG_FLAGS) $(NOTTHATSPECIALFLAGS) -c $< -o $@
endif


http://9gag.com/gag/744366. Makefile이 개그 소재가 될 수도 있다.



위의 코드가 하려는 일을 간단히 요약하면 현재 컴파일하려는 대상이 위치한 디렉터리가 mySpecialDirectory와 일치하면 이렇게 컴파일하고, 아니라면 저렇게 컴파일되도록 하겠다는 것이죠. 위의 코드가 정상 동작하지 않는 이유는...

Conditional Statements

All instances of conditional syntax are parsed immediately, in their entirety; this includes the ifdef, ifeq, ifndef, and ifneq forms. Of course this means that automatic variables cannot be used in conditional statements, as automatic variables are not set until the command script for that rule is invoked. If you need to use automatic variables in a conditional you must use shell conditional syntax, in your command script proper, for these tests, not make conditionals.


그러니까 '실행되는 순간에 그 값이 설정되는 자동 변수' (위의 예제에서는 $(*D))에 대해서는 ifeq 같은 조건절이 정상적으로 동작하지 않는다는 것이죠.


따라서 위의 예제가 정상적으로 동작하도록 만들려면, 다음과 같이 바꿔야 해요.


.c.o .cpp.o .cc.o:
   $(CC) $(DEBUG_FLAGS) $(if $(subst mySpecialDirectory,,$(*D)),$(NOTTHATSPECIALFLAGS),$(MYSPECIALFLAGS)) -c $< -o $@

$(subst mySpecialDirectory,,$(*D))는 mySpecialDirectory와 $(*D)가 일치하는 경우 빈 문자열을 반환합니다. 그리고 그 결과는 $(if condition, then-part [,else-part])에 의해 false condition으로 해석되죠.
저도 이것 때문에 좀 애먹었는데... 결국 다음과 같은 Makefile을 작성해서 문제를 해결했습니다.

$(TARGET): $(OBJS) $(LIBS) $(TARGET): %: %.cc $(CC) $(if $(subst icnfs,,$@), $(CFLAGS), $(FUSE_CFLAGS)) \ $(INCLUDE) $(LIBDIR) -o $@ $< $(OBJS) \ $(if $(subst icnfs,,$@), \ -lbjlee-process -lpthread, \ -lbjlee-process -lpthread -lfuse \ )


$(TARGET)에 명시된 컴파일 대상에 대해 $(CC)를 실행할 때, $@, 즉 컴파일 대상의 이름이 icnfs와 일치할 경우 -lfuse의 플래그가 포함되도록 하는 문장입니다.


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^