우리는 source code를 짜고, compile한 후, 실행한다. 이때 compile이란 특정 프로그래밍 언어로 쓰인 code를 다른 언어로 옮기는 과정이다. 즉, compiler가 작용하면 비교적 사람이 이해하기 쉬운 high-level언어로 쓰인 source code 내용을 컴퓨터가 읽을 수 있는 low-level 어셈블리어로 번역해준다.
compiler로 직접 compile하는 과정을 거치기도 하지만, 나의 경우 linux를 사용한다면 terminal에서 ' 'make' 라는 명령어를 사용해 쉽게 build 하고 실행하는 방법을 주로 사용한다.
그렇다면 'make' 라는 명령어가 정확히 어떤 역할을 해주는 것일까??? 라는 의문을 가지고 살펴보겠다.
: 프로그램을 관리하는 프로그램이다. 특정 프로그램의 일정 부분이 수정돼 재 컴파일이 필요할 경우 이를 용이하게 해주는 파일이다.
:파일 관리 유틸리티이다. 파일 간의 종속관계를 파악하여 Makefile(기술파일) 에 적힌 대로 컴파일러에 명령해 shell 명령이 순차적으로 실행될 수 있게 한다.
- make의 장점
- 각 파일에 대한 반복적 명령의 자동화로 인한 시간 절약
- 프로그램의 종속 구조를 빠르게 파악할 술 이씅며 관리가 용이
- 단순 반복 작업 및 재작성을 최소화
Header file: "diary.h"
#include "diary.h"
int main(void)
{
memo();
calendar();
return 0;
}
C file: memo.c, calendar.c, main.c
memo.c
#include "diary.h"
void memo()
{
printf("I'm function Memo!\n");
}
calendar.c
#include "diary.h"
void calendar()
{
printf("I'm function Calendar\n");
}
main.c
#include "diary.h"
int main(void)
{
memo();
calendar();
return 0;
}
파일이 모두 제대로 생성되었다면,
gcc -c -o memo.o memo.c
gcc -c -o calendar.o calendar.c
gcc -c -o main.o main.c
1.각 c file에서 object 파일을 생성해 준다.
-c는 object file을 생성하는 옵션이고, -o는 생성될 파일 이름을 지정하는 옵션이다.
( -o옵션을 넣지 않아도 object 파일이름이 (c file name).o로 자동 생성된다. 하지만 실행 파일 생성시 -o 옵션을 넣지 않으면 모든 파일이 a.out이라는 이름을 가지게 되므로 여러 개의 실행 파일을 생성해야 할 때 효율적인 옵션이다. )
2.각 object file을 묶어 컴파일을 통해 diary_exe 실행파일 생성하기!
gcc -o diary_exe main.o memo.o calendar.o
object file 순서는 상관 없다.
3.실행 확인!
./diary_exe
기본적인 컴파일 과정이 크게 복잡하지는 않다. 그러나 하나의 실행 파일생성에 필요한 c파일 수가 엄청나게 많다면???? 이런 상황을 해결해주는 것이 'make'와 'Makefile'이다!!!
Makefile의 구성
-목적파일(Target) : 명령어가 수행되어 나온 결과를 저장할 파일
-의존성(Dependency) : 목적파일을 만들기 위해 필요한 재료
-명령어(Command) : 실행 되어야 할 명령어들
-매크로(macro) : 코드를 단순화 시키기 위한 방법
Makefile의 기본구조
구성요소들이 실제 Makefile 코드에서 다음과 같이 배치된다.
Makefile의 작성규칙
목표파일 : 목표파일을 만드는데 필요한 구성요소들
(tab)목표를 달성하기 위한 명령 1
(tab)목표를 달성하기 위한 명령 2
// 매크로 정의 : Makefile에 정의한 string 으로 치환한다.
// 명령어의 시작은 반드시 탭으로 시작한다.
// Dependency가없는 target도 사용 가능하다.
Makefile을 만들어 보자!!
vi Makefile
diary_exe : memo.o calendar.o main.o
gcc -o diary_exe memo.o calendar.o main.o
memo.o: memo.c
gcc -c -o memo.o memo.c
calendar.o: calendar.c
gcc -c -o calendar.o calendar.c
main.o: main.c
gcc -c -o main.o main.c
clean:
rm *.o diary_exe
make clean
더미타겟은 파일을 생성하지 않는 개념적인 타겟으로, 위의 명령어를 입력하면, 현재 디렉토리의 모든 objec file들과 생성된 실행파일인 diary_exe를 rm명령어로 제거해 준다.
make
로 Makefile을 실행해 준다.
diary_exe가 만들어졌다!!!
실행결과는 기본적인 컴파일 과정과 동일하다!
위의 코드를 더욱 단순화 시키기 위해 macro매크로 를 사용해 보자!!
Macro작성규칙
- 매크로를 참조 할 때는 소괄호나 중괄호 둘러싸고 앞에 ‘$’를 붙인다.
- 탭으로 시작해서는 안되고 , :,=,#,”” 등은 매크로 이름에 사용할 수 없다.
- 매크로는 반드시 치환될 위치보다 먼저 정의 되어야 한다.
-W -Wall는 컴파일 시 컴파일이 되지 않을 정도의 오류라도 모두 출력되게 하는 옵션!
Makefile
CC = gcc
CFLAGS = -W -WALL
TARGET = diary_exe
$(TARGET): memo.o calendar.o main.o
$(CC) $(CFLAGS) -o $(TARGET) memo.o calendar.o main.o
memo.o: memo.c
gcc -c -o memo.o memo.c
calendar.o: calendar.c
gcc -c -o calendar.o calendar.c
main.o: main.c
gcc -c -o main.o main.c
clean:
rm *.o diary_exe
make clean후 실행하면, 실행파일이 잘 만들어진다!
실행 결과
CC = gcc
CFLAGS = -W -WALL
TARGET = diary_exe
OBJECTS = memo.o main.o calendar.o
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm *.o diary_exe
!!코드가 굉장히 단순해졌다!!
- “$@” : 현재 타겟의 이름
- “$^” : 현재 타겟의 종속 항목 리스트
코드를 해석해보면,
- gcc 컴파일러를 이용
- 사소한 오류까지 출력
- 최종 타겟 파일은 diary_exe
- OBJECT 로 정의할 파일들은 memo.o main.o calendar.o
- all 은 현재는 사용하지 않았지만 타겟 파일이 여러개 일때 사용됨.
- 타겟 파일을 만들기 위해 OBJECT 들을 사용.( 단, OBJECT 파일이 없다면 OBJECT 파일과 이름이 동일한 C파일을 찾아 OBJECT파일을 생성한다. )
- gcc -o diary_exe memo.o main.o calendar.o과 동일
- 더미타겟
Makefile을 생성해 make 명령을 사용하면 다음과 같은 장점이 있다.
- 입력파일 변경 시 결과파일 자동 변경을 원할 때 지능적 배치작업을 수행할 수 있다!
- 일일히 gcc명령으로 컴파일 하지 않고 진행할 수 있다!
make를 사용해 쉽게 컴파일 해보자:)