Library4developers

Ubuntu Korea Community Wiki
imported>Drake님의 2014년 6월 9일 (월) 11:08 판 (→‎Chapter 4)
둘러보기로 이동 검색으로 이동

라이브러리란?

  • 도서관이라는 뜻처럼, 헤더 파일과 실행 루틴이 모여 있는 것으로 프로그래밍 언어에서 입출력과 문자열 관리와 같은 일상적인 작업을 추가할 때 사용한다.

동적 라이브러리와 정적 라이브러리의 특징

동적 라이브러리

  • 일반적으로 .so 로 끝나는 이름을 하고 있다.
  • 윈도우의 DLL 파일이라고 생각하면 된다.
  • 실행할 때 시스템에 설치되어 있는 라이브러리를 가져다 사용하므로, 정적 라이브러리에 비해 상대적으로 느리다.
  • 공유 라이브러리를 사용하면 실행파일에 라이브러리를 포함할 필요가 없으므로 스토리지가 절약된다.
  • 컴파일러의 기본값이다.
  • 사용법
gcc --shared -o parse parse.c -lxml2

정적 라이브러리

  • 일반적으로 .a 로 끝나는 이름을 하고 있다.
  • 윈도우의 lib 파일이라고 생각하면 된다.
  • 컴파일할 때 함수를 실행파일에 포함한다.
  • 실행할 때 모든 함수가 실행파일 안에 있으므로, 동적 라이브러리에 비해 상대적으로 빠르다.
  • 정적 라이브러리를 사용하면 의존성 등에서 조금 더 자유로울 수 있다.
  • 사용법
gcc --static -o parse parse.c -lxml2

라이브러리의 설치

  • sudo apt-get install로 설치가 가능하다.

ex) <syntaxhighlight lang="bash"> sudo apt-get install libxml2-dev </syntaxhighlight>

  • 설치된 라이브러리는 일반적으로 /usr/include에 헤더파일이 들어가며, /usr/lib에 .so파일과 .a파일이 들어간다.

라이브러리 사용법

Chapter 1

  • 두개의 함수가 포함되어 있는 작은 라이브러리를 만들어보자. 예제에서는 이들 중 하나를 사용할 것이다. 이 함수들은 fred와 bill이며, 간단한 인사말을 출력한다. 우리는 각자 따로 소스파일을 작성할 것이다.

<source lang="c" title="fred.c"> /* fred.c */

  1. include <stdio.h>

void fred(int arg) {

 printf("fred: you passed %d\n", arg);

} </source> <source lang="c" title="bill.c"> /* bill.c */

  1. include <stdio.h>

void bill(char *arg) {

 printf("bill: you passed %s\n", arg);

} </source>

  • 이러한 함수들을 각자 컴파일한 후 오프젝트파일을 만듦으로서 라이브러리파일에 포함시킬 수 있다. 우리는 -c 옵션을 사용함으로서 gcc가 실행가능한 완벽한 프로그램을 만들지 못하도록 해야 한다(.o 파일을 뽑아야 한다). 만일 이 소스를 -c옵션을 사용하지 않고 컴파일하면 main이 정의되지 않았다고 지랄실패할 것이다.

<source lang="bash"> $ cc -c bill.c fred.c $ ls *.o bill.o fred.o </source> </source>

Chapter 2

  • bill 함수를 호출하는 프로그램을 작성해보자. 먼저, 라이브러리에 필요한 헤더파일을 만들자. 이 헤더파일은 라이브러리 내부에서 함수들을 선언하는 것이며, 본 라이브러리를 사용하는 프로그램은 모두 이 헤더파일을 포함해야 한다.

<source lang="c" title="lib.h"> /* 이건 lib.h다. fred와 bill을 사용할 어플들은 모두 이걸 include하도록 */ void bill(char *); void fred(int); </source>

Chapter 3

  • 본 라이브러리를 사용하는 프로그램(program.c)을 작성하는 일은 존나 쉽다. 필요한 라이브러리와 헤더파일을 포함하고, 라이브러리에 들어있는 함수만 호출하면 된다.

<source lang="c" title="program.c"> /* program.c */

  1. include "lib.h"

int main() {

 bill("헬로 월드");
 return 0;

} </source>

  • 이제 프로그램을 컴파일하고 테스트해보자. gcc한테 소스코드를 모두 오브젝트 파일로 컴파일하고 실행파일로 링크하라고 하자.

<source lang="bash"> $ cc -c program.c $ cc -o program program.o bill.o $ program bill : you passed 헬로 월드 $ </source>

Chapter 4

  • 이제 라이브러리를 만들고 사용해보자. ar프로그램을 사용하여 archive을 만들고 여기에 오프젝트 파일을 추가한다. 이 프로그램이 ar이라 불리는 까닭은 archive를 만들거나 각각의 파일을 모아서 하나의 커다란 파일에다 모아주기 때문이다.아카이빙이라고 하면 있어보이긴 하는데 못알아듣잖아 ar은 텍스트 파일들의 archive를 만들때에도 사용할 수 있기 때문에 주목해야 한다.리눅스는 뭐하나 알면 두고두고 우려먹을 수 있으니까 좋잖아

