본문 바로가기

Linux/C

[linux] 라이브러리 사용하기

주제 : 리눅스에서 라이브러리 사용하기

학습목표 : 리눅스에서 사용하는 라이브러리를 만들 수 있고 라이브러리가 어떤 건지 알 수 있으면 좋겠다.

참고 사이트 : 

http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C/Documents/Make_Library

http://www.hanbit.co.kr/network/view.html?bi_id=1013



라이브러리 : 특정한 코드를 포함하고 있는 컴파일된 파일. 오브젝트 파일들을 모아 놓은 것.

o 라이브러리의 종류

- 정적라이브러리 :  컴파일시에 적재된다.

- 공유라이브러리 :  프로그램이 시작될 때 적재된다. (런타임)    ---> 윈도우에서 dll

- 동적라이브러리 :  프로그램 시작중 특정한 때에 적재된다.



** windows 

정적라이브러리 : ~.lib        동적라이브러리 : ~.dll

** linux 

정적라이브러리 : ~.a        동적(공유)라이브러리 : ~.so



o 소스파일 hello.c 를 실행파일 hello 로 컴파일하는 과정

c 컴파일러 : cc1  

어셈블러 : as  

링커 : ld , collect2                                                

소스파일 --> 전처리된파일 --> 어셈블리파일 --> 목적파일 --> 실행파일

hello.c        hello.i         hello.s         hello.o      hello

   gcc -E hello.c   gcc -S hello.i   gcc -c hello.s  gcc -o hello hello.o

----------------->  -------------->  ------------->  --------------->

                       gcc --save-temps -o hello hello.c

-------------------------------------------------------------------->

  전처리 과정       컴파일 과정      어셈블 과정         링킹 과정

  (컴파일러)         (컴파일러)       (어셈블러)         (링커)

  (gcc -E)              cc1              as            collect2, ld  

                          <----------------------------------------

                                    디스어셈블 과정(objdump)

                                 리버싱, 리버스엔지니어링, 역공학

                                 리버스코드엔지니어링, RCE

   <---------------------------------------------------------------

           디컴파일 과정

                   


===========================================================================

LAB1> main.c 소스를 각 단계별로 컴파일 해보자.


- gcc 에서 save-temps 를 이용하면 각 단계별로 작성된 파일을 얻을 수 있다.

- gcc --save-temps -o main main.c


# vi main.c

-- main.c --

#include <stdio.h>

int main()

{

  printf("Hello C! \n");

  return 0; 

}

-- main.c --


#mkdir library ; cd library

 ;  => 앞의 명령어와 뒤의 명령어를 이어주는 기호(앞의 명령어 실행 한 후 뒤의 명령어를 실행해라)


- 각 단계별로 컴파일하기

# gcc -E main.c -o main.i

# gcc -S main.i 

# gcc -c main.s 

# gcc -o main main.o 

# ./main 

#ldd main ( -> 가지고 있는 라이브러리들이 출력된다. 의존관계를 알려준다.)

Hello C! 

===========================================================================


===========================================================================

LAB2> main.c 에 함수 func1() 을 추가해보자.

- 소스파일에서 한번에 컴파일해서 실행파일을 얻고 싶다면 아래와 같이 한다. 

- gcc -o main main.c


# vi main.c

-- main.c --

#include <stdio.h>

void func1();

int main(){

  printf("Hello C! \n");    // printf()정의가 라이브러리로 따로 외부에 파일로 존재한다.

  func1();

  return 0; 

}

void func1(){

  printf("func1 call \n");

}

-- main.c --

# gcc -E main.c -o main.i

# gcc -S main.i

# gcc -c main.s 

# gcc -o main main.o

# ./main 

Hello C! 

func1 call 

===========================================================================



===========================================================================

LAB3> main.c 에 함수 func2() 을 추가해보자.


# vi main.c

-- main.c --

#include <stdio.h>

void func1();

void func1();

int main(){

  printf("Hello C! \n");    // printf()정의가 라이브러리로 따로 외부에 파일로 존재한다.

  func1();

  return 0; 

}

void func1(){

  printf("func1 call \n");

}

void func2(){

  printf("func2 call \n");

}

