Unisquads
로그인
홈
이용약관·개인정보처리방침·콘텐츠정책·© 2026 Unisquads
이용약관·개인정보처리방침·콘텐츠정책
© 2026 Unisquads. All rights reserved.

Make (r1)

이 문서의 과거 버전 (r1)을 보고 있습니다. 수정일: 2026.02.24 08:39

Make

정식 명칭

GNU Make

개발자

Stuart Feldman

최초 등장

1976년

주요 용도

빌드 자동화

설정 파일

Makefile

주요 대상 운영체제

Unix 계열 운영체제

주요 대상 언어

C언어

상세 정보

개발 배경

CLI 환경에서 소스 코드 파일 수가 많아지면 입력해야 할 컴파일 명령어의 양이 늘어나는 문제를 해결하기 위해 개발됨[?]

작동 방식

Makefile 이라고 불리는 설정 파일을 읽어 소스 코드와 라이브러리로부터 실행파일을 생성하는 작업을 자동화함

비교 대상

VC++ 컴파일러의 .vcxproj 파일과 동일한 역할

파생 소프트웨어

CMake

소속 프로젝트

GNU 프로젝트

1. 개요

GNU Make는 빌드 자동화 도구이다. 1976년 스튜어트 펠드먼에 의해 개발되었으며, 소스 코드로부터 실행 파일을 생성하는 과정을 자동화하는 데 사용된다. 이 도구는 주로 유닉스 계열 운영체제에서 C언어 프로젝트의 컴파일 및 링킹 작업을 관리하기 위해 고안되었다.

Make의 핵심은 Makefile이라는 설정 파일에 있다. Makefile은 빌드할 대상(타겟), 그 대상이 의존하는 파일들(의존성), 그리고 빌드를 수행하기 위한 명령어들의 규칙을 정의한다. 사용자는 단순히 make 명령어를 실행하기만 하면, Make는 Makefile을 읽어 변경된 파일만을 감지하고 필요한 최소한의 작업만을 수행하여 최종 결과물을 생성한다.

이는 특히 파일 수가 많은 대규모 프로젝트에서 빌드 시간을 단축하고, 수동으로 명령어를 입력하는 번거로움과 실수를 줄이는 데 큰 도움을 준다. GNU Make는 자유 소프트웨어 재단의 GNU 프로젝트의 일부로서, 오픈 소스로 유지보수되고 있으며 리눅스 및 다양한 플랫폼에서 널리 사용된다.

2. 역사

Make는 1976년 벨 연구소의 스튜어트 펠드먼(Stuart Feldman)에 의해 개발된 최초의 빌드 자동화 도구이다. 이 도구는 유닉스 환경에서 C언어로 작성된 소프트웨어의 컴파일 과정을 자동화하기 위해 만들어졌다. 당시 소스 코드 파일이 많아질수록 수동으로 컴파일러 명령을 입력하는 작업은 번거롭고 오류가 발생하기 쉬웠는데, Make는 이러한 문제를 해결했다.

Make의 핵심 아이디어는 타겟, 의존성, 명령의 관계를 기술한 Makefile을 통해 빌드 과정을 정의하는 것이다. 개발자는 최종 산출물과 이를 생성하기 위해 필요한 중간 파일들, 그리고 각 단계에서 실행할 셸 명령어를 Makefile에 기록한다. Make는 이 파일을 읽어 의존성 그래프를 분석하고, 변경된 파일들만을 선별적으로 재빌드하여 시간을 절약한다.

이 도구는 이후 오픈 소스 GNU 프로젝트의 일부인 GNU Make로 재구현되어 널리 보급되었으며, 현대 소프트웨어 개발의 기초 도구로 자리 잡았다. Make의 등장은 이후 CMake, Apache Ant, Gradle 등 다양한 고급 빌드 도구와 CI/CD 파이프라인의 발전에 중요한 토대를 제공했다.

3. 필요성

Make의 필요성은 소프트웨어 빌드 과정의 복잡성과 반복적인 수작업을 자동화하기 위함이다. 초기 유닉스 환경에서 C언어로 작성된 프로그램을 빌드할 때, 개발자는 컴파일러와 링커를 직접 호출하는 긴 명령어를 수동으로 입력해야 했다. 소스 코드 파일이 많아질수록 이러한 명령어의 조합은 기하급수적으로 복잡해지고, 하나의 파일만 수정되어도 관련된 모든 파일을 다시 빌드하는 과정은 번거로웠다. 이는 개발 효율을 저하시키고 실수를 유발하는 주요 원인이 되었다.

