운영체제 lab 개발하면서 make 처음으로 사용해보았습니다. 기본개념 및 사용법을 기억하기 위해 기록합니다!!
Make
: 유닉스계열 운영체제에서 사용되는 빌드 자동화 도구
- 빌드(build) : 소스코드를 실행가능한 프로그램으로 변환하는 과정( 컴파일, 링크, 리소스 결합 등 )
# -c : 소스코드를 컴파일하여 오브젝트 생성
gcc -c main.c foo.c bar.c
# -o : 하나이상의 오브젝트파일을 대상으로 실행파일 생성(링크)
gcc -o app.out main.o foo.o bar.o
- 주로 C/C++ 프로젝트에서 사용
- Makefile에 정의된 빌드 작업에 따라 빌드를 실행 → 빠르고 효율적인 빌드가 가능해진다.
- Incremental build : 반복적인 빌드 과정에서 변경된 소스코드에 의존성이 있는 대상만 다시 빌드하는 기능
- foo, bar은 헤더파일을 가짐 & 여기서 정의된 함수를 main에서 호출(의존성)
Makefile
: 소스코드 파일들 간의 의존성 정의 & 각 파일의 컴파일, 링크를 정의한 파일
[ Makefile 명령 ]
make : 정의된 내용으로 빌드를 실행
make
make + Target : 해당 Target만 빌드
make foo.o
[ Makefile의 문법 및 구성 ]
** 기본문법 **
$(TARGET): $(OBJ)
$(CC) $(CFLAGS) -o $@ $^
- 매크로 정의 : 변수로 이용되며 재사용, 대문자로 작성
CC = gcc
- 재귀확장변수(=) : 재귀적으로 다른 변수의 값을 참조 → 값이 변동될때마다 갱신 ⇒ 성능주의, 무한반복주의
- 단순확장변수(:=) : 변수가 평가(정의)되는 시점에만 한번 확장
- 룰 정의 : 스파일을 컴파일하고 실행파일을 생성하는 규칙을 정의
target: dependencies
[tab] command
hello: hello.c
[tab] gcc -o hello hello.c
@ : shell명령어를 실행 & 명령어를 출력하지 않음
- 기본 타켓 정의 : Makefile이 실행될 때 자동으로 실행되는 타겟, 대개 첫번째에 위치한 룰
all: hello
- 내장변수
- $(CC) : 컴파일러
- $(CFLAGS) : 컴파일 옵션
- 이외의 자동변수
- $@ : 현재 타겟의 이름 / $^ : 모든 종속성
hello: hello.c
[tab] $(CC) -o $@ $^
- $< : 첫 번째 Dependency 이름을 지칭
- $? : 현재 Target이 의존하는 대상들 중 Target 보다 새롭게 변경된 Dependencies 의 전체 목록
- 함수의 기본문법 : $(function arguments)
- 치환
(1) 변수 치환
$(변수명 : pattern=replacement) : 해당변수에서 pattern을 replacement로 치환한다.
SRCS := first.c second.c third.c
OBJS := $(SRCS:.c=.o)
# 치환 결과
# OBJS = first.o second.o third.o
(2) subst 함수 / patsubst 함수
$(subst pattern, replacement, target)
$(patsubst pattern, replacement, 대상변수 )
$(subst ee,EE,feet on the street)
# 함수실행결과 : fEEt on the strEEt
[ Makefile 내장 규칙 (Built-in Rule) ]
: 소스 파일(.c)을 컴파일해서 오브젝트 파일(.o)로 만드는 규칙
app.out : main.o foo.o bar.o
gcc -o gcc.out main.o foo.o bar.o
# 각 target에 대한 의존성 명시
main.o : foo.h bar.h main.c
foo.o : foo.h foo.c
bar.o : bar.h bar.c
make는 소스파일의 마지막 변경시점만 확인, 소스코드의 변경사항을 확인하지 않음 → 첫번째룰만 명시할 경우 gcc.out을 만들때 헤더파일의 변경을 감지하지 못함
각 타겟의 의존성 명시 → command는 생략되었지만 소스파일을 오브젝트파일로 만든다는 내부규칙에 의거하여 컴파일이 수행된다.
[ 리링크(Relink) ]
: 의존성이 변경되었을 때에만 타켓을 생성하는 것
hello: $(OBJ_B)
[tab] $(CC) $(TARGET) $^
의존성($(OBJ_B))이 존재한다면 command를 수행하여 $(TARGET)을 생성한다.
의존성변경을 체크하지 않기에 make hello 실행시 무조건 리링크된다.
ifdef WITH_BONUS
OBJ = $(OBJ_O) $(OBJ_B)
else
OBJ = $(OBJ_O)
endif
...
hello:
make WITH_BONUS=1 all
make hello를 실행시 with_bouns를 1로 지정하는 옵션(WITH_BONUS=1)과 함께 make all 명령어를 실행한다..
WITH_BONUS=1로 매크로가 정의되어있다면 OBJ의 의존성은 $(OBJ_O) $(OBJ_B)를 모두 포함하고 아니라면 $(OBJ_O)만 포함한다
$(OBJ_B)가 변경되었을 때만 WITH_BONUS=1 옵션을 주어 변경사항을 체크하여 리링크가 가능해진다! ( 이후 $OBJ가 의존성요소로 사용될 예정 )
라이브러리(Library)
: 다른 프로그램들과 링크되기 위해 존재하는 하나 이상의 서브루틴이나 함수들의 집합 파일
- 컴파일된 오브젝트 파일(*.o) 형태로 존재 → 링크작업으로 이어져서 컴파일 시간을 단축
- 동적 라이브러리 : 완성프로그램을 실행할때 포함
- 리눅스의 *.so , 윈도우 *.dll
- 실행후 필요할때만 라이브러리의 함수 참조
- 암시적 링킹(Implicit LInking) : 시작할때 같이 로딩, 종료될때 메모리에서 해제
- 정적 라이브러리 : 프로그램을 컴파일하는 과정에서 포함
- 리눅스의 *.a , 윈도우의 *.lib
- 링커가 프로그램이 필요한 부분을 라이브러리에서 찾아 실행파일에 복사
- 빌드 시(링킹단계)에서 실행파일에 함께 결합
하나의 main.cpp를 컴파일할때 참조되는 것들
참고자료들 :
https://data-flair.training/blogs/makefile-in-linux/
https://www.tuwlab.com/27193
'dev tech' 카테고리의 다른 글
[C++] 디자인패턴 RAII를 이용한 자원관리 (1) | 2024.06.11 |
---|---|
Google Test framework의 기본개념 및 사용법 (0) | 2024.05.20 |
WSL(Windows Subsystem for Linux)의 개념과 기본명령 (0) | 2024.05.20 |
형상관리 Git 사용법 (0) | 2024.03.10 |