강좌
클라우드/리눅스에 관한 강좌입니다.
자격증 분류

리눅스마스터1급: 리눅스 GNU컴파일러 gcc에 대하여

작성자 정보

  • 관리자 작성
  • 작성일

컨텐츠 정보

본문

리눅스마스터1: 리눅스 GNU컴파일러 gcc에 대하여

 

 

GNU 컴파일러 GCC

 

 

 

일반적으로 GNU C 컴파일러로 알려진 GCC“GNU Compiler Collection”의 약자로서 C, C++, Objective-C, Fortran, Java, Ada Go에 대한 프런트엔드와 이들 언어들을 위한 라이브러리들(libstdc++, libgcj )을 포함한다.

 

 

 

GCC는 원래 GNU 운영체제를 위한 컴파일러로서 작성되었고, GNU 시스템은 사용자의 자유를 반영하는 측면에서 100% 자유 소프트웨어로서 개발되었다.

 

 

 

GCC의 저작권은 FSF(자유 소프트웨어 재단)에 있지만 GPL이 적용된 자유 소프트웨어이다.

 

 

 

 

그렇지만 GCC는 주로 C 또는 C++ 언어로 프로그래밍하는 데 사용되기 때문에 C 컴파일러로 알려져 있다.

 

 

 

게다가 리눅스 운영체제와 관련하여 커널의 대부분이 C 언어로 되어 있고, 대부분의 응용프로그램도 C 언어로 되어 있다.

 

 

 

따라서 자의든 타의든 리눅스 사용자들은 GCC를 주로 C 컴파일러로 사용하고 있는 것이다.

 

 

 

 

이런 점에서 이 교재는 GCC를 활용하여 C 소스코드를 컴파일하는 방법에 대해서 간략히 다루고자 한다.

 

 

 

GCC를 이용한 프로그래밍과 컴파일에 대한 사항들은 전문서적을 참고하기 바란다.

 

 

 

 

 

먼저, 명령 행 상태에서 “gcc v”라고 명령을 내리면 gcc 버전을 보여준다.

 

 

 

배포판에 따라 다를 수 있지만, SULinux, RockyLinux, CentOS, Redhat 등은 다음과 같이 출력된다.

 

 

 

여기에서 GCC의 설치 시의 설정 내용 및 버전을 알 수 있다.

 

 

 

설치 시의 설정 내용에서 GCC의 설치 내역을 비교적 상세하게 알 수 있다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 ~]# gcc -v

Using built-in specs.

COLLECT_GCC=gcc

COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/11/lto-wrapper

OFFLOAD_TARGET_NAMES=nvptx-none

OFFLOAD_TARGET_DEFAULT=1

Target: x86_64-redhat-linux

Configured with: ../configure --enable-bootstrap --enable-host-pie --enable-host-bind-now --enable-languages=c,c++,fortran,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.rockylinux.org/ --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --without-isl --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_64=x86-64-v2 --with-arch_32=x86-64 --build=x86_64-redhat-linux --with-build-config=bootstrap-lto --enable-link-serialization=1

Thread model: posix

Supported LTO compression algorithms: zlib zstd

gcc version 11.3.1 20220421 (Red Hat 11.3.1-2) (GCC)

[root@RockyLinux01 ~]#

 

 

 

 

 

 

 

 

그럼 간단한 C 프로그램을 작성하여 gcc컴파일을 해보도록 한다.

 

 

 

아래의 C 소스코드의 파일명은 superuser.c 라는 C 프로그램으로서 gcc의 예를 들기 위해 간단히 작성한 것이다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# ls -l linux.c

-rw-r--r-- 1 root root 90 62 16:34 linux.c

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# cat linux.c

#include <stdio.h>

 

int

main (void)

{

printf ("Welcome, www.linux.co.kr \n");

return 0;

}

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

 

 

위의 예는 linux.c라는 C 소스코드 파일의 내용을 확인한 것이다.

 

 

 

그리고 다음은 앞에서 확인한 linux.c 파일을 ls 명령어로 확인한 것이다.

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# ls -l

합계 4

-rw-r--r-- 1 root root 90 62 16:34 linux.c

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

 

gcc로 컴파일을 하는 가장 기본적인 형식은 다음과 같다.

 

 

 

 

 

 

 

 

 

컴파일 형식 : gcc [C 소스코드 파일명]

 

 

 

 

 

 

 

 

아래의 예는 linux.c 라는 C 소스코드 파일을 gcc로 컴파일하는 간단한 예이다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# gcc linux.c

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# ls -l

합계 32

-rwxr-xr-x 1 root root 25792 62 16:37 a.out

-rw-r--r-- 1 root root 90 62 16:34 linux.c

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

위에서 gcc로 컴파일 할 때에 아무 에러 메시지 없이 종료되었다면 컴파일이 정상적으로 종료되었다는 것을 의미하며 만약 에러가 발생하였다면 그에 대한 에러 메시지를 출력하게 된다.

 

 

 

