2.2. GCC를 사용하여 코드 빌드
소스 코드를 실행 코드로 변환해야 하는 상황에 대해 알아봅니다.
2.2.1. 코드 양식 간 관계 링크 복사링크가 클립보드에 복사되었습니다!
C 및 C++ 언어에는 빌드 프로세스의 다양한 단계를 통해 생성되는 세 가지 형태의 코드가 있습니다. 이러한 관계를 이해하면 GCC에서 효과적으로 작업할 수 있습니다.
C 및 C++ 언어에는 세 가지 형태의 코드가 있습니다.
C 또는 C++ 언어로 작성된 소스 코드 는 일반 텍스트 파일로 제공됩니다.
파일은 일반적으로
.c.cc,.cpp,.h,.i.i와 같은 확장자를사용합니다.지원되는 확장 기능 및 해석의 전체 목록은 gcc 매뉴얼 페이지를 참조하십시오.$ man gcc컴파일러로 소스 코드를 컴파일 하여 생성된 개체 코드입니다. 이는 중간 형식입니다.
오브젝트 코드 파일은
.o확장자를 사용합니다.개체 코드를 링커 와 연결하여 생성된 실행 코드 .
Linux 애플리케이션 실행 파일은 파일 이름 확장자를 사용하지 않습니다. 공유 오브젝트( Cryostat) 실행 파일은
.so파일 이름 확장자를 사용합니다.
정적 연결을 위한 라이브러리 아카이브 파일도 있습니다. 이는 .a 파일 이름 확장을 사용하는 오브젝트 코드의 변형입니다. 정적 연결은 권장되지 않습니다. 정적 및 동적 연결을 참조하십시오.
소스 코드에서 실행 가능한 코드를 생성하는 작업은 다음 두 단계로 수행되며, 이 단계는 다른 애플리케이션 또는 툴이 필요합니다.
- 소스 파일은 오브젝트 파일로 컴파일됩니다.
- 오브젝트 파일 및 라이브러리가 연결되어 있습니다(이전의 컴파일된 소스 포함).
GCC는 컴파일러와 링커 둘 다에 대한 지능형 드라이버로 사용할 수 있습니다. 이를 통해 필요한 작업(컴파일 및 연결)에 대해 단일 gcc 명령을 사용할 수 있습니다. GCC는 작업 및 해당 시퀀스를 자동으로 선택합니다.
GCC를 실행하여만 컴파일하거나 링크만 실행하거나 두 단계를 수행할 수 있습니다. 이는 입력 유형 및 요청된 출력 유형에 따라 결정됩니다.
대규모 프로젝트에는 일반적으로 각 작업을 위해 GCC를 별도로 실행하는 빌드 시스템이 필요하므로 GCC가 동시에 수행할 수 있더라도 컴파일 및 연결을 두 가지 작업으로 사용하는 것이 좋습니다.
2.2.2. 소스 파일을 오브젝트 코드로 컴파일 링크 복사링크가 클립보드에 복사되었습니다!
즉시 실행 파일이 아닌 소스 파일에서 오브젝트 코드 파일을 생성하려면 GCC에 오브젝트 코드 파일만 출력으로 생성하도록 지시해야 합니다. 이 작업은 대규모 프로젝트의 빌드 프로세스의 기본 작업을 나타냅니다.
사전 요구 사항
- C 또는 C++ 소스 코드 파일
- GCC가 시스템에 설치되어 있음
프로세스
- 터미널에서 소스 코드 파일이 포함된 디렉터리에 대해 엽니다.
-c옵션을 사용하여gcc를 실행합니다.$ gcc -c source.c another_source.c오브젝트 파일은 원래 소스 코드 파일을 반영하는 파일 이름으로 생성됩니다.
source.c결과는source.o입니다.참고C++ 소스 코드를 사용하면 C++ 표준 라이브러리 종속성을 편리하게 처리하기 위해
gcc명령을g++로 바꿉니다.
2.2.3. GCC를 사용하여 C 및 C++ 애플리케이션 디버깅 활성화 링크 복사링크가 클립보드에 복사되었습니다!
컴파일러는 바이너리를 작게 유지하기 위해 기본적으로 디버그 정보를 생략합니다. C 및 C++ 애플리케이션을 디버깅할 수 있도록 하려면 컴파일러에 디버깅 데이터를 생성하도록 명시적으로 지시해야 합니다.
프로세스
C 또는 C++ 애플리케이션을 GCC로 컴파일하고 연결할 때 디버깅 정보를 생성하려면 컴파일 명령에
-g옵션을 추가합니다.$ gcc ... -g ...이 옵션은 GCC에 출력 바이너리에 디버그 정보를 포함하도록 지시합니다.
-g옵션 및 추가 디버깅 옵션에 대한 자세한 내용은 GCC 매뉴얼 페이지를 참조하십시오.디버그 정보에 매크로 정의를 포함하려면 -g 대신
옵션을 사용합니다.-g3$ gcc ... -g3 ...디버그 옵션이 실행 코드에 영향을 미치지 않는지 테스트하려면
-fcompare-debugGCC 옵션을 사용합니다. 이 옵션은 다음과 같습니다.- 디버그 정보를 사용하여 한 번 코드를 두 번 컴파일합니다.
- 생성된 바이너리 파일 비교
두 바이너리가 동일한 경우 테스트를 통과합니다.
이 테스트에서는 디버깅 옵션이 코드에 숨겨진 버그를 도입하지 않도록 합니다.
-fcompare-debug를 사용하면 컴파일 시간이 크게 증가합니다. 자세한 내용은 GCC 매뉴얼 페이지를 참조하십시오.중요컴파일러 및 링커 최적화는 다음을 통해 디버깅을 어렵게 만들 수 있습니다. * 사용되지 않는 것으로 표시되는 변수 제거 * 루프 병합 * 작업 병합 * 소스 코드와 실행 코드 간의 관계 변경
디버깅 환경을 개선하려면
-Og옵션을 사용하는 것이 좋습니다. 그러나 최적화 수준을 변경하면 실행 코드 동작을 변경하고 잠재적으로 버그를 숨길 수 있습니다.
2.2.4. GCC를 사용한 코드 최적화 링크 복사링크가 클립보드에 복사되었습니다!
단일 프로그램은 하나 이상의 일련의 머신 명령으로 변환될 수 있습니다. 컴파일 중에 코드를 분석하는 데 더 많은 리소스를 할당하면 최적의 결과를 얻을 수 있습니다.
GCC를 사용하면 -O 수준 옵션을 사용하여 최적화 수준을 설정할 수 있습니다. 이 옵션은 수준 대신 값 집합을 허용합니다.
| level | 설명 |
|---|---|
|
| 컴파일 속도를 최적화 - 코드 최적화(기본값) 없음. |
|
| 코드 실행 속도를 높이기 위해 최적화합니다(숫자가 클수록 속도가 커집니다). |
|
| 파일 크기에 맞게 최적화합니다. |
|
|
레벨 |
|
| 디버깅 환경을 위해 최적화합니다. |
릴리스 빌드의 경우 최적화 옵션 -O2 를 사용합니다.
개발 중에 -Og 옵션은 일부 상황에서 프로그램 또는 라이브러리를 디버깅하는 데 유용합니다. 일부 버그는 특정 최적화 수준에서만 표시되므로 릴리스 최적화 수준으로 프로그램 또는 라이브러리를 테스트합니다.
GCC는 개별 최적화를 활성화하는 다양한 옵션을 제공합니다. 자세한 내용은 gcc 도움말 페이지를 참조하십시오.
2.2.5. GCC를 사용하여 코드 강화 옵션 링크 복사링크가 클립보드에 복사되었습니다!
컴파일러가 소스 코드를 개체 코드로 변환하면 일반적으로 악용되는 상황을 방지하고 보안을 강화하기 위해 다양한 검사를 추가할 수 있습니다. 올바른 컴파일러 옵션 집합을 선택하면 소스 코드를 변경하지 않고도 더 안전한 프로그램 및 라이브러리를 생성하는 데 도움이 될 수 있습니다.
- 릴리스 버전 옵션
다음 옵션 목록은 Red Hat Enterprise Linux를 대상으로 하는 개발자에게 권장됩니다.
$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=3 ...-
프로그램의 경우
-fPIE및-pieWITH independent Executable 옵션을 추가합니다. -
동적으로 연결된 라이브러리의 경우 필수
-fPIC(Independent Code) 옵션을 통해 보안이 간접적으로 증가합니다.
-
프로그램의 경우
- 개발 옵션
다음 옵션을 사용하여 개발 중에 보안 결함을 탐지합니다. 릴리스 버전의 옵션과 함께 이러한 옵션을 사용합니다.
$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...- -
fhardened -
GCC 14는 새로운 플래그인
-fhardened를 제공하여 ABI에 영향을 주지 않고 생성된 코드의 보안을 개선할 수 있는 여러 다른 플래그를 사용할 수 있습니다. - -
Falyzer -
GCC는 보안 관련 문제를 포함하여 소스 코드의 잠재적인 문제에 대한 경고를 트리거하는
-fanalyzer플래그를 제공합니다.-fanalyzer는 종종 잘못된 긍정 및 음수를 가지고 있기 때문에 공식적인 분석 도구가 아닌 더 많이 조사해야하는 잠재적 버그를 찾는 데 사용해야합니다. 이 플래그는 컴파일 중에 사용된 시간과 메모리를 크게 늘립니다. C 코드에서만 사용하십시오.
2.2.6. 실행 파일을 생성하기 위해 코드 연결 링크 복사링크가 클립보드에 복사되었습니다!
링크는 C 또는 C++ 애플리케이션을 빌드할 때 최종 단계입니다. 링크는 모든 오브젝트 파일 및 라이브러리를 실행 파일로 결합합니다.
사전 요구 사항
- 하나 이상의 오브젝트 파일
- gcc가 시스템에 설치되어 있어야 함
프로세스
- 오브젝트 코드 파일이 포함된 디렉터리로 변경합니다.
run
gcc:$ gcc ... objfile.o another_object.o ... -o executable-fileexecutable-file 이라는 실행 파일은 제공된 오브젝트 파일 및 라이브러리에서 생성됩니다. 추가 라이브러리를 연결하려면 오브젝트 파일 목록 뒤에 필요한 옵션을 추가합니다.
자세한 내용은 GCC에서 라이브러리 사용을 참조하십시오.
참고C++ 소스 코드를 사용하면 C++ 표준 라이브러리 종속성을 편리하게 처리하기 위해
gcc명령을g++로 바꿉니다.
추가 리소스
2.2.7. 예: GCC를 사용하여 C 프로그램 빌드(단일 단계로 컴파일 및 연결) 링크 복사링크가 클립보드에 복사되었습니다!
이 예제에서는 간단한 예제 C 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서는 코드를 컴파일하고 연결하는 것은 한 단계로 수행됩니다.
프로세스
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.o를 만들고 개체 파일에서 실행 파일helloworld를 연결합니다.결과 실행 파일을 실행합니다.
$ ./helloworldHello, World!
추가 리소스
2.2.8. 예: GCC를 사용하여 C 프로그램 빌드( 두 단계로 컴파일 및 연결) 링크 복사링크가 클립보드에 복사되었습니다!
이 예제에서는 간단한 예제 C 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서 코드를 컴파일하고 연결하는 것은 두 가지 별도의 단계입니다.
프로세스
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!선택 사항: 상위 디렉터리로 다시 변경합니다.
$ cd ..선택 사항:
hello-c디렉터리를 제거합니다.$ rm -r hello-c
추가 리소스
2.2.9. 예: GCC를 사용하여 C++ 프로그램 빌드(단 단계로 컴파일 및 연결) 링크 복사링크가 클립보드에 복사되었습니다!
이 예제에서는 샘플 최소 C++ 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서는 코드를 컴파일하고 연결하는 것은 한 단계로 수행됩니다.
프로세스
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.o를 만들고 개체 파일에서 실행 파일helloworld를 연결합니다.결과 실행 파일을 실행합니다.
$ ./helloworldHello, World!선택 사항: 상위 디렉터리로 다시 변경합니다.
$ cd ..선택 사항:
hello-cpp디렉터리를 제거합니다.$ rm -r hello-cpp
2.2.10. 예: GCC를 사용하여 C++ 프로그램 빌드( 두 단계로 컴파일 및 연결) 링크 복사링크가 클립보드에 복사되었습니다!
이 예제에서는 샘플 최소 C++ 프로그램을 빌드하는 정확한 단계를 보여줍니다.
이 예제에서 코드를 컴파일하고 연결하는 것은 두 가지 별도의 단계입니다.
프로세스
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결과 실행 파일을 실행합니다.
$ ./helloworldHello, World!선택 사항: 상위 디렉터리로 다시 변경합니다.
$ cd ..선택 사항:
hello-cpp디렉터리를 제거합니다.$ rm -r hello-cpp