반응형

핵심 정리

이 글은 Makefile을 처음 사용할 때 헷갈리기 쉬운 기본 동작을 실행 예제로 확인한 메모입니다. 인자 없이 make를 실행할 때 어떤 target이 선택되는지, C 소스 파일이 오브젝트 파일로 암시적으로 컴파일되는 방식, CC와 CFLAGS로 컴파일러와 옵션을 지정하는 흐름을 정리합니다.

  • make를 인자 없이 실행하면 Makefile에 적힌 첫 번째 target이 기본 목표로 실행됩니다.
  • 특정 target을 실행하려면 make a.out처럼 목표 이름을 직접 지정하거나 의존 관계에 포함시켜야 합니다.
  • C 소스 파일에서 오브젝트 파일로 만드는 기본 규칙은 make가 암시적 규칙으로 처리할 수 있습니다.
  • CC와 CFLAGS를 지정하면 암시적 컴파일에 사용할 컴파일러와 디버그 같은 옵션을 바꿀 수 있습니다.
  • 여러 오브젝트 파일에 같은 의존성과 recipe를 적용할 때는 target 목록을 이용해 규칙을 묶어 적을 수 있습니다.

본문에는 작은 Makefile 예제와 실제 출력 명령이 이어집니다. 먼저 기본 target과 암시적 컴파일의 역할을 잡은 뒤 CC, CFLAGS 예제를 따라가면 동작 차이를 확인하기 쉽습니다.

괜찮은 링크

http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/

공식매뉴얼

kldp 한글 매뉴얼

일반

make with no arguments executes the first rule in the file


재밌는건 아래와 같은 Makefile의 경우 가장 처음 target만 무조건 수행된다는 점이다.
clean:test.c
        echo "clean"
 
clean2:test.c
        echo "clean2"
 
a.out : test.c
        gcc test.c
즉 위와 같은 Makefile 이 있을 때, make를 수행하면 가장 위에있는 target인 clean 만 수행되고 나머지 target인 clean2, a.out 은 깡그리 무시된다는 점이다.
clean2나 a.out 이 수행되려면 만앞에 있는 clean의 dependency chain에 언급해주거나 make a.out 이런식으로 직접 파라미터로 넣어주는 수밖에 없는것 같다.

.c를 .o로 바꾸어 주는 것은 자동이다.

이 특징을 이용하는게 좋은 것이.. 특정 .c 하나만 바뀌었을때 그 파일만 빌드되도록 만들기 쉽다는 점


아하!! 정말 중요한 것을 깨달았다.

1.  컴파일 (.c 파일에서 .o 로 변환되는 것) 은 원래 부터 자동이라는 것.

2.  그리고 이 컴파일에 사용되는 것이 바로 predefined macro 라는 것!! 즉 CC, CFLAGS 같은 애들이 이와 같이 자동 컴파일 될 때 쓰인다는 것이다!

그 예로서 다음과 같은 Makefile 이 있을 때.

  6 OBJ = main.o func1.o
  7
  8 test : $(OBJ)
  9     gcc -o test $(OBJ)

보면은 원래는 다음처럼 .c를 .o로 바꾸어주는 부분도 있어야 하지만

  3 OBJ = main.o func1.o
  4
  5 test : $(OBJ)
  6     gcc -o test $(OBJ)
  7
  8 main.o : main.c
  9     gcc -c main.c
 10
 11 func1.o : func1.c
 12     gcc -c func1.c

실제로 위에거 처럼해도 잘 되는걸 볼 수 있고 실행시 나타나는 명령은 다음과 같다.

cc    -c -o main.o main.c
cc    -c -o func1.o func1.c
gcc -o test main.o func1.o

보면은 컴파일러로 자동으로 cc 가 쓰였고 컴파일 옵션에는 -c 만 있음을 알 수 있다.

위를 gcc로 바꾸고 디버깅 옵션인 -g 를 추가하려면 다음과 같이 Makefile을 수정해주면 된다.

  3 CC = gcc
  4 CFLAGS = -g
  5
  6 OBJ = main.o func1.o
  7
  8 test : $(OBJ)
  9     gcc -o test $(OBJ)

바로 predefined macro를 통하여 컴파일 옵션을 지정해 준것이다.

그럼 나타나는 명령어가 다음과 같이 잘 바뀐다.

gcc -g   -c -o main.o main.c
gcc -g   -c -o func1.o func1.c
gcc -o test main.o func1.o

타겟이 여러개인 경우도 가능하다


