[makefile] #0. makefile 시작하기

문연수·2022년 9월 14일
0

Makefile

목록 보기
1/8

 이하의 글을 https://makefiletutorial.com/ 의 글을 번역하고 갈무리하여 작성한 글입니다. 자세한 사항은 원문을 참조하길 바랍니다.

0. makefile 이 왜 필요한가?

Makefile 은 큰 규모의 프로그램에서 어떤 부분이 다시 컴파일되어야 하는지 찾는데 도움을 준다. 단순 프로그램 컴파일을 넘어서 파일의 변경사항에 종속적인 일련의 작업들을 수행할 때에도 이용될 수 있다.

 가령 가계부를 작성한다고 했을 때, 특정 월의 총 수입은 그 달의 지출과 수입을 결산한 결과일 것이다. 만일 특정 월의 누락된 수입이 존재하여 해당 내역을 추가하게 된다면 해당 월의 총 수입 또한 같이 변경되어야 한다. 년간 총 수입도 계산해야 한다면 월간 총 수입이 변경되었으므로 그 또한 변경이 이뤄져야 할 것이다.

 다양한 용도로 사용이 가능하지만 일반적으로 Makefile 의 핵심은 C/C++ 빌드 시스템으로써 파일들의 변경사항(각 파일들의 수정시간)을 기반으로 하여 필요에 따라 컴파일을 수행하는 것이다.

1. Makefile 의 문법

 Makefile 은 rule 의 집합으로 구성된다. rule 은 일반적으로 다음의 형태를 가진다:

targets: preprequisites
	command
    command
    command
    ...
  • targets 는 공백으로 나뉘어진 파일의 이름들이다. 보통은 rule 당 하나씩 존재한다.
  • commandstargetmake 하기 위한 일련의 과정이다. 이들은 공백이 아닌 탭(tab) 으로 시작한다.
  • prerequisites 또한 파일의 이름이며 공백으로 구분된다. 위 파일들은 targetmake 하기 위한 commands 를 실행하기 전에 존재해야 한다.

- 간단한 일상 생활의 예시

 전술한 가계부 예시로 makefile 을 작성하려 한다. 실제 문법은 아래와 다르지만 이해를 돕기 위해 일부 명령은 의사코드로 작성해보았다:

total: yearly
	total = 0
    for entry in yearly
		total += entry

yearly: monthly
	yearly = 0
    for entry in monthly
    	yearly += entry
        
monthly: daily
	monthly = 0
    for entry in daily
    	monthly += entry

 최종 수입에 해당하는 targettotal 을 계산하기 위해선 연간 총 수입(yearly) 을 모두 더해야 한다는 rule 이 필요할 것이다. 연간 총 수입에 해당하는 yearly 역시 월간 총 수입인 monthlyprerequisites (전제, 필요조건) 으로 가진다. monthly 또한 daily 가 모여서 완성된 결과일 것이다.

 만일 2022/08/24.txt 라는 이름의 일간 가계 내역의 변경(츄파츕스 구매 내역을 누락함)이 발생한다면 그 상위의 2022/08.txt 라는 이름의 월간 가계 내역, 2022.txt 라는 연간 가계 내역, 그리고 최종 결산 내역인 results.txt 또한 변경해야 한다.

make 는 이러한 상황에서 각 파일들의 최종 수정일만을 비교하여 수 많은 파일들 중 2022/08/24.txt 파일과 연관된 2022/08.txt, 2022.txt, 그리고 results.txt 만 수정하게 된다.

2. 실제 Makefile 작성하기

 실제 makefile 을 작성하고 또 실행시키기 위해선 make 프로그램을 설치해야 한다. 설치 방법은 운영체제, 그리고 배포판마다 다르지만 보통 본인이 사용하는 배포판의 패키지 매니저에게 make 설치를 요청하면 자동으로 다운로드 받아 설치해준다.

- makefile 작성하고 실행하기

hello:
	echo "hello, world!"