Make는 이러한 문제를 해결하기 위해 등장했다. 개발자는 Makefile이라는 설정 파일에 빌드 자동화를 위한 규칙(의존성과 명령)을 한 번만 작성하면 된다. 이후 make 명령어 하나로 전체 또는 변경된 부분만을 자동으로 빌드할 수 있다. 이는 특히 대규모 프로젝트에서 소스 코드, 헤더 파일, 목적 파일, 라이브러리 간의 복잡한 의존 관계를 관리하고, 최종 실행 파일을 생성하는 과정을 단순화한다. 결과적으로 개발자는 빌드 과정보다 코드 작성에 더 집중할 수 있게 되었다.

4. 기본 개념

4.1. Makefile

Make의 핵심 구성 요소는 Makefile이다. Makefile은 빌드 과정을 정의하는 텍스트 기반의 설정 파일로, 소스 코드로부터 실행 파일을 생성하는 데 필요한 규칙과 명령을 기술한다. 이 파일은 일반적으로 프로젝트의 루트 디렉터리에 위치하며, make 명령을 실행하면 해당 디렉터리의 Makefile을 읽어 빌드 작업을 수행한다.

Makefile의 기본 구조는 타겟(Target), 의존성(Dependency), 명령(Command)으로 이루어진 규칙 블록을 따른다. 타겟은 빌드할 대상(예: 최종 실행 파일이나 중간 목적 파일)의 이름이다. 의존성은 해당 타겟을 빌드하는 데 필요한 파일들(예: 소스 파일, 헤더 파일)을 나열한다. 명령은 의존성을 바탕으로 타겟을 생성하기 위해 실행할 셸 명령어(예: 컴파일러 호출)를 의미한다. 명령 줄은 반드시 탭(Tab) 문자로 시작해야 하는 문법적 제약이 있다.

Makefile은 매크로(Macro) 또는 변수(Variable)를 사용하여 반복되는 값을 정의하고 재사용할 수 있어 유지보수성을 높인다. 예를 들어, 사용할 컴파일러(CC), 컴파일 옵션(CFLAGS), 목적 파일 목록(OBJS) 등을 변수로 선언하여 여러 규칙에서 참조한다. 또한 all이나 clean과 같은 가상 타�트(Phony Target)를 정의하여 특정 작업 그룹을 실행하거나 중간 파일을 정리하는 데 활용한다.

Makefile의 가장 큰 장점은 의존성 분석을 통한 증분 빌드이다. make는 타겟과 그 의존성 파일들의 최종 수정 시간을 비교하여, 타겟보다 의존성 파일이 더 최신인 경우에만 해당 명령을 실행한다. 이를 통해 변경된 소스 파일만 다시 컴파일하고, 나머지는 기존 빌드 결과를 재사용함으로써 전체 빌드 시간을 단축한다.

4.2. 타겟(Target)

타겟은 Makefile에서 빌드 과정의 최종 산출물이나 중간 산출물을 지칭하는 이름이다. 이는 일반적으로 생성하려는 실행 파일의 이름이 되거나, 목적 파일과 같은 중간 파일의 이름이 될 수 있다. 또한 'all'이나 'clean'과 같이 특정 작업을 수행하기 위한 가상의 목표를 나타내는 가상 타겟으로 사용되기도 한다. 타겟은 의존성과 명령과 함께 Makefile의 기본 규칙을 구성하는 핵심 요소이다.

하나의 규칙은 '타겟: 의존성'의 형태로 시작하며, 그 아래 탭으로 들여쓰기된 명령들이 위치한다. make 유틸리티는 사용자가 지정한 타겟을 빌드하기 위해 실행된다. 예를 들어 'make main' 명령은 'main'이라는 타겟을 찾아 해당 규칙에 정의된 명령들을 실행한다. 타겟이 지정되지 않으면 Makefile의 첫 번째 타겟이 기본 목표로 선택된다.