그리고 생성된 실행 파일은 a.out이라는 파일이다.

 

 

 

, gcc로 컴파일 할 때에 생성된 실행파일을 지정하지 않으면 a.out 이라는 파일이 기본적으로 생성된다.

 

 

 

 

 

그리고 아래의 예는 생성된 실행 파일을 실행한 예이다.

 

 

 

, a.out 이라는 파일을 실행하면 컴파일되어 생성된 a.out 일는 실행 파일이 실행되어 그 결과를 출력한다.

 

 

 

, a.out 의 실행 결과 “Welcome, www.linux.co.kr”이 출력된 것이다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# ./a.out

Welcome, www.linux.co.kr

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

 

그리고 gcc로 컴파일을 할 때에 생성될 실행 파일명을 지정하여 컴파일 하면 지정한 파일명으로 실행 파일이 생성된다.

 

 

 

아래의 예는 linux.c 소스코드 파일을 gcc로 컴파일하여 생성되는 실행 파일로 superuser를 지정한 것이다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# ls -l

합계 4

-rw-r--r-- 1 root root 90 62 16:34 linux.c

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# gcc -o linux linux.c

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# ls -l

합계 32

-rwxr-xr-x 1 root root 25792 62 16:39 linux

-rw-r--r-- 1 root root 90 62 16:34 linux.c

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

위와 같이 gcc로 컴파일 시에 생성될 실행 파일명을 지정할 때에는 o 옵션 다음에 파일명을 지정하면 된다.

 

 

 

위의 예에서는 생성될 실행 파일명으로 linux 를 지정하였기 때문에 linux라는 실행 파일이 생성된 것이다.

 

 

 

 

 

그리고 다음은 생성된 linux 파일을 실행한 예이다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# ./linux

Welcome, www.linux.co.kr

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

 

이번 예는 linux.c 라는 소스코드 파일을 gcc로 컴파일하여 그 결과로 생성된 linux라는 실행 파일을 실행한 것이다.

 

 

 

실행 결과 “Welcome, www.linux.co.kr”라는 문장이 출력된 것을 확인할 수 있다.

 

 

 

 

앞의 예에서는 gcc로 컴파일하는 가장 일반적이고 기본적인 방법을 설명하였다.

 

 

 

그럼 이제 컴파일 과정에 대해서 좀 더 자세히 알아보도록 한다.

 

 

 

, 우리가 생각하고 있는 컴파일이라는 개념을 다시 정리해 본다.

 

 

 

깊이 있고 세부적인 설명은 생략하고 gcc를 이용한 컴파일 과정의 이해에 필요한 부분만을 설명한다.

 

 

 

 

 

결론적으로, 앞의 예에서 gcc를 수행했던 컴파일은 컴파일 작업 + 링크 작업을 동시에 수행한 것이다.

 

 

 

이를 조금 더 정리하면 다음과 같다.

 

 

 

 

 

컴파일 작업 :

 

 

C 소스코드 파일을 입력으로 하여 목적 파일(object file)을 생성해 내는 과정을 의미한다.

 

 

 

 

링크 작업 : 컴파일 결과 생성된 목적 파일들에 필요한 함수들과 라이브러리들을 연결하여 바이너리 형태의 실행 파일을 만들어 내는 과정이다.

 

 

 

 

 

, 앞의 예에서 gcclinux.c 파일을 컴파일하면 컴파일 과정 후에 링크 작업을 자동으로 해 준다.

 

 

 

그리고 링크 작업의 결과 실행 파일이 생성된 것이다.

 

 

 

 

 

그렇다면 이번 예에서는 컴파일 작업과 링크 작업을 별도로 수행해 보도록 한다.

 

 

 

아래의 예는 gcc 컴파일러에 c 옵션을 사용한 것으로 c 옵션은 컴파일 작업만 수행할 뿐 링크 작업은 수행하지 말라는 옵션이다.

 

 

 

, 목적 파일을 생성하라는 옵션이다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# gcc -c linux.c

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# ls -l

합계 36

-rw-r--r-- 1 root root 90 62 16:34 linux.c

-rw-r--r-- 1 root root 1512 62 16:59 linux.o

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

 

위의 “gcc c linux.c”의 결과 생성된 linux.o 파일은 컴파일 결과로 생성된 목적 파일로서 링크 작업이 수행되지 않은 단지 목적 파일일 뿐이다.

 

 

 

 

 

그리고 이번에는 위에서 생성된 linux.o 라는 목적 파일을 가지고 링크 작업을 수행하는 예이다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# gcc -o linux linux.o

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# ls -l

합계 36

-rwxr-xr-x 1 root root 25792 62 17:01 linux

-rw-r--r-- 1 root root 90 62 16:34 linux.c

