Search
Duplicate

[한글로 Makefile 가볍게 읽어보기] 01. intro

간단소개
Makefile을 쪼개서 읽어보자.
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
Makefile
Scrap
태그
교육과정
makefile
9 more properties

intro.

단순히 makefile은 make에게 무엇을 할 것인가 말하는 파일이다. 따라서 makefile은 보통 어떻게 컴파일하고, 링크하는 지 명세되어있다.
make가 에디터를 다시 컴파일 할 때, 변경된 c소스 파일들이 있다면 반드시 다시 컴파일 되어야 한다.
만약, 헤더 파일이 변경된다면 헤더 파일을 include 하는 각 C 소스파일도 반드시 다시 컴파일 되어야 한다. 각, 컴파일은 소스파일에 대응하는 오브젝트 파일을 생성한다.
어떤 소스파일이 다시 컴파일이 되었다면, 모든 오브젝트 파일들은 들은 그것들이 새로 만들어진 것이든 아니든 반드시 같이 링크되어서 새로운 편집기 실행파일을 만들어야 한다.

1. Makefile 규칙의 모습

target ... : dependencies ... command ... ...
Makefile
복사

정의

target
dependency
command
makefile rule
1.
일반적으로 command는 dependencies와 함께 한 규칙한에 존재한다.
2.
dependencies 중 어떤 것이라도 변했다면 target 파일을 생성하는 일을 하지만 target을 위한 command들을 지정하는 규칙이 반드시 dependencies를 가질 필요는 없다.
ex) clean이라는 target과 연관된 삭제 command를 담고 있는 규칙은 dependencies를 가지지 않는다.
3.
make는 target을 생성하거나 업데이트하기 위해서 dependencies에 command를 수행한다.

2 - 1. 단순한 Makefile

# example file edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
Makefile
복사
makefile을 사용하여 ‘edit’ 실행파일을 만들기 위해서는 ‘make’라고 입력한다.
실행 파일과 모든 파일을 삭제하기 위해서 ‘make clean’을 입력한다.
예제 makefile에서 target들은 ‘edit’ 이라는 실행파일과 각종 object file을 포함한다.
dependencies는 ‘main.c’, ‘defs.h’와 같은 파일들이다. 각 ‘ *.o ’파일은 target이면서 동시에 dependency이다.
command는 ‘cc -c main.c’와 ‘cc -c kbd.c’를 포함한다.
target이 파일이라면 어떤 dependencies 중 하나가 변경되었을 때, 다시 컴파일 되거나 다시 링크 되어야 한다. 또한 자동으로 생성된 어떤 dependencies는 맨 먼저 업데이트되어야 한다.
target과 dependencies를 담고 있는 각 라인 뒤에 쉘 명령이 나타난다.
‘clean’이라는 target은 파일이 아니라 액션의 이름이다. ‘clean’은 일반적인 경우에 실행되는 것을 바라지 않기 때문에 ‘clean’이 스스로 dependency가 아니며 어떤 dependency도 가지지 않는다. 그래서 이 규칙의 단 하나의 목적은 특정 명령들을 실행하는 것이다.
파일이 아닌 그냥 액션을 지칭하는 target은 phony target이라고 불린다.

2 - 2. make가 Makefile을 처리하는 방법

기본값
1.
goal은 make가 궁극적으로 업데이트 하려고 하는 target이다.
2.
이전 단순 Makefile 예제에서 default goal은 실행 프로그램 edit을 업데이트하는 것이다. 그래서 그 규칙이 맨 처음에 있었고 make를 쓰면 현재 디렉토리에서 makefile을 읽고 첫번째 규칙을 처리하기 시작한다.
3.
소스파일 또는 dependencies에 있는 헤더파일들 중 어떤 것이라도 오브젝트 파일보다 더 최근의 것이거나 오브젝트 파일이 존재하지 않는다면 재컴파일은 반드시 일어나야 한다.
4.
다른 규칙은 해당 target 이 goal의 필수 구성요소로 나타나기 때문에 처리된다.
5.
다른 규칙이 goal( 또는 해당 규칙에 종속된 모든 규칙 등)에 의해 종속되지 않는 경우, make clean과 같은 명령을 사용하여 지시하지 않는 한 해당 규칙은 처리되지 않는다.
6.
오브젝트 파일을 다시 컴파일하기 전에 필수 구성요소인 소스파일 및 헤더파일의 업데이트를 고려한다. 이 makefile은 ‘ .h ‘ 및 ‘ .c ‘ 파일은 규칙의 대상이 아니므로 makefile은 이러한 파일에 대해 아무것도 수행하지 않는다. 그러나 make는 Bison이나 Yacc가 만든 C 프로그램과 같이 자동으로 생성된 데이터를 현재 자신의 규칙에 따라 업데이트 한다.
7.
오브젝트 파일들이 필요로 하는 것이면 무엇이든 컴파일한 후 make는 ‘edit’을 링크할 것인가를 결정한다. 이것은 ‘edit’파일이 존재하지 않거나 오브젝트 파일들 중 어떤 것이라도 그것보다 더 최근의 것이라면 반드시 수행되어야 한다. 어떤 오브젝트 파일이 재컴파일 되었다면 그것은 현재 ‘edit’보다 더 새로운 것이고 그래서 ‘edit’이 리링크 된다.
8.
따라서 우리가 .c파일이나 .h파일을 변경하고 make를 실행하면 make는 해당 파일을 갱신하기 위해 그 파일을 재컴파일 할 것이고 그리고 나서 edit을 링크할 것이다.