타겟은 파일 시스템에 실제로 존재하는 파일의 이름과 일치할 수도 있고, 그렇지 않을 수도 있다. make는 타겟 이름에 해당하는 파일의 최종 수정 시간을 확인하여, 해당 파일이 의존성 파일들보다 오래되었거나 아직 존재하지 않을 경우에만 명령들을 실행한다. 이 메커니즘을 통해 변경된 소스 코드만 다시 컴파일하는 점진적 빌드가 가능해진다.

4.3. 의존성(Dependency)

의존성은 Make가 빌드 작업을 수행할 때 특정 타겟을 생성하기 위해 필요한 파일이나 다른 타겟을 가리킨다. Makefile 내의 각 규칙은 타겟, 의존성, 그리고 이를 생성하는 명령으로 구성된다. 의존성은 타겟이 최신 상태인지 판단하는 기준이 된다. 즉, 타겟 파일의 수정 시간이 모든 의존성 파일의 수정 시간보다 최신이면 해당 타겟은 이미 빌드된 것으로 간주하고 명령을 실행하지 않는다. 만약 의존성 중 하나라도 타겟보다 최신이면, 타겟은 오래된 것으로 판단되어 관련 명령이 실행되어 타겟을 다시 빌드한다.

의존성은 직접적일 수도 있고 간접적일 수도 있다. 예를 들어, 최종 실행 파일이 목적 파일에 의존하고, 그 목적 파일은 다시 소스 코드와 헤더 파일에 의존하는 구조를 가질 수 있다. 이러한 의존 관계는 Makefile에 명시적으로 정의되며, GNU Make는 이 관계를 따라 재귀적으로 의존성을 해석한다. 의존성 그래프가 올바르게 정의되어 있지 않으면, 필요한 파일이 업데이트되지 않았음에도 불구하고 타겟이 최신 상태로 잘못 판단되어 빌드가 누락되는 문제가 발생할 수 있다.

의존성 관리의 핵심은 빌드의 정확성과 효율성을 보장하는 데 있다. 불필요한 재컴파일을 방지하여 빌드 시간을 단축시키는 동시에, 소스 코드가 변경되면 반드시 관련된 모든 출력물이 갱신되도록 한다. 복잡한 프로젝트에서는 의존성 추적이 자동으로 이루어지도록 make depend 같은 방법이나, CMake와 같은 고수준 빌드 도구를 활용하기도 한다.

4.4. 명령(Command)

명령(Command)은 Makefile 내의 각 타겟(Target) 섹션에서 실제로 수행할 작업을 정의하는 부분이다. 이는 셸에서 실행 가능한 하나 이상의 명령어로 구성되며, 타겟을 빌드하기 위해 필요한 구체적인 단계를 기술한다. 예를 들어, C언어 소스 코드를 컴파일하거나 목적 파일들을 링킹하는 gcc 명령어가 여기에 해당한다. 명령은 의존성이 갱신되었거나 타겟 파일이 존재하지 않을 때만 실행되어 불필요한 작업을 반복하지 않도록 한다.

명령을 작성할 때는 중요한 문법적 규칙을 따라야 한다. 명령 줄은 반드시 탭(Tab) 문자으로 시작해야 하며, 공백으로 들여쓰기를 하면 Make가 이를 명령으로 인식하지 못하고 오류를 발생시킨다. 각 명령은 별도의 줄에 작성되며, 한 타겟 아래에 여러 개의 명령을 순차적으로 나열할 수 있다. 명령 앞에 '@' 기호를 붙이면 해당 명령 자체가 터미널에 출력되지 않아 빌드 출력을 깔끔하게 만들 수 있다.

명령 블록 내에서는 Make의 자동 변수를 활용하여 보다 유연하고 간결한 스크립팅이 가능하다. 자주 사용되는 변수로는 $@ (현재 타겟의 이름), $< (첫 번째 의존성의 이름), $^ (모든 의존성의 목록) 등이 있다. 예를 들어, gcc -o $@ $^라는 명령은 모든 의존성 파일을 링크하여 현재 타겟 이름의 실행 파일을 생성하라는 의미가 된다. 또한 매크로 (사용자 정의 변수)를 사용하여 컴파일러나 컴파일 플래그를 중앙에서 관리할 수 있어 Makefile의 유지보수성이 높아진다.