make 프로그램을 설치했다면 위 예제를 복사한 뒤 makefile 이라는 이름의 파일을 생성하여 붙여넣은 뒤, 같은 경로에서 make hello 를 입력하면 이하와 같은 결과를 확인할 수 있다:

 위 예제를 조금 뜯어보면 다음과 같다:

  • makefile 은 오직 하나의 target 에 대한 하나의 rule 만을 가진다.
  • targethello 는 하나의 command 를 가진다.
  • targetprerequisites 를 필요로 하지 않는다.

hello 라는 이름의 파일만 동일 경로에 존재하지 않는다면 make hello 를 입력할 때마다 반복적으로 echo 명령을 수행한다. 만일 hello 라는 이름의 파일이 존재한다면 이미 target 에 해당하는 파일이 존재하므로 command 를 실행하지 않는다.

3. makefile 분석하기

output: main.o
        cc main.o -o output # Runs third

main.o: main.c
        cc -c main.c -o main.o  # Runs second

main.c:
        echo "int main(void) { return 0; }" > main.c

 다시 위 내용의 makefile 을 생성한 뒤 해당 파일만을 남기고 make 명령을 입력하면 자동으로 빌드가 진행되고 최종적으로 output 파일이 생성되는 것을 확인할 수 있다.

make 의 동작을 순서대로 설명하자면 이하와 같다:

  1. make 명령으로 어떠한 target 도 지정하지 않았기 때문에 첫 번째 targetoutputdefault 로 설정된다.
  2. outputprerequisite 으로 main.o 를 가지지만 main.o 가 없기 때문에 main.o 를 완성하기 위해 main.otarget 으로 하는 rule 을 찾는다.
  3. main.omain.c 가 없다면 2번과 동일한 과정을 거친다. 그러나 main.c 가 이미 존재한다면 main.o 보다 새로운(최종 수정일) 경우에만 컴파일이 수행된다.
  4. main.cprerequisite 을 가지지 않으므로 곧바로 command 를 실행한다. 이는 main.c 를 생성하게 된다.
  5. 이제 main.c 가 생성되었으므로 main.otarget 으로 가지는 rule 을 수행할 수 있게 되었다. main.c 를 컴파일하여 main.o 를 생성하는 command 를 수행한다.
  6. output 역시 main.o 가 생성되었으므로 이를 통해 command 를 수행하고 output 이라는 이름의 파일을 생성하게 된다.

 만일 main.c 를 삭제하게 된다면 target 생성을 위해 위 세 rule 을 모두 실행하게 된다. 혹은 touch main.o 명령을 입력하여 main.o 의 최종 수정일을 변경하게 되면 output 만 다시 실행된다.

- make clean

clean 은 종종 다른 targetoutput 을 제거하기 위한 target 으로 사용된다. 그러나 이는 make 에 있어 특별한 키워드는 아니다. 필요에 따라 빌드 부산물 등을 제거하기 위해 make clean 을 이용할 수 있다:

some_file:
	touch some_file

clean:
	rm -f some_file

4. Variables

Variable 은 오직 문자열(string)으로만 존재한다. 변수에 값을 대입하기 위해 := 혹은 = 을 사용할 수 있다. 이들의 차이점은 이후에 설명한다.

files := file1 file2

some_file: $(files)
	echo "Look at this variable: " $(files)
    touch some_file
    
file1:
	touch file1
    
file2:
	touch file2
    
clean:
	rm -f file1 file2 some_file

makefile 내에서 작은 따옴표와 큰 따옴표는 어떠한 의미도 가지지 않는다. 따라서 file1file2 도 변수에 대입되는 단순한 문자열에 불과하다. 따라서 이하의 예제는 동일한 결과를 반복 출력한다:

a := one two
b := 'one two'

all:
	printf '$a'
    printf $b

 변수의 참조를 위해 ${}$() 두 가지 형태 모두 사용이 가능하다:

x := dude

all:
	echo $(x)
    echo ${x}
    
    # Bad practice, but works
    echo $x

출처

[사이트] https://makefiletutorial.com/#getting-started

profile
2000.11.30

0개의 댓글