1. 컴파일과 링크와 실행 파일 만들기
- C프로그램 소스를 컴파일러로 컴파일.
- gcc는 '컴파일러 드라이버'라고 불리며, 소스 코드의 빌드 과정을 순차적으로 실행하는 명령이다.
- 아래와 같은 과정 수행
1) 프리프로세서(전처리기)에 의한 파일 포함과 매크로 처리
2) 어셈블리 코드로 컴파일하고 어셈블 과정을 거쳐 오브젝트 파일로 변환
3) 오브젝트 파일 결합과 라이브러리 링크
*프리프로세서(Preprocessor)의 처리
- 원시코드를 컴파일러에 인도하기 전에 특정한 변수를 그것에 대응하는 정의된 문자열로 치환하는 등의 일을 하는 프로그램
1) 매크로 정의(Macro Definition) - #define 매크로명 치환문자열, 매크로 명이 기록된 곳을 모두 치환문자열로 변환하는 기능
2) 매크로 확장(Macro Expansion) - #define SQUARE(x) (x*y), 인수를 동반하는 문자열 치환 매크로 허용.
3) 파일 포함(File inclusion) - #include "파일명" or <파일명>, 파일명에 의해 지시되는 파일 전체가 프로그램내에 삽입
4) 기타 프로세서 명령어 : #undef-define 해제, #ifdef, #else, #endif, #if
출처 : 요기
* 어셈블리어(Assembly Language) : 기계어와 일대일 대응 되는 컴퓨터 프로그래밍의 저급언어
- 컴퓨터 구조에 따라 사용하는 기계어가 달라지며, 따라서 기계어에 대응되어 만들어지는 어셈블리어도 각각 다름.
--> 기계어는 실제 컴퓨터의 CPU가 읽어서 실행할 수 있는 0과 1로 이루어진 명령어의 조합. 이러한 각 명령어에 대해 사람이 알아보기 쉬운 니모닉(mnemonic symbol)를 정해 사람이 좀 더 쉽게 컴퓨터의 행동을 제어할 수 있도록 한 것.
출처 : 위키
* 오브젝트 파일(Object File) : PE(Portable Executable)- windows, COFF(Common Object File Format), EFL(Executable and Linking Format)- Unix, Linux, Solaris. 등등
- 목적코드 또는 목적파일, 컴파일러나 어셈블러가 소스코드 파일을 컴파일 또는 어셈블해서 생성하는 파일. 목적파일들은 기계어나 혹은 이에 준하는 RTL과 같은 이진 코드로 이루어져 있다.
- 오브젝트 파일의 세가지 타입
1) 재배지 가능한 오브젝트 파일(Relocatable object file) : 실행가능한 오브젝트 파일을 만들기 위해 컴파일타임떄 재배치 가능한 다른 오브젝트 파일들과 결합될 수 있는 것
2) 실행 가능한 오브젝트 파일(Executable Object File) : 바이너리 코드와 데이터를 갖고 있으며 메모리로 직접 로드되어 실행
3) 공유 오브젝트 파일(Shared Object File) : 로드타임이너 런타임 시 동적으로 메모리로 로드되고 링킹될수 있다.
출처 : 위키, KLDP 위키
* Linking : 여러 개로 나눠진 오브젝트 파일을 하나로 합치는 역할
- 일반적으로 하나의 프로그램은 여러 개의 오브젝트 파일과 공용 라이브러리의 조합. 하나의 실행할 수 있는 프로그램을 완성하기 위해 링킹(Linking)이란 작업 수행. 코드를 컴파일과정과 링킹 과정을 거치면 사용자가 실행할 수 있는 실행파일이 생성.
* Loader : 완성된 실행파일을 사용자가 실행하게 되면 해당 프로그램을 메모리에 적재(Load)시키고 내용에 따라 프로그램 수행. 이러한 일을 수행하는 프로그램
출처 :요기
2. gcc 컴파일
- 일반적으로 명령어를 수행하는 방법은 아래와 같다.
1 | $ gcc test.c -o test | cs |
* -c 옵션을 사용하면 오브젝트 파일을, -s 옵션을 사용하면 어셈블리 파일까지 생성된다.
- 파일 분할 ( 두개의 파일 test1.c test2.c 준비)
test1.c
1 2 3 4 5 6 | #include <stdio.h> void function1() { printf("hello from function No.1\n"); } | cs |
test2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <stdio.h> void function2() { printf("Hello from function No.2\n"); } int main() { function1(); function2(); return 0; } | cs |
아래와 같이 컴파일하면 결과 생성.
1 | gcc test1.c test2.c -o test | cs |
그러나 분할한 각 소스는 개별적인 오브젝트 파일로 컴파일이 가능하다.
1 2 3 | $ gcc test1.c test2.c -c $ ls test1.c test1.o test2.c test2.o | cs |
각각의 오브젝트 파일을 별도로 링크해서 실행파일을 만들 수도 있다.
1 | $ gcc test1.o test2.o -o test | cs |
파일의 부분적인 수정을 할 경우, test1.c를 아래와 같이 수정한다.
test1.c
1 2 3 4 5 6 | #include <stdio.h> void function1() { printf("hello from function No.1!!!!\n"); } | cs |
아래와 같이 test1.c의 오브젝트파일만을 생성하고 링킹시켜주면 된다.
1 2 3 4 5 | $ gcc test1.c -c $ gcc test1.o test2.o -o test $./test hello from function No.1!!!!!! Hello from function No.2 | cs |
*프로그램 소스를 분할하는 이유
1) 프로그램의 구조화 : 프로그램 전체를 각각의 파일로 나누면 프로그램 전체의 구성 파악이 쉬워진다.
2) 빌드 시간 단축 : 일반적으로 컴파일에는 시간이 걸린다. 그러나 위에서 본 분할 컴파일 예와같이 소스코드를 나눠두면 일부분을 수정했을 때 그 파일만 다시 컴파일하면 된다. 새로 컴파일된오브젝트파일을 링크하면 전체를 갱신할 수 있기 때문이다.
3) 여러 개발자에 의한 개발
4) 유지보수 향상
'개발 > Linux' 카테고리의 다른 글
우분투에서 쉽게 동영상 캡쳐하기 (0) | 2018.01.20 |
---|---|
삼바 연결 끊길 경우 방법 (0) | 2017.07.28 |
리눅스 파티션 나누기 (0) | 2017.07.25 |
우분투 환경에서 C언어로 배우는리눅스 프로그래밍-1. 개념정리 (0) | 2017.07.02 |
Linux Ubuntu USB 만들기 (0) | 2017.04.19 |