110 – GCC 옵션(최적화 관련)

성능을 개선시키기 위해 코드를 최적화하여 불필요하거나 비효율적인 계산 과정을 효율적으로 대체하여 코드의 크기와 실행 시간을 줄인다. 그러면 컴파일 시간이 늘고 컴파일 과정에서 메모리 사용량이 늘어나기도 하는 단점이 존재하기도 한다. 실행 최적화를 위해 진행하는 과정에서 발생하는 것인데, 사람이 직접 최적화하는 과정 또한 존재하지만 컴파일러에 의한 자동 최적화 또한 존재한다. 이 옵션은 컴파일러에 의한 자동 최적화를 다룬다.

  • -O

뒤에 숫자를 써줌으로써 최적화 단계를 구분할 수 있다. gcc의 버전마다 차이가 나고, 값이 커질수록 더욱 최적화된 결과물이 나온다. 일반적으로는 -O1, -O2를 주로 이용하고, 오래된 gcc에서도 -O3까지는 기본적으로 지원한다.

  • -O1 | -O 옵션과 같은 간뎨의 옵션으로 최소한으로 스레드 분기 동작 횟수를 줄이고, 호출된 각 함수 반환 시 스택에 인수를 모아 두었다가 동시에 꺼내게 해준다.
  • -O2 | -O1 단계의 최적화와 함께 프로세서가 닫른 명령어의 결과나 캐시 메모리 또는 메모리의 데이터를 기다리는 동안 컴파일러가 다른 명령어를 실행하도록 한다. 컴파일 시간이 더 오래 걸리지만, 수정된 코드는 더 최적화되어 실행이 빨라진다.
  • -O3 | -O2 단계의 모든 최적화와 루프 해체, 그 밖의 프로세서 전용 특징을 포함하여 최적화한다.

이걸로 일단 간단하게 gcc의 옵션을 다 다뤄봤다. 이제 make에 대한 글로 이어지겠다.

109 – GCC 옵션(디버깅 관련)

이 블로그에서는 솔직이 엄청 간단한 레벨에서만 C 언어를 주로 다뤄왔다. 그러나, 대부분의 C 언어를 처음 다루는 사람에게는 이 예제를 따라하다가도 실수를 해서 오류가 많이 생기기도 한다. 그럴 때, 왜 컴파일이 안되지?” 하는 사람들이 있다. 사실 몇 줄 안되는 프로그램이라 쉽게 잡을 수 있다만, 몇 만 라인 이상의 프로그램의 버그를 찾는 것은 쉽지 않다. 이러한 이유로 디버깅을 위한 프로그램인 gdb를 이용하기도 한다. gdb에 대한 것은 나중에 확인해 보겠다.

-g, -ggdb 옵션은 이런 디버거를 사용해 디버깅을 할 때, 좀 더 쉽게 할 수 있도록 정보를 삽입해주는 옵션이다. 그 중에서도 -g 옵션에 대해서 살펴보겠다.

  • -g

-g 옵션은 디버깅 정보의 양에 따라 3 단계로 된다. -g1, -g2, -g3 이렇게 구성되어 있는데,  -g로만 하면 기본적으로 -g2로 인식된다. 이 단계에 대한 자세한 내용은 다음과 같다.

  • -g1 | 역추적 스텍 덤프 생성에 필요한 정보를 포함하지만 지역 변수, 문장 번호를 위한 디버깅 정보는 삽입하지 않는다.
  • -g2 | 확장 기호 테이블, 문장 번호, 지역과 외부 변수에 대한 디버깅 정보를 삽입한다.
  • -g3 | -g2 옵션의 디버깅 정보와 모든 매크로 관련 정보를 삽입한다.

이를 확인하기 위해 간단한 예시 프로그램을 작성하였다.

스크린샷_2017-06-21_18-00-47.png

hello world 레벨의 간단한 코드이다. 이 프로그램에 -g 옵션을 적용시켜 컴파일을 진행하고, 결과물의 파일 사이즈를 확인해 보기로 하였다.

옵션이 커지면 커질수록 사이즈가 늘어나는 것을 볼 수 있다. (kyuling 뒤에 쓰여진 숫자가 파일 사이즈이다.) 늘어난 사이즈만큼 디버깅 정보가 추가되었다는 것이다.

-ggdb 옵션도 -g 옵션과 거의 유사하나 다른 점이 있다면, 디버깅 작업을 도와주는 추가 정보가 필요하고, gdb 외에 다른 디버그에서는 사용이 불가능하다.

