'shared object library'에 해당되는 글 2건

  1. 2008.11.23 Making your code more portable by avoiding inlining??? 6 by Dansoonie
  2. 2008.10.25 GNU Libtool 사용해서 shared object library 만들어보기 5 by Dansoonie
요새 컴퓨터 속도의 증가로, 소프트웨어를 디자인 하는데 있어서 퍼포먼스의 측면보다는 유지 관리 보수를 하는데 초점을 맞춘 디자인을 하는 경향이 있다고 한다. 그렇다고 퍼포먼스를 전혀 신경쓰지 않을수는 없겠지만, 예전에 비해서는 퍼포먼스의 측면을 덜 따지기 시작했다는 뜻일 것이다...

성질 급하신 분들을 위해서 이 글에 대한 설명을 먼저 하자면...
내가 최근에 봉착한 문제는 정말 쥐꼬리만큼의 퍼포먼스의 이득을 보기 위해서 사용한 inline function들이, 코드의 portability를 떨어뜨리는 결과를 낳게 되었다는 것이다... 아직까지는 내 추측이지만, 그 문제 때문에 이틀간의 삽질이 계속되었다...

나는 현재 다른 사람이 짜놓은 프로그램에 어떤 기능을 추가하는 일을 하고 있다. 그 과정을 좀 쉽게 하기 위해서 꼼수를 써서, 기존에 없던 가상의 layer를 구현 함으로써 그 layer를 통해서 원래 하고자 하는 함수들을 호출하게 하고, 그 과정에서 내가 새로 추가해야 하는 기능들을 구현하기로 하였다. 회사에서 하는 일이라서 구체적으로 어떤 일을 하고 있는지 말하기는 좀 그렇다... 하지만 도식적으로 나타내자면 대충 이렇다...



어쨌든, 문제는 이랬다...
하나의 layer를 추가하게 됨에 다라서 함수 호출하는 일이 더 많아지기 때문에 추가된 함수 호출에 의한 overhead를 최소한으로 줄이기 위해서 나는 inline이라는 키원드를 사용해서 내가 구현한 부분은 main()에서 호출할때 inline으로 호출하도록 하였다. 퍼포먼스의 영향을 많이 주지 못할것을 뻔히 알면서 그냥 뭔가 있어보이려고 시도했다... 하지만 계속 빌드를 하면 최종 결과물인 so(shared object) file을 linking하여 생성할때 내가 추가한 함수들에 대한 reference를 찾을 수 없다는 것이다. ㅡ.ㅡ;

이틀간 삽질 끝에 곰곰히 생각해보다가... 막연히 결과물이 shared object file이라는 점과 내가 inline을 사용했다는 점이 떠올라 inline keyword를 모두 지워버렸더니 그런 linking 에러가 없어져버렸다는... 물론 그 문제가 어느정도 해결되면서 다른 build error들이 발생하였지만, 이틀간 거의 밤새고 그 문제를 태클하던 터라 일단 쉬기로 하였었다...

한숨 자고 친구 결혼식 다녀와서 집에 내려가서 쉬다 왔는데도 오늘 하루종일 졸렸다... 지금도 일하러 사무실에 나왔는데, 배만 고프고 졸립다 ㅜ.ㅜ;


어쨌든, 그러니까 inline function을 사용한 것이 shared object library를 생성하는데 문제가 된다면, inlining은 code의 portability에 문제를 가지고 온다는 말인데... 내가 생각한 문제가 맞긴 맞나? 문제를 찾긴 찾은거 같은데, 아무리 결과가 shared object library file이지만, inline이 문제가 되나??? build하는 방식에 문제가 있나??? 좀더 확인해 봐야 할 것이 많은데도 불구하고, 졸립고 피곤하고 배고프고 귀칞아서 일단은, 누군가 이 문제에 대해서 글을 써서 트랙백을 달아주거나 리플을 기다려보고, 나중에 더 파고들어봐야겠다...

아~ 석사학위까지 있는데, 참으로 부끄럽다... 
고수님들 알려주세요 ㅡ.ㅡ;
Orz     
Posted by Dansoonie