-- main.c --

# gcc -E main.c -o main.i

# gcc -S main.i

# gcc -c main.s 

# gcc -o main main.o

# ./main 

Hello C! 

func1 call 

func2 call 

===========================================================================


===========================================================================

LAB4> main.c 에 함수 func2() 를 Object 파일로 분리해보자.

# vi main.c

-- main.c --

#include <stdio.h>

void func1();

void func2();

int main()

{

  printf("Hello C! \n");

  func1();

  func2();

  return 0; 

}

-- main.c --

# vi func1.c

-- func1.c --

#include <stdio.h>

void func1(){

  printf("func1 call \n");

}

-- func1.c --


# vi func2.c

-- func2.c --

#include <stdio.h>

void func2(){

  printf("func2 call \n");

}

-- func2.c --


- func1.o, func2.o, main.o 의 object 파일을 생성한다.

# gcc -c func1.c 

# gcc -c func2.c 

# gcc -c main.c 


- 생성한 object 파일들을 결합하여 main 이라는 실행파일을 생성한다.

# gcc -o main main.o func1.o func2.o 


# ./main

Hello C! 

func1 call 

func2 call 

===========================================================================



===========================================================================
LAB5> Makefile 을 생성해보자.

참고 : 
http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C/Documents/minzkn_make

Makefile 을 생성하는 방법
1. 수동으로 생성하는 방법
- 사용자가 직접 생성한다.

2. 자동으로 생성하는 방법
- GNU autoconf 검색

# vi Makefile
-- Makefile --
CC = gcc
main : main.o func1.o func2.o
$(CC) -o main main.o func1.o func2.o   => 반드시 맨 앞에 tab으로 띄워야 함!!!!
main.o : main.c
$(CC) -c main.c
func1.o : func1.c
$(CC) -c func1.c
func2.o : func2.c
$(CC) -c func2.c
clean : 
rm -fv main main.o func1.o func2.o
-- Makefile --

# make clean
# ls
# make
# ls
#./main

- func1.c 파일의 내용을 수정하고 make를 하면 새롭게 컴파일한다.
  func1.o 와 func1.c 의 시간을 비교하여 func1.o 보다 func1.c 가 더 최근의 시간을 가지면 새롭게 소스를 수정했다고 판단하고 다시 func1.c 를 컴파일을 한다.

# vi func1.c 
-- func1.c --
#include <stdio.h>
void func1()
{
  printf("func1 call \n");
  printf("func1 call \n");
}
-- func1.c --

# make
gcc -c func1.c
gcc -o main main.o func1.o func2.o

# ./main 
Hello C! 
func1 call 
func1 call 
func2 call 
===========================================================================


===========================================================================

LAB6> 정적라이브러리를 아래 조건에 맞추어 생성해보자. 

( 정적라이브러리로 생성된 파일은 라이브러리가 삭제되도 실행 된다.   <--->   동적(공유)는 실행이 안된다.)

라이브러리 모여있는 디렉토리 : /lib /usr/lib

라이브러리명 : lib라이브러리명.[a,so]

정적라이브러리 : libksw.a

동적라이브러리 : libksw.so


ex) 표준라이브러리

: /usr/lib/libc.a, /usr/lib/libc.so


libz.a, libz.so  :  압축에 관한 라이브러리


-- 조건 --

라이브러리명 : libmy.a

-- 조건 --


-- 참고 --

- 아카이브 파일은 ar 뿐만이 아니라 tar 로도 만들 수 있다.

- # tar cvf libmy2.a func1.o func2.o 

- # tar tvf libmy2.a 


- 라이브러리와 같이 컴파일할 때는 아래와 같이 사용한다.

- 옵션 설명 : -o <실행파일명>  -l<라이브러리명> -L<라이브러리의 경로명> 

- # gcc -o main main.c -lmy -L.

                            >> libmy.a 에서 앞에 lib와 뒤에 .a는 생략하고 my만 적는다

                            >> c 라이브러리는 기본이기 때문에 추가하지 않는다.



- main.c 안에 fun1(), fun2(), printf() 함수가 있으므로 

