728x90

1. Makefile 개요

더보기

1. Makefile 기본구조

target: dependency1 dependency2 ...
<TAB>command
  • target: 만들고자 하는 대상(예: .out 실행파일, .o 오브젝트 파일 등)
  • dependency: target을 만들기 위해 먼저 있어야 하는 파일(.c 소스 코드와 같은 파일들)
  • command: target을 만들기 위해 실행할 gcc 빌드 (쉘) 명령어 (반드시 탭으로 들여쓰기 해야 함)

 

 

 

 

2. 생성방법

 

  1. 텍스트 에디터 열기
  2. Makefile 내용 작성
  3. Makefile 이름으로 저장 (확장자 없이)

 

 

 

 

3. 주의사항

  • Makefile 파일명
    • 보통 Makefile (첫 글자 대문자 M)이나 makefile (모두 소문자)로 저장합니다.
    • 대부분의 시스템(특히 리눅스, 유닉스)은 대소문자를 구분하기 때문에
      Makefile과 makefile은 서로 다른 파일로 인식됩니다.
    • 기본적으로 make 명령은 현재 디렉터리에서 먼저 Makefile을 찾고, 없으면 makefile을 찾습니다.
    • 따라서 대문자 M으로 시작하는 Makefile이 표준이며 권장됩니다.
  • command 들여쓰기 탭 문자
    • Makefile 내 명령어(명령을 실행하는 줄) 들은 반드시 탭 문자로 들여쓰기 해야 합니다.
      (스페이스 4개(또는 여러개)로 바꾸면 안 됩니다.
  • 작성 방법: 메모장, Visual Studio Code, Vim, Sublime Text 등 원하는 텍스트 에디터로 작성합니다.
  • 내용: 빌드 규칙(target, dependencies, commands)을 텍스트로 기술합니다.
  • 이외의 추가 주의사항은 다음 포스트에서 확인할 것.

 

 

  

 

 

 

3. 공식문서 GNU make

 

GNU make

The information that tells make how to recompile a system comes from reading a data base called the makefile. 3.1 What Makefiles Contain Makefiles contain five kinds of things: explicit rules, implicit rules, variable definitions, directives, and comments.

www.gnu.org

 

 

make 키워드 살펴보기

 

make를 이용한 빌드 방법 · snowdeer's Code Holic

make를 이용한 빌드 방법 06 Sep 2017 | C++ make 사용법 gcc를 이용한 빌드 방법 일반적으로 gcc를 이용한 빌드는 다음과 같은 형태의 명령을 이용합니다. $ gcc -o helloworld helloworld.c 이 때 -o 옵션 뒤에는

snowdeer.github.io


 

2. Makefile 실습 예제 파일

더보기

1. 예제 파일

make.zip
0.00MB
// foo.h

#ifndef FOO_H
#define FOO_H

void foo();

#endif
// foo.c

#include <stdio.h>
#include "foo.h"

void foo() {
    printf("This is foo()\n");
}

// bar.h

#ifndef BAR_H
#define BAR_H

void bar();

#endif
// bar.c

#include <stdio.h>
#include "bar.h"

void bar() {
    printf("This is bar()\n");
}

// main.c

#include "foo.h"
#include "bar.h"

int main() {
    foo();
    bar();
    return 0;
}

 

3. Makefile 기본구조 실습

더보기

1. [준비1] 빌드 명령어

gcc main.c foo.c bar.c -o program

 

 

 

 

2. [준비2] Makefile 기본구조

target: dependency1 dependency2 ...
<TAB>command

 

 

 

 

3. [준비1 + 준비2] 빌드 명령어를 Makefile 구조로 만들기

myprogram: main.c foo.c bar.c
	gcc -o myprogram main.c foo.c bar.c

 

 

 

 

4. clean 구현

clean:
	rm -f myprogram

 

4. Makefile을 활용한 증분 빌드 (1) - 시나리오

더보기

1. 컴파일과 링크 과정 분리하는 이유

  • 증분 빌드 (Incremental Build)
    1. 프로젝트가 커지면 소스 파일이 많아지고
      하나의 파일만 수정할 때, 전체 프로젝트를 다시 컴파일한다면 시간이 매우 오래 걸림
    2. 정한 소스 파일만 컴파일해서 .o 생성하여, 링크하고
      변경되지 않은 .o 파일은 다시 만들지 않는다면 빌드 시간 대폭 단축
  • 문제 발생 시 어느 파일에서 문제인지 빠르게 찾기 용이
  • 병렬 컴파일(멀티코어 CPU 활용) 가능

 

 

 

 

2. Makefile 시나리오

  • 전체 소스: foo.c, bar.c, main.c
  • 처음 빌드: foo.o, bar.o, main.o 모두 생성 → 링크 → 실행파일 생성
  • 일부 수정: foo.c만 수정
                    foo.o만 다시 컴파일 → 나머지는 그대로 유지 → 링크 → 실행파일 생성
  • 초기화: make clean 실행
                myprogram과 모든 .o 파일을 삭제하여 빌드에 사용한 파일 삭제

 

 

 

 

3. 사전학습 build 명령어

 

빌드

1. 빌드와 실행더보기1. 빌드와 실행 빌드와 실행 basiclike.tistory.com 2. 빌드 과정각 단계별 파일을 만들고, 실제로 눈으로 확인하세요. 2. 간단한 gcc 명령어 살펴보기더보기1. 소스 코드#include int main

basiclike.tistory.com

 

 

 

 

4. Makefile을 활용한 증분 빌드 (2) - makefile 생성

더보기

0. 프로젝트 구조와 스크립트 구조

 

 

 

 

1. 목적 파일 생성

# main.o 파일 생성
main.o: main.c
    gcc -c main.c

# foo.o 파일 생성
foo.o: foo.c foo.h
    gcc -c foo.c

# bar.o 파일 생성
bar.o: bar.c bar.h
    gcc -c bar.c
make main.o
make foo.o
make bar.o

 

 

 

 

2. 목적 파일 기반 → 링킹  실행 파일 생성

# 실행파일 생성
myprogram: main.o foo.o bar.o
    gcc main.o foo.o bar.o -o myprogram

# main.o 파일 생성
main.o: main.c
    gcc -c main.c

# foo.o 파일 생성
foo.o: foo.c foo.h
    gcc -c foo.c

# bar.o 파일 생성
bar.o: bar.c bar.h
    gcc -c bar.c

 

  • 동작 순서
    1. $ make myprogram
    2. make가 기본 타겟 myprogram 빌드를 시도
    3. myprogram이 main.o, foo.o, bar.o에 의존하므로, 먼저 [1] .o 종속 파일들이 있는지, [2] 최신인지 검사
    4. .o 파일이 없거나 오래되었다면,
      1. main.o를 만들기 위해 main.c와 main.h 확인 후 컴파일
      2. foo.o를 만들기 위해 foo.c와 foo.h 확인 후 컴파일
      3. bar.o를 만들기 위해 bar.c와 bar.h 확인 후 컴파일
    5. 모든 .o 파일이 최신 상태가 되면
      gcc main.o foo.o bar.o -o myprogram 실행 → 링크 및 실행파일 생성
    6. myprogram* 실행파일 생성

 

 

 

 

3. clean 타겟 (빌드 결과물 리셋)

# 실행파일 생성
myprogram: main.o foo.o bar.o
	gcc main.o foo.o bar.o -o myprogram

# main.o 파일 생성
main.o: main.c
	gcc -c main.c

# foo.o 파일 생성
foo.o: foo.c foo.h
	gcc -c foo.c

# bar.o 파일 생성
bar.o: bar.c bar.h
	gcc -c bar.c

# clean 타겟 (실행파일과 오브젝트 파일 삭제)
clean:
	rm -f myprogram *.o

 


 

4. Makefile을 활용한 증분 빌드 (3) - make 실행 테스트

더보기

1. [처음 빌드]: make myprogram 명령어 실행

 

 

 

2. [일부 수정]: foo.c만 수정 → make myprogram 명령어 실행

  • 증분 빌드 (Incremental Build) 동작 순서
    1. foo.o만 다시 컴파일 → 나머지는 그대로 유지 → 링크 → 실행파일 생성
    2. main.o, foo.o, bar.o 중에서 최신이 아닌 파일들을 찾음
    3. 각 .o 파일을 만들기 위해 필요한 .c, .h 파일의 변경 여부 확인
    4. 필요하면 컴파일 명령어를 실행
    5. 마지막에 오브젝트 파일들을 링크해 myprogram 생성

 

 

 

 

3. [초기화] make clean 실행

  • myprogram 실행파일과 모든 .o 파일(main.o, foo.o, bar.o) 삭제
  • 빌드 이전 상태로 돌아감

 

 

 

 

4. makefile(2) 추가 학습하기 ☜

CC = gcc
CFLAGS = -Wall -g
LDFLAGS = -lmysqlclient -lpthread
 
SRCS = main.c foo.c bar.c 
OBJS = $(SRCS:.c=.o)
 
myprogram: $(OBJS)
	$(CC) $(OBJS) -o $@ $(LDFLAGS)
 
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@
 
clean:
	rm -f $(OBJS) myprogram

 

*위 Makefile 예시처럼, 컴파일러 지정, 프로젝트 파일 관리, 디버깅 정보 설정, 외부 라이브러리 링크 등 다양한 옵션을 효율적으로 추가하면,ㅍ 빌드 관리가 훨씬 용이해집니다.


개념 설명 예시 / 적용 부분
타겟
(Target)
빌드하려는 결과물 또는 작업 이름.
실행파일, 오브젝트 파일 등이 해당됨.
myprogram, clean, foo.o
의존성
(Dependency)
타겟을 만들기 위해 먼저 있어야 하는 파일 또는 타겟들.
타겟은 의존성보다 최신이어야 함.
myprogram: $(OBJS), foo.o: foo.c foo.h
명령어
(Command)
타겟을 만들기 위해 실행하는 쉘 명령어.
반드시 탭 문자로 들여쓰기 해야 함.
$(CC) $(OBJS) -o $@ $(LDFLAGS)
자동 변수
(Automatic Variables)
빌드 과정에서 자동으로 할당되는 변수들.
예: $@(타겟 이름), $<(첫 번째 의존성), $^(모든 의존성)
$@, $< 사용: gcc -c $< -o $@
변수
(Variables)
컴파일러, 옵션, 파일 목록 등을 변수로 정의해
재사용성과 관리 편의성 제공.
CC = gcc, CFLAGS = -Wall -g, SRCS = main.c foo.c bar.c
.PHONY 가상 타겟 선언. 실제 파일과 이름이 충돌해도 명령어를 항상 실행하도록 보장. .PHONY: clean