gcc compiler & Library

Hyungseop Lee·2023년 10월 8일
0

gcc

  • gcc :
    • GNU C/C++ Compiler의 약자.
    • Linux계열 system에서 가장 많이 사용되는 compiler.
    • 주로 C program을 compile할 때 사용된다.
      gcc는 C program 뿐만 아니라 ADA, Java와 같은 다양한 language를 compile할 수 있도록
      architecture가 설계되어 있다.
    • C++ Program을 compile하려면 g++라는 별도의 compiler를 사용.
    • gcc는 소스파일부터 실행파일까지 여러 일을 수행한다.
      • preprocessing : 매크로 처리
      • compilation, assembly
      • linking
  • cross-compile :
    예를 들어 x86에서 ARM용 object code를 생성하는 cross-compile도 gcc를 통해서 한다.

Building an executable file

  • xxx.c라는 source file이 있다고 가정.

    1. gcc가 cpp라는 명령어를 수행하여 c file에 있는 macro들(#inclue, #define)을 처리하여
      compile하기 직전에 또 다른 source file(확장자 : .i)로 만들어 준다.

    2. 실제적으로 gcc가 관계된다.
      gcc는 .i source file을 assembly code(확장자 : .s)로 만들어준다.
      예를 들어 x86을 사용한다면, x86용 assembly code를 생성.
      ARM을 사용한다면, ARM용 assembly code를 생성.

    3. as라고 하는 assembler의 assembling을 통해서
      object(확장자 : .o)file을 만들어준다.
      object file은 우리가 사용하는 architecture(x86 or ARM)에 해당하는 기계어 명령어들이 들어가 있는 코드.

  1. ld라고 하는 linker가 object file을 실행파일(a.out)로 만들어줌
  • gcc가 직접적으로 일을 할 때는 2.뿐이고,
    Preprocessing, assembling, linking할 때는 gcc가 기타 명령어들을 내부적으로 호출하여 사용함.

gcc architecture

  • gcc architecture는 왜 3단계로 나누어져 있는가?
    • Front End :
      어떠한 language가 오던지 Generic이라고 하는 중간 코드로 변환한다.
      만약 우리가 새로운 언어를 만들었다면,
      Front End에 Generic으로 변환할 수 있는 module을 넣어줘야 한다.
    • Middle End :
      Front End에서 생성된 Generic(중간코드)을 최적화하는 과정을 거친다.
      opt(optimization pass 1 ~ N)
      최적화를 통해 RTL(Register Transfer Language)이라는 언어로 변환한다.
    • Back End :
      RTL 형태의 중간코드를 실제 machine code로 변환한다.
      x86이라면 x86용 assembly code로 만들고,
      ARM이라면 ARM용 assembly code로 만듦.

      ➡️ language와 target architecture에 관계없이 항상 공통되었다.
      그래서 새로운 언어를 개발했으면,
      middle end와 back end는 그대로 사용하고,
      front end에서 새로운 언어에 대한 generic format으로 만들어 줄 module만 넣어주면 된다.
      ➡️ 만약 새로운 architecture를 개발했다면,
      새로운 architecture에 대해 assembly code로 변환시킬 back end를 만들면 된다.

gcc 간단한 사용법

  • gcc -o hello hello.c -g -Wall
    • -o : tells the compiler to name the executable
    • -g : adds symbolic information to hello for debugging
    • -Wall : tells it to print out all warnings

gcc major options

Compiler path options

  • -IIdir : 해당 dir에서 header file을 cumulative하게(반복해서) 찾아라.
  • -LLdir : 해당 dir에서 library를 cumulative(반복해서) 찾아라.
  • -ll : Link to lib;
    • llfoo : links to libfoo.so(shared library) if it exists, or to libfoo.a(static library) as a second choice

Compiler preprocessor options

  • -EE : Preprocessing only
    (gcc가 preprocessor까지만 불러서 사용하고 그 다음인 compiling, assembling, linking을 하지 말고 멈춰라.)
  • -DDdef : Define def
    (외부 define을 사용할 수 있다.)
  • -UUdef : Undefin def
    (외부 define을 사용할 수 없다.)

Compiler warning options

  • -vv : verbose mode.
    (message를 많이 찍어줘라 + gcc version 정보)
  • -ww : Suppress warnings
    (message를 적게 찍어줘라)
  • -WW : More verbose mode
    (-vv보다 더 많이 찍어줘라)
  • -WWall : 모든 warning을 찍어줘라

Complier debugging options

  • -g : gdb의 정보를 포함하라
  • -pg : profiler의 정보를 포함하라
    (profiler를 통해 어떤 함수의 어떤 부분에서 시간을 많이 소요하는지 정보를 얻을 수 있음)

(중요) Compiler input/output options

  • -c : Stop after creating object files, don't link
    (linking단계 직전인 assembling까지만 하라.)
    = (실행파일을 만들지 말고 object file까지만 만들어라)

  • -o file명 : 지정한 file명으로 실행파일을 생성하라.

Compiler control options

  • -ansi : c90이라는 문법 standard에 맞게 compile하라
  • -pedantic : c standard에 있는 문법들만 사용하고, extension을 사용하지 마라
  • -std=c99 : c99에 맞게 compile하라.
  • -O[lev] : 최적화 level을 설정. (0, 1-default, 2, 3가 있는데, 2 level을 주로 사용한다)
  • -Os : 속도를 위한 최적화가 아닌, size를 위한 최적화를 해라

Common set of options

  • -O2 -Wall -pedantic :
    • -O2 : Level 2까지 optimization 해라.
    • -Wall : 모든 Warning message를 출력해라
    • -pedantic : gcc extension 말고, 순수한 C언어 문법에만 맞도록 compile하라.
      Linux kernel을 compile할 때는 gcc extension을 많이 사용하기 때문에 -pedantic 옵션을 사용하면 안된다.

gcc example

  • example 1 :
    Object file 생성 (linking 전 assembling까지만 수행) :
    실행 file 생성 (Linking) :
  • example 2 :
    여러 파일에서 include하면 중복이 많아지기 때문에 "funcs_2.h"처럼 만들 수 있다.

Library

  • Library : compile된 다양한 object file들을 모아놓은 file들.
    예를 들어, pThread Library는 thread에 관련된 함수들을 종합적으로 모아놓은 file.

  • Library는 두가지 type으로 나눌 수 있다.

    1. Static Library (정적 라이브러리)
    2. Shared Library (공유 라이브러리 = 동적 라이브러리)

1. Static Library

  • Static Library : Link at compile time

How to build/use an archive file(=static library)

  • ar : creates, updates, lists and extracts files from the library

  • nm : 생성한 정적 라이브러리에 만든 함수들이 있는지 확인할 수 있다.

Example

  • example 1 :

    gcc src/main.c ./lib/static_lib.a -I./include -o bin/main (O)

    gcc src/main.c -L./lib -l./static_lib -I./include -o bin/main (X)
    -l 옵션 문법이 맞지 않다.

  • example 2 : nm(생성한 정적 라이브러리에 만든 함수들이 있는지 확인할 수 있다.)

  • example 3 : ldd (해당 프로그램이 돌기 위한 라이브러리)

  • example 4 : -static (필요한 라이브러리들을 해당 파일에 한꺼번에 저장. 버전정보가 달라져도 피해 없음)

2. Shared Library

  • Shared Library : Linked to any program at run-time

Building a Shared Library

  • Functions must be reentrant = No global variables :
    여러 program들이 공유 라이브러리를 공유할 때, 간섭효과를 없애야 한다
  • Code must be position-independent :
    공유 라이브러리가 memory 어디에 load될지 가정하고 program을 짜면 안된다.
    항상 바뀌기 때문.

Shared library names

  • libmyfuncs.so.1.0 : 실제로 생성한 library
  • libmyfuncs.so.1 : library가 runtime에 사용될 때, 누구를 pointing하는지에 따라 어떤 version이 사용될지 결정된다.
    (.so.1.0, .so.1.1, ...)
  • libmyfuncs.so : .so는 실제 파일이 아니라, libmyfuncs.so.1.0의 symbolic link이다.

Finding shared libraries at runtime

  • library를 link할 때, 모든 directory를 다 찾아볼 수 없으니까 어느 directory를 찾아볼지 지정해줄 수 있다.
    • system library : /etc/ld.so.conf
    • 자체 library : LD_LIBRARY_PATH라는 환경변수에 해당 공유라이브러리가 있는 경로를 적어준다.
      ex: LD_LIBRARY_PATH=$HOME/foo/lib

Example

example 1 :
궁금한 점> symbolic link를 만드는 것을 lib directory에서 수행하면 되는데,
lib directory의 상위 directory에서 수행하면 안된다..

1. 실험 : /lib의 상위 directory에서 ln -s 수행, 상위에서 export, 오류 :

2. 실험 : /lib의 상위 directory에서 ln -s 수행, /lib에서 export, 오류 :

3. 실험 : /lib에서 ln -s 수행, /lib의 상위 directory에서 export, 정상동작 :

4. 실험 : /lib에서 ln -s 수행, /lib에서 export, 정상동작 :

/lib에서 symbolic link를 만들 때만 정상 동작.. 왜 그럴까?

symbolic link(libshared.so와 libshared.so.1)가 libshared.so.1.0을 pointing하는데,
libshared.so는 link할 때 사용되고,
libshared.so.1은 runtime할 때 사용된다.
만약 ln -s lib/libshared.so.1.0 lib/libshared.so 라고 했으면
libshared.so는 lib/libshared.so.1.0을 pointing하기 때문에 엉뚱한 곳을 pointing하는 것이라 linking이 안됐던 것임.
그래서 아래와 같이 해야 제대로 linking된다.

profile
Efficient Deep Learning Model

0개의 댓글