- 실제 컴파일은 gcc -o main main.c -lmy -L. -lc -L/usr/lib 와 같이 해야하지만 

- 기본적으로 c 라이브러리는 아래와 같이 생략이 가능하다.

- # gcc -o main main.c -lmy -L.

- # ls -l /usr/lib/libc.a 

- -rw-r--r-- 1 root root 3016658  2월 22  2012 /usr/lib/libc.a

-- 참고 --


-- 순서 --

1. 정적라이브러리 파일을 생성한다.

- ar 명령어로 func1.o func2.o 파일을 가진 libmy.a 라는 아카이브 파일을 생성한다.

#make clean

#make func1

#make func2

#ar rcv libmy.a func1.o func2.o

#ar t libmy.a

2. main.c 를 라이브러리와 같이 컴파일한다.

-- 순서 --


1. 정적라이브러리 파일을 생성한다.

- ar 명령어로 func1.o func2.o 파일을 가진 libmy.a 라는 아카이브 파일을 생성한다.


# ar rcv libmy.a func1.o func2.o 

# ar t libmy.a 

func1.o

func2.o


2. main.c 를 라이브러리와 같이 컴파일한다.

- 만약 object 파일이 많을때는 gcc -o main main.c func1.o func2.o ... 처럼 

- 파일들을 일일히 나열할 수 없으므로 object 파일들을 하나의 아카이브 파일안에 

- 넣어두고 사용하는 것이 좋다.  결국 이것이 라이브러리를 만드는 주 목적이다.

# make clean

# gcc -o main main.c  <-- X

# gcc -o main main.c libmy.a   <-- O

# gcc -o main2 main.c -lmy -L. <-- O


===========================================================================

===========================================================================

LAB7> 공유라이브러리를 아래 조건에 맞추어 생성해보자.

-- 참고 --

o 공유라이브러리 사용하기

- 공유라이브러리는 실행시에 라이브러리를 적재하고 프로그램을 실행하므로 프로그램을 배포할때는 공유라이브러리도 함께 배포되어야 한다. 그렇지 않을경우 공유라이브러리를 찾을수 없다는 메시지를 출력하면서 프로그램 실행이 중단된다. 


o 공유라이브러리를 인식하는 세 가지 방법

- 1. 기본 라이브러리 디렉토리에 공유라이브러리를 넣는 방법 : /usr/lib, /lib (ksw X)

 => root 가 아닌 guest는 불가

- 2. 공유라이브러리가 있는 디렉토리를 설정파일에 등록하는 방법 : /etc/ld.so.conf (ksw X) 

=> root 가 아닌 guest는 불가

- 3. 공유라이브러리가 있는 디렉토리를 환경변수로 등록하는 방법 : LD_LIBRARY_PATH (ksw O)


- LD_LIBRARY_PATH 을 지정하는 방법은 쉘에서의 PATH 변수와 동일하다.

- : 을 기준으로 공유라이브러리가 있는 경로를 나열하면 된다.

- LD_LIBRARY_PATH=디렉토리명:디렉토리명:디렉토리명:...

LD_LIBRARY_PATH 를 export 하는 이유는 LD_LIBRARY_PATH 의 변수를 환경변수로 만들기 위해서

- 쉘에서 만드는 변수는 모두 지역변수다.

- 지역변수로 만든 변수명을 다른쪽으로 가져가기 위해서는 환경변수로 만들어야 한다.

- 환경변수는 전역변수의 내용을 가지고 있다.

- 환경변수를 만드는 명령어는 export 이다.

- ex) export LD_LIBRARY_PATH=.


-- 순서 --

1. 공유라이브러리 형식으로 컴파일한다.

2. 공유라이브러리를 생성한다.

3. main.c 를 라이브러리와 같이 컴파일한다.

4. main 을 실행한다.

-- 순서 --


1. 공유라이브러리 형식으로 컴파일한다.

- 컴파일시 -fPIC 옵션이 추가된다. (PIC : 포지션 인디펜던트 코드)

#make clean

#rm -f libmy.a

# gcc -fPIC -c func1.c 

# gcc -fPIC -c func2.c 


2. 공유라이브러리를 생성한다. (so : shared object)