명령의 실행은 기본적으로 각 줄이 독립적인 셸 세션에서 수행된다. 이는 한 줄의 작업 디렉토리 변경 명령이 다음 줄에 영향을 주지 않음을 의미한다. 여러 명령을 하나의 셸 세션에서 연속적으로 실행하려면, 명령들을 한 줄에 나열하거나 줄 끝에 백슬래시를 사용하여 이어줘야 한다. Make는 명령의 종료 상태를 검사하여 실패 시(0이 아닌 값 반환) 전체 빌드 과정을 중단시킨다.

5. 사용 예제

사용 예제

GNU Make의 기본적인 사용법은 Makefile이라는 설정 파일을 작성하는 것이다. Makefile은 타겟, 의존성, 명령의 규칙으로 구성된다. 가장 간단한 예로, hello.c라는 C언어 소스 파일로부터 hello라는 실행 파일을 생성하는 경우를 살펴본다.

먼저, 다음과 같은 내용의 Makefile을 프로젝트 디렉토리에 생성한다.

```makefile

hello: hello.o

gcc -o hello hello.o

hello.o: hello.c

gcc -c hello.c

clean:

rm -f hello hello.o

```

이 Makefile에는 세 개의 타겟이 정의되어 있다. 첫 번째 규칙은 최종 타겟인 hello 실행 파일을 생성하는 방법을 명시한다. 이 파일은 hello.o라는 목적 파일에 의존하며, 의존성이 충족되면 gcc -o hello hello.o 명령이 실행되어 링킹을 수행한다. 두 번째 규칙은 hello.o 파일이 hello.c 소스 코드에 의존함을 나타내고, gcc -c hello.c 명령으로 컴파일을 지시한다. 마지막 clean 타겟은 생성된 파일들을 삭제하는 유틸리티 규칙이다.

터미널에서 make 명령을 실행하면, Make는 현재 디렉토리의 Makefile을 읽고 기본적으로 첫 번째 타겟(hello)을 빌드한다. Make는 의존성 그래프를 분석하여 hello.o가 필요하고, hello.o는 hello.c에서 생성됨을 확인한다. 따라서 hello.c를 컴파일하여 hello.o를 만들고, 이를 링킹하여 최종 hello 실행 파일을 생성하는 순서로 작업을 수행한다. 생성된 파일을 정리하려면 make clean 명령을 사용한다.

Makefile은 매크로를 사용하여 보다 효율적이고 유지보수하기 쉬운 형태로 작성할 수 있다. 컴파일러와 컴파일 옵션, 소스 파일 목록을 변수로 정의하면 프로젝트 규모가 커졌을 때 유리하다.

```makefile

CC = gcc

CFLAGS = -Wall -O2

OBJS = hello.o

TARGET = hello

$(TARGET): $(OBJS)

$(CC) -o $@ $(OBJS)

%.o: %.c

$(CC) $(CFLAGS) -c $<

clean:

rm -f $(TARGET) $(OBJS)

```

이 예제에서 CC와 CFLAGS는 Make의 내장 변수를 재정의한 것이며, OBJS와 TARGET은 사용자 정의 변수이다. $@는 현재 타겟의 이름을, $<는 첫 번째 의존성의 이름을 나타내는 자동 변수이다. %.o: %.c 규칙은 패턴 규칙으로, 확장자가 .c인 파일에서 동일한 이름의 .o 파일을 생성하는 일반적인 방법을 정의한다. 이렇게 작성하면 새로운 소스 파일이 추가될 때마다 Makefile을 크게 수정하지 않고도 변수 목록만 업데이트하면 된다.

6. 파생 소프트웨어

6.1. CMake

CMake는 Make와 Makefile의 복잡성과 플랫폼 의존성을 해결하기 위해 개발된 크로스플랫폼 빌드 자동화 도구이다. Kitware사가 개발한 이 도구는 개발자가 플랫폼에 독립적인 빌드 스크립트를 작성하면, CMake가 해당 환경에 맞는 네이티브 빌드 파일(예: 유닉스 계열의 Makefile, 마이크로소프트 윈도우의 Visual Studio 솔루션 파일, Xcode 프로젝트 파일 등)을 자동으로 생성해준다. 이는 특히 리눅스, macOS, 윈도우 등 다양한 운영체제에서 동일한 소스 코드를 빌드해야 하는 크로스플랫폼 개발에 필수적인 도구로 자리잡았다.

