Wednesday, June 2, 2010

이클립스 자동 컴파일 취소하고싶어요.

이클립스 자동 컴파일 취소하고싶어요.

이클립스에서 jsp파일 수정 후 저장하면 자동 컴파일이 됩니다.
이거 Disable하려면 어떻게 해야하나요?

    Tag
    tag는 게시물의 성격을 나타내는 키워드를 입력하는 공간입니다.
    tag는 로그인 후 사용하실 수 있습니다.
    • 이클립스가 jsp를 컴파일 하진 않아요.

      java라면 위쪽 프로젝트 메뉴에 오토 빌드 관련 채크가 있으니 해제하시고..

      jsp를 저장했을때 컴파일이라면 서버가 구동된 상태에 서버 핫디플로이가 켜져있으면

      그렇게 됩니다..

      뭐 톰켓이라면 server.xml 가셔서 오토리로드를 false로 바꿔주시면 됩니다.

    vnc linux 설치

    http://mroon.egloos.com/4247075

    [Linux]VNC 서버 계정 만들기

    리눅스에서는 윈도우의 원격 데스크톱 연결과 같은 vnc 서비스 기능을 제공한다.
    이 서비스 사용을 위해서는 각 사용자 계정별로 vncserver 설정을 해준 후 vnc viewer 프로그램으로 접속하면 된다.


    [vncserver 설정]
    vncserver 관련 설정파일은 /etc/sysconfig/vncservers 스크립트이다.
    이 파일에 vnc 서비스를 사용할 계정 아이디와 할당할 vnc에서 사용할 xterminal을 배정해 주면 된다.

    VNCSERVERS="NUM:ACCOUNT_NAME" //여기서 NUM가 590? 에서 ? 포트번호가 된다.
    VNCSERVERARGS[NUM1]="-geometry SCREEN_RESOLUTION"

    위와 같은 형식으로 사용자 정보를 입력해주면 된다.

    예)
    VNCSERVERS="1:root 2:windsong 3:zenadoo"
    VNCSERVERARGS[1]="-geometry 1280x960"
    VNCSERVERARGS[2]="-geometry 1024x768"
    VNCSERVERARGS[3]="-geometry 800x600"


    다음으로, 각 사용자 계정 홈디렉토리에서 아래와 같은 작업을 수행한다. 이는 각 계정별 vnc 관련 환경설정 및 접속시의 패스워드 설정이다.

    #cd ~ //home 디렉토리로 이동
    #mkdir .vnc //.vnc 디렉토리 생성
    #cd .vnc //.vnc 열기
    #vncpasswd //vnc 서버 암호 설정

    이때 주의할 점은 각 계정별 사용자 환경 구성인 경우이므로 생성하는 .vnc 디렉토리에 계정 사용자가 접근이 가능해야 한다.관리자 권한(root)으로 일반 사용자 계정 설정을 진행한 경우, 계정 사용자가 .vnc 디렉토리에 접근할 수 없게되어vncserver 사용이 불가능해진다. 따라서 각 계정별 환경구성시에는 계정 사용자로 전환해서 진행해야 한다.

    vnc 패스워드 지정 후 다시 관리자 권한으로 vncserver 서비스를 시작하도록 한다.

    #service vncserver start

    또는

    #/sbin/service vncserver start


    마지막으로 vnc에서 xterminal GUI 환경을 사용하기 위해 각 계정의 홈디렉토리에서 다음 파일의 2라인을 활성화한다.

    #vi /home/.vnc/xstartup

    unset SESSION_MANAGER
    exec /etc/x11/xinit/xinitrc


    --> 2라인 앞의 주석문(#) 제거하고 저장한다.
    이래야 GUI를 사용하여, 바탕화면이 뜬다. 안 할경우 Terminal만 접속이 된다.

    이제 모든 설정이 끝났다.
    vncserver 서비스를 재시작한다.

    #service vncserver restart



    윈도우에서 vnc viewer로 리눅스에 접속해 사용하기 위해서는 접속용 프로그램이 필요하다.
    RealVNC, Ultra VNC, 기호에 맞게 아무거나 사용하면 된다.

    리눅스에 접속하기 위해 서버의 어드레스, 환경 구성시 설정한 계정별 xterminal 식별 번호, vnc 접속 패스워드가 필요하다.


    형식으로 서버 정보를 입력하고 연결, VNC 접속 패스워드로 연결한다. 경우에 따라 vnc 접속 후 사용자 계정으로 로그인해야 될 경우도 있

    linux iptables 방화벽

    http://nizistyle.tistory.com/1

    # 방화벽 상태 알아보기
    service iptables status

    # 방화벽 올리고 내리기
    service iptables stop
    service iptables start

    # 방화벽 설정 수정하기
    vi /etc/sysconfig/iptables

    # 방화벽 해제
    iptable -F 혹은
    ipchains -F


    redhat 9.0 이라면 lokkit 으로 방화벽 설정을 할 수도 있습니다.

    Usage: lokkit [OPTION...]
    -f, --fwtype Write Red Hat style
    /etc/sysconfig/iptables rules,
    instead of a shell script
    -q, --quiet Run noninteractively; process
    only command-line arguments
    -n, --nostart Configure firewall but do not
    activate it
    --high Enable 'high' security level
    (default)
    --medium Enable 'medium' security level
    --disabled Disable firewall
    --dhcp Allow DHCP through the firewall
    -p, --port=port:protocol (e.g, ssh:tcp)Allow specific ports through the
    firewall
    -t, --trust=device to trust Allow all traffic on the
    specified device

    Help options:
    -?, --help Show this help message
    --usage Display brief usage message

    lokkit -q --disabled 라고 하면 방화벽이 해제됩니다.
    iptables -F라고 직접 명령을 주어도 됩니다 F는 Flush 를 뜻합니다.
    Kernel 2.2대의 linux 배포판이라면 ipchains -F 하면 됩니다.


    service iptables restart

    리눅스 하드추가

    http://linuxis.tistory.com/558

    http://myblog.oranc.co.kr/201


    fdisk -l
    한후 장착한 /dev/sdc 찾기


    하드추가시에는 세가지 작업을 해주셔야 합니다.

    * 파티션생성
    * 파일시스템생성
    * 마운트포인트생성


    1. 서버에 하드 추가 후 OS 부팅시 하드가 올라오는지 확인한다.

    2. vi /etc/fstab을 열어 ext2, ext3인지 판단..

    3. fdisk로 파티션을 잡는다.
    예)

    3-0. fdisk -l 로 확인
    3-1. fdisk /dev/hdb (IDE 하드인 경우), fdisk /dev/sdb (SCSI 하드인 경우)
    3-2. p로 기존 파티션이 잡혀있는지 확인한다.
    3-3. d로 기존 파티션이 잡혀있으면 삭제후 p로 확인한다.
    3-4. n으로 파티션 추가- > p(primary로) -> 1 -> 크기지정 default 1 입력(Full로 잡을시, 디폴트가 Full) -> 엔터
    3-5. w로 쓴다.

    4. format
    ext3 : mke2fs -j /dev/hdb
    ext2 : mkfs -t ext2 /dev/hdb

    5. 마운트할 디렉토리 생성
    /에서 mkdir /home2 등등

    6. mount
    ext3 : mount -t ext3 /dev/hdb /home2
    ext2 : mount -t ext2 /dev/hdb /home2

    7. fstab 수정 (vi /etc/fstab)
    예)
    LABEL=/home /home ext3 defaults 1 2 (를 카피하여 페이스트 하여 아래와 같이 편집)
    ->
    /dev/hdb /home2 ext3 defaults 1 2 (앞 두부분만 수정) LABEL 은 삭제

    8. df -h로 마운트 확인

    9. 재부팅후 이상없이 올라온후 마운트 되었는지 확인





    /etc/fstab 에서 파티션을 잘못 셋팅하면 에러가 나면서 부팅이 되지 않습니다.
    (혹은 있던 드라이브가 없어지면 fstab 의 내용이랑 틀려서 부팅이 되지 않습니다.)

    이때 정상적인 부팅이 되지 않아서 Root Password를 넣을 것을 요구합니다.
    (참고적으로 Ctrl+D 누르면 재부팅됩니다.)
    Password를 넣으시면 복구모드로 들어가지만, 파일시스템이 ReadOnly 이기 때문에
    /etc/fstab 파일을 수정할 수가 없습니다.

    여기서 꽁수...

    mount -o remount,rw /dev/hda1 <= hda1 은 / filesystem

    이제 파일쓰기가 가능하므로 vi /etc/fstab 을 수정한 후 재부팅하면 됩니다


    ex)mount -o remount,rw /

    ex)

    LABEL=/ / ext3 defaults 1 1

    LABEL=/home /home ext3 defaults 1 2

    LABEL=/usr /usr ext3 defaults 1 2

    LABEL=/var /var ext3 defaults 1 2

    LABEL=/tmp /tmp ext3 defaults 1 2

    LABEL=/usr/local /usr/local ext3 defaults 1 2

    LABEL=/boot /boot ext3 defaults 1 2

    /dev/sdb1 /mnt/hdd1 ext3 defaults 1 2

    /dev/sdb2 /mnt/hdd2 ext3 defaults 1 2

    /dev/sdb3 /mnt/hdd3 ext3 defaults 1 2

    tmpfs /dev/shm tmpfs defaults 0 0

    devpts /dev/pts devpts gid=5,mode=620 0 0

    sysfs /sys sysfs defaults 0 0

    proc /proc proc defaults 0 0

    LABEL=SWAP-sda7 swap swap defaults 0 0

    Friday, May 28, 2010

    Program Library HOWTO 동적라이브러리 동적로딩

    http://wiki.kldp.org/HOWTO/html/Program-Library-HOWTO/index.html

    Program Library HOWTO

    WheelerDavid A.

    dwheeler (at) dwheeler.com

    박상민

    mskrap (at) kaist.ac.kr

    고친 과정
    고침 1.0022 March 2002
    고침 0.602000-05고친이 황진희
    최초 번역

    이 HOWTO문서는 프로그래머들이 리눅스 상에서 어떻게 라이브러리를 만들고 사용하는지에 대한 방법을 논의한다. 이 문서는 정적 라이브러리, 공유 라이브러리, 동적 적재 라이브러리를 다룬다.

    c++ 동적라이브러리 / 동적 클래스

    1 http://wiki.kldp.org/wiki.php/DocbookSgml/C%2B%2B-dlopen#LOADINGCLASSES

    C++ dlopen mini HOWTO

    IsottonAaron

    김경태

    dlopen API를 이용하여 동적으로 C++ 함수와 클래스를 적재하는 방법을 설명한다.

    고친 과정
    고침 1.002002-06-19고친이 AI
    copyright와 license부분을 앞쪽으로 옮겼다. 용어에 관한 부분을 추가했다. 약간 변화가 있었다.
    고침 0.972002-06-19고친이 JYG
    문장과 문법을 약간 가다듬었다.
    고침 0.962002-06-12고친이 AI
    참고 문헌을 추가했다. 외부 함수와 변수들의 설명을 수정했다.
    고침 0.952002-06-11고친이 AI
    아주 약간 개선.
    고침 0.92002-06-10고친이 AI
    초안 작성.

    1. 소개

    Unix C++ 프로그래머 사이에서 자주 발생하는 질문은 dlopenAPI를 이용하여 C++ 함수와 클래스를 적재하는 방법에 관한 것입니다.

    사실 이것은 항상 간단한 것만은 아니기 때문에,약간의 설명이 필요합니다. 이 mini HOWTO에서 그것에 관한 내용을 다루고 있습니다.

    이 문서를 이해하기 위해서는 C, C++,그리고dlopen API 에 대해서 어느 정도 알고 있어야 할 것입니다.

    이 HOWTO의 원문은 http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/에 있습니다.


    1.1. Copyright and License

    이 문서 C++ dlopen mini HOWTO의 저작권은 Aaron Isotton 에게 있습니다. 자유 소프트웨어 재단에서 발표한, 1.1 혹은 그 이후 버전의 GNU Free Documentation License의 조항에 따라 이 문서를 복사하거나, 배포 혹은 변경하는 것이 허용됩니다.


    1.2. 경고(Disclaimer)

    이 문서의 내용으로 인한 책임은 지지 않습니다. 여기에 쓰여진 개념이나 예제 그리고 정보를 사용하여 발생한 문제에 대한 책임은 모두 당신의 책임입니다. 여기에는 당신의 시스템에 피해를 줄 수 있는 오류나 부정확한 것들이 있을수도 있습니다. 주의하여 주시기 바라며, 저는 여기에 어떠한 책임도 지지 않을 것입니다.

    모든 저작권은 구체적으로 언급하지 않았다면, 그것들 각각의 소유자가 가지고 있습니다. 이 문서에 있는 용어의 사용이 어느 등록상표나 서비스 마크의 효력에 영향을 끼치는 것으로 간주해서는 안 됩니다. 특별한 제품이나 브랜드를 지명하는 것이 상품등의 추천으로 보여서는 안 됩니다.


    1.3. 도와 주신분

    이 문서에서, 나는 이 분들께 감사하게 되어 기쁘게 생각합니다.

    • Joy Y Goodreau 씨 는 교정에 도움을 주셨습니다.

    • D. Stimitis 씨 는 formatting 과 name mangling에 대한 몇가지 이슈를 지적해주셨고, extern "C"에 대한 몇가지 난해한 점을 지적해주셨습니다.


    1.4. Feedback

    이 문서에 대한 반응은 언제나 환영입니다. 당신이 추가했으면 하는 것, 의견, 비판을 다음 주소로 보내주시기 바랍니다 .


    1.5. 이 문서에서 쓰인 용어들

    dlopen API

    dlclose, dlerror, dlopen,그리고 dlsym 함수는 dlopen(3) 매뉴얼 페이지에서 설명하고 있습니다.

    이 글에서"dlopen"이라고 썼을 때는, dlopen함수 하나를 지칭하는 것이고, "dlopen API" 라고 썼을 때에는, API 전체를 지칭하는 것입니다.


    2. 문제

    프로그램이 실행될때, 라이브러리를 적재해야 할 때가 가끔씩 있을 것입니다. 당신이 프로그램에 들어가는 플러그인이나 모듈을 만들고 있을때 이러한 일은 종종 발생합니다.

    C언어에서, 동적으로 라이브러리를 적재하는 것은 매우 간단합니다. (dlopen, dlsym 그리고 dlclose를 호출하는 것만으로 충분합니다) C++에서는 약간 더 복잡합니다. C++ 라이브러리를 동적으로 적재하는 것이 어려운 이유중에 일부분은name mangling 때문이고, 일부분은 dlopen API가 C를 염두에 두고 만들어졌기 때문에 class를 적재하는 적당한 방법을 제공하지 못하기 때문입니다.

    C++에서 라이브러리를 적재하는 방법에 대해 설명하기 전에, name mangling에 대해서 자세히 살펴보고, 문제를 분석해 봅시다. 비록 당신이 name mangling에 관심이 없더라도, 나는 당신이 그것에 대한 설명을 읽기를 바랍니다. 왜냐하면 그것은 당신이 왜 문제가 발생하고 어떻개 해결해야 하는지를 이해하는데 도움을 주기 때문입니다.


    2.1. Name Mangling

    모든 C++프로그램(혹은 라이브러리나 Object 파일)에서, 모든 non-static 함수는 이진 파일에서 symbol로 표현됩니다. 이러한 symbol들은 프로그램(혹은 라이브러리나 Object 파일)에서, 유일하게 함수를 확인하는, 특수한 문자열입니다.

    C에서는, symbol의 이름은 함수의 이름과 동일합니다. strcpy의 symbol은 strcpy입니다. C에서는 두개의 non-static 함수가 같은 이름을 가질 수 없기 때문에 이것이 가능합니다.

    C++은 오버로딩을 허용하고 (같은 이름을 가지지만 인자가 다른 함수를 정의할 수 있다), C가 가지고 있지 않은 여러가지 특징들 — Class, member function, exception specifications — 을 가지고 있기 때문에, 그냥 단순히 함수 이름을 symbol 이름으로 쓸 수는 없습니다. 이 문제를 해결하기 위해서, C++에서는 name mangling(이름 엉망으로 만들기)이라는 것을 사용합니다. 이것은 함수이름과 모든 필요한 정보 모두를(인자의 크기나 갯수와 같은) 컴파일러만이 알아볼 수 있는 이상한 문자열로 바꿔버립니다. 예를 들어 foo라는 함수가 있다면, name mangling에 의해 foo@4%6^로 바뀔 것입니다.

    name mangling과 관련하여 생기는 문제점의 하나는 C++ 표준 (현재는 [ISO14882])이 그 방법을 정의해 놓지 않았다는 점입니다. 이것은 모든 컴파일러들마다 자기만의 방법 으로 name mangling을 한다는 것을 의미합니다. 어떤 컴파일러는 name mangling 알고리즘이 버전에 따라 다르기도 합니다. (g++ 2.x 와 3.x에서 뚜렷하게 드러납니다.) 비록 당신이 특정한 컴파일러가 어떻게 이름을 바꾸는지 이해했다고 해도(그래서 dlsym을 통해 그 함수를 적재할 수 있게 된다고 해도), 그것은 아마 그 특정한 컴파일러에서만 효과가 있을 것이고, 다음 버전의 컴파일러에서는 이미 사용할 수 없을지도 모릅니다.


    2.2. Classes

    dlopen API 의 또다른 문제는, 이들이함수를 적재하는 것만을 지원하고 있다는 점입니다. 하지만 C++에서는 라이브러리가 종종 당신이 프로그램에서 쓰고자 하는 Class를 노출시키고는 합니다. 분명히, 클래스를 사용하기 위해서 당신은 그것의 인스턴스를 만들어야 하지만, 그것은 쉽지 않습니다.


    3. 해결 방법

    3.1. extern "C"

    C++에는 extern "C"라는, C binding으로 함수를 정의하는 특별한 키워드가 있습니다. extern "C"로서 선언된 함수는 C처럼 함수의 이름을 symbol의 이름으로 사용합니다. 이러한 이유로, 멤버함수가 아닌 함수들만이 extern "C"로서 선언될 수 있고, 이러한 함수들은 오버로딩을 할 수 없습니다.

    이런 심한 제한이 있지만, extern "C"함수는 C 함수처럼 dlopen을 써서 동적으로 적재할 수 있기 때문에 매우 유용합니다.

    이것은 extern "C"로 선언된 함수가 C++ 코드를 포함할 수 없다는 것을 의미하는 것이아닙니다. 이런 함수는 어느 종류의 인자라도 받을 수 있고, C++의 특징을 쓸 수 있습니다.


    3.2. 함수를 적재하는 법

    C++에서 함수는 dlsym을 통해 C처럼 적재됩니다. 당신이 적재하고자 하는 함수는 symbol의 이름이 엉망으로 되지 않도록(name mangling이 이루어지지 않도록), extern "C"로서의 자격을 갖춰야 할 것입니다.

    예 1. 함수를 적재하기

    main.cpp:

    #include  #include    int main() {     using std::cout;     using std::cerr;      cout << "C++ dlopen demo\n\n";      // open the library     cout << "Opening hello.so...\n";     void* handle = dlopen("./hello.so", RTLD_LAZY);          if (!handle) {         cerr << "Cannot open library: " << hello =" (hello_t)">

    hello.cpp:

    #include   extern "C" void hello() {     std::cout << "hello" << '\n'; }

    hello라는 함수는 hello.cpp에서 extern "C"로 선언되었습니다. 이것은 main.cpp에서 dlsym을 사용하여 적재할 수 있습니다. 함수는 extern "C" 로서의 자격을 갖추어야 합니다. 그렇지 않다면 우리는 hello 함수의 symbol의 이름을 알 수 없을테니까요.

    주의

    extern "C"의 선언에는 두가지의 다른 형태가 있습니다: 하나는 위에서 썼던extern "C"의 방법이고, 또 다른 하나는 extern "C" { … }형태로 중괄호 사이에 선언이 들어가는 방법입니다. 첫번째(inline)형태는 extern 연결과 C 언어 연결을 갖습니다. 두번째 형태는 C언어 연결에만 영향을 끼칩니다. 따라서 아래의 두 가지 선언 방법은 동일한 것입니다.

    extern "C" int foo; extern "C" void bar();             
    extern "C" {      extern int foo;      extern void bar();  }

    extern과 extern이 아닌 함수의 선언에는 차이가 없기때문에, 당신이 어떠한 변수도 선언하지 않는 한 문제가 없습니다. 당신이 변수를 선언한다면,다음의 두 선언 방법은 같지 않다는 것을 명심해야 합니다.

    extern "C" int foo;
    extern "C" {     int foo; }

    좀 더 자세한 설명을 원하시면, paragraph 7에 주의를 기울여 [ISO14882]의 7.5를 읽어보시거나, [STR2000]의 paragraph 9.2.4.를 참조해주십시오.

    외부 변수로 무언가를 하기 전에, see also부분에 적혀 있는 문서들을 정독해주시기 바랍니다.


    3.3. 클래스를 적재하는 법

    클래스를 적재하는 것은 좀 더 어렵습니다. 왜냐하면 우리는 클래스의인스턴스를 필요로 하지, 함수에 대한 포인터를 필요로 하는게 아니기 때문입니다.

    클래스가 실행파일에 정의되어 있지 않은데다가,(몇몇 상황에서는) 클래스의 이름조차도 알 수 없기 때문에, 우리는 new 를 이용하여 클래스의 인스턴스를 생성할 수 없습니다.

    이것은 다형성(polymorphism) 을 통해 해결할 수 있습니다. 우리는 기반 클래스, 가상의 멤버를 가지고 있는 인터페이스클래스를 실행파일내에 선언하고, 실제 구현부의 클래스를 모듈 에 선언합니다. 일반적으로 인터페이스 클래스는 추상적입니다. (클래스가 순수가상함수(pure virtual function)을 가지고 있을때 클래스가 추상적이라고 합니다.)

    클래스의 동적인 적재는 일반적으로 플러그인 — 명확하게 정의된 인터페이스를 보여주어야 하는 — 에 쓰이기 때문에, 우리는 어쨌거나 인터페이스 클래스와 거기서 파생된 구현부 클래스를 정의해야 합니다.

    다음으로,모듈 안에Class factory function이라는 두개의 도움을 주는 함수를 추가로 선언해야 합니다. 이 함수 중 하나는 클래스의 인스턴스를 만들고 그것의 포인터를 반환하는 역할을 하고, 또 다른 하나의 함수는 factory에서 만들어진 함수의 포인터를 받아 그것(클래스의 인스턴스)를 파괴하는 역할을 합니다. 이 두 함수는 extern "C"의 자격을 가지고 있어야 합니다.

    클래스를 모듈에서 쓰기 위해서,두개의 factory function을 우리가 hello함수를 적재했던 것처럼dlsym을 사용하여 적재하십시오.그럼 우리는 우리가 원하는 만큼의 인스턴스를 생성할수도 있고, 파괴할 수도 있습니다.

    예 2. 클래스를 적재하는 법

    여기서 우리는 일반적인다각형을 인터페이스로 하고, 삼각형을 구현부분으로 할 것입니다.

    main.cpp:

    #include "polygon.hpp" #include  #include   int main() {     using std::cout;     using std::cerr;      // load the triangle library     void* triangle = dlopen("./triangle.so", RTLD_LAZY);     if (!triangle) {         cerr << "Cannot load library: " << create_triangle =" (create_t*)" destroy_triangle =" (destroy_t*)" poly =" create_triangle();">set_side_length(7);         cout << "The area is: " <<>area() << '\n';      // destroy the class     destroy_triangle(poly);      // unload the triangle library     dlclose(triangle); }

    polygon.hpp:

    #ifndef POLYGON_HPP #define POLYGON_HPP  class polygon { protected:     double side_length_;  public:     polygon()         : side_length_(0) {}      void set_side_length(double side_length) {         side_length_ = side_length;     }      virtual double area() const = 0; };  // the types of the class factories typedef polygon* create_t(); typedef void destroy_t(polygon*);  #endif

    triangle.cpp:

    #include "polygon.hpp" #include   class triangle : public polygon { public:     virtual double area() const {         return side_length_ * side_length_ * sqrt(3) / 2;     } };   // the class factories  extern "C" polygon* create() {     return new triangle; }  extern "C" void destroy(polygon* p) {     delete p; }

    클래스를 적재할때 주의해야 할 점이 몇가지 있습니다:

    • 당신은 인스턴스를 생성하는 함수와 파괴하는 함수를 모두 제공해야 합니다. 또 당신이 인스턴스를 파괴할때에는 실행파일 내에서 delete를 이용해서 지우지 마시고 ,항상 모듈로 넘겨서 주시기 바랍니다. 이는 C++ 에서 new와 delete 가 오버로딩 될 수 있기 때문입니다. 이 경우에 서로 맞지 않는 new와 delete 가 호출될 수 있고, 그렇게 되면 메모리 누수나 segmentation fault가 일어날 수도 있습니다.이것은 모듈과 실행파일을 링크할때 서로 다른 표준 라이브러리를 사용했을 경우에도 적용됩니다.

    • 인터페이스 클래스의 소멸자는 구현부 클래스에 소멸자가 없는경우를 제외하고는 가상(virtual)이어야 합니다. 그렇지 않으면 그것은 호출되지 않을 것이고, 메모리 누수나 segmentation fault가 일어날 수도 있습니다.


    4. See Also


    서지사항

    ISO14482 ISO/IEC 14482-1998 — The C++ Programming Language. http://webstore.ansi.org/에서 PDF로 이용가능합니다.

    STR2000 Stroustrup Bjarne The C++ Programming Language, Special Edition. ISBN 0-201-70073-5. Addison-Wesley.










    1 이유

    다양한 애플리케이션에 사용가능한 로그분석 프로그램을 만들려고 한다. 이러한 프로그램의 경우 어떤 애플리케이션에서 사용할지 알 수 없기 때문에, 원본소스에는 수정할 필요 없이 로그분석 알고리즘만 적재가능하도록 만들 필요가 있다.

    가장좋은 방법은 main 코드와 알고리즘을 분리시키는 것으로, 이것은 라이브러리의 동적적재를 이용해서 달성가능 하다. 동적적재는 라이브러리문서에 언급되어 있다.

    즉 알고리즘을 플러그인 형태로 적재하는 기술인데, 여기에 더해서 C++의 클래스를 동적으로 적재시킬 수 있기를 원했다. 그렇다면, 클래스의 추상화를 이용해서, 좀더 일관된 개발자 인터페이스를 제공할 수 있을 것이기 때문이다.

    그러므로 다음의 두가지를 달성하는게 주요 목표가 될 것이다.
    1. 로그분석 알고리즘을 플러그인 형태로 적재할 수 있도록 한다.
    2. 클래스를 적재함으로써, 일관된 개발자 인터페이스를 제공한다.

    이것은 전술패턴의 구현으로 볼 수 있을 것이다.

    2 C++로 작성된 라이브러리사용의 문제

    C++에서 클래스의 동적적재 가능성에 대해 생각해 본다.

    C에서의 라이브러리의 동적적재는 명료하다. 이에 대한 내용은 라이브러리만들기 문서를 참고한다.

    C++에서는 name mangling 때문에 dlopen()을 이용해서 라이브러리를 적재하는데, 어려움이 있다. 애시당초 dlopen()이 C++을 염두에 두지 않고 만들었다는 것도 문제일 것이다.

    C와 C++은 함수를 가리키기위한 symbol 테이블을 가지고 있다. 어떤 함수를 호출하면 symbol 테이블을 뒤져서, 이진파일 내에서 함수의 원본의 위치를 알아내어서 읽어들이고 실행하는 것으로 묘사할 수 있다.

    C는 symbol이 하나의 함수와 대응한다. 그렇지만 C++은 overloading으로 인하여서, 함수이름과 심볼이 일치하지 않는 경우가 발생한다. 이름은 같지만 인자가 다른 함수가 대표적인 경우다. 그러므로, C++로 공유라이브러리를 만들고자 할경우, 이 함수는 반드시 유일하다는 것을 컴파일러에게 알려줄 필요가 있다.

    3 extern "C" 를 이용한 해결

    오버로딩으로 인해서 발생하는 문제는 extern "C"를 이용하면 해결할 수 있다. extern "C" 는 해당 함수가 심볼이름과 일치될 것이라는 것을 알려준다. 이를테면 C 함수와 마찬가지로 사용하겠다는 의미다. 대신 C++의 기능인 overload등은 사용할 수 없게 된다.

    예컨데 hello란 함수가 있다면, 다음과 같이 extern "C"를 이용해서 정의할 수 있다.
    #include     using namespace std;  extern "C" void hello()  {      cout << "hello" << "\n";      }   

    4 class의 동적적재

    exern "C"를 이용해서, 오버로딩이 필요없는 함수를 적재시키는 법에 대해서 알아봤다. 그렇다면, class는 어떨까.

    안타깝게도 class는 dlopen()을 이용해서 호출할 수가 없다. 애초에 dlopen이 class를 염두에 두고 만들어진게 아니기 때문이다. 가장 일반적으로 사용할 수 있는 방법은 class에 대한 포인터를 넘겨주는 factory 함수를 만들고, 이 포인터를 이용해서 메서드를 호출하는 방법일 것이다.

    다음은 factory 함수를 이용해서 클래스를 호출하는 예제 프로그램이다. 프로그램이름은 main.cc로 하겠다.
    #include   #include   #include   #include   #include   #include "mymodule1.h"    int main(int argc, char **argv)  {    void *handle;      char *error;    Test *LTest;      handle = dlopen("libmymodule.so", RTLD_LAZY);    if (!handle)    {      perror("Open Library\n");      exit(0);    }      // Func_Init    init_t* init_myFunc = (init_t *)dlsym(handle, "Func_Init");    if ((error = dlerror()) != NULL)    {      printf("ERROR : %s\n",error);      exit(0);    }    LTest = init_myFunc();    LTest->Count();    LTest->Count();    LTest->Print();      // Func_destory    destroy_t *destroy_myFunc = (destroy_t *)dlsym(handle, "Func_destory");    destroy_myFunc(LTest);  }   

    mymodule1.h로 class Test가 선언되어 있다.
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 
    #ifndef _MYMODULE_H_  #define _MYMODULE_H_    #include   #include     using namespace std;    class Test  {    private:      int count;    public:      Test();      ~Test()      {        printf("Destory\n");      }      void Count();      void Print();  };  extern "C" class Test* Func_Init();  extern "C" void Func_destory(class Test *aTest);    typedef void destroy_t(Test*);  typedef Test* init_t();  #endif   
    Funic_init와 Func_destory라는 factory 함수가 선언되어있다.

    다음은 Test 클래스와 factory 함수가 정의되어 있는 코드로 파일명은 mymodule1.cc다.
    #include "mymodule1.h"    Test::Test()  {      printf("Init\n");      count=0;  }    void Test::Count()  {      count++;  }    void Test::Print()  {      printf("Count is %d\n", count);  }    class Test* Func_Init()  {      Test *myTest;      myTest = new Test;      return myTest;  }    void Func_destory(class Test *aTest)  {      delete aTest;  }    void Func_Test(class Test *aTest)  {      aTest->Count();      aTest->Print();  }   

    다음은 컴파일 방법이다. 먼저 mymodule1.cc를 공유라이브러리형태로 컴파일 한다.
    # g++ -fPIC -c mymodule1.cc  # g++ -shared -W1,-soname,libmymodule.so.1 -o libmymodule.so.1.0.1 mymodule1.o   

    main.cc를 컴파일 한다.
    g++ -o main main.c -ldl -lmymodule   
    일반적인 동적적재의 경우 함수원형이 필요 없지만 class의 경우에는 메서드를 호출해야 하기 때문에 -l옵션을 이용해서 메서드에 대한 정의가 있는 라이브러리 명시적으로 지시해줘야 한다.

    만들어진 프로그램을 실행시켜 보자.
    $ ./main  Init  Count is 2  Destory   
    제대로 실행됨을 알 수 있다.

    5 다형성의 구현

    factory 함수를 이용해서 클래스를 로딩할 수 있는 방법을 터득했으니, 이제 로그분석 프로그램 제작에 대한 계획을 세워보기로 하자.

    이 로그분석 프로그램은 다음과 같은 사항들을 만족시켜야 한다.
    1. 다양한 로그에 대응할 수 있도록 플러그인형식으로 적재할 수 있어야 한다.
    2. 프로그래머에게 공통의 인터페이스를 제공할 수 있어야 한다.
    1번 요구사항은 라이브러리의 동적적재를 이용해서 해결할 수 있다. 즉 설정파일을 만든다음에, 해당 로그파일에 대응되어서 적재할 라이브러리를 명시해주면 된다. 이것에 대한 간단한 예는 라이브러리의 사용에 언급되어 있으니, 응용하는데 문제없을 것이다.

    2번 요구사항은 클래스를 적재시키고, 클래스의 메서드를 가상함수화 하는 것으로 달성할 수 있을 것이다. 일종의 Interface 클래스를 만들고, 개발자는 Interface의 메서드를 구현하는 방식으로 필요한 모듈을 개발하는 것이다.

    6 예전 방식 구현

    예전에도 로그분석 비스무레한 프로그램을 만들었던 적이 있다. 보안로그분석프로그램이였는데, 보안장비로 부터 syslog, snmp 혹은 전용socket으로 부터 보안로그를 받아서 분석하고, 이벤트를 생성하는 프로그램이였다. 기본개념은 DOS 공격검사 프로그램의 제작에 소개된 바가 있다.

    기본 시스템/네트워크 구성은 다음과 같다.

    dos.png

    보안장비는 다양한 종류의 보안소프트웨어가 설치되어 있으며, 로그 또한 전혀표준화 되어 있지 않으며, 나름대로의 정책을 가지고 만들어진다. 만약 새로운 장비가 추가된다면, 분석소프트웨어는 해당 장비의 보안로그를 분석할 수 있는 기능이 추가되어야 한다.

    이 프로그램은 다음의 조건을 만족할 수 있어야 했다.
    1. 새로운 보안장비 혹은 새로운 보안 제품이 추가되면, 다음과 같은 이유로 새로운 분석모듈을 개발해야 한다.
      • 보안로그가 표준화 되어 있지 않았기 때문
      • plain text, binary 데이터 혹은 DB로 log를 저장하는 등 방식의 차이
      • snmp, syslog, 전용 socket 등 다양한 통신 방법
    2. 가능한 main 코드는 수정되지 않아야 한다.
    3. 모듈의 개발은 일관성이 담보될 수 있어야 한다.
    위의 요건들을 만족시키기 위해서 다음의 방법을 사용했다. 일종의 전술패턴의 응용이라고 볼 수 있을 것이다.
    1. 각 제품에 대응되는 라이브러리를 생성한다. 10개의 제품의 로그를 분석해야 한다면, 10개의 라이브러리가 만들어질 것이다.
    2. {해당장비 => 해당장비의 로그를 분석할 수 있는 알고리즘이 포함된 라이브러리}를 선택하도록 전술을 구사한다.
    이 방식은 함수포인터를 이용한 프로토콜 처리에 비슷하게 구현되어 있으니 참고하기 바란다.

    이 방식은 만족시켜야할 조건중 1번과 2번은 어느정도 만족시킬 수 있지만, 3번을 만족시키지는 못했다. 코드가 객체지향적이지 않았기 때문에, 즉C로 개발되었기 때문이다. 물론 좀더 노력과 시간을 들였다면, 3번을 만족시킬 수 있는 프로그램의 제작이 가능했겠지만, 그때는 그럴만한 실력을 갖추지 못했다.

    7 방법의 개선

    그래서 class의 가상함수를 이용해서 개발자 인터페이스를 만들고, 이 인터페이스를 상속받아서 실제 구현을 하도록 하는 방법을 생각했다. 여기에서는 대략적인 개념만 소개하는 정도로 하겠다.

    다음과 같이 순수가상함수를 포함하는 Interface 클래스를 만들도록 한다. interface.h로 하겠다.
    #ifndef _INTERFACE_H_  #define _INTERFACE_H_    class Log  {    private:      int data;    public:      virtual int Create()=0;      virtual int Anly()=0;      virtual int Read()=0;      virtual int Destroy()=0;      virtual ~LogAnly()      {      }  };    #endif   
    • 이제 개발자는 모듈의 작성시 위의 Log클래스를 상속받고, 각 가상함수를 실구현하면 된다.
      • Create : 객체를 생성한다.
      • Anly : 실제 분석을 한다.
      • Read : 분석된 데이터를 읽어들인다.
      • Destroy : 객체를 파괴한다.
    다음은 실구현을 포함한 코드다.
    #include   #include     class TestLogAnly : public Log  {    private:    struct _CountData    {      int count1;      int count2;    };    _CountData CData;    Config *Cfg;    public:      TestLogAnly();      int Create(char *);      int Anly();      int Read();      int Destroy();      ~TestLogAnly();  };    using namespace std;  int TestLogAnly::Create()  {    cout << "Create " << href="http://www.joinc.co.kr/modules/moniwiki/wiki.php/manSearch?google=none&name=TestLogAnly::Destroy" style="color: rgb(51, 153, 204); text-decoration: none; ">TestLogAnly::Destroy()  {    cout << "Module Anly Destroy" << href="http://www.joinc.co.kr/modules/moniwiki/wiki.php/manSearch?google=none&name=TestLogAnly::Anly" style="color: rgb(51, 153, 204); text-decoration: none; ">TestLogAnly::Anly()  {    CData.count1 = 100;    CData.count2 = 200;    cout << "Log Anly" << href="http://www.joinc.co.kr/modules/moniwiki/wiki.php/manSearch?google=none&name=TestLogAnly::Read" style="color: rgb(51, 153, 204); text-decoration: none; ">TestLogAnly::Read()  {    cout << "ReadData count 1 : "<< href="http://www.joinc.co.kr/modules/moniwiki/wiki.php/manSearch?google=none&name=memset" style="color: rgb(51, 153, 204); text-decoration: none; ">memset((void *)&CData, 0x00, sizeof(CData));  }    // factory 함수의 선언  extern "C" TestLogAnly *Obj_Create();  extern "C" void Obj_Destroy(TestLogAnly *);    TestLogAnly *Obj_Create()  {          TestLogAnly *rtv;          rtv = new TestLogAnly();          return rtv;  }    void Obj_Destroy(TestLogAnly *aLog)  {          delete aLog;  }   
    이것으로 동적적재에도 클래스의 가상화, 추상화, 은닉을 적용할 수 있게 되었다.

    Thursday, May 27, 2010

    gcc library 만들기

    http://poongcha.blogspot.com/2009/06/gcc-library.html

    2009년 6월 6일 토요일

    gcc library 만들기


    정적 라이브러리 만들기

    1.Object 만들기
    $ g++ -c Squawk.cpp Cat.cpp Dog.cpp Lion.cpp Car.cpp

    2.라이브러리 만들기
    $ ar cr libSquawk.a Squawk.o Cat.o Dog.o Car.o Lion.o

    3.라이브러리 인덱스 만들기 (optional)
    ranlib == ar -s와 같으며, 만들어진 index는 nm -s를 통해 확인 가능
    $ ranlib libSquawk.a

    정적 라이브러리 사용하기

    1.컴파일
    라이브러리 Header 파일 디렉토리 지정 필요
    $ g++ -c -I ../CoreSquawk main.cpp

    2.링크
    라이브러리 및 라이브러리 디렉토리 지정 필요
    $ g++ -o TestSquawk.exe main.o -L ../CoreSquawk -lSquawk

    공유 라이브러리 만들기

    하나 이상의 프로세스에서 사용되는 경우 메모리 양과 실행 파일 크기 줄여줌, 개발 과정 용이, 라이브러리의 변경시에도 대부분 애플리케이션 재컴파일 불필요

    1.재배치가능한 Object (Position Independent Code) 만들기
    $ g++ -fPIC -c Squawk.cpp Cat.cpp Dog.cpp Lion.cpp Car.cpp

    2.공유 라이브러리 만들기
    $ gcc -shared -o libSquawk.so Squawk.o Cat.o Dog.o Car.o Lion.o

    공유 라이브러리 사용하기

    1.컴파일 라이브러리 Header 파일 디렉토리 지정 필요
    $ g++ -c -I ../CoreSquawk main.cpp

    2.링크 라이브러리 및 라이브러리 디렉토리 지정 필요
    $ g++ -o TestSquawk.exe main.o -L ../CoreSquawk -lSquawk

    꼭 정적인 라이브러리를 링크 하고자 할 때
    $ g++ -o TestSquawk.exe main.o ../CoreSquawk/libSquawk.a

    ldd 명령: 실행 프로그램이 사용하는 공유 라이브러리 나열
    $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/user/CoreSquawk
    $ ldd TestSquawk.exe

    참고자료 :
    윈도우에서 유닉스로 이식하기 http://www.ibm.com/developerworks/kr/library/au-porting/index.html

    0 개의 댓글:

    댓글 쓰기