리눅스의 프로그래밍 도구인 GCC, make, gdb가 무엇인지 정리해본다.
Reference: [책] 사물인터넷을 위한 리눅스 프로그래밍 with 라즈베리파이, 78-104
1. GCC (GNU Compiler Collection)
GCC란 무엇일까? 정확하게 알아보자.
GCC(GNU Compiler Collection)를 알기 위해선 GNU가 무엇인지부터 알아야겠다.
GNU 홈페이지의 정의를 살펴보았다. "GNU는 여러 사람들이 합작으로 만든 운영체제이며, GNU의 주된 목적은 100% 무료로 유닉스 운영체제에 호환 가능한 시스템을 제공하는데에 있다고 한다."
다시말해, GCC는 유닉스 계열 운영체제에 호환 가능한 100% 무료인 오픈소스 컴파일러 모음집인 것이다.
GCC는 다음과 같이 유닉스 계열 운영체제에서 빌드를 위한 여러 도구(전처리기, 컴파일러, 어셈블러, 링커)를 제공한다.

이처럼, GCC는 GNU의 컴파일 모음을 의미하기도 하지만 gcc라고 소문자로 쓰면 컴파일러 자체를 의미하기도 한다. gcc는 리눅스의 기본 컴파일러로, 일반적으로 리눅스 시스템 프로그램이나 리눅스 커널의 소스 코드를 빌드하기 위해서 사용된다.
2. make 유틸리티
많이도 마주했던 make 명령어. 빌드를 도와주는 유틸리티라는 것은 어렴풋이 알았지만, 정확한 정의를 이해하진 아직 못해 책의 내용을 찾아 정리해보았다.
일반적으로 애플리케이션 제작은 프로젝트를 기반으로 진행되는데 하나의 프로젝트에는 아주 많은 수의 소스 코드가 사용된다. 이러한 소스 코드를 gcc를 이용해서 하나하나 컴파일하기에는 너무 많은 작업과 시간이 소요된다. 이 때 make 유틸리티를 도입해 이러한 빌드 과정을 자동화할 수 있다고 한다.
make 유틸리티는 makefile이라는 파일에 특수한 형태의 의존 규칙(dependency rule)들을 정의하고, 이 파일을 기준으로 해서 소스 코드들을 자동으로 빌드할 수 있다. 구체적인 예를 통해서 이해해보자.
/* main.c */
#include "common.h"
int main()
{
char* str = input();
print(str);
print("\n");
return 0;
}
이러한 main.c 라는 C 소스 파일이 있다고 하자.
main() 함수에서 사용한 외부함수인 input()과 print()는 common.h 헤더파일을 통해 main.c에 참조해준다.
/* common.h */
#ifdef __COMMON_H__
#define __COMMON_H__
extern void print(char* str);
extern char* input();
#endif /* __COMMON_H__ */
/* print.c */
#include <stdio.h>
#include "common.h"
void print(char* str)
{
print("%s", str);
}
/* input.c */
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
char* input()
{
char *str;
std = (char*)malloc(BUFSIZE);
scanf("%s", str);
return str;
}
위 코드들은 gcc를 이용해 다음과 같이 빌드할 수 있다.
$ gcc -o test main.c print.c input.c
하지만, 규모가 큰 프로젝트의 경우 이처럼 터미널에서 일일히 gcc를 이용해 빌드하는 것은 비효율적일 수 있다. 여기서 make 유틸리티를 사용해 빌드 프로세스를 효율화시킬 수 있다.
# makefile !!
test :
gcc -o test main.c print.c input.c
makefile을 작성한 후 make 유틸리티를 실행하면 자동으로 빌드가 완료된다!
$ make
위의 makefile을 조금 더 수정해보자. make 시 빌드와 관련된 의존관계와 필요한 사항을 이렇게 추가한다.
# makefile !!
test : main.o print.o input.o
gcc -o test main.o print.o input.o
main.o : main.c common.h
gcc -c main.c
print.o : print.c common.h
gcc -c print.c
input.o : input.c common.h
gcc -c input.c
main.c, print.c, input.c 파일의 소스 파일들과 common.h의 헤더 파일을 각각 설정하고, gcc의 -c옵션을 이용해서 컴파일한 후, 이를 다시 하나로 링크해서 실행 파일을 생성할 수 있다. 이때 앞에서 살펴본 gcc 옵션을 사용할 수 있다.
이 makefile을 살펴보면 파일의 목적 파일을 만드는 곳에서 비슷한 과정이 반복된다. 이러한 반복 작업을 쉽게 처리할 수 있도록 make 유틸리티에서는 확장자 규칙이나 매크로 등의 방법을 제공한다.
2.1. makefile의 매크로
매크로는 makefile에서 편리하게 사용하기 위해 미리 정의된 변수이다. '${macro}', '$(macro)', '$macro' 같은 형태를 사용할 수 있으나 일반적으로 '$(macro)'형태를 사용한다.
위 makefile을 매크로를 이용해 변경해보자. 일반적으로 매크로에는 대문자를 사용하며, '='을 이용해서 값을 설정하고, 앞에서 정의한 매크로를 사용하기 위해 $()를 이용한다.
# makefile !!
OBJECTS = main.o print.o input.o
test : $(OBJECTS)
gcc -o test $(OBJECTS)
main.o : main.c common.h
gcc -c main.c
print.o : print.c common.h
gcc -c print.c
input.o : input.c common.h
gcc -c input.c
make 유틸리티는 CC나 GCC처럼 미리 정의되어있는 매크로도 제공한다. make 유틸리티에서 제공하는 매크로는 터미널 창에서
$ make -p
이 명령어를 입력해 확인할 수 있다.
이러한 매크로를 이용해 이 makefile을 조금 더 수정해보자!
# makefile !!
OBJECTS = main.o print.o input.o
SRCS = main.c print.c input.c
CFLAGS = -g
TARGET = test
$(TARGET) : $(OBJECTS)
$(CC) -o $(TARGET) $(OBJECTS)
clean :
rm -f $(OBJECTS) $(TARGET) core
main.o : main.c common.h
print.o : print.c common.h
input.o : input.c common.h
위의 makefile에서는 소스 코드 파일을 저장하는 SRCS 매크로를 설정했다. 또한, 컴파일 시 플래그를 위해 CFLAGS를 지정한다.일반적으로 컴파일과 관련해서는 CFLAGS라는 정의어를 사용하고, 링크와 관련해서는 LDFLAGS라는 매크로를 사용한다.
3. gdb 유틸리티
gdb(GNU Debugger) 유틸리티는 리눅스에서 프로그래밍 오류를 찾기 위한 디버깅에 사용되는 도구이다.
gdb 유틸리티는 애플리케이션이 실행되는 도중에 지정된 breakpoint에 멈출 수 있으며, 해당 지점의 변수나 포인터 값 등의 내부 상태를 조사하거나, 에러가 발생했을 때 원인을 규명하기 위해 사용된다. gdb를 실행하기 위해서는 gdb 유틸리티의 이름 뒤 검사하고자 하는 프로그램의 이름을 인자로 주면 된다.
$ gdb [프로그램 이름]
'Embedded Systems > 리눅스' 카테고리의 다른 글
| [Linux] 임베디드 리눅스 부팅 순서 + 비글본 블랙(BBB) 부팅 순서 (0) | 2025.10.28 |
|---|---|
| [Linux] 디바이스 드라이버란 무엇일까? (0) | 2025.10.27 |
| [linux] gcc를 이용한 소스 코드 빌드 과정 (0) | 2025.10.21 |
| 부트로더(bootloader)란 무엇인가? (0) | 2025.10.21 |
| /bin/bash^M: bad interpreter: No such file or directory 오류 (0) | 2022.06.09 |