-rw-r--r-- 1 root root 1512 62 16:59 linux.o

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

 

, 위의 예에서 “gcc o linux linux.o”는 목적 파일(linux.o)을 가지고 링크 작업을 수행한 것이다.

 

 

 

그 결과 o 옵션에서 지정한 실행 파일명(linux)으로 실제 실행 파일을 생성하였다.

 

 

 

 

 

위와 같이 gcc를 이용하여 컴파일 작업과 링크 작업을 각각 분리하여 수행하였다.

 

 

 

이번 예에서 말하고자 하는 것은 우리가 흔히 C 소스코드 파일을 가지고 실행 파일을 만들어내는 컴퓨터 파일이라는 것은 컴파일 작업과 링크 작업을 함께 수행한 것이라는 점이다.

 

 

 

 

다음은 gcc 컴파일러를 이용하여 두 개 이상의 C 소스코드 파일을 각각 컴파일하고 그 결과 생성된 각각의 목적 파일로 링크하는 예이다.

 

 

 

 

 

 

 

 

아래의 예를 보면 main.cprint.c 두 개의 C 소스코드 파일이 있다.

 

 

 

그리고 이 두 개의 소스코드 파일의 내용을 살펴보기 위하여 cat 명령어로 main.cprint.c를 각각 살펴보았다.

 

 

 

 

 

 

 

 

 

[root@RockyLinux01 test]# ls -l

합계 8

-rw-r--r-- 1 root root 85 62 17:04 main.c

-rw-r--r-- 1 root root 63 62 17:05 print.c

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# cat main.c

#include <stdio.h>

 

void print(void);

 

int main(void)

{

print()

return()

}

[root@RockyLinux01 test]#

[root@RockyLinux01 test]#

[root@RockyLinux01 test]# cat print.c

void print(void)

{

printf("Welcome www.superuser.co.kr \n")

}

[root@RockyLinux01 test]#

 

 

 

 

 

 

 

 

위의 소스코드 파일을 보면 main.c에서 print.c 파일에 있는 print() 함수를 불러들이고 있다.

 

 

 

 

 

이제 위의 C 소스코드 파일 두 개를 동시에 컴파일 해보도록 한다.

 

 

 

, 아래의 예는 main.cprint.c를 동시에 컴파일하는 예이다.

 

 

 

그 결과 목적 파일인 main.o 파일과 print.o 파일이 각각 생성되었다.

 

 

 

 

 

 

 

 

 

[root@sulinux ~]# gcc c main.c print.c

[root@sulinux ~]# ls l

total 16

-rw-r--r-- 1 root root 80 Mar 25 23:53 main.c

-rw-r--r-- 1 root root 704 Mar 25 23:57 main.o

-rw-r--r-- 1 root root 64 Mar 25 23:54 print.c

-rw-r--r-- 1 root root 808 Mar 25 23:57 print.o

[root@sulinux ~]#

 

 

 

 

 

 

 

 

그리고 위의 컴파일 결과로 생성된 main.o 파일과 print.o 파일을 가지고 링크 작업을 하도록 한다.

 

 

 

, 아래의 예는 main.oprint.o 파일을 가지고 링크 작업을 수행하며 o 옵션에서 지정한 superuser라는 실행 파일을 그 결과로서 생성한다.

 

 

 

 

 

 

 

 

 

[root@sulinux ~]# gcc o superuser main.o print.o

[root@sulinux ~]# ls l

total 16

-rw-r--r-- 1 root root 80 Mar 25 23:53 main.c

-rw-r--r-- 1 root root 704 Mar 25 23:57 main.o

-rw-r--r-- 1 root root 64 Mar 25 23:54 print.c

-rw-r--r-- 1 root root 808 Mar 25 23:57 print.o

-rwxr-xr-x 1 root root 11675 Mar 25 23:59 superuser

[root@sulinux ~]#

 

 

 

 

 

 

 

 

이렇게 생성된 superuser 실행 파일을 실행한 결과 “Welcome www.superuser.co.kr”가 실행이 되었다.

 

 

 

또한 위의 컴파일 과정과 링크 과정을 한꺼번에 하기 위해서는 다음과 같이 한다.

 

 

 

뒤의 소스코드 파일들은 2개 이상 나열할 수 있다.

 

 

 

다만, 이 경우에는 각각의 소스코드 파일에 작은 변경을 하는 경우에도 전체를 컴파일해야 하는 단점이 있다.

 

 

 

따라서 위와 같이 각각의 소스코드를 별도로 컴파일하여 링크를 하는 것이 효율적일 수 있다.

 

 

 

 

 

 

 

 

[root@sulinux ~]# gcc o superuser main.c print.c

 

 

 

 

 

 

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,043 명
  • 현재 강좌수 :  35,854 개
  • 현재 접속자 :  122 명