make
1. 개요
1. 개요
make는 소스 코드 파일들로부터 실행 파일이나 라이브러리를 생성하는 빌드 과정을 자동화하는 도구이다. 이 도구는 Makefile이라는 이름의 설정 파일에 정의된 규칙을 읽어, 소프트웨어 개발 과정에서 필요한 컴파일과 링킹 작업을 관리한다.
주요 동작 원리는 타겟, 의존성, 명령어의 관계를 기반으로 한다. 사용자가 특정 타겟(예: 최종 프로그램)을 빌드하도록 요청하면, make는 해당 타겟이 의존하는 파일들의 최신 상태를 확인한다. 의존 파일이 타겟 파일보다 최신이거나 타겟 파일이 존재하지 않을 경우에만 관련 명령어들을 실행하여 타겟을 갱신한다. 이를 통해 변경된 파일만 다시 빌드하는 점진적 빌드가 가능해져 불필요한 작업을 줄이고 개발 효율을 높인다.
이 도구는 C나 C++ 프로젝트를 비롯한 다양한 프로그래밍 언어의 빌드 과정에 널리 사용되며, 소프트웨어 공학에서 빌드 자동화의 초기이자 핵심적인 도구로 자리 잡았다. GNU Make가 가장 일반적인 구현체이며, BSD Make, CMake, Ninja 등의 변종 및 대체 도구도 존재한다.
2. 기본 개념
2. 기본 개념
2.1. Makefile 구조
2.1. Makefile 구조
Makefile의 기본 구조는 타겟, 의존성, 명령의 세 가지 핵심 요소로 구성된다. 이 구조는 "타겟: 의존성" 형태의 규칙으로 정의되며, 그 아래에 탭 문자로 시작하는 명령들이 위치한다. Makefile은 일반적으로 프로젝트 루트 디렉토리에 Makefile 또는 makefile이라는 이름으로 저장된다.
주요 구성 요소로는 명시적 규칙, 변수, 주석, 특수 타겟 등이 있다. 명시적 규칙은 특정 파일(타겟)을 생성하기 위해 필요한 파일(의존성)과 실행할 셸 명령을 정의한다. 변수는 문자열 값을 저장하여 Makefile 내에서 반복 사용되는 값들을 관리하고 재사용성을 높인다. 주석은 # 문자로 시작하며, Makefile을 읽는 사람을 위한 설명을 추가한다.
Makefile은 또한 패턴 규칙이나 암시적 규칙과 같은 고급 기능을 포함할 수 있다. 패턴 규칙은 % 와일드카드를 사용하여 유사한 구조를 가진 여러 규칙을 하나로 일반화한다. 암시적 규칙은 make가 미리 정의한 내장 규칙으로, 특정 확장자를 가진 파일을 다른 확장자로 변환하는 방법을 알고 있어 사용자가 모든 규칙을 명시적으로 작성하지 않아도 된다.
Makefile의 실행은 단순히 터미널에서 make 명령을 입력하는 것으로 시작된다. make는 기본적으로 Makefile의 첫 번째 규칙을 찾아 실행한다. 특정 타겟을 빌드하려면 make 타겟이름과 같이 명령을 내리면 된다. 이 구조는 소프트웨어 빌드 과정을 자동화하고, 변경된 파일만을 효율적으로 재빌드하여 개발 시간을 단축하는 데 기여한다.
2.2. 타겟(Target)과 의존성(Dependency)
2.2. 타겟(Target)과 의존성(Dependency)
타겟은 빌드 과정에서 생성하려는 최종 산출물이나 중간 산출물을 가리킨다. 일반적으로 실행 파일이나 라이브러리 파일의 이름이 타겟이 된다. 의존성은 해당 타겟을 생성하는 데 필요한 입력 파일이나 다른 타겟을 의미한다. 예를 들어, 실행 파일을 타겟으로 지정했다면, 그 실행 파일을 컴파일하기 위한 소스 코드 파일들과 오브젝트 파일들이 의존성이 된다.
Makefile의 기본 규칙은 타겟: 의존성들의 형태로 정의된다. 이는 "타겟은 의존성들로부터 만들어진다"는 관계를 선언하는 것이다. 이 선언 아래에 들여쓰기로 작성된 명령들은 의존성 파일들이 타겟 파일보다 최신일 때, 즉 타겟을 다시 만들어야 할 필요가 있을 때 실행된다. 이 메커니즘은 불필요한 재빌드를 방지하여 빌드 시간을 단축하는 핵심이다.
의존성은 여러 단계로 중첩될 수 있다. 실행 파일 타겟은 여러 오브젝트 파일에 의존하고, 각 오브젝트 파일은 다시 해당 C 소스 파일과 헤더 파일에 의존한다. make는 이러한 의존성 그래프를 따라 최종 타겟부터 역으로 추적하며, 최신 상태가 아닌 타겟만을 찾아 해당 명령들을 실행한다.
가상의 타겟인 PHONY 타겟도 존재한다. clean이나 all과 같이 실제 파일을 생성하지는 않지만, 특정 명령어 집합을 실행하기 위한 목적으로 사용된다. 이는 파일 이름과 충돌을 방지하고 의도된 동작을 보장하기 위해 Makefile에 명시적으로 .PHONY로 선언하는 것이 일반적이다.
2.3. 명령(Command)
2.3. 명령(Command)
명령은 Makefile에서 타겟을 빌드하기 위해 실제로 실행되는 셸 명령어들이다. 명령은 타겟과 의존성을 정의한 줄 바로 다음 줄에 작성되며, 반드시 탭 문자로 시작해야 한다는 문법적 규칙을 가진다. 이는 make가 명령 줄을 식별하는 핵심적인 방법이다. 각 명령은 별도의 셸 프로세스에서 실행되며, 명령이 실패(0이 아닌 종료 상태를 반환)하면 make는 일반적으로 빌드 과정을 중단한다.
명령은 일반적으로 컴파일러나 링커를 호출하여 소스 코드를 오브젝트 파일로 변환하거나, 실행 파일을 생성하는 작업을 수행한다. 또한 파일 복사, 디렉터리 생성, 정적 분석 도구 실행 등 빌드 과정에 필요한 모든 작업을 포함할 수 있다. 명령 앞에 @ 기호를 붙이면 해당 명령 자체를 표준 출력에 표시하지 않고 실행 결과만 출력하는 데, 이는 빌드 출력을 깔끔하게 정리하는 데 유용하다.
명령 블록 내에서는 make의 자동 변수들을 활용할 수 있다. 예를 들어, $@는 현재 타겟의 이름을, $<는 첫 번째 의존성의 이름을, $^은 모든 의존성의 목록을 나타낸다. 이러한 변수들은 명령을 일반화하고 Makefile의 중복을 줄이는 데 기여한다. 또한, 명령 줄 앞에 - 기호를 붙이면 해당 명령이 실패하더라도 make가 빌드 과정을 계속 진행하도록 할 수 있다.
3. 주요 기능
3. 주요 기능
3.1. 자동 의존성 추적
3.1. 자동 의존성 추적
자동 의존성 추적은 Make가 제공하는 핵심 기능 중 하나로, 소스 코드 파일 간의 의존성을 자동으로 분석하여 변경된 파일만 다시 빌드하는 메커니즘이다. 이 기능은 C 언어나 C++와 같이 헤더 파일을 포함하는 프로그래밍 언어를 사용하는 프로젝트에서 특히 중요하다. 예를 들어, 특정 소스 파일이 수정되거나, 그 소스 파일이 포함하는 헤더 파일이 변경되면, 해당 소스 파일로부터 생성되는 오브젝트 파일과 이를 사용하는 실행 파일만 다시 빌드한다. 이를 통해 불필요한 전체 재컴파일을 방지하고 빌드 시간을 크게 단축시킨다.
이 기능은 전통적으로 make 명령어에 -M 옵션을 지원하는 컴파일러 (예: GCC)와의 조합으로 구현된다. Makefile에 특별한 규칙을 작성하면, 컴파일러가 소스 파일을 분석하여 그 파일이 직접 또는 간접적으로 포함하는 모든 헤더 파일 목록을 생성한다. 이렇게 생성된 의존성 정보는 보통 .d 확장자를 가진 파일에 저장되고, 이후 빌드 과정에서 이 파일들을 참조하여 어떤 타겟이 최신 상태가 아닌지 판단한다.
자동 의존성 추적이 없으면, 개발자는 모든 헤더 파일과 소스 파일 간의 관계를 수동으로 Makefile에 명시해야 한다. 이는 매우 번거롭고 오류가 발생하기 쉬우며, 헤더 파일이 추가되거나 변경될 때마다 Makefile을 지속적으로 업데이트해야 하는 부담을 준다. 따라서 현대적인 소프트웨어 프로젝트에서는 자동 의존성 추적을 필수적으로 사용하여 빌드 시스템의 유지보수성을 높이고 효율성을 보장한다.
3.2. 병렬 빌드
3.2. 병렬 빌드
make 도구의 병렬 빌드 기능은 -j 또는 --jobs 옵션을 통해 활성화된다. 이 옵션 뒤에 숫자를 지정하여 동시에 실행할 수 있는 작업(Job)의 최대 개수를 제어할 수 있다. 예를 들어 make -j4는 최대 4개의 작업을 병렬로 처리하도록 지시한다. 옵션 값으로 -j만 지정하거나 특정 숫자 대신 -j를 사용하면, make가 시스템의 가용 CPU 코어 수를 자동으로 감지하여 이에 맞춰 최적의 병렬 작업 수를 결정한다. 이는 멀티코어 프로세서가 일반화된 현대 시스템에서 빌드 시간을 획기적으로 단축시키는 핵심 기능이다.
병렬 빌드는 의존성 그래프를 분석하여 서로 독립적인 타겟들을 동시에 처리하는 방식으로 작동한다. 예를 들어, 서로 의존 관계가 없는 여러 개의 오브젝트 파일 생성을 각기 다른 스레드나 프로세스에서 동시에 컴파일할 수 있다. 그러나 특정 타겟이 다른 타겟의 출력에 의존하는 경우, make는 의존성 순서를 준수하며 자동으로 작업의 실행 순서를 조정한다. 따라서 올바르게 작성된 Makefile이라면 병렬 빌드를 통해 빌드 정확성을 해치지 않으면서도 성능만을 향상시킬 수 있다.
병렬 빌드 사용 시 주의할 점도 존재한다. 첫째, 모든 명령어가 병렬 실행에 안전해야 한다. 예를 들어, 임시 파일을 같은 이름으로 생성하는 명령어가 분리된 작업에서 동시에 실행되면 충돌이 발생할 수 있다. 둘째, 표준 출력과 표준 에러 출력이 여러 작업에서 섞여 출력되어 가독성이 떨어질 수 있다. make는 일반적으로 각 명령어의 출력을 완전히 받은 후 다음 출력을 표시하려고 하지만, 완벽하게 분리되지 않을 수 있다. 이러한 문제를 해결하기 위해 .NOTPARALLEL 특수 타겟을 지정하거나, 특정 타겟이나 규칙에 대해 병렬 빌드를 제한하는 방법을 사용할 수 있다.
3.3. 변수와 매크로
3.3. 변수와 매크로
Make에서 변수는 값을 저장하고 재사용하기 위한 이름이다. 변수를 사용하면 Makefile 내에서 반복되는 값(예: 컴파일러 이름, 컴파일 옵션, 소스 파일 목록)을 한 곳에서 정의하고 관리할 수 있어 유지보수성이 크게 향상된다. 변수는 변수명 = 값 또는 변수명 := 값과 같은 형태로 정의하며, $(변수명) 또는 ${변수명}의 형태로 참조하여 사용한다. =는 재귀적 확장 변수로, 참조될 때마다 값을 평가하며, :=는 단순 확장 변수로, 정의되는 순간의 값을 고정한다는 차이가 있다.
매크로는 Make에서 여러 명령을 하나의 이름으로 묶어 재사용할 수 있게 하는 기능이다. 사용자 정의 함수와 유사하게 동작하며, define 지시어를 사용하여 정의한다. 매크로는 특히 복잡하거나 반복되는 명령어 시퀀스를 캡슐화할 때 유용하다. 매크로 내부에서는 자동 변수($@, $< 등)를 사용할 수 있으며, $(call 매크로명, 인자1, 인자2)와 같은 형태로 호출하여 인자를 전달할 수 있다.
변수/매크로 타입 | 정의 방식 | 평가 시점 | 주요 용도 |
|---|---|---|---|
재귀적 확장 변수 |
| 참조될 때마다 | 다른 변수를 참조하는 동적 값 |
단순 확장 변수 |
| 정의되는 순간 | 고정된 값이나 명령어 결과 |
조건부 할당 변수 |
| VAR이 미정의된 경우에만 | 기본값 설정 |
매크로 |
|
| 복잡한 명령 시퀀스 묶기 |
이러한 변수와 매크로를 효과적으로 활용하면 Makefile을 더 간결하고 강력하게 작성할 수 있으며, 빌드 자동화 과정에서 발생할 수 있는 오류를 줄이고 소프트웨어 개발 생산성을 높이는 데 기여한다.
3.4. 패턴 규칙
3.4. 패턴 규칙
패턴 규칙은 여러 유사한 파일에 대해 반복적으로 작성해야 하는 명시적 규칙을 간결하게 정의할 수 있는 메이크의 강력한 기능이다. 특정 패턴을 가진 소스 파일을 같은 패턴을 가진 목표 파일로 변환하는 방법을 일반화하여 기술한다. 이는 Makefile을 더욱 간결하고 유지보수하기 쉽게 만들어 준다.
패턴 규칙은 퍼센트 기호(%)를 와일드카드로 사용하여 정의한다. 예를 들어, .c 확장자를 가진 소스 코드 파일을 .o 오브젝트 파일로 컴파일하는 일반적인 규칙은 %.o: %.c와 같은 형태로 작성한다. 이 한 줄의 규칙은 foo.o는 foo.c에 의존한다는 규칙과 bar.o는 bar.c에 의존한다는 규칙을 모두 대체할 수 있다. 규칙의 명령 부분에서는 자동 변수인 $<(첫 번째 의존 파일)이나 $@(타겟 파일명) 등을 활용하여 각 파일 이름을 참조한다.
이 기능은 특히 C 프로젝트나 C++ 프로젝트처럼 동일한 확장자를 가진 수많은 소스 파일들을 처리할 때 빛을 발한다. 개발자는 각 파일 쌍마다 개별적인 규칙을 중복 작성할 필요 없이, 하나의 패턴 규칙으로 모든 빌드 과정을 관리할 수 있다. 또한, 내장 패턴 규칙이라는 형태로 GNU Make에 미리 정의된 규칙들도 존재하여, 사용자가 최소한의 Makefile만으로도 표준적인 빌드를 수행할 수 있게 한다.
4. 사용 예시
4. 사용 예시
4.1. 간단한 C 프로젝트 빌드
4.1. 간단한 C 프로젝트 빌드
간단한 C 프로젝트를 빌드하는 전형적인 예는 main.c, hello.c, hello.h 세 개의 파일로 구성된 경우를 들 수 있다. 이 프로젝트에서 main.c는 hello.h에 선언된 함수를 호출하고, hello.c는 해당 함수의 구현을 담고 있다. 이때 Makefile은 각 소스 코드 파일이 목적 파일로 컴파일되고, 이들이 링커에 의해 하나의 실행 파일로 결합되는 과정을 정의한다.
Makefile의 핵심 규칙은 최종 타겟인 실행 파일이 의존하는 목적 파일들을 나열하고, 각 목적 파일이 의존하는 소스 파일과 헤더 파일을 명시하는 것이다. 예를 들어, myapp이라는 실행 파일을 생성하기 위한 규칙은 myapp: main.o hello.o로 시작한다. 이는 myapp이 main.o와 hello.o에 의존함을 나타낸다. 다음 줄에는 이 의존 관계를 해결하기 위한 링킹 명령인 gcc -o myapp main.o hello.o가 들여쓰기로 작성된다.
각 목적 파일을 생성하는 규칙도 비슷한 패턴으로 작성된다. main.o: main.c hello.h와 hello.o: hello.c hello.h 규칙은 각 목적 파일이 어떤 소스 파일과 헤더 파일에 의존하는지 정의한다. 그 아래에는 해당 목적 파일을 생성하는 컴파일 명령, 예를 들어 gcc -c main.c가 온다. 이렇게 의존성을 명시함으로써, hello.h가 수정되면 main.o와 hello.o를 모두 재생성해야 함을 make가 자동으로 판단할 수 있다.
이러한 기본 구조는 프로젝트 규모가 커지더라도 동일하게 확장 적용된다. 소스 파일이 수십 개가 되어도, 각 파일에 대한 오브젝트 파일 생성 규칙을 추가하고, 최종 타겟의 의존성 목록에 이를 포함시키면 된다. 또한, CC와 CFLAGS 같은 변수를 사용하여 컴파일러와 컴파일 옵션을 중앙에서 관리하면 Makefile의 유지보수성이 크게 향상된다.
4.2. Makefile 작성 패턴
4.2. Makefile 작성 패턴
Makefile을 작성할 때는 몇 가지 일반적인 패턴과 모범 사례가 존재한다. 이러한 패턴을 따르면 빌드 과정을 효율적으로 구성하고 유지보수성을 높일 수 있다.
가장 기본적인 패턴은 타겟, 의존성, 명령의 삼단 구조를 명확히 하는 것이다. 자주 사용되는 변수 정의 패턴으로는 CC(C 컴파일러), CFLAGS(컴파일러 플래그), LDFLAGS(링커 플래그), TARGET(생성할 실행 파일명), SRCS(모든 소스 파일 목록), OBJS(객체 파일 목록) 등이 있다. SRCS와 OBJS는 와일드카드 함수인 wildcard와 문자열 치환 함수인 patsubst를 조합해 자동으로 생성하는 것이 일반적이다. 이렇게 하면 새 소스 파일을 추가할 때마다 Makefile을 수정할 필요가 없어진다.
또 다른 핵심 패턴은 패턴 규칙을 활용하는 것이다. 예를 들어 %.o: %.c와 같은 규칙을 정의하면 각 .c 파일을 해당 .o 파일로 컴파일하는 방법을 일일이 기술하지 않아도 된다. 이 패턴 규칙과 함께 자동 변수인 $@(타겟 이름)와 $<(첫 번째 의존성)를 사용하면 명령어를 일반화할 수 있다. 최종 실행 파일 타겟은 이러한 객체 파일들에 의존성을 두고 링크 단계를 수행하도록 작성한다.
마지막으로, .PHONY 타�트 선언은 중요하다. all, clean, install 같은 실제 파일을 생성하지 않는 가상 타겟을 명시적으로 선언함으로써, 동일한 이름의 파일이 존재할 때 발생할 수 있는 빌드 오류를 방지한다. 또한, 명령 앞에 @ 기호를 붙여 명령어 자체를 출력하지 않거나, - 기호를 붙여 명령 실패 시에도 빌드를 계속 진행하도록 제어할 수 있다. 이러한 패턴들은 GNU Make와 BSD Make 등 다양한 구현체에서 공통적으로 적용 가능하다.
5. 변종 및 대체 도구
5. 변종 및 대체 도구
5.1. GNU Make
5.1. GNU Make
GNU Make는 GNU 프로젝트의 일환으로 개발된 빌드 자동화 도구이다. 이는 리처드 스톨먼이 작성한 원본 make 프로그램을 기반으로 하며, 현재 가장 널리 사용되는 make 구현체이다. 소프트웨어 개발 과정에서 소스 코드 파일들로부터 실행 파일이나 라이브러리를 생성하는 빌드 과정을 자동화하는 데 주로 사용된다.
GNU Make의 핵심은 Makefile이라는 이름의 설정 파일에 있다. 이 파일은 타겟, 의존성, 명령의 관계를 정의하여, 변경된 파일만을 효율적으로 다시 빌드할 수 있게 한다. 이를 통해 대규모 프로젝트에서도 빌드 시간을 크게 단축할 수 있다. GNU Make는 C나 C++ 프로젝트와 전통적으로 깊은 연관이 있지만, 자바, 파이썬 등 다른 언어의 프로젝트나 문서 생성, 파일 처리 등 다양한 작업 자동화에도 활용된다.
GNU Make는 원본 make보다 향상된 많은 기능을 제공한다. 주요 기능으로는 자동 변수($@, $< 등)를 포함한 강력한 변수와 매크로 시스템, 패턴 규칙을 통한 일반화된 규칙 정의, 다중 타겟 규칙, 그리고 조건문을 통한 유연한 Makefile 작성 등이 있다. 또한, -j 옵션을 통한 병렬 빌드를 지원하여 멀티코어 시스템에서의 빌드 성능을 극대화한다.
이 도구는 리눅스, macOS를 포함한 대부분의 유닉스 계열 시스템과 마이크로소프트 윈도우에서도 사용 가능하다. GNU Make의 광범위한 사용과 강력한 기능은 이를 빌드 도구의 사실상의 표준으로 자리잡게 했으며, CMake나 Ninja 같은 현대적인 빌드 시스템들도 종종 최종적인 빌드 단계에서 GNU Make를 백엔드로 호출하기도 한다.
5.2. BSD Make
5.2. BSD Make
BSD Make는 BSD 계열 운영 체제에서 개발된 Make 구현체이다. GNU Make와 마찬가지로 소프트웨어 빌드 자동화 도구로, Makefile을 해석하여 빌드 자동화를 수행한다. 주로 FreeBSD, NetBSD, OpenBSD와 같은 시스템에서 기본적으로 제공되며, 이들 시스템의 포트나 패키지 빌드 시스템의 근간을 이룬다. GNU Make와 기본적인 철학과 구문을 공유하지만, 몇 가지 차별화된 문법과 기능을 가지고 있다.
주요 특징으로는 조건부 구문과 같은 제어 흐름 기능이 강화되어 있으며, 병렬 빌드를 위한 .WAIT 지시어를 지원한다는 점이 있다. 또한, 자동 의존성 추적을 위한 MKDEP 방식 등 고유한 내장 규칙과 변수 체계를 갖추고 있다. 이러한 차이로 인해 BSD Make용으로 작성된 Makefile은 GNU Make에서 제대로 동작하지 않을 수 있으며, 그 반대의 경우도 마찬가지이다. 이는 이식성을 고려할 때 중요한 고려 사항이 된다.
BSD Make는 역사적으로 유닉스 make 유틸리티의 원래 구현에 더 가까운 경향이 있다. 현대적인 소프트웨어 개발에서는 CMake나 Ninja와 같은 더 추상화된 빌드 시스템이 널리 사용되지만, BSD 계열 시스템의 핵심 도구로서 여전히 중요한 역할을 하고 있다. 특히, 시스템 자체의 빌드나 간단한 프로젝트에서 여전히 직접 사용된다.
5.3. CMake
5.3. CMake
CMake는 Make와 같은 전통적인 빌드 도구와 달리, 플랫폼에 독립적인 빌드 설정 파일을 작성하고, 이를 통해 특정 플랫폼에 맞는 네이티브 빌드 파일(예: 유닉스 계열의 Makefile이나 마이크로소프트 비주얼 스튜디오의 프로젝트 파일)을 생성하는 메타 빌드 시스템이다. 즉, 개발자는 CMake의 스크립트 언어로 빌드 과정을 한 번 정의하면, CMake가 대상 운영체제와 컴파일러에 맞는 빌드 파일을 자동으로 만들어낸다. 이는 크로스 플랫폼 소프트웨어 개발에서 빌드 시스템의 통일과 관리를 크게 용이하게 한다.
CMake의 핵심 작업 흐름은 크게 구성(Configure)과 생성(Generate) 단계로 나뉜다. 먼저 개발자가 작성한 CMakeLists.txt 파일을 바탕으로 CMake는 시스템 환경을 검사하고, 필요한 변수와 설정을 구성한다. 이어서 구성된 정보를 바탕으로 실제 빌드를 수행할 네이티브 빌드 파일을 생성한다. 이 방식 덕분에 리눅스, macOS, 윈도우 등 다양한 환경에서 동일한 CMake 스크립트로 빌드할 수 있으며, IDE 통합도 원활하다.
주요 기능으로는 외부 라이브러리 탐색을 위한 find_package, 소스 파일 그룹화와 빌드 대상 정의를 위한 add_library 및 add_executable, 디렉터리별 설정 관리를 위한 add_subdirectory 등이 있다. 또한 변수와 캐시, 함수, 매크로를 지원하여 복잡한 빌드 로직을 모듈화하고 관리할 수 있다. 최근 버전에서는 C++ 모듈과 같은 현대적인 언어 기능에 대한 지원도 지속적으로 추가되고 있다.
CMake는 오픈 소스 프로젝트에서 사실상의 표준 메타 빌드 도구로 자리 잡았으며, Qt와 같은 대형 프레임워크나 VTK, ITK 등의 과학 컴퓨팅 라이브러리에서도 빌드 시스템으로 채택되어 널리 사용된다. Ninja와 같은 고속 빌드 도구를 백엔드로 사용하는 경우도 많아, 빌드 속도와 편의성을 모두 확보할 수 있다.
5.4. Ninja
5.4. Ninja
Ninja는 빌드 자동화 도구의 일종으로, 특히 속도와 확장성에 중점을 둔다. 기존의 Make와 같은 도구들이 복잡한 기능을 제공하는 반면, Ninja는 빌드 스케줄러로서의 핵심 임무, 즉 의존성 그래프를 따라 빌드 작업을 빠르게 실행하는 데 집중한다. 이로 인해 CMake나 GNU Make와 같은 상위 레벨 빌드 시스템 생성기의 백엔드로 널리 사용된다.
Ninja의 설계 철학은 단순함과 속도에 있다. Makefile에 비해 Ninja의 빌드 파일(build.ninja) 문법은 매우 간결하고 제한적이며, 조건문이나 복잡한 함수를 제공하지 않는다. 대신, 빌드 규칙과 의존 관계를 최소한의 오버헤드로 빠르게 읽고 처리할 수 있도록 최적화되어 있다. 이는 대규모 프로젝트, 예를 들어 구글 크롬이나 Android와 같은 프로젝트의 빌드 시간을 크게 단축시키는 데 기여했다.
주요 기능으로는 병렬 빌드를 기본적으로 지원하고, 빌드 중 변경된 파일만 재빌드하는 증분 빌드를 효율적으로 수행한다. 또한, 빌드 로그를 상세히 기록하여 빌드 실패 시 원인을 파악하기 쉽게 한다. 이러한 특징들로 인해 Ninja는 현대적인 소프트웨어 개발 환경, 특히 지속적 통합 파이프라인에서 선호되는 빌드 도구 중 하나가 되었다.
