2장. C 또는 C++ 애플리케이션 생성
2.1. GCC를 사용하여 코드 빌드
소스 코드를 실행 코드로 변환해야 하는 상황에 대해 알아봅니다.
2.1.1. 코드 양식의 관계
사전 요구 사항
- 컴파일 및 연결의 개념 이해
가능한 코드 양식
C 및 C++ 언어는 다음 세 가지 형식을 지원합니다.
C 또는 C++ 언어로 작성된 소스 코드는 일반 텍스트 파일로 제공됩니다.
일반적으로 파일은
.c,.
cc,.
cpp,.
h,.
hpp,.
i,.
inc
등의 확장 프로그램을 사용합니다. 지원되는 확장 기능 및 해석의 전체 목록은 gcc 도움말 페이지를 참조하십시오.$ man gcc
컴파일러 로 소스 코드를 컴파일 하여 생성된 개체 코드입니다. 이는 중간 형식입니다.
오브젝트 코드 파일은
.o
확장자를 사용합니다.개체 코드를 링커 와 연결하여 만든 실행 코드.
Linux 애플리케이션 실행 파일은 파일 이름 확장자를 사용하지 않습니다. 공유 오브젝트(library) 실행 파일은
.so
파일 이름 확장자를 사용합니다.
정적 연결을 위한 라이브러리 아카이브 파일도 존재합니다. 이것은 .a
파일 이름 확장을 사용하는 오브젝트 코드의 변형입니다. 정적 연결은 권장되지 않습니다. 2.2.2절. “정적 및 동적 연결”을 참조하십시오.
GCC에서 코드 양식 처리
소스 코드에서 실행 가능한 코드를 생성하는 작업은 두 단계로 수행되며 서로 다른 애플리케이션 또는 도구가 필요합니다. GCC는 컴파일러와 링커 모두에 대한 지능형 드라이버로 사용할 수 있습니다. 이렇게 하면 필수 작업(컴파일링 및 연결)에 단일 gcc
명령을 사용할 수 있습니다. GCC는 작업 및 해당 시퀀스를 자동으로 선택합니다.
- 소스 파일은 오브젝트 파일로 컴파일됩니다.
- 오브젝트 파일과 라이브러리가 연결되어 있습니다(이전 컴파일된 소스 포함).
단일 단계에서 컴파일, 연결 또는 컴파일 및 연결을 모두 수행할 수 있도록 GCC를 실행할 수 있습니다.It is possible to run GCC so that it performs only compiling, only linking, or both compiling and linking in a single step. 입력 유형과 요청된 출력 유형에 따라 결정됩니다.
대규모 프로젝트에는 각 작업에 대해 일반적으로 GCC를 별도로 실행하는 빌드 시스템이 필요하므로 GCC가 두 가지 개별 작업으로 항상 컴파일하고 연결하는 것이 좋습니다.
2.1.2. 개체 코드로 소스 파일 컴파일
소스 파일에서 개체 코드 파일을 즉시 생성하고 실행 파일이 아닌 경우 GCC는 출력으로 개체 코드 파일만 생성하도록 지시해야 합니다. 이 작업은 대규모 프로젝트에 대한 빌드 프로세스의 기본 작업을 나타냅니다.
사전 요구 사항
- C 또는 C++ 소스 코드 파일
- 시스템에 GCC가 설치됨
절차
- 소스 코드 파일이 포함된 디렉터리로 변경합니다.
c
옵션을
사용하여gcc
를 실행합니다.$ gcc -c source.c another_source.c
개체 파일은 원본 소스 코드 파일을 반영하는 파일 이름을 사용하여 생성됩니다
. source.c
는source.o
가 됩니다.참고C++ 소스 코드로
gcc
명령을g++로 교체하여 C++
표준 라이브러리 종속성을 편리하게 처리하십시오.
2.1.3. GCC를 사용하여 C 및 C++ 애플리케이션 디버깅 활성화
디버깅 정보는 크기 때문에 기본적으로 실행 파일에 포함되지 않습니다. C 및 C++ 애플리케이션을 디버깅할 수 있도록 하려면 컴파일러에 이를 명시적으로 지시해야 합니다.
코드를 컴파일하고 연결할 때 GCC 를 사용하여 디버깅 정보를 생성할 수 있도록 하려면 -g
옵션을 사용합니다.
$ gcc ... -g ...
-
컴파일러 및 링커에 의해 수행되는 최적화는 원래 소스 코드와 관련되기 어려운 실행 코드를 초래할 수 있습니다. 변수가 최적화되고, 스크롤되지 않고, 작업이 주변에 병합될 수 있습니다. 이는 디버깅에 부정적인 영향을 미칩니다. 디버깅 환경을 개선하려면
-Og
옵션으로 최적화를 설정하는 것이 좋습니다. 그러나 최적화 수준을 변경하면 실행 코드가 변경되며 일부 버그 제거를 포함하여 실제 동작을 변경할 수 있습니다. -
디버그 정보에 매크로 정의를 포함하려면 g 대신
-g
3 -
f
compare-debug
GCC 옵션은 디버그 정보와 디버그 정보 없이 GCC에서 컴파일한 코드를 테스트합니다. 결과 두 바이너리 파일이 동일한 경우 테스트가 통과합니다. 이 테스트를 사용하면 디버깅 옵션의 영향을 받지 않으므로 디버그 코드에 숨겨진 버그가 없습니다. fcompare-debug
옵션을 사용하면 컴파일 시간이 크게 증가합니다. 이 옵션에 대한 자세한 내용은 GCC 도움말 페이지를 참조하십시오.
추가 리소스
- 3.1절. “디버깅 정보를 사용하여 디버깅 활성화”
- GCC(GNU 컴파일러 컬렉션) 사용 - 프로그램 디버깅 옵션
- GDB를 사용하여 디버깅 - 별도의 파일에 정보 디버깅 https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
GCC 도움말 페이지:
$ man gcc
2.1.4. GCC를 사용한 코드 최적화
단일 프로그램은 2개 이상의 머신 명령어로 변환될 수 있습니다. 컴파일 중 코드를 분석하는 데 더 많은 리소스를 할당하면 더 최적의 결과를 얻을 수 있습니다.
GCC를 사용하면 -O 수준옵션을
사용하여 최적화 수준을 설정할 수 있습니다. 이 옵션은 수준 대신 값 집합을 허용합니다.
level | 설명 |
---|---|
| 컴파일 속도에 최적화 - 코드 최적화(기본값) 없음. |
| 코드 실행 속도를 높이도록 최적화합니다(숫자가 클수록 속도가 증가). |
| 파일 크기에 최적화. |
|
레벨 |
| 디버깅 환경에 최적화. |
릴리스 빌드의 경우 최적화 옵션 -O2
를 사용합니다.
개발 중에 -Og
옵션은 일부 상황에서 프로그램 또는 라이브러리를 디버깅하는 데 유용합니다. 일부 버그 매니페스트는 특정 최적화 수준으로만 표시되므로 릴리스 최적화 수준으로 프로그램 또는 라이브러리를 테스트하십시오.
GCC는 개별 최적화를 가능하게 하는 다양한 옵션을 제공합니다. 자세한 내용은 다음 추가 리소스를 참조하십시오.
추가 리소스
- GNU 컴파일러 컬렉션 사용 - 제어 최적화 옵션
GCC의 Linux 도움말 페이지:
$ man gcc
2.1.5. GCC를 사용하여 코드 강화 옵션
컴파일러가 소스 코드를 개체 코드로 변환할 때 일반적으로 악용되는 상황을 방지하고 보안을 강화하기 위해 다양한 점검을 추가할 수 있습니다. 컴파일러 옵션 집합을 선택하면 소스 코드를 변경할 필요 없이 보다 안전한 프로그램과 라이브러리를 생성할 수 있습니다.
릴리스 버전 옵션
다음은 Red Hat Enterprise Linux를 대상으로 하는 개발자에게 최소 권장 옵션 목록입니다.
$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=2 ...
-
프로그램의 경우
-fPIE
및-pie
Position Independent Executable 옵션을 추가합니다. -
동적으로 연결된 라이브러리의 경우 필수
-fPIC
(Position Independent Code) 옵션은 간접적으로 보안을 강화합니다.
개발 옵션
다음 옵션을 사용하여 개발 중에 보안 결함을 감지합니다. 릴리스 버전 옵션과 함께 다음 옵션을 사용합니다.
$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...
추가 리소스
- Defensive Coding 가이드
- GCC를 사용한 메모리 오류 감지 - Red Hat 개발자 블로그 게시
2.1.6. 실행 가능한 파일 생성을 위한 코드 연결
C 또는 C++ 애플리케이션을 빌드할 때의 마지막 단계는 연결입니다. 연결은 모든 개체 파일과 라이브러리를 실행 파일로 결합합니다.
사전 요구 사항
- 하나 이상의 오브젝트 파일
- gcc는 시스템에 설치되어 있어야 합니다.
절차
- 개체 코드 파일이 포함된 디렉터리로 변경합니다.
gcc
실행 :$ gcc ... objfile.o another_object.o ... -o executable-file
executable-file이라는 실행 가능한 파일은 제공된 오브젝트 파일 및 라이브러리에서 생성됩니다.
추가 라이브러리를 연결하려면 오브젝트 파일 목록 뒤에 필요한 옵션을 추가합니다. 자세한 내용은 2.2절. “GCC와 함께 라이브러리 사용”의 내용을 참조하십시오.
참고C++ 소스 코드로
gcc
명령을g++로 교체하여 C++
표준 라이브러리 종속성을 편리하게 처리하십시오.
2.1.7. 예제: GCC를 사용하여 C 프로그램 빌드(한 단계로 컴파일 및 연결)
이 예에서는 간단한 샘플 C 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서는 코드를 컴파일하고 연결하는 작업이 한 단계로 수행됩니다.
사전 요구 사항
- GCC 사용 방법을 알아야 합니다.
절차
hello-c
디렉터리를 생성하고 변경합니다.$ mkdir hello-c $ cd hello-c
다음 콘텐츠를 사용하여
hello.c
파일을 생성합니다.#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }
GCC로 코드를 컴파일하고 연결합니다.
$ gcc hello.c -o helloworld
이렇게 하면 코드가 컴파일되고, 오브젝트 파일
hello.o
를 생성하고, 오브젝트 파일에서 실행 파일helloworld
를 연결합니다.결과 실행 파일을 실행합니다.
$ ./helloworld Hello, World!
2.1.8. 예제: GCC로 C 프로그램 빌드(두 단계로 컴파일 및 연결)
이 예에서는 간단한 샘플 C 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서는 코드를 컴파일하고 연결하는 방법은 두 가지입니다.
사전 요구 사항
- GCC 사용 방법을 알아야 합니다.
절차
hello-c
디렉터리를 생성하고 변경합니다.$ mkdir hello-c $ cd hello-c
다음 콘텐츠를 사용하여
hello.c
파일을 생성합니다.#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }
GCC를 사용하여 코드를 컴파일하십시오.
$ gcc -c hello.c
오브젝트 파일
hello.o
가 생성됩니다.오브젝트 파일에서 실행 가능한 파일
helloworld
를 연결합니다.$ gcc hello.o -o helloworld
결과 실행 파일을 실행합니다.
$ ./helloworld Hello, World!
2.1.9. 예제: GCC로 C++ 프로그램 빌드(단일 단계로 컴파일 및 연결)
이 예에서는 샘플 최소 C++ 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서는 코드를 컴파일하고 연결하는 작업이 한 단계로 수행됩니다.
사전 요구 사항
-
gcc
와g++
의 차이점을 이해해야 합니다.
절차
hello-cpp
디렉터리를 생성하고 변경합니다.$ mkdir hello-cpp $ cd hello-cpp
다음 콘텐츠를 사용하여
hello.cpp
파일을 생성합니다.#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }
코드를 컴파일하고
g++
로 연결 :$ g++ hello.cpp -o helloworld
이렇게 하면 코드가 컴파일되고, 오브젝트 파일
hello.o
를 생성하고, 오브젝트 파일에서 실행 파일helloworld
를 연결합니다.결과 실행 파일을 실행합니다.
$ ./helloworld Hello, World!
2.1.10. 예제: GCC로 C++ 프로그램 빌드(두 단계로 컴파일 및 연결)
이 예에서는 샘플 최소 C++ 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서는 코드를 컴파일하고 연결하는 방법은 두 가지입니다.
사전 요구 사항
-
gcc
와g++
의 차이점을 이해해야 합니다.
절차
hello-cpp
디렉터리를 생성하고 변경합니다.$ mkdir hello-cpp $ cd hello-cpp
다음 콘텐츠를 사용하여
hello.cpp
파일을 생성합니다.#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }
g++
로 코드를 컴파일하십시오.$ g++ -c hello.cpp
오브젝트 파일
hello.o
가 생성됩니다.오브젝트 파일에서 실행 가능한 파일
helloworld
를 연결합니다.$ g++ hello.o -o helloworld
결과 실행 파일을 실행합니다.
$ ./helloworld Hello, World!