헤더 파일 

헤더 파일은 프로그램에서 사용할 전처리 지시자 #include, #define 혹은 전역 data, 함수들이 선언된 파일입니다.

주로 정의 파일들이 실행 파일로 변환될 때에 컴파일러에게 컴파일 및 링크에 대한 정보를 제공합니다
헤더 파일 내부에는 함수의 선언부가 있고, 라이브러리와 함께 사용되는 데이터 유형 및 상수도 포함될 수 있습니다.

• 확장자는 .h 
• 함수 선언이 포함 
• 자체적으로 "include sub directory" 안에 포함 
• 헤더 파일은 사람이 읽을 수 있으며 소스 코드 형식
• 프로그램의 헤더 파일은 전처리기에 의해 내부적으로 처리되는 #include 명령을 사용하여 포함 

 

라이브러리 

라이브러리는 함수에 대한 정의가 구현되는 부분입니다.
라이브러리(library)는 다른 프로그램들과 링크되기 위하여 존재하는, 하나 이상의 서브루틴(subroutine)이나 함수(function)들의 집합 파일 말하는데 함께 링크(link)될 수 있도록 보통 컴파일된 형태인 목적코드(object code) 형태로 존재합니다.

라이브러리는 코드 재사용을 위해 조직화된 오래된 기법 중의 하나이며 많은 다른 프로그램들에서 사용할 수 있도록 운영체계나 소프트웨어 개발 환경 제공자들에 의해 제공되는 경우가 많습니다.

라이브러리라는 기술이 생긴 이유는 코드의 재사용 및 부품화 실현, 소스를 제공하지 않음으로서 중요 기술의 유출을 방지할 수 있고, 라이브러리는 사용하는 개발자들로서는 대형 어플리케이션 개발 시간을 단축시킬 수 있다는 장점들이 주어지기 때문입니다.

라이브러리들은 사용자의 프로그램과 링크되어, 실행이 가능한 완전한 프로그램을 이루는데, 이러한 링크는 대개 정적으로 연결(static link)되지만, 시스템에 따라 동적으로 연결(dynamic link)될 수도 있습니다.

 

확장자는 .lib .dll .a .so
함수 정의를 포함
자체적으로 "lib sub directory" 안에 포함
라이브러리 파일은 사람이 읽을 수 없는 기계 코드 형태
프로그램의 라이브러리 파일은 링커라는 특수 소프트웨어에 의해 마지막 단계에 포함

 

정적 라이브러리 

정적 라이브러리에는 최종 사용자 응용 프로그램과 연결된 개체 코드가 포함되어 있으며 실행 파일의 일부가됩니다. 
이 라이브러리는 컴파일 타임에 특별히 사용되므로 사용자가 C 또는 C ++ 프로그램을 컴파일하려는 경우 라이브러리가 올바른 위치에 있어야 합니다. 

 

라이브러리에 포함된 목적 코드(object code)가 실행 프로그램 컴파일 시에 실행 파일에 복사(포함)되어 배포되는 방식입니다.

기본적을 필요한 기능(routine)이 실행 파일과 동일한 위치에 존재하기 때문에 프로그램 실행파일이 커지는 단점이 있지만,

배포해야 하는 파일이 실행파일 하나 만으로 충분하다는 장점을 가지고 있습니다.
일반적으로 Unix, Linux, DOS 등 소개된지 오래된 OS에서는 정적 라이브러리 확장자로 .lib, .a 등을 사용합니다.

 

컴파일 과정에서 공유 라이브러리의 루틴을 사용하지 않고, 프로그램 내에서 라이브러리 루틴의 복사본을 같도록 컴파일하는 것
정적 라이브러리는 여러 개의 오브젝트 파일을 묶어서 관리한다는 의미로 주로 .a(archive) 확장자를 가짐

 

ex. gcc -c test.c 
      gcc -c app.c
      ar cr libtest.a test.o -> 오브젝트 파일로 해당 정적 라이브러리 생성
      gcc -o static_app app.o -L. -ltest -> -L: 경로지정, -l: 라이브러리 libtest.a 의미

 

공유 or 동적 라이브러리

정적 라이브러리의 단점은 실행 프로그램의 크기가 커지는 문제뿐만 아니라, 동일한 라이브러리를 포함한 유사한 프로그램들이 동시에 실행될 경우, 똑같은 코드(code)들이 불필요하게 많은 메모리 자원을 중복해서 사용하는 문제가 발생합니다.

게다가 점차 복잡해지는 소프트웨어의 구조 상 실행 파일 크기가 기하급수적으로 커지는 단점도 있어 어플리케이션들에서 사용되는 공통되는 모듈을 메모리에 단 한 차례만 적재하고 사용할 수 있는 방안을 강구하게 되었습니다.

 

이 방식은 실행 프로그램에 항상 라이브러리를 포함하하는 것이 아니라 필요할 때만 라이브러리를 메모리로 불러 들이기 때문에 동적 라이브러리라고 불렸고, 장점은 앞서 설명한 바와 같이 실행 파일의 크기를 줄여주며, 사용이 끝나면 메모리에서 삭제되기 때문에 메모리를 보다 효율적으로 사용할 수 있습니다.

하지만, 프로그램 배포시에 .exe 파일과 함께 .so 파일이나 .dll 파일이 추가로 배포해야 한다는 단점이 있는데,
.so 파일이나 .dll 파일이 없으면 컴파일 시에는 에러가 나지 않지만 실행 시에는 라이브러리를 찾을 수 없다는 오류가 발생하며, 라이브러리의 이름은 정확하지만 만일 버전이 다르다면 역시 문제가 발생할 우려가 있습니다.

 

공유라이브러리는 런타임에만 필요하기 때문에 사용자는 라이브러리를 사용하지 않고도 코드를 컴파일 할 수 있습니다. 
컴파일 타임에 연결되어 정의되지 않은 참조를 확인한 다음 응용 프로그램에 배포되어 응용 프로그램이 런타임에 로드할 수 있도록합니다.
리눅스에서 .so 확장자,  Windows에서는 .dll 확장자를 가집니다.

 

해당 동적 라이브러리가 존재하는 경로를 설정해주어야 하는데, 아래와 같이 3가지 방법이 존재합니다.

1. system default 경로 -> ld.so.conf 공유 라이브러리 캐시(/etc/ld.so/cache) 재생성 필요 (ldconfig)

2. LD_LIBRARY_PATH -> export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:[라이브러리 경로]
3. binary code 에 hard-coding 된 경로 -> 프로그램 내에서 설정

 

실행 시점에 필요한 함수를 가져오고 동적 라이브러리를 사용하여 빌드시 적은 양의 코드가 프로그램에 추가되어 프로그램이 시작될 때, ld.so 의 동적 링커를 실행하게 됩니다.

 

동적 라이브러리를 사용하여 컴파일된 프로그램은 스텁(Stub) 루틴이라는 것에 링크되는데,

스텁 루틴은 실행파일 내에서 실제 공유 라이브러리대신 자리를 차지하며 실행시 ld.so에 의해 실제 루틴으로 대체됩니다.

 

ex. gcc -c -fPIC test.c -> (fPIC: Position-Independent Code)
      gcc -c app.c

      gcc -shared -fPIC -o libtest.so test.o -> test.o 오브젝트 파일을 .so 파일로 묶음

      gcc -o dynamic_app app.o -L. -ltest