과거에는 개발자가 shared libraries를 사용하기 위해서는자신이 개발하는 package가 지원해야 하는 모든 플랫폼에 대해서 각 플랫폼에만 국한되는 일은 모두따로따로 작업을 해야만 했다고 한다. , configurationinterface를 따로 설계하여 package installer가 어떤 library들을 설치해야 하는지 선택할 수 있도록 해야만 했다고 한다.GNU Libtool platform-specific dependencies user interface에 대한 정보를 하나의 스크립트에 설정할 수 있게 함에 따라 개발자가 예전에 짊어져야했던 많은 짐을 덜어준다. (GNU Libtool manual 서문의 첫 세 문장을 번역한 것이다. 원문을 보는 것이 아마 더 이해가 빠를 것이다. - click "more" to read it)


 

하지만, 아직 잘모르겠다어쨌든. Linux에서 개발 환경을 구축하는데있어서 GNU Build System을 이해해야 할 필요성을 느끼게 되어 가장먼저 Libtool을 공부하게 되었고, 지금까지 공부한 내용을 예를 들어 정리하고자한다.

* 본문의 내용에 대해서 잘 아시는 분은 틀린부분에 대해서 바로잡아주시고, 명확하지 않은 부분에 대해서는 어떤 보충설명을 하면 좋을지 의견을 남겨주시기 바랍니다.

* 해보시면서 의문이 드는 점도 물어봐주시면 아는대로 성심성의껏 답변해 보도록 하겠습니다.

* 빨간 글씨로 된 부분은 잘 모르겠거나 이해가 안 가는 부분이므로, 이 부분에 대해서 설명해 주실분은 댓글로 친절하게 설명해 주시면 정말 쌩큐베리 감솨 드리겠습니다...


학습목표
- /home/dansoonie/Work/fyi에 libfyi라는 간단한 library를 만들어 build한다.
- /home/dansoonie/
Work/fyitest에서 위에서 build libfyi를 가져다 쓴다
- libfyi를 /usr/lib에 설치한다.
- /home/dansoonie/Work/fyitest에서
/usr/lib에 설치된 libfyi를 가져다 쓴다.

작업 환경:
VMware Player, Ubuntu 8.04 - the Hardy Heron - release in April 2008
libtool version: 1.5.26-lubuntul (1.1220.2.493 2008/02/01 16:58:18)

참고 문헌:
GNU Libtool Manual(첨부파일 참고)


1. Shared Object Library로 만들간단한 소스 작성하기


간단하게 함수 두 개를 가지고 있는 라이브러리를 작성해보자.


/home/dansoonie/Work/fyi/fyi.h listing

#ifndef FYI_H
#define FYI_H

void name();
void birthday();

#endif

/home/dansoonie/Work/fyi/fyi.c listing

#include <stdio.h>
#include "fyi.h"