# gcc -shared -W1,-soname,libmy.so.1 -o libmy.so.1.0.1 func1.o func2.o (실행파일 형태로 생성)

# ln -s libmy.so.1.0.1 libmy.so.1

# ln -s libmy.so.1 libmy.so

# ls -l lib*

-rw-r--r-- 1 root root  1908 Sep  4 21:51 libmy.a

lrwxrwxrwx 1 root root    10 Sep  4 22:16 libmy.so -> libmy.so.1

lrwxrwxrwx 1 root root    14 Sep  4 22:16 libmy.so.1 -> libmy.so.1.0.1

-rwxr-xr-x 1 root root  4268 Sep  4 22:08 libmy.so.1.0.1



3. main.c 를 라이브러리와 같이 컴파일한다.

- 같은 디렉토리에 정적라이브러리(libmy.a) 와 공유라이브러리(libmy.so) 파일이

- 동시에 존재한다면 먼저 공유라이브러리를 우선순위로 컴파일한다.

# gcc -o main main.c -lmy -L.


4. main 을 실행한다.

- 공유라이브러리를 찾을 수 없을때 나오는 에러 메세지

# ./main

./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory


%%%%%%%%%%%%%%%%%%%%%여기까지 수업함%%%%%%%%%%%%%%%%%%%%%%%%%%%%






- 공유라이브러리가 있는 현재 디렉토리를 LD_LIBRARY_PATH 에 설정하고 실행한다.

# LD_LIBRARY_PATH=. ./main

Hello C! 

func1 call 

func2 call 


- LD_LIBRARY_PATH 변수가 계속 유지 되지 못해서 에러가 발생된다면 

- LD_LIBRARY_PATH 변수가 계속 유지될 수 있도록 export 명령어를 사용하면 된다.

# ./main

./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory


# export LD_LIBRARY_PATH

# ./main

Hello C! 

func1 call 

func2 call 


- 공유라이브러리 설정파일에 등록하는 방법 

- 공유라이브러리가 있는 디렉토리를 적어주고 ldconfig 명령어를 실행한다.

# vi /etc/ld.so.conf

-- /etc/ld.so.conf --

/root/programming

-- /etc/ld.so.conf --


- ldconfig 명령어를 실행하면 /etc/ld.so.cache 파일이 업데이트가 된다.

- 따라서 공유라이브러리로 컴파일한 파일을 실행할때 이 파일의 경로를 참고한다.

# ldconfig

# file /etc/ld.so.cache 

/etc/ld.so.cache: data

# strings /etc/ld.so.cache | grep programm

/root/programming/libmy.so.1.0.1

/root/programming/libmy.so.1

/root/programming/libmy.so


# ./main

Hello C! 

func1 call 

func2 call 


- /etc/ld.so.conf 를 이용하는 방법

# unset LD_LIBRARY_PATH

# ./main 

./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory

# cat /etc/ld.so.conf

include ld.so.conf.d/*.conf

# pwd

/root/library

# pwd >> /etc/ld.so.conf

# cat /etc/ld.so.conf

include ld.so.conf.d/*.conf

/root/library

# ./main 

./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory

# ldconfig

# ./main 

Hello C! 

func1 call 

func2 call 



- /usr/lib 디렉토리를 이용하는 방법

# cat /etc/ld.so.conf

include ld.so.conf.d/*.conf

# ldconfig

# ./main 

./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory

# mv libmy.so* /usr/lib -v

`libmy.so' -> `/usr/lib/libmy.so'

`libmy.so.1' -> `/usr/lib/libmy.so.1'

`libmy.so.1.0.1' -> `/usr/lib/libmy.so.1.0.1'

# ./main 

Hello C! 

func1 call 

func2 call 

===========================================================================


**C -> Unix/Windows system programming -> Win32API programming -> .........


'Linux > C' 카테고리의 다른 글

[linux] 사용자 정보 구하기  (0) 2015.04.24
[linux] gdb 사용하기  (0) 2015.04.17
[VS] 차량번호 분류  (1) 2011.09.19
[VS] 영문한글 글자수 세기  (0) 2011.09.19
[VS] 네모찍기  (0) 2011.09.14