CMake의 핵심은 CMakeLists.txt라는 이름의 설정 파일이다. 개발자는 이 파일에 프로젝트명, 소스 파일 목록, 라이브러리 의존성, 컴파일 옵션 등을 선언적으로 기술한다. CMake는 이 파일을 읽고, 현재 시스템의 컴파일러와 빌드 환경을 감지하여 해당 플랫폼에 최적화된 빌드 시스템용 파일을 출력한다. 예를 들어, GCC가 설치된 리눅스 환경에서는 Makefile을 생성하고, MSVC가 있는 윈도우 환경에서는 .vcxproj 파일을 생성한다.

CMake는 Make의 직접적인 파생 소프트웨어라기보다는 상위 레벨의 메타 빌드 시스템(Meta-build System)으로 분류된다. 사용자는 복잡한 Makefile 문법 대신 CMake의 간결한 명령어를 사용하여 빌드 과정을 정의할 수 있으며, CMake가 내부 의존성 분석과 빌드 스크립트 생성을 대신 처리한다. 이로 인해 대규모 프로젝트의 빌드 설정 관리가 훨씬 용이해졌으며, 오픈 소스 프로젝트에서 사실상의 표준 빌드 도구로 널리 채택되었다.

항목

설명

설정 파일

CMakeLists.txt

주요 기능

크로스플랫폼 빌드 파일 자동 생성, 의존성 관리

생성 가능한 빌드 시스템

Makefile, Ninja, Visual Studio 솔루션, Xcode 프로젝트 등

라이선스

BSD 라이선스

CMake의 등장으로 개발자는 각 플랫폼별로 별도의 빌드 스크립트를 유지보수할 필요 없이, 하나의 CMakeLists.txt로 다양한 환경을 관리할 수 있게 되었다. 이는 소프트웨어 개발의 효율성을 크게 높이고, CI/CD 파이프라인 구축을 단순화하는 데 기여했다.

7. 빌드 과정

Make의 빌드 과정은 Makefile에 정의된 규칙과 의존성을 기반으로, 최종 타겟을 생성하기 위해 필요한 명령들을 순차적으로 실행하는 자동화된 절차이다. 이 과정은 기본적으로 의존성 분석과 명령 실행의 두 단계로 구성된다.

먼저, 사용자가 make 명령을 실행하면, Make는 현재 디렉토리의 Makefile을 읽어들인다. Makefile에는 타겟, 의존성, 명령이 규칙 형태로 정의되어 있다. Make는 사용자가 지정한 타겟(지정하지 않으면 Makefile의 첫 번째 타겟)을 최종 목표로 설정하고, 해당 타겟이 의존하는 다른 타겟이나 파일들을 재귀적으로 분석하여 의존성 그래프를 구성한다. 이 분석 과정에서 각 타겟의 최종 수정 시간을 비교하여, 타겟보다 의존성이 더 최신인 경우에만 해당 타겟을 재빌드해야 한다고 판단한다.

의존성 분석이 완료되면, Make는 변경이 필요한 타겟들에 대해서만 정의된 명령들을 순서대로 실행한다. 명령은 일반적으로 컴파일러나 링커를 호출하여 소스 코드를 목적 파일로 변환하거나, 여러 목적 파일을 하나의 실행 파일로 결합하는 작업을 수행한다. 이때, -j 옵션을 사용하면 여러 명령을 병렬 처리하여 빌드 시간을 단축할 수 있다.

빌드 과정이 성공적으로 완료되면 최종 타겟 파일이 생성된다. 만약 중간에 오류가 발생하면 Make는 해당 지점에서 빌드 과정을 중단하고 오류 메시지를 출력한다. make clean과 같은 특정 타겟을 명시적으로 호출하면, 정의된 정리 명령을 실행하여 생성된 목적 파일이나 실행 파일을 삭제할 수 있다. 이렇게 Make는 복잡한 소프트웨어 빌드 작업을 의존성에 따라 효율적이고 자동으로 관리한다.

8. 관련 문서

  • GNU - GNU Make

  • 위키백과 - Make (소프트웨어)

  • CMake - 공식 사이트

  • 위키백과 - CMake

  • GNU - GNU Make 매뉴얼

  • Microsoft - NMAKE 참조

  • FreeBSD - BSD Make (pmake)

  • IBM - Make 명령 사용법

  • 오라일리 - Managing Projects with GNU Make

리비전 정보

버전r1
수정일2026.02.24 08:39
편집자unisquads
편집 요약AI 자동 생성