섹션 3-2: 빌드단계
63. 소스코드에서 실행파일까지, C프로그램의 빌드 과정
- 소스코드가 어떻게 기계어로 변화되는가
- C 프로그램의 빌드과정
- 빌드란 소스코드를 기계어 명령어로 변환하는 과정
- 빌드는 전처리, 컴파일, 어셈블, 링크의 4단계로 나뉘어져 있음. 컴파일 + 링크의 2단계로 분류하기도 함.
- C 프로그램의 빌드과정 2
- 소스코드 -> 컴파일러 -> 어셈블리 코드 -> 어셈블러 -> 오브젝트 코드 -> 링커 -> 실행파일.
- clang에서 4단계를 한번에 처리해 줬었음.
int adder(const int a, const int b)
64. .c와 .h 파일
- .h
- C 파일 : 함수정의, 전역변수, 매크로 포함, 실제 프로그램을 도는 로직
- 헤더파일 : 함수선언, 매크로, extern 변수 포함, 여러 소스코드에서 공유하고 싶은 것들.
- 메인함수에서 컴파일시 함수의 원형을 알아야 하는데, include된 헤더파일을 참조하여 함수의 원형을 파악한다.
65. 헤더파일이 필요한 이유
- 반드시 필요하진 않지만 편의상 헤더를 활용하는게 좋음
- 모든 소스를 한파일에 삽입시 관리가 매우매우 어렵다.
- 동일한 함수를 여러 파일에서 사용시 중복문제 해결?
- 헤더를 활용해서 함수 선언을 여러 파일과 공유 가능
- 헤더파일의 존재로 정의없이 선언만 된 함수를 컴파일 가능 (링크 단계에서 문제 생기긴 함)
66. #include < >, " "의 차이
- < >는 시스템 경로에서만 헤더파일을 검색
- " "는 현재 작업중인 디렉터리에서 검색 후 시스템 경로를 검색
67. 빌드과정 : 전처리 단계
- 전처리 단계
- 전처리기가 담당
- 주석제거 -> 매크로 복붙 -> 인클루드 파일 복붙 (예외적으로 컴파일 속도향상을 위해 .c파일을 인클루드 하기도 함)
- 전처리 단계의 출력
- 확장된 소스코드 : 트랜슬레이션 유닛
68. 트랜슬레이션 유닛 보는 법
- 컴파일 도중에 -E 플래그를 넣으면 화면에 결과가 출력됨.
69. 빌드과정 : 컴파일 단계
- 컴파일 단계
- 트랜슬레이션 유닛을 입력으로 받아 어셈블리어코드 출력
- 어셈블리어는 하드웨어와 아주 가깝지만 텍스트파일이어서 읽기 가능하긴 함.(기계는 모름)
- 어셈블리어코드는 정의를 모르는 심볼을 사용가능.
- 정의를 못찾을 경우 비워둠
- 추후 링커가 구멍을 보완
70. 어셈블리어 보는 방법
- 컴파일 -S 플래그 사용
- 어셈블리어 코드가 나왔다는 의미
- 이제부터 특정 플랫폼에 종속된다는 뜻
- 플랫폼에 따른 자료형 크기를 반영하여 뱉어낸 코드임.
71. 빌드과정: 어셈블 단계
- 어셈블 단계
- 어셈블러 라는 프로그램이 담당
- 어셈블리어 입력을 오브젝트 코드(기계어)로 출력
- 아직 메꿔야 하는 구멍이 있음
72. 오브젝트 코드 보는법
- 오브젝트 보는 법 : main.o
- -c 플래그를 넣어 컴파일 한다.
- 일반 텍스트 편집기에서는 깨짐 hex editor 등으로 볼 수 있음.
73. 빌드과정 : 링크단계
- 링크 단계
- 모든 오브젝트 코드를 입력으로 받아 실행파일을 출력함.
- 어셈블리 코드의 레이블을 상응하는 메모리 주소로 점프하는 코드로 바꾼다.
74. 링크 단계가 분리되어 있는 이유
- 수많은 .c파일의 구멍을 컴파일 단계에서 메꾸기 어려움
- 여러 개의 .c파일에서 동일한 외부 함수를 사용할 경우 해당 함수 정의가 중복으로 들어가는 것도 막아야 함.
- 하나의 .c파일만 변경되었을 때 모든 파일을 다시 컴파일해야됨?
- 결론은 .c 파일 개별적으로 컴파일해서 obj파일로 저장해 두는 방법이 낫다.
- obj 파일로 .exe 만드는 방법
clang -std=c89 -W -Wall -pedantic-errors main.o adder.o
75. 라이브러리, 정적/동적 라이브러리와 링크
- 라이브러리로도 빌드 가능
- 빌드 결과를 라이브러리로도 가능
- 라이브러리란 함수 등을 기계어로 변환하여 파일에 저장해 놓은 것. 추후에 링크해서 활용가능
- 정적/동적 라이브러리가 있다.
- 정적 라이브러리와 링크
- 정적링킹이라 함.
- 라이브러리의 기계어를 실행파일에 복사함
- 파일의 크기가 커지고 메모리를 많이 차지하지만 실행속도가 빠르다는 장점 존재
- 동적 라이브러리와 링크
- 동적링킹
- 실행파일에 여전히 구명을 남겨둠
- 실행할 때 운영체제에 의해 링킹 일어남
- 게임할 때 dll 오류가 뜰때
- 동적 링킹의 장점
- 실행파일 크기가 작다
- 여러 실행파일이 동일한 라이브러리를 공유하여 메모리가 절약됨
76. 분할 컴파일과 전역변수
- 여러개의 파일과 C 빌드
- 굉장히 큰 프로젝트면 비슷한 기능별로 파일에 저장함.
- 여러 개의 파일이 어떻게 컴파일되는지 알 필요 있음.
- 분할 컴파일
- 각 파일을 개별적으로 컴파일해서 obj파일 만듦
- obj파일을 서로 링크해서 실행파일을 만듬
77. 다른 파일에 있는 전역변수 사용시 문제점
- 왜 컴파일 오류가 나지?
- 다른 파일에 정의된 전역변수는 알 수 없음.
- 동일 이름의 전역변수를 중복정의하면 링커오류 뱉어냄
- 다른 방법이 필요하다.
- 컴파일러에게 특정 파일안의 전역변수를 가져다 쓴다고 말해줘야 한다.
- 해당 변수를 비워 두고 컴파일
78. extern
- extern 키워드
- .h 파일에 extern int g_mob_count; 삽입하고,
main.c에 .h를 인클루드 하거나 extern 선언을 직접해준다. (사실 둘은 동일함) - 다른 파일에 있는 전역변수에 접근하기 위해선 extern 키워드 사용한다.
- .h 파일에 extern int g_mob_count; 삽입하고,
- extern 키워드의 사용 방법
- c파일에 넣을시 해당 파일에서만 사용
- h파일에 넣을시 누구라도 사용할 수 있게
- 이렇게 해도 링커오류
79. 코드보기 : extern 키워드
80. 전역 변수의 문제, static 키워드
- 전역 변수의 문제
- 전역변수는 문제가 있음
- extern 사용시 누구나 확인, 접근 가능하고
- 값이 어디서 변경되는지 파악 어려움
- 내 파일에서만 쓰기 위해선 static 키워드
- static ignores extern
- static 변수의 접근 범위는 해당 파일로 한정됨
- 여전히 전역변수로 실행동안 공간을 차지하고는 있음
- static의 또 다른 의미
- static을 쓰면 개념상 전역변수처럼 활용된다.
- 함수가 최초로 호출될때만 초기화되고, 이후에는 함수 내부의 전역변수로 작동함.
- 접근제어자처럼 흉내내서 활용가능.
- 함수도 static을 넣으면 외부접근을 막을 수 있음.
81. 코드보기 : static 키워드
82. .c와 .h 정리, 순환 헤더 인클루드
- 헤더 파일에는 선언만 들어간다.
- .c 파일에는 정의가 들어간다.
- 순환 헤더 인클루드 방지
- 인클루드 가드 활용한다.
83. 인클루드 가드 작동법
- #ifndef 전처리기 지시문을 통해서 조건적으로 코드를 컴파일하라고 지시함.
- #pragma once
- 표준아니고, 최신 컴파일러에서만 적용됨
- 포팅 생각한다면 인클루드가드 사용할 것
84. 인클루드 가드 예제
- 요약은 생략
85. C 컴파일러의 종류와 특징
- GCC (GNU Compiler Collection)
- Visual C++
- 윈도우 기반에서 주로 활용
- Clang
- LLVM 컴파일러 구조를 사용하는 컴파일러 프론트엔드
- gcc 대신 Clang으로 옮겨가는 추세
86. 정리
- 앞의 헤더를 살펴볼 것.
- 여기까지 다룬 내용은 넘 많아서 한번에 정리가 쉽지 않음
Author And Source
이 문제에 관하여(섹션 3-2: 빌드단계), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@atoye1/섹션-3-2-빌드단계저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)