void name()
{
     printf("Yoon-Soo Lee\");
}

void birthday()
{
     printf("Januaary 18th\n");
}





2. Object File 생성하기


 쉘에서 다음 명령어를 수행한다.($PWD = /home/dansoonie/Work/fyi/)

libtool --mode=compile gcc -g -O -c fyi.c


설명:

     libtool :
libtool 실행 커맨드

     --mode=compile :
mode는 컴파일하기

     gcc -g -O -c fyi.c :
 gcc 실행문
. gcc 옵션은 -c(링크하지 않기)만 꼭 있어야 하고 나머지는 없어도 되는것 같다.

output은

 gcc -g -O -c fyi.c -fPIC -DPIC -o .libs/fyi.o

 gcc -g -O -c fyi.c -o fyi.o >/dev/null 2>&1


생성물은

/home/dansoonie/Work/fyi/fyi.o 

/home/dansoonie/Work/fyi/fyi.lo

/home/dansoonie/Work/fyi/.libs/fyi.o

이다...


shared object library가 지원되는 플랫폼이면 Libtool이 gcc를 실행할때 -fPIC -DPIC 와 같은 옵션을 달아서 실행한다고 한다. PIC가 들어가는 옵션들은 Position-Indipendent code를 의미하므로 shared object library를 만드는데 있어서 매우 중요한 옵션이므로, output에서 그 옵션들이 나오는지 꼭 확인하자 !!!

output의 두번째 줄의 ">/dev/null 2>&1" 은 뭔지 잘 모르겠다... 그냥 gcc의 outputd르 redirect하고 있는것 같은데 정확히 무슨 짓을 하는지는 잘 모르겠다.



3. Library들 link하여 생성하기


 쉘에서 다음 명령어를 수행한다. ($PWD = /home/dansoonie/Work/fyi/)

libtool --mode=link gcc -g -O -o libfyi.la fyi.lo -rpath /usr/lib


설명:

     libtool :
libtool 실행 커맨드

     --mode=link :
mode는 링크하기

    - gcc -g -O -o libfyi.la fyi.lo -rpath /usr/lib :
gcc 실행문. libfyi.la는 libtool control file name으로 확장자가 .a인 standard library name과는 다르다. 어쨌든, 출력을 왜 확장자가 .la인 파일로 정해야 하는지는 잘 모르겠다. fyi.lo는 fyi.la를 출력하기 위해 필요한 파일이고, -rpath 옵션을 통해서 library가 최종적으로 설치(복사)될 경로를 지정해 준다.
질문... /usr/lib, 즉 궁극적으로 설치될 경로를 지정해 주는 이유는 무엇인가? 나중에 libtool을 사용해서 library를 install할때 또 libtool에 argument로 그 경로를 넘겨주는것 같은데 말이다...

output은

 gcc -shared .libs/fyi.o -Wl,-soname -W;, libfyi.so.0 -o .libs/libfyi.so.0.0.0

 (cd .libs && rm -f libfyi.so.0 && ln -s libfyi.so.0.0.0 libfyi.so.0)

 (cd .libs && rm -f libfyi.so && ln -s libfyi.so.0.0.0 libfyi.so)

 ar cru .libs.libfyi.a fyi.o

 ranlib .libs/libfyi.la

 creating libfyi.la

 (cd .libs && rm -f libfyi.la && ln -s ../libfyi.la libfyi.la)


생성물은

/home/dansoonie/Work/fyi/libfyi.la

/home/dansoonie/Work/fyi/.libs/libfyi.a

/home/dansoonie/Work/fyi/.libs/libfyi.la -> ../libfyi.la

/home/dansoonie/Work/fyi/.libs/libfyi.lai

/home/dansoonie/Work/fyi/.libs/libfyi.so -> libfyi.so.0.0.0

/home/dansoonie/Work/fyi/.libs/libfyi.so.0 -> libfyi.so.0.0.0

/home/dansoonie/Work/fyi/.libs/libfyi.so.0.0.0

이다...



4. Library를  executable에 link해서 사용하기


일단 libfyi를 가져다쓸 executable을 테스트로 만들어보자. ($PWD = /home/dansoonie/Work/fyitest/)

/home/dansoonie/Work/fyitest/fyitest.c listing

#include <stdio.h>
#include "fyi.h"

int main()
{
name();
birthday();
return0;
}

 쉘에서 다음 명령어를 수행하여 위의 코드를 컴파일 한다. ($PWD = /home/dansoonie/Work/fyitest/)

gcc -I ../fyi -g -O -c fyitest.c


설명:

    
- -I../fyi :
/home/dansoonie/Work/fyi 디렉터리를 include path에 추가하여 fyi.h가 include될 수 있도록 한다.

     - -g :
debug 정보 포함되도록 컴파일하는 옵션

     - -O :
optimization 하는 옵션

     - -c :
링크는 하지 않는 옵션

생성물은

/home/dansoonie/Work/fyitest/fyitest.o

이다...


fyitest를 libfyi와 링크하여 executable을 만들기 위해서는 쉘에서 다음 명령어를 수행한다.

libtool --mode=link gcc -g -O -o fyitest fyitest.o ../fyi/libfyi.la
* library를 install하기 전에 link를 해서 사용하게 되면 꼭 libtool을 사용해서 link를 해야 한다. Section 3.3 참고


output

gcc -g -O -o .libs/fyitest fyitest.o ../fyi/.libs/libfyiso

creating fyitest


생성물

/home/dansoonie/Work/fyitest/fyitest

/home/dansoonie/Work/fyitest/.lib/fyitest  <- 이 파일 생성의 정체 불명 (실행 안됨)

/home/dansoonie/Work/fyitest/.lib/lt-fyitest  <- 이 파일 생성의 정체 불명 (실행됨)


생성물 실행시 output 결과

Yoon-Soo Lee

January 18th




5. Library를 Install하기


 쉘에서 다음 명령어를 수행한다. ($PWD = /home/dansoonie/Work/fyi/)

libtool --mode=install install -c libfyi.la /usr/lib/libfyi.la

설명
     su 권한 상태에서 명령어를 실행하던지, 저 명령어 앞에 sudo를 사용하여 그 명령어만 su권한으로 실행하도록 한다. 당연히 su 비밀번호는 알아야 한다.

질문... library의 install경로는 libfyi.la에 저장되어있는데 왜 또 따로 /usr/lib이라고 명시해 주었는가? install 명령어 사용 방법이 install [option] SOURCE DEST 라서 그런가? 그리고 중요한 사실은 library를 build할때 -rpath 옵션으로 준 경로랑 위에서 명시해주는 DEST의 경로가 같아야 한다는데, 이렇게 실수를 다분히 유발할 수 있는 여지를 남겨놓은 이유는?

output은

install -c .libs/libfyi.so.0.0.0 /usr/lib/libfyi.so.0.0.0
(cd /usr/lib && { ln -s -f libfyi.so.0.0.0 libfyi.so.0 || { rm -f libfyi.so.0 && ln -s libfyi.so.0.0.0 libfyi.so.0; }; })
(cd /usr/lib && { ln -s -f libfyi.so.0.0.0 libfyi.so || { rm -f libfyi.so && ln -s libfyi.so.0.0.0 libfyi.so; }; })
install -c .libs/libfyi.lai /usr/lib/libfyi.la
install -c .libs/libfyi.a /usr/lib/libfyi.a
chmod 644 /usr/lib/libfyi.a
ranlib /usr/lib/libfyi.a
PATH="$PATH:/sbin" ldconfig -n /usr/lib
-----------------------------------------------------------------------
Libraries have been installed in:
   /usr/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,--rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------

library를 가져다 사용할때 header파일으로의 접근을 쉽게 하기 위해 library의 header 파일을 /usr/include로 복사하는 작업을 다음 명령어를 통해 수행한다. ($PWD = /home/dansoonie/Work/fyi/)
cp fyi.h /usr/include 

설명
     su 권한 상태에서 명령어를 실행하던지, 저 명령어 앞에 sudo를 사용하여 그 명령어만 su권한으로 실행하도록 한다. 당연히 su 비밀번호는 알아야 한다.



6. Install된 Library를  executable에 link해서 사용하기


이전에 만들었던 /home/dansoonie/Work/fyitest/fyitest.c 을 사용하자


 쉘에서 다음 명령어를 수행하여 fyitest.c를 컴파일 한다. ($PWD = /home/dansoonie/Work/fyitest/)

gcc -g -O -c fyitest.c


설명:

 
   - -g :
debug 정보 포함되도록 컴파일하는 옵션

     - -O :
optimization 하는 옵션

     - -c :
링크는 하지 않는 옵션

생성물은

/home/dansoonie/Work/fyitest/fyitest.o

이다...


fyitest를 /usr/lib에 install된 libfyi와 링크하여 executable을 만들기 위해서는 쉘에서 다음 명령어를 수행한다.

gcc -L/usr/lib -lfyi -o fyitest fyitest.o


생성물

/home/dansoonie/Work/fyitest/fyitest


최종 생성물 실행시 output 결과

Yoon-Soo Lee

January 18th



질문... -rpath를 /usr/local/lib으로 하면 6번과정을 마치고 ldd fyitest를 하여 fyitest가 어떤 library를 link했는지 살펴보면 libfyi.so.0 => not found 라고 나온다.


Posted by Dansoonie