4. 탄생 배경
Google Chome의 소스 파일 크기는 4만개 이상
전체빌드 소요시간 1시간 (i7, 16GB, SSD)
소스 한 줄 수정후 증분 빌드 시간 5분
대부분 Link 작업에 소요됨
5. Chrome의 빌드구조
GYP, 플랫폼 독립적인 타겟 프로젝트 생성
Visual Studio, Xcode, Ninja
빌드에 포함할, .cc, .h 등의 파일들의 나열
Ninja, 컴파일러를 실행하여 빌드할 파일을 생성
커맨드라인 명령의 나열
gcc -c foo.c -o foo.o
Compiler, 실제 빌드 작업을 수행
GYP Ninja Compiler
6. Ninja가 하는 일
Rule 생성
!
!
변수
cflags = -Wall
rule compile
command = gcc $cflags -c $in -o $out
rule compile
command = gcc -Wall -c $in -o $out
build out/foo.o: compile src/foo.c
build out/bar.o: compile src/bar.c
추상화
텍스트 기반, 가독성이 중요
7. Ninja가 하는 일
빌드가 필요한 대상을 찾기
빌드 의존성 그래프 생성
특정 노드가 수정되었으면 의존성 그래프에 따라 빌드해야할 집합 생성
실행
빌드가 필요한 그래프 간선을 따라다니며 빌드 실행
9. 문자열 파싱
Chrome은 10MB 이상의 Ninja 스크립트 파일을 생성함
static bool IsIdentifierCharacter(char c) {
return
('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
// and so on...
}
cs = set()
for c in string.ascii_letters + string.digits + r'+,-./_$':
cs.add(ord(c))
for i in range(256):
print '%d,' % (i in cs),
Lookup Table 이용
10. 정규화
Ninja는 수많은 파일 경로를 다루므로 최적화된 경로 식별 방법 필요
/bar.h
/foo/../bar.h
/bar.h
/bar.cc
/abc.h
/abc.c
경로 객체 경로 비교
0x2000
0x3000
Memory Addr
단순 포인터 비교연산
≠
11. 빌드 로그
이전 빌드와 새로운 빌드간의 로그를 비교해야함
이 역시 다량의 문자열 비교이므로 병목지점임
문자열 대신 명령의 해시를 기록하고 비교
200MB -> 2MB 미만, 20배 시간 단축
12. 의존성 파일 분석
#include “bar.h”
…
foo.c
#include “baz.h”
…
bar.h
class foo; baz.h
#include “bar.h”
…
#include “baz.h”
…
class bar;
baz.h 수정
모두 재빌드 필요
13. 의존성 파일 분석
방법들
헤더 스캐너 사용, 느리고 부정확
의존성을 일일이 빌드파일에 수작업으로 명시, 유지보수 어려움
컴파일러가 컴파일시점에 출력하게 함.(gcc, visual studio 모두지원)
gcc -> Makefile 형식으로 의존성 출력
총 용량 약 90MB. 빌드시작할때 이걸 모두 분석한 뒤에 빌드를 시작하기엔 시간소모가 큼
의존성 처리시점을 지연
컴파일이 이뤄지는 동안 Ninja가 하는 일은 컴파일러 프로세스 종료를 대기하는 것 뿐, 이시간을 이용
대기시간동안 의존성 정보파일을 파싱, 정규화, 의존성 처리
14. 빌드의 실행
빌드 실행성능은 전적으로 컴파일러에 의존
병렬실행의 결과를 버퍼에 저장후 순차적으로 출력
명령행 버퍼링.
빌드 성공시 출력은 단 한줄
Ninja가 빠르다는 느낌을 주는데 일조.
조용히 빠르게 치고 빠진다는 특징에서 Ninja의 이름이 비롯됨
15. Windows 이슈
명령줄의 최대 길이가 비교적 짧음 (8191 chars)
파일연산이 느림
GetFileAttributesEx()는 리눅스의 stat()보다 100배는 느림
파일 의존성 출력 이슈
Visual Studio 의존성 파일
gcc
Makefile 형식
변환파일 생성
16. Windows 이슈
명령줄의 최대 길이가 비교적 짧음 (8191 chars)
파일연산이 느림
GetFileAttributesEx()는 리눅스의 stat()보다 100배는 느림
파일 의존성 출력 이슈
Visual Studio 의존성 파일
gcc
Makefile 형식
변환파일 생성
병목지점
17. Windows 이슈
명령줄의 최대 길이가 비교적 짧음 (8191 chars)
파일연산이 느림
GetFileAttributesEx()는 리눅스의 stat()보다 100배는 느림
파일 의존성 출력 이슈
Visual Studio
Ninja 명령행
버퍼링 기능
gcc
Makefile 형식
변환명령행 출력
기존의 명령행 버퍼링 기능을 재사용하여 파일작업 제거
19. Design Principles
더 최적화 하기, Ninja Daemon
PC에 항상 상주하여 파일수정감시, 성능 향상 가능
하지만 Ninja의 설계 원칙은 Simplicity
단순함은 소프트웨어 설계의 미덕
중요한건 얼마나 단순함을 오래 유지하는가
복잡한 작동방식을 동원하는 대신 작업을 줄임으로써 속도를 올린다는 원칙
20. Design Principles
최대한 많은 기능들을 다른 도구에 위임
GYP, CMake
Ninja 자신은 빌드를 만들어내는 목표 하나에만 집중
덕분에 다른 프로젝트에서 가져다 조립해 사용하기 쉬움
빠른 빌드의 의미
프로젝트가 가볍다는 인상을 주면 프로젝트를 가지고 노는 것이 즐거워진다
가지고 놀기 좋은 코드가 소프트웨어 작성의 목표