
리눅스 개발환경 도구의 두 번째이자 마지막 편이다.
make와 Makefile이 중요해서 거의 이 내용 위주로 작성되어 있다.
컴파일 언어
소스를 한 번에 실행 파일로 변환 후 실행
예 : C, C++
인터프리터 언어
실행 시에 한 줄씩 읽어가며 바로 실행
내부적으로 on-the-fly 방식으로 컴파일이 일어남
예 : Python, JavaScript, Bash
make의 역할
Makefile을 읽고 필요한 컴파일/링크 명령을 실행하는 빌드 자동화 도구
여러 .c , 라이브러리가 있는 프로젝트를 빌드할 때 변경된 파일만 다시 컴파일해서 시간을 줄임
같은 명령을 매번 입력하지 않아도 make 명령어 한 번으로 반복되는 작업을 처리
임베디드에서는 C/C++을 주로 사용하기 때문에 빌드(컴파일) 작업 자동화가 중요함
Makefile의 역할
타겟 파일, 의존성, 명령 등 빌드 규칙을 적어 둔 스크립트/설정 파일
make와 Makefile 사용의 이점
빌드 명령이 길고 파일이 많다면 수동 컴파일은 비효율적이며 실수를 유발함
협업 또는 배포 환경에서 Makefile을 명시해 두면 누구나 동일한 빌드 결과를 얻을 수 있음
make의 설치
sudo apt install make 로 설치도움말 사용
터미널에 make --help 또는 make -h 를 입력하여 옵션 및 사용법 요약 확인
Makefile 작성 기본 규칙
target: prerequisites(dependencies)
<TAB>recipe...
bash가 실행하는 명령을 make가 대신 호출하는 형태
target : 만들어질 대상 (실행파일, 오브젝트, 가상 타깃 등)
prerequisites(dependencies) : 의존성, 타깃을 만들기 전에 먼저 있어야 할 파일
recipe: 실제로 실행할 쉘 명령들로, 반드시 앞에 탭 문자(TAB)가 와야 함
출력 제어와 @
기본적으로 make는 쉘 명령을 echo 한 다음 실행됨
recipe 앞에 @ 를 붙이면 터미널 출력을 막을 수 있음
foo:
@echo foo
타겟 실행과 디폴트 타겟
make # 아무 인자 없으면 첫 번째 타겟이 디폴트로 실행
make foo # foo 타겟만 실행
make foo bar # 여러 타겟을 한 번에 실행 가능
Makefile의 가장 위에 있는 첫 번째 타겟은 디폴트 타겟
관례적으로 all 이라는 이름을 디폴트 타겟으로 두고, 빌드해야 할 내용들을 의존성으로 작성
올 타겟(all target)
all: app1 app2 lib
디폴트 타겟으로 주로 사용됨
recipe가 없는 가상 타겟으로, 의존성에 있는 파일들을 모두 최신 상태로 만드는 역할
의존성과 실행 순서
foo:
@echo foo
bar: foo
@echo bar
baz: bar
@echo baz
; make baz를 입력하면
; foo -> bar -> baz 순으로 실행
타겟을 호출하면 해당 타겟의 의존성들이 먼저 빌드되고 나서 해당 타겟의 recipe 실행
기본 Makefile 종류
옵션 없이 make 를 실행하면, 아래 Makefile을 읽어들임
세 개가 모두 있으면 순서대로 Makefile을 찾아 사용함
GNUmakefilemakefileMakefile옵션 지정하여 Makefile 사용하기
기본 이름이 아닌 Makefile을 사용하려면 -f 또는 --makefile 옵션을 씀
$ make -f MyRules.mk
$ make --makefile=build.mk
make의 데이터베이스
make 는 내부에 데이터베이스를 가지고 있으며, make -p 로 내용을 볼 수 있음
Variables
내장 변수, 환경 변수, Makefile에서 정의한 변수의 최종 값
Pattern-specific variables/rules
특정 패턴에만 적용되는 변수/규칙
Files
각 타겟과 그 의존성, 갱신 여부(타임스탬프 정보)
Implicit rules
컴파일/링크에 대해 make 가 기본으로 사용하는 암시적 규칙 목록
예시
$ make -p | grep -w ^CC
CC = cc ; C 컴파일러는 cc
$ make -p | grep -w ^LD
LD = ld ; 링커는 ld
make 디버그 옵션
make -d 를 입력하면 make 의 동작을 상세히 보여주어 처리 과정을 분석할 수 있음
%.o : %.c, %.c : %.y)예시
all: bar baz
@echo makefile
bar:
@echo bar
baz:
@echo baz
$ touch all bar baz
$ ls
Makefile all bar baz
$ make
make: 'all' is up to date.
make는 기본적으로 파일 타겟을 다루는 구조
폴더에 타겟 이름과 같은 실제 파일이 있고 타임스탬프가 더 최신이라면 작업이 일어나지 않음
$ make -d
Considering target file 'all'.
File 'all' was considered already.
No need to remake target 'all'.
rule 구조
target: prerequisites
<TAB>recipe...
target : 만들고자 하는 것 (파일, 실행 파일, 혹은 가상 타겟)
prerequisites = dependencies : 타깃을 만들기 전에 먼저 준비되어 있어야 할 것들
recipe : 실제로 실행할 쉘 명령 (반드시 TAB으로 시작)
주석(comment)
# comment
# 뒤에 작성한 내용은 make 가 무시함
변수(Macro / Variable), 줄 나누기
VAR = world
hello: ${VAR}
@echo hello \
${VAR}
# world 파일에 의존하므로, 해당 파일을 만든 뒤에 정상 실행됨
VAR = world : 변수 정의
${VAR} 또는 $(VAR)로 참조할 수 있고 셸 변수($VAR)와 헷갈리지 않게 ${VAR}를 많이 사용
\ (Split-line) 로 길이가 긴 한 줄을 여러 줄로 나눌 수 있음
include로 다른 Makefile 불러오기
하나의 Makefile 안에서 다른 설정 파일 등을 불러와 합쳐서 사용할 수 있음
설정/변수 정의/공통 규칙 등을 별도의 파일로 관리하고 include로 합칠 수 있음
(예 : include config.mk rules.mk paths.mk)
# config.mk
CC:=gcc
# makefile
include config.mk
all:
@echo my c compiler is ${CC}
자식 Makefile 불러오기
상위 Makefile에서는 하위 Makefile을 호출할 수 있음
프로젝트를 디렉토리별로 나누어 관리 가능
프로젝트/
├── Makefile # 부모
└── subdir/
├── Makefile # 자식
└── main.c
# 부모 Makefile (루트 디렉토리)
# echo 실행한 뒤에 subdir로 이동해서 그 안의 Makefile 실
hello:
@echo hello
${MAKE} -C subdir --no-print-directory
${MAKE}
${MAKE}는 현재 사용 중인 make 프로그램을 의미하는 특수 변수이다.
(예: 사용자가 make로 호출했으면 make , gmake로 호출했으면 gmake )
디렉토리 변경 방법
-C 옵션
${MAKE} -C subdir --no-print-directory
# --no-print-directory 옵션을 주면 디렉토리 변경 메시지가 사라져 로그가 깔끔해짐
명령 실행 전에 작업 디렉토리를 subdir 로 바꾸고 make 를 실행하라는 의미
cd 명령어
cd subdir && ${MAKE}
같은 의미이지만 -C 로 표기하는 것이 선호됨
make 변수와 셸 변수
Makefile의 변수(CC, CFLAGS 등)는 make 내부에서만 보이는 변수
일반 셸에서 echo $CC 같은 식으로는 확인 불가
쉘 환경 변수는 make 실행 시에 기본값으로 들어오지만 Makefile에서 바꾼 것이 셸에 반영되지 않음
자식 Makefile에 변수 전달
부모 Makefile에서 자식으로 변수를 넘기려면 export를 사용
# 부모 Makefile
export CC = gcc
export CFLAGS = -Wall -g
hello:
@echo "CC in parent: $(CC)"
${MAKE} -C subdir
# subdir/Makefile
all:
$(CC) $(CFLAGS) -o main main.c # 부모의 변수 사용
export CC = gcc : make가 자기 자식 프로세스를 실행할 때 환경 변수로 CC를 넘겨줌
${MAKE} -C subdir로 자식 make를 실행하면, 자식 Makefile에서도 $(CC), $(CFLAGS)를 사용 가능
전체 변수 자동 상속
.EXPORT_ALL_VARIABLES 을 사용하면 모든 변수를 자식에게 자동으로 export 할 수 있음
# 모든 make 변수 자동 상속
.EXPORT_ALL_VARIABLES:
CC = gcc
CFLAGS = -O2
hello:
${MAKE} -C subdir
특정 변수의 상속 막기
unexport 를 사용하면 특정 변수는 자식에게 넘겨주지 않음
export CC = gcc
unexport PRIVATE_VAR # 자식에게 전달 안 함
hello:
${MAKE} -C subdir
디폴트 타겟
기본으로 실행할 타겟을 디폴트 타겟으로 설정할 수 있음
make 명령만 입력했을 때 Makefile의 최상단에 있고 . 으로 시작하지 않는 타겟이 디폴트 타겟이 됨
관례적으로 이 타겟을 all 로 두고, 프로젝트 전체 빌드를 걸어 둠
디폴트 타겟을 명시적으로 바꾸기 위해서는 .DEFAULT_GOAL:=타겟명 으로 지정
파일 타겟과 빌드 여부 판단
1. 타겟 파일 존재 여부 확인
↓
2. 존재 시 → 타겟 타임스탬프 vs 의존성 파일 최신 타임스탬프 비교
↓ 타겟이 더 최신
3. 타겟 최신 → "make: 'target' is up to date." (스킵)
↓ 타겟이 더 오래되거나 없음
4. 명령 실행 → 타겟 재생성 (타임스탬프 갱신)
| 타겟 | 실제 파일 존재 여부 | 의존성과의 관계 | 동작 |
|---|---|---|---|
app | 없음 | - | 컴파일/링크해서 생성 |
app | 있음 | 타겟이 최신 | make: 'app' is up to date. |
app | 있음 | 의존성이 더 최신 | 다시 컴파일/링크 |
clean | 없음 (보통 파일 아님) | - | 항상 실행되게 .PHONY로 선언 |
타임스탬프에는 access(읽음), modify(내용 수정), change(링크 등 메타데이터 변경)가 있음
make 가 사용하는 것은 modify(mtime, 내용 변경 시각)임
Trivial Prerequisite
타겟을 재생성할 필요가 없는 특별한 의존성 상태
의존성이 있더라도 내용을 건드릴 필요 없이 타임스탬프만 맞추면 되는 상황
make -t 옵션
각 타겟을 실제로 빌드하지 않고 touch 만 해서 타임스탬프를 갱신
mtime만 최신으로 표시하는 용도이며, 실제로 명령은 실행하지 않음
파일 타겟
실제 파일 이름을 가진 타겟으로, 타임스탬프 비교를 통해 재성성 여부를 판단
소스 코드
입력 파일로, 변경되면 의존하는 목적 코드나 실행 파일을 갱신해야 함
목적 코드
소스 파일에서 컴파일된 중간 결과물, 링커가 실행 파일을 만들 때 사용
실행 코드(타겟)
최종적으로 만들어지는 실행 파일, 보통 가장 먼저 만드는 디폴트 타겟에 지정
all: hello # 디폴트 타겟
hello: hello.o # 실행 파일 타겟
cc -o hello hello.o
hello.o: hello.c # 목적 코드 타겟
cc -c hello.c
더미 타겟(Dummy Target)
실제로 파일을 생성하지 않지만, 빌드 작업을 제어하거나 편의성을 위해 사용하는 가상의 타겟
타임스탬프와 관련 없이 실행하면 계속 실행할 수 있음
디폴트 타겟 ( all )
실제 파일을 만들지 않고 여러 타겟을 묶는 제어용 타겟
가상 작업 타겟 (clean, install)
파일을 만들지 않고 작업 이름만 가진 타겟
강제 재빌드 (FORCE)
항상 Non-trivial prerequisite 상태로 만들어 재빌드 강제
포니 타겟(.PHONY)
실제 파일이 아닌 가상의 타겟으로, 항상 명령을 실행하게 하는 특별한 선언
.PHONY: 타겟명 으로 나열한 타겟들은 파일 존재 여부와 상관없이 항상 실행
따로 선언하지 않은 더미 타겟은 파일이 있으면 스킵되므로 .PHONY로 선언해야 정상 동작
표준 정리 타겟
| 타겟 | 삭제 내용 | 목적 | .PHONY |
|---|---|---|---|
| all | 삭제하지 않음 | 전체 빌드(디폴트) | ✅ |
| clean | .o, 실행파일 | 개발 중 임시파일 정리 | ✅ |
| distclean | clean+ config 파일 | 소스 배포 상태로 복원 | ✅ |
| clobber | distclean+ 모든 생성물 | 완전 초기화 | ✅ |
포스 타겟 (FORCE)
항상 재빌드 필요(Non-trivial prerequisite) 상태로 만드는 독립적인 더미 타겟
캐시 무효화나 강제 갱신 목적으로 사용
# 매번 데이터 재생성
data.txt: generate.sh FORCE
./generate.sh > data.txt
FORCE:
# 의도적으로 빈 recipe
이차 타겟 (Secondary Target)
중간 파일을 make가 자동으로 삭제하지 않도록 하는 선언
# 모든 .o 파일 보존
.SECONDARY: %.o
# 모든 중간 파일 보존
.SECONDARY:
조용한 타겟 (Silent target)
레시피 명령어 실행 전 echo를 억제하는 타겟으로, 출력을 깔끔하게 정리하는 기능
.SILENT: 타겟명
단일 접미사 규칙(Single suffix rule)
확장자가 없는 타겟을 특정 소스로부터 만들어 주는 옛날 형식의 implicit rule
# makefile
foo: foo.c
# 빈 recipe로 두어도 내장 규칙으로 자동 컴파일
접미사 목록
make -p | grep .SUFFIXES 결과를 확인하면 make 기본 suffix 목록을 볼 수 있음
.SUFFIXES: .out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el
makefile 내에 .SUFFIXES: 를 작성하면 지정한 목록으로 접미사 리스트를 덮어씀
내장된 suffix를 사용할 수 없고, explicit rule/다시 정의한 규칙만 사용됨
이중 접미사 규칙(Double suffix rule)
소스 접미사에서 타겟 접미사를 만드는 변환 규칙을 정의하는 옛날 형식의 implicit rule
.c.o:
cc -c $< -o $@
recipe-less suffix rule
.SUFFIXES 뒤에 레시피가 없는 더미 규칙
GNU의 make는 내장된 규칙을 사용하기 때문에 실질적으로는 의미 없음
패턴 룰(Pattern Rule)
% 와일드카드를 사용해 여러 파일에 동일한 변환 규칙을 한 번에 적용하는 암시적 규칙
현대 Makefile에서 권장되는 형태
타겟: 의존성
레시피
# 예시
%.o: %.c
cc -c $< -o $@
recipe 추가하기
recipe는 타겟에 대해 실제로 실행되는 쉘 명령의 집합
모든 recipe 줄은 반드시 탭 문자로 시작(tab-leading)해야 함
recipe 함수 만들기
여러 타겟에서 같은 recipe를 반복하고 싶을 때 define 으로 내용을 정의할 수 있음
define 과 endef 사이에 여러 줄의 recipe를 작성
define BUILD_APP
@echo building $@
@cc -c main.c
@cc -o $@ main.o
endef
app1:
$(BUILD_APP)
app2:
$(BUILD_APP)
recipe에서 for 루프 만들기
recipe는 기본적으로 한 줄로 작성하기 때문에 for 루프를 쓰려면 \ 와 $$ 에 주의하여 사용
\ : 줄을 잇는 역할로, 쉘 입장에서는 한 줄짜리 for문을 받을 수 있도록 함
$$ : make 처리 시에 $ 하나가 사라지기 때문에 쉘에 $x 로 전달하기 위해 두 번 사용
LIST = a b c
loop:
@for x in $(LIST); do \
echo $$x; \
done
Makefile의 조건문
조건문을 사용하여 특정 부분을 포함하거나 제외할 수 있음
조건은 Makefile을 읽는 시점에 평가됨
값을 비교하는 조건
ifeq , else , endif
같은 값인지 판단하여 블록을 활성화/비활성화하는 조건문
# 3가지 형태 지원
ifeq ($(VAR), value)
ifeq "$(VAR)" "value"
ifeq '$(VAR)' 'value'
ifeq ($(VAR), value)
# VAR == value 일 때만 이 블록이 유효
MSG := "matched by , 형식"
else
MSG := "not matched"
endif
정의 여부를 확인하는 조건
ifdef, ifndef
변수가 정의되어 있는지 여부를 확인하는 조건문으로, 값은 검사하지 않음
# CC가 환경변수나 Makefile에 정의되어 있는지 체크
ifdef CC
COMPILER = $(CC)
else
COMPILER = gcc
endif
# 정의되어 있지 않을 때를 체크하려면 ifndef 사용
recipe 밖의 변수 정의
Makefile 언어의 변수로, 이전에는 macro라고 호칭하던 것
변수는 전역으로 사용되며 이름은 대문자로 설정하는 것이 권장됨
대표적인 대입 연산자
V = foo # 지연(재귀) 확장(Deferred / Recursive)
V1 := foo # 즉시(단순) 확장(Immediate / Simple)
V2 ?= foo # 약한 대입(Weak), 값이 비어 있을 때만 설정
V3 += bar # 기존 값에 이어 붙이기
Deferred (=)
V = foo
참조되는 시점에 오른쪽 값을 다시 해석
다른 변수들과 혼용하여 쓸 때 값이 바뀌었다면 변경된 값으로 적용
Immediate (:=)
V := foo
정의 시점에 오른쪽을 한 번 평가하고 그 결과만 저장
이후 다른 변수 값이 바뀌어도 영향 없음
Weak (?=)
변수 값이 이미 정의되어 있으면 건드리지 않고, 비어 있을 때만 대입
Append (+=)
기존 값 뒤에 공백을 두고 문자열 추가
recipe 안의 변수 정의
$(eval) 은 문자열을 Makefile 코드처럼 파싱하여 실행 시점에 동적으로 변수를 생성하는 함수
make의 전역 변수 생성은 되지만 다른 recipe에서 사용 불가
변수 해제하기
undefine 변수명 으로 이미 정의된 변수를 없앨 수 있음
변수 참조 방법
| 문법 | 예시 |
|---|---|
$변수명 | $CC |
$(변수명) | $(CC) |
${변수명} | ${CC} |
${변수명} 형태가 쉘 변수와 혼동이 없어 가장 권장됨
변수 치환
변수 문자열에서 특정한 패턴을 찾아 치환하는 간편한 문법
$(변수명:패턴=치환문자열)
패턴 : %.x (와일드카드 % 포함)
치환 : .y (패턴의 % 부분 유지)
SOURCES = main.c utils.c parse.c
OBJECTS = $(SOURCES:.c=.o)
# 결과 : OBJECTS = main.o utils.o parse.o
CFLAGS = $(CFLAGS:-g=-O2) # -g → -O2
Computed Variable Names
foo = bar
bar = baz
VAR = $($(foo)) # → $(bar) → baz
변수 이름 안에 변수를 참조하는 형태
자동 변수(Automatic Variables)
현재 타겟과 의존성에 대해 자동으로 설정하는 특수 변수로 자주 사용됨
| 변수 | 의미 | 예시 (foo.o: foo.c bar.h) |
|---|---|---|
$@ | 타겟 전체 | foo.o |
$< | 첫 번째 의존성 | foo.c |
$^ | 모든 의존성 | foo.c bar.h |
$+ | 중복을 포함한 모든 의존성 | foo.c bar.h bar.h (순서대로) |
$? | 타겟보다 나중에 변경된 의존성 | foo.c (bar.h 최신이면) |
$* | stem (패턴 규칙) | foo (%.o: %.c에서) |
%.o: %.c
gcc -c $< -o $@ # foo.c → foo.o
lib%.a: %.o
ar rcs $@ $^ # libfoo.a: foo.o (lib%.a 패턴)
자동 변수 확장형(참고)
이전에 타겟 경로와 파일명을 분리하는 데 사용되었으며 현재는 dir/notdir 함수를 주로 사용
| 변수 | 의미 | 예시 (obj/foo.o: src/foo.c) |
|---|---|---|
$(@D) | 타겟 디렉토리 | obj |
$(@F) | 타겟 파일명 | foo.o |
$(<D) | 첫 의존성 디렉토리 | src |
$(<F) | 첫 의존성 파일명 | foo.c |
CMake
빌드 스크립트를 만들어 주는 메타 빌드 시스템
CMakeLists.txt라는 빌드 설정 파일을 기준으로, 타겟을 정의하고 컴파일 옵션·링크할 라이브러리 등의 속성을 설정
Makefile/Ninja/VS 프로젝트 등 각 환경에 맞는 빌드 시스템 파일을 자동 생성
CMake의 설치와 사용
# 설치
sudo apt install cmake
# 사용법
cmake . # 현재 디렉토리에서 빌드 파일 생성
cmake build/ # 별도 build 디렉토리에서 재생성
cmake -S . -B build # 명시적 source/build 지정
cmake -S . -B build -G "BS_name" # 빌드 시스템 지정
S <source> : 소스 디렉토리 설정
B <build> : 빌드 결과물 디렉토리 지정
G <generator> : 생성할 빌드 시스템 (Unix Makefiles, Ninja, Xcode 등)
CMakeLists.txt
CMake 빌드 시스템의 핵심 입력 파일로
프로젝트의 소스 파일, 타겟(실행 파일이나 라이브러리), 컴파일 옵션, 의존성 등을 정의하는 스크립트
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 실행 파일 타겟 정의
add_executable(hello main.c util.c)
# 컴파일 옵션
target_compile_options(hello PRIVATE -Wall -g)
# 라이브러리 링크
target_link_libraries(hello PRIVATE m pthread)
project(NAME) : 프로젝트 이름 정의
add_executable(NAME SOURCES...) : 실행 파일 타겟
add_library(NAME SOURCES...) : 라이브러리 타겟
target_*() : 타겟별 속성 설정 (옵션, include, 링크 등)
CMakeLists.txt 기본 템플릿
# 주석은 #으로 시작
cmake_minimum_required(VERSION 3.16) # 최소 필요 버전 명시
project(MyApp) # 프로젝트 이름 지정
message("hello cmake!") # 출력 메시지
# 실행 파일 타겟 추가
add_executable(${CMAKE_PROJECT_NAME}
hello.c
world.c
)
cmake_minimum_required() : 최소 필요 버전을 필수적으로 명시하여 호환성을 보장
project(NAME) : 프로젝트명을 정의하고 이후 ${CMAKE_PROJECT_NAME}으로 참조
message() : 빌드 로그 출력
CMake로 빌드하기
# 1. 버전 확인
cmake --version # cmake version 3.16.3
# 2. 빌드 디렉토리 생성 + Makefile 생성
cmake -S . -B build
# 3. 프로젝트 빌드
cmake --build build # 권장
cd build && make -j4 # 전통적인 방법
# 4. 실행
./build/MyApp
라이브러리 만들고 링크하기
# 정적 라이브러리
add_library(mylib STATIC mylib.c)
# 공유 라이브러리
add_library(mylib_shared SHARED mylib.c)
# STATIC 명시하지 않아도 기본은 정적
add_library(mylib mylib.c)
add_executable(MyApp main.c)
# 라이브러리 링크
target_link_libraries(MyApp PUBLIC mylib)
# 또는 PRIVATE mylib (내부용), INTERFACE mylib (헤더만)
# 서브 디렉토리 추가, 하위 CMakeLists.txt 실행
add_subdirectory(dirname)
Git
분산 버전 관리 시스템으로, 소스 코드 변경 사항을 관리하고 협업을 편리하게 하는 도구
| 구분 | 주요 내용 |
|---|---|
| 버전 관리 | 파일 변경 이력을 시간순으로 저장 |
이전 상태로 되돌리기
변경 내용 추적 |
| 백업 | 로컬 저장소 + 원격 저장소
push만 해도 백업 효과
복구 용이 |
| 협업 | 브랜치 기반 병렬 작업
pull/push로 변경 공유
PR로 코드 리뷰 가능 |
Git/Github 비교
| 항목 | Git | GitHub |
|---|---|---|
| 역할 | 분산 버전 관리 시스템, 로컬 저장소 | 원격 저장소 호스팅 서비스 |
| 기능 | 커밋, 브랜치, 머지 | Git + PR, Issue, Wiki, CI/CD |
Git 설치와 초기 설정
# 설치
$ sudo apt install git
$ git --version
# 사용자 정보 설정
$ git config --global user.email "your@email.com"
$ git config --global user.name "Name"
# 확인
$ git config --global --list
Git 워크플로우
작업 트리 (Working Directory)
수정/생성한 파일들
스테이징 영역 (Index/Staging Area)
git add로 올린 파일들
로컬 저장소 (Repository)
git commit으로 저장된 히스토리
# 1. 파일 수정/생성
$ echo "hello" > file.txt
# 2. 스테이징 (add)
$ git add file.txt # 특정 파일만 스테이징
$ git add . # 모든 변경사항을 스테이징
$ git add *.c # 패턴에 해당하는 파일 스테이징
# 3. 커밋 (commit)
$ git commit -m "Add file.txt" # 커밋 메시지 남기기
Git 주요 명령어
| 명령 | 기능 |
|---|---|
git init | 새 저장소 초기화 |
git clone <url> | 원격 저장소 복사 |
git status | 상태 확인 (가장 자주 씀) |
git add <file> | 스테이징 |
git commit -m "msg" | 커밋 |
git log | 커밋 히스토리 |
git checkout <commit> | 특정 커밋으로 이동 |
git reset --hard HEAD~1 | 최근 커밋 취소 |
git remote add origin <url> | 원격 저장소 추가 |
git push origin main | 푸시 |
git pull origin main | 풀 |
Docker
컨테이너를 생성·관리·배포하는 오픈소스 플랫폼
애플리케이션을 깔아서 쓸 수 있는 환경을 똑같이 만드는 것
애플리케이션을 인프라와 분리하여 빠르게 배포 가능
가상화 (Virtual Machine, VM)
CPU, 메모리, 디스크, 네트워크 등 하드웨어 전체를 가상 환경으로 만듦
각 VM마다 완전한 OS가 필요하므로 차지하는 용량이 큰 편
VM 간에는 독립되어 있으므로 보안이 강력함
컨테이너 (Docker)
패키지란 애플리케이션 실행에 필요한 코드, 라이브러리, 설정 파일 등을 하나로 묶은 것
이를 격리된 컨테이너에서 실행하여 모든 환경에서 동일하게 동작하도록 하는 기술
호스트의 OS 커널 하나를 공유하면서 다른 어플리케이션과 격리된 환경에서 실행
하이퍼바이저→가상머신 여러 개 운영보다는 가벼운 레벨
Docker 워크플로우
1. docker pull # Docker Hub에서 이미지 가져오기
docker pull ubuntu:20.04
2. docker build # Dockerfile로 이미지 빌드
docker build -t myapp .
3. docker run # 컨테이너 실행
docker run -d -p 8080:80 myapp
make를 안 써본 건 아니지만 잘 모른다고 생각했는데,
내가 생각했던 것보다 더 몰랐던 것 같다.
빌드 과정도 잘 모르고 gcc를 썼었는데, 그 부분에 대한 개념도 잡혔고
make랑 타겟에 대해서도 쭉 배우면서 작성된 스크립트를 이해할 수 있게 되었다.
나중에 프로젝트에서 잘 활용해 보면 좋겠다.