-g, -ggdb 옵션에 의한 디버깅 코드 삽입은 파일의 크기를 크게 하기 때문에 최종 실행 파일을 생성할 때에는 이러한 옵션을 주지 말고 컴파일 하는 것이 바람직하다. 이 옵션들에 의해 실행 속도 및 실행 과정에서의 차이가 발생한다. 또한 최적화된 코드의 경우에는 디버깅을 어렵게 만들기 때문에 최적화 수행은 디버깅이 다 끝난 다음에 하는 것이 좋다.

108 – GCC 옵션(라이브러리 지정)

라이브러리를 지정하는 옵션 이전에, 일단 라이브러리에 대해서 간단하게 정의하고 이걸 어떻게 만드는지를 먼저 좀 써야 할 거 같다. 도중에 한번도 안적었었다.

라이브러리 함수에 대해서 살펴볼 때, 자주 사용되는 유용한 함수에 대한 오브젝트 파일을 모아둔 것을 라이브러리라고 한다고 하였다. 여기에 라이브러리에는 함수 목록 또한 포함된다.

위에 화면은 예제를 만드는 노트북에 있는 라이브러리들 중 일부를 보여준다. 궁금하다면 /usr/lib32/ 폴더 안에 있는 것을 보면 된다. lib로 시작하는 이름의 파일들이 라이브러리 파일이고, 확장자는 .a다. 이 중에서 libc.a는 표준 라이브러리고, libm.a 파일은 수치 연산 라이브러리 파일이다. ar 명령어를 통해서 libc.a가 어떤 오브젝트 파일로 이루어졌는지 알 수 있다. ar 명령어는 정적 라이브러리를 생성, 조회, 편집하기 위해 이용되는 명령어이다.

라이브러리를 직접 만들어보기 위해서 실제로 예시를 작성해 보기로 하겠다. 라이브러리 파일로 이용하기 위해 두 함수를 각각의 파일로 만들어서 오브젝트 파일까지 만들었다.

이제 plus, minus 함수를 이용할 수 있는 라이브러리 파일을 생성할 준비가 끝났다. ar 명령어를 사용하면 라이브러리 파일을 생성할 수 있는데, r옵션을 이용하여 .a 파일을 먼저 생성한다.

라이브러리가 생성되었다. 그리고 나서 이제 라이브러리에 목록을 추가하여 완벽하게 처리해야 하는데, s 옵션을 이용하면 알아서 목록을 생성한다.

이제 해당되는 옵션에 대해서 살펴보도록 하겠다.

  • -l

표준 라이브러리가 아닌 라이브러리를 사용하고자 할 때 그 라이브러리를 지정해 주는 옵션이다. 여러 라이브러리가 존재하는데, libc 표준 라이브러리에 없는 표준 함수를 이용하고자 할 때에 이용이 필요하다. 예제를 만들어봤다.

수학 함수이다. sqrt 함수인데, math.h 함수 안에 정의되어 있으며 libm.a에 정의되어 있다. 실제로 코딩을 진행하고 gcc로 실행하면 에러가 나야 정상이다. (?!)

양쪽 다 실행되었는데, 규링의 환경이 문제가 있는지 추가 글을 작성해야 할 거 같다.

원래대로라면 위에서 그냥 컴파일하면 gcc에서 오류를 내야 한다. 그래서 -l옵션을 통해 어떠한 라이브러리를 이용해야 할 것인지를 적어야 하고, 적는 이름은 lib와 뒤에 확장자를 제외한 나머지를 그대로 쓰는 것이다. lib[m].c 를 쓰기 때문에 대괄호로 작성한 m만 적는 것이다.

  • -L

사용할 라이브러리 위치를 지정해주므로써 사용자가 라이브러리 파일을 직접 만들어 사용하거나 새 라이브러리를 내려받아서 사용할 때 이용한다.

아까 만든 libmy.a를 이용한 예제 코드를 작성하였따.

ld 링커가 에러를 냈다. 라이브러리를 찾을 때, /lib나 /usr/lib* 와 같이 정해진 디렉토리만을 찾기 때문에 그 안에 없는 libmy.a를 쓰려고 하니 오류가 발생한 것이다. libmy.a 라이브러리를 mylib 폴더로 복사해뒀다. 그래서 이걸 이용하고자 한다. 옵션 뒤에 폴더를 그대로 작성하면 된다.

라이브러리 관련된 옵션은 주로 링크에 관련된 옵션이 주로 존재하였고, 필요에 따라서 링크를 추가해주면 되는 경우가 상당히 많다.