(미완성)평범한 개발자의 C 프로그래밍 이야기

make - 간단한 예제

 

먼저 아주 단순한 Makefile을 작성해보겠습니다. GNU make가 제공하는 매크로는 사용하지 않고, 개발자가 모든 명령을 직접 Makefile에 써주는 형태를 보여드리겠습니다.

가장 먼저 만들 것은 소스 트리의 가장 상위 Makefile입니다. 지금부터 소스에서 가장 상위 디렉토리가 현재 디렉토리라고 가정하겠습니다. 따라서 가장 상위의 Makefile은 ./Makefile이라고 표시됩니다. 다음은 ./Makefile의 내용입니다.


# config.mk is generated by configure
include config.mk


all:
    make -C src
    make -C test


clean:
    make -C src clean
    make -C test clean


이 Makefile이 하는 일은 config.mk를 포함하고 src, test 디렉토리의 Makefile을 실행시키는 것 뿐입니다. config.mk는 configure가 생성한 파일입니다. config.mk는 컴파일러와 기타 빌드 관련 유틸리티의 정보를 가지고 있기 때문에 모든 Makefile이 공통적으로 포함시켜야할 파일입니다.

다음은 src/Makefile 입니다.

include ../config.mk

SRCS = sys_info.c hello.c
OBJS = $(SRCS:.c=.o)
TARGET = libca.a


all: $(TARGET)

$(TARGET): $(OBJS)
    ar sruv $@ $^
    cp $@ ../lib

%.o:%.c
    $(CC) -c -Wall -I../include -o $@ $<

clean:
    rm $(OBJS) $(TARGET)

간단히 설명하자면 빌드할 소스를 SRCS 변수에 저장하고, 빌드된 오브젝트 파일의 이름을 OBJS에 저장합니다. TARGET은 최종적으로 생성될 라이브러리의 이름입니다. 각 소스는 %.o:%.c 라벨에서 지정된대로 오브젝트 파일로 컴파일되고, 각 오브젝트 파일을 묶어서 libca.a로 생성합니다. 

이 Makefile은 컴파일과 라이브러리 생성, 라이브러리 복사 등 전체 빌드 과정을 개발자가 일일이 입력했습니다. 즉 src디렉토리에 파일을 추가하는 개발자가 Makefile도 직접 수정해주어야하는 제약이 있습니다. 또 라이브러리의 이름을 바꾸거나 라이브러리가 저장될 디렉토리가 바뀌거나 하는 경우에도 src/Makefile을 수정해야 합니다. 소스 컴파일과 라이브러리 빌드가 하나의 Makefile에서 처리되므로, 각각의 단계를 분리할 수 없습니다. 만약 src 디렉토리 밑에 소스가 있지 않고 src/module1, src/module2 등 src 밑에 여러개의 디렉토리가 있고 소스가 여러개의 디렉토리에 나눠져있다면 라이브러리에 관련된 사항을 바꿀 때도 여러개의 Makefile을 찾아서 일일이 고쳐야 합니다.

다음은 test/Makefile 입니다.


include ../config.mk

CFLAGS=-Wall -I../include
LFLAGS=../lib/libca.a

all: test_hello test_sys_info

test_hello: test_hello.c ../lib/libca.a
    gcc $(CFLAGS) -o $@ $< $(LFLAGS)

test_sys_info: test_sys_info.c ../lib/libca.a
    gcc $(CFLAGS) -o $@ $< $(LFLAGS)

clean:
    rm -rf test_hello test_sys_info

all: 라벨에 테스트 프로그램을 하나씩 적어놓았습니다. 그리고 각 테스트 프로그램마다 빌드 명령을 일일이 써놓았습니다. 테스트 프로그램을 하나씩 추가할 때마다 all: 라벨에 실행 파일 이름을 추가하고 빌드 명령도 추가해야합니다. clean: 라벨에도 프로그램을 지울 수 있도록 실행 파일 이름을 추가해야합니다. 당연히 테스트가 많아질 수록 관리가 불편해집니다.


1단계에서 작성한 빌드 처리를 보면 여러가지 공통적인 단점이 있습니다. 가장 큰 단점을 소스나 생성 프로그램을 추가하려면 여기저기를 수정해야한다는 것입니다. 그리고 소스를 컴파일하는 일과 라이브러리를 생성하는 단계가 서로 얽혀있어서 작업이 분리되지 못한다는 것입니다.

마지막으로 컴파일 옵션을 여러가지로 실행해야하는 경우나 여러가지 버전으로 라이브러리를 생성해야하는 경우에 불편한 점이 있습니다. 일반적으로 어떤 라이브러리나 프로그램을 배포할때는 하나의 운영체제만을 대상으로 배포하지 않습니다. 또 32비트와 64비트를 모두 제공해야합니다. 즉, 배포용 패키지를 만들 때 다양한 방법으로 빌드를 해야하는데 이렇게 모든 빌드 명령을 직접 Makefile에 기록하는 방식에서는 각각의 명령들을 수정해야하므로 작업할 양이 너무나 많아지고, 그 과정에서 여러가지 실수나 문제가 발생하게 됩니다.

결론은 빌드 관련된 최대한 많은 사항들을 몇몇 .mk 파일에 저장해두고 각 디렉토리의 Makefile에는 최소한의 사항들만 남기는 것이 필요합니다. 소스나 생성 결과물을 추가할 때도 하위 Makefile을 수정할 필요가 없도록하고, 빌드 옵션도 일일이 바꿀 필요가 없도록 해야합니다. 최대한 모든 것을 자동화하도록 해야합니다.

댓글

댓글 본문
작성자
비밀번호
  1. 좋은 글 감사합니다.
  2. gurugio
    소스는 여기에
    https://github.com......3.2
graphittie 자세히 보기