예제 2.1에서는 안 나왔지만 타겟이 여러 개인 경우는 어떻게 될까요? 그때에는 각 타겟에 대해서, 하나의 타겟을 가지는(그리고 나머지 선행조건 및 레시피는 모두 동일한) 다수의 규칙들을 작성하는 것과 동일합니다. 즉 다음의 규칙을 보시죠.

$(OBJS) : MyCommon.h
	echo “$@ depends on MyCommon.h”
$(OBJS)는 MySocket.o MyClient.o 으로 정의되어 있기 때문에, 위의 규칙은 다음 두 개의 규칙으로 풀어 쓴 것과 동일합니다.

MySocket.o : MyCommon.h
	echo “$@ depends on MyCommon.h”
 
MyClient.o : MyCommon.h
	echo “$@ depends on MyCommon.h”
당연히 풀어 쓴 것 보다야 하나의 규칙이 훨씬 컴팩트해서 보기도 좋고 유지 보수도 용이합니다.. (아, 물론 타이핑도 적습니다.) 이제 실제 규칙의 처리는 어떻게 되는 지 알아 보도록 하겠습니다.

internal macro


내부적으로 정해짐. 바꿀수없음.

$@  현재의 목표 파일(Target) ( :의 왼쪽 부분)

$^  :의 오른쪽 부분

$*  확장자가 없는 현재의 목표 파일(Target) 

$<  :의 오른쪽 부분중 첫번째 거

$?  현재의 목표 파일(Target)보다 더 최근에 갱신된 파일이름

gccmakedep

=== mac에서 gccmakedep 설치하기 ===

http://egloos.zum.com/manwooo/v/1808309

위에 링크보고 macport 깔고 gccmakedep 설치하면 됐다.

단, 터미널은 다시 구동해야 하더라.

=== 설명 ===


다른 것들은 모두 편리하고 좋은 것 같은데, Makefile 하단에 있는 파일 간의 종속에 대한 정보를 모두 타이핑해서 넣어야 할까요? 파일이 많을 경우 어떻게 일일이 입력할 수 있있겠습니까?  당연한 말씀입니다. 게으른 프로그래머에게는 말도 안되죠. 그래서 이와 같은 귀찮은 작업을 make에 떠 넘기겠습니다. 바로 파일간의 의존성을 찾아서 그 내용을 직접 구성해 달라고 요청하는 것이죠.
  이렇게 파일의 의존성을 검색해서 그 내용을 작성해 주는 것이 gccmakedep 입니다. 아래와 같이 수정해서 make dep를 실행합니다.
TARGET =	sample
OBJS = main.o tcp.o rs232.o
SRCS = $(OBJS:.o=.c)
CC = -I/home/jwjw/prjs/include	-g	-c
$(TARGET): $(OBJS)
    gcc -lm -o $@ $^

.c.o:
    gcc $(CC) $<

dep : 
    gccmakedep $(SRCS)
  이렇게 추가 작성해서 make dep 를 실행하시면 make는 컴파일과 링크 작업 대신에 라벨 dep: 밑의 명령을 실행합니다. 새로 만들어진 SRCS는 OBJS에 열거된 파일 모록에 대해서 확장자를 .o를 .c로 바뀐 목록을 가지게 됩니다. gccmakedep는 소스 파일을 가지고 의존성을 검색할 수 있기 때문이죠.
]$ make dep
]$ vi Makefile
TARGET =	sample 
OBJS = main.o tcp.o rs232.o 
SRCS = $(OBJS:.o=.c) 
CC = -I/home/jwjw/prjs/include	-g	-c 
    $(TARGET): $(OBJS) gcc -lm -o $@ $^ 
.c.o: 
   	gcc $(CC) $< 
dep :	gccmakedep $(SRCS)
# DO NOT DELETE
main.o: main.c /usr/include/stdio.h .........
tcp.o: tcp.c /usr/include/stdio.h .........
rs232.o: rs232.c /usr/include/stdio.h .........
  하단에# DO NOT DELETE 행과 함께 밑으로 각 .o 에 대한 관련 파일 목록이 자동으로 생성되는 것을 보실 수 있습니다. 이제 make를 실행하면 위 정보에 맞추어 컴파일하게 됩니다.

재귀적 사용(sub directories)

이 링크가 좋네

옵션

j 옵션

make -j 12

위처럼하면 12개의 명령어를 동시에 패러럴 하게 수행하라는 것(논리 CPU개수 적어주면 될 듯)

반응형

+ Recent posts