<source lang="bash"> $ ar crv lib.a bill.o fred.o c - bill.o c - fred.o $ </source>

  • 이제 라이브러리를 만들었고, 두개의 오브젝트파일을 추가했다. 버클리 유닉스에서 파생된 몇몇 시스템에서는 라이브러리를 성공적으로 사용하기 위해 라이브러리 목록이 필요하다. 이 일은 ranlib라는 명령으로 처리한다. 하지만 리눅스와 같은 시스템에서 GNU 개발툴(build-essential)을 사용하면 이 과정은 필요없다.BSD에선 필요하다. 짜증

<source lang="bash"> $ ranlib lib.a </source>

  • 이제 라이브러리를 사용할 준비는 끝났다. 보통 프로그램을 만들 때 이러한 라이브러리를 추가할 수 있다.

<source lang="bash"> $ cc -o program program.o lib.a $ ./program bill : you passed 헬로 월드 $ </source>

  • 오브젝트 파일이나, 라이브러리 또는 실행 가능한 프로그램에 어떤 함수가 포함돼있는지 알아보기 위해 nm이라는 명령어를 사용할 수 있다. program과 lib.a를 살펴보면, 라이브러리는 fred와 bill을 포함하고 있지만 program은 단지 bill만 포함하고 있다는걸 알 수 있다. 프로그램이 만들어질 때, 실제로 필요한 함수들만 라이브러리에 포함된다. 라이브러리의 모든 함수들이 선언된 헤더 파일을 포함한다고 해서 모든 라이브러리 함수들이 포함되는건 아니다.
  • 만약에 여러분이 MSDOS나 윈도우 소프트웨어 개발에 대해 좀 알고 있다면 몇가지 유사한 점을 살펴볼 수 있다.
Item Unix DOS / Windows
오브젝트 모듈 lib.a lib.lib
실행파일 program program.exe

Chapter 5

  • 정적라이브러리의 단점은 동시에 여러 프로그램을 띄웠을 경우 이들이 모두 같은 라이브러리의 함수들을 사용하니까 메모리에 같은 함수들을 여러번 복사하고, 프로그램 파일에도 같은 라이브러리를 여러번 복사한다는거다. 이는 메모리 용량과 디스크 용량을 많이 소모한다. 많은 유닉스 시스템에서는 이러한 불편함을 극복할 수 있게 공유라이브러리를 제공한다.
  • 공유라이브러리랑 정적라이브러리는 같은데 저장돼있는데 확장자가 다르다. 전형적인 리눅스 시스템에서 표준 C 라이브러리의 공유 라이브러리 버전은 /lib/아키텍쳐/libc.so.N이다. 32비트의 경우 그냥 /lib/i386-linux-gnu/libc.so.6일 것이고, 64비트라면 /lib/amd64-linux-gnu/libc.so.6일 것이다. 여기서 N은 대부분 메이저 버전 숫자를 나타내며 현재는 6이다.
  • 프로그램이 공유라이브러리를 사용할 때, /usr/lib/아키텍쳐/libc.so라는 라이브러리에 링크된다. 이 라이브러리는 그 자체로 함수코드를 포함하고 있지 않은 특별한 라이브러리다. 하지만 런타임에 포함할 공유라이브러리를 참조한다.
  • 프로그램이 실행을 위해 메모리에 적재될 때 함수에 대한 참조 부분이 분석되어 공유라이브러리의 적재가 가능하게 되며, 필요한 경우에 공유라이브러리는 메모리상에 적재된다.
  • 이경우 시스템은 많은 응용프로그램들이 하나의 라이브러리를 공유할 수 있게 해준다. 또, 프로그램마다 같은 라이브러리를 실행파일에 포함할 이유가 없으니 하드도 절약된다.
  • 공유라이브러리는 이것에 의존하는 프로그램과 상관없이 지혼자 업그레이드할 수 있는 부가적인 이점도 있다.이점은 무슨 씨벌 맨날 꼬이는데 사람들은 일반적으로 마이너버전 번호 수정은 라이브러리를 사용하는 프로그램한테 별 영향이 안 가도록 노력한다.이 구역에 미친놈 하나 나오면 끝장이야
  • 리눅스 시스템에서 공유 라이브러리의 적재를 관리하며, 클라이언트 프로그램의 함수 참조를 분석하는 일은 ld.so 또는 ld-linux.so가 맡고 있다. 공유 라이브러리 검색 디렉토리는 /etc/ld.so.conf에 설정된다. /etc/ld.so.conf파일에 변경이 있었다면 ldconfig를 수행해야 한다. 하나의 예로, X11 공유 라이브러리 검색 디렉토리가 추가됐을 때를 들 수 있겠다.x가 존나 빡치게 만들긴 하지 ㅇㅅㅇ
  • ldd를 사용하면 해당 프로그램에서 어떠한 공유 라이브러리를 요구하는지 알아볼 수 있다.

<source lang="bash"> $ ldd program

 linux-gate.so.1 => (0xb7785000)
 libc.so.6 => /lib/i386-linux/gnu/i686/cmov/libc.so.6 (0xb760e000)
 /lib/ld-linux.so.2 (0xb7786000)

</source>

  • 위의 경우 표준 C라이브러리(libc)가 공유되고 있음을 알 수 있다. 다른 유닉스 시스템에서도 공유라이브러리 접근 방법은 비슷비슷하다. 좀더 자세한 사항은 아는사람 있으면 추가바람
  • 공유라이브러리는 Windows에서 사용되는 동적 링크 라이브러리와 많은 부분이 비슷하다. .so라이브러리는 .dll과 대응되며, .a라이브러리는 .lib와 비슷하다고 보면 된다.