2 - 3. Makefile을 좀 더 쉽게 만드는 변수들

우리는 예제에서 ‘edit’을 위한 규칙을 위해 모든 오브젝트 파일들을 두번씩 기술했다.
edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
Makefile
복사
이렇게 반복하는 것은 에러를 발생하거나 깜빡하고 리스트를 추가하지 않을 수 있다.
따라서 우리는 변수를 사용하여 이런 위험을 없애고 makefile을 단순하게 만들 수 있다.
이것이 변수이다.
우리는 위의 makefile 에서 오브젝트 파일을 objects 라고 정의할 수 있다.
모든 오브젝트 파일 이름들의 리스트에 대해 objectsOBJECTS,  objs,  OBJS,  objOBJ 라고 쓰는 것은 표준 관례이다.
그리고 우리는 오브젝트 파일의 리스트를 놓고자 하는 곳마다 그 변수의 값을 $(objects) 라고 써서 대입할 수 있다.
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit $(objects)
Makefile
복사

2 - 4. make가 명령 추론하도록 하기

개별 c소스 파일들을 컴파일 하기 위한 명령들을 전부 나열하는 것은 make가 추측할 수 있기 때문에 불필요하다.
‘cc -c’ 명령을 사용해서 대응되는 ‘.c’ 파일로부터 ‘.o ‘ 파일을 갱신하기 위한 암묵적 규칙(implicit rule)을 가지고 있다.
ex)
‘ .c ‘ 파일이 이런 식으로 자동으로 사용될 때, 이것은 dependencies 리스트에 자동으로 추가된다. 그러므로 우리는 우리가 그 명령을 생략했다면 dependencies로 부터 ‘ .c’ 파일들을 생략할 수 있다.
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : -rm edit $(objects)
Makefile
복사
묵시적 규칙은 편리하기 때문에 중요하다.

2 - 5. Makefile의 다른 스타일

makefile의 오브젝트들이 단지 암묵적 규칙에 의해서만 생성될 때 다른 스타일의 makefile이 가능해진다.
다음 스타일의 makefile에서는 target대신 필수 구성요소를 기준으로 그룹화한다.
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h
Makefile
복사
여기서 ‘defs.h’ 는 모든 오브젝트 파일들의 dependency로 주어졌다. ‘command.h’와 ‘buffer.h’는 그것을 위해 리스트된 특정 오브젝트 파일들의 dependencies이다.
어떤 것이 나은가는 취향의 문제다. 이렇게 사용하는 것이 더 간결하지만 어떤 사람은 한자리에 각 target에 대한 정보를 모두 넣는 것이 더 명확하다고 생각하여 이것을 싫어한다.

2 - 6. 디렉토리를 정리하는 규칙

어떤 프로그램을 컴파일 하는 것만이 makefile을 쓰는 유일한 목적은 아니다.
ex) 디렉토리가 ‘clean’ 되도록 모든 오브젝트 파일들과 실행 파일들을 지우는 종류의 목적이 있다.
clean: rm edit $(objects)
Makefile
복사
실제로 우리는 예견하지 못한 상황들을 처리하기 위해 더 복잡한 방법으로 규칙을 사용하려고 하는지도 모른다.
.PHONY : clean clean : -rm edit $(objects)
Makefile
복사
이렇게 하면 make가 clean이라는 실제 파일로 인해 혼동되는 것을 방지하고 rm의 오류에도 불구하고 계속 진행된다.
이런 규칙은 기본적으로 실행하지 않기 때문에 makefile의 시작 부분에 배치하면 안된다! 따라서 이 makefile 예제에서 편집기를 다시 컴파일하는 편집 규칙을 default goal 로 유지한다.
clean이 edit의 dependency가 아니기 때문에 이 규칙은 우리가 make에 매개변수를 주지 않는다면 전혀 실행되지 않을 것이다. 실행시키려 한다면 ‘make clean’이라는 매개 변수를 주어야 한다.
참고