http://www.kaizou.org/2015/01/linux-libraries.html

Better understanding Linux secondary dependencies solving with examples

A few months ago I stumbled upon a linking problem with secondary dependencies I couldn’t solved without overlinking the corresponding libraries. I only realized today in a discussion with my friend Yann E. Morin that not only did I use the wrong solutio

www.kaizou.org


https://nglee.github.io/2018/10/11/Study-Linker-Options.html

라이브러리 배포 과정에서 알아두면 좋을 링커 옵션

이 포스트에서는 링커 ld(1) 가 제공하는 수많은 옵션들 중 라이브러리 배포 과정에서 요긴하게 활용할 수 있는 몇 가지 옵션들에 대해 알아보겠습니다.

nglee.github.io


$ readelf -d libxxx.so

LDFLAGS=“-Wl, -rpath, ../libs/“
gcc는 -Wl 옵션을 통해 linker에 전달할 옵션을 지정하는 것이 일반적이다(portable)

yocto bitbake에서 생성되는 환경변수 BUILD_LDFLAGS는 build-ccos/poky/meta/conf/bitbake.conf에 정의되어 있고, 명시적으로 -rpath-link가 추가되고 있다.
recipe에서 AAC_HOME과 BUILD_LDFLAGS 환경변수를 이용해서, -rpath-link를 추가 해 주면 될 듯.

recipe에서 EXTRA_OECMAKE를 사용하면, cmake 설정을 추가할 수 있다. (ex. EXTRA_OECMAKE=“-DCONNECTIVITY=ON”)

Posted by 세월의돌

우선 결론은, 업그레이드 이후 키보드/마우스가 먹통이 되는 경우, NVIDIA GPU 드라이버 문제일 수 있으며, recovery mode로 부팅 후,

 

$ sudo apt dist-upgrade

 

로 NVIDIA GPU 드라이버를 강제로 설치해서 문제 해결!

 

회사에서 HP PC에 ubuntu 20.04 설치해서 사용하고 있다.

희안하게 ubuntu 18.04는 화면표시에 문제가 있는데, NVIDA 그래픽카드 지원 문제가 아닐까 의심스럽다.

암튼, 잘 사용하고 있다가 어제는 apt로 업그레이드를 했는데, NVIDIA GPU 관련 몇 개의 항목은 업그레이드가 되지 않는 상태로 남아 있었다.

 

"The following ... kept back."

 

윈도우 생각하며, 별 생각없이 재부팅 하면 업그레이드 되겠지라고 생각하고 재부팅을 했는데, 이후 로그인 화면에서 키보드/마우스가 1초 정도 동작하다가 먹통!

찾아보니 ubuntu는 major 업데이트 이후 입력장치 관련 문제가 흔하다고 하고, recovery mode로 부팅해서 다시 설치하면 된다고 되어 있었는데, 망할 HP는 recovery mode에서 설정하는 console GUI에서도 문제가 발생해서 뭘 해도 안되더라;;

한참 고생 하다가, 낮은 커널 버전의 recovery mode 부팅하니 해결-_-;

 

이후, X 입력장치 관련 설치를 시도 했으나, 정상적으로 설치되어 있는 상태였고, 그래서 "The following ... kept back."으로 검색을 해 보니, 다른 것들과의 의존성 때문에 업데이트를 못하는 상태라고 했다.

그중 가장 agreesive 한 방법이라고 표시되어 있는 dist-upgrade를 해보고, 문제 생기면 시스템 다시 설치하겠다는 각오(?)로 시도 했더니 바로 문제 해결 됨.

 

다른 분은 DELL PC를 사용을 하는데, HP고 DELL이고 NVIDIA GPU 드라이버 땜에 이래저래 고생을 많이 한다.

우리 둘은 ubuntu의 NVIDIA GPU 지원이 미흡하거나 한발 늦는게 아닌가 조심스럽게 결론을 내렸다.

Posted by 세월의돌

1. Cloning the dlt-viewer from Github. (https://github.com/GENIVI/dlt-viewer)
2. Checking out with proper tag. (it’s v2.21.2 now)
3. Executing doc/convert.sh to generate pdf docs which need to build. (You may need to install ‘asciidoc-base’ package)
4. Executing build_viewer_debs.sh. (You may need to install several packages such as devscripts, qt5-default, debhelper, libqt5serialport5-dev and so on)
5. You can find deb packages in debtmp/.

Posted by 세월의돌
리눅스 & 안드로이드2020. 7. 22. 14:23

우분투에서 아래 페이지를 참고하면, CMake를 최신 버전으로 유지할 수 있다!

apt.kitware.com/

 

Kitware APT Repository

Kitware APT Repository This is Kitware, Inc.'s third-party APT repository, which we use for hosting our own Ubuntu packages, such as CMake. We currently support Ubuntu 16.04, 18.04, and 20.04 on our repository. To add the repository to your installation, d

apt.kitware.com

최신 버전 설치하려고 바이너리를 다운로드 받거나, 소스 받아서 빌드 했었는데, 그럴 필요가 없었네-_-;

위와 같이 하면, apt 통해서 자동으로 업데이트도 될 듯!

Posted by 세월의돌

1. https://github.com/alexa/alexa-auto-sdk/blob/master/builder/README.md

$ sudo apt update

$ sudo apt upgrade -y

$ cd ~

$ git clone git://git.openembedded.org/openembedded-core oe-core -b rocko

$ cd oe-core

$ git clone git://git.openembedded.org/bitbake -b 1.36

$ export OE_CORE_PATH=$(pwd)

$ sudo apt install chrpath diffstat gawk texinfo \
python python3 wget unzip build-essential cpio \
git-core libssl-dev quilt cmake \
libsqlite3-dev libarchive-dev python3-dev \
libdb-dev libpopt-dev zlib1g-dev

$ sudo apt install libssl-dev

$ wget http://downloads.yoctoproject.org/releases/yocto/yocto-2.3.4/toolchain/x86_64/poky-glibc-x86_64-core-image-sato-aarch64-toolchain-2.3.4.sh

$ sudo ./poky-glibc-x86_64-core-image-sato-aarch64-toolchain-2.3.4.sh

$ sudo apt install -y gstreamer1.0-libav \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-good \
libgstreamer-plugins-bad1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgstreamer-plugins-good1.0-dev \
libgstreamer1.0-dev

2. $AAC_SDK_HOME/builder/build.sh linux -t native,pokyarm64 --pokysdk-path /opt/poky/2.3.4

Posted by 세월의돌
리눅스 & 안드로이드2020. 2. 17. 11:18

I got an error as follow when I tried to clone a gitlab repository:

 

server certificate verification failed. CAfile: /etc/ssl/certs/cacertificates.crt CRLfile: none

 

I've found a solution or workaround for that issue from StackOverflow.

https://stackoverflow.com/questions/21181231/server-certificate-verification-failed-cafile-etc-ssl-certs-ca-certificates-c

 

server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none

I can push by clone project using ssh, but it doesn't work when I clone project with https. The error message that shows me is: server certificate verification failed. CAfile: /etc/ssl/certs/

stackoverflow.com

 

Make a long story short, you can configure the git to ignore the server certification if you are sure to trust the server. The methods are as below:

 

export GIT_SSL_NO_VERIFY=1

 

#or

 

git config --global http.sslverify false

 

Posted by 세월의돌
리눅스 & 안드로이드2018. 8. 13. 10:51

Dual ABI https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html

프로젝트 빌드를 하다가 링크에러가 발생했는데, 전혀 예상하지 못했던 링크 에러라 뭔가 싶었다.


구글신을 통해 에러메시지를 가지고 검색 해 보니, Dual ABI를 알려 주었다.

대략 내용은 이러하다. GCC가 C++11 Comformance를 위해 5.0에서부터 std::string과 std::list를 새로 개발 했는데, std::string과 std::list는 오만데서 엄청 사용하고 있는 놈들이니, 두 버전을 동시에 지원해 줘야해서 define을 하나 추가 했다는 것.

기본은 새로운 구현이 활성화 되어 있고, 끄고 싶으면 _GLIBCXX_USE_CXX11_ABI=0 을 추가해 주어야 한다.


내가 만났던 링크 에러 메시지의 부분을 발췌하면 다음과 같다.


undefined reference to ... (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)

undefined reference to ... std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >[abi:cxx11]

undefined reference to ... [abi:cxx11]

undefined reference to ... (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ...)

collect2: error: ld returned 1 exit status


문서 상에서는 친절하게(?) 아래와 같이 안내하고 있음.

If you get linker errors about undefined references to symbols that involve types in the std::__cxx11 namespace or the tag [abi:cxx11] then it probably indicates that you are trying to link together object files that were compiled with different values for the _GLIBCXX_USE_CXX11_ABI macro. This commonly happens when linking to a third-party library that was compiled with an older version of GCC. If the third-party library cannot be rebuilt with the new ABI then you will need to recompile your code with the old ABI.


Posted by 세월의돌
리눅스 & 안드로이드2018. 5. 29. 18:51

불행하게도, 현재의 개발환경은 Ubuntu 14.04가 대부분이다. (정말 보수적이다... 이해는 한다)

JAVA 8이 필요해서 설치하려고 보니, Ubuntu 14.04에서는 JAVA 8 package를 apt-get을 이용해 설치할 수가 없다.

그래서 인터넷에서 찾아보고, 액기스(명령어)만 정리한다.

어디선가는 추천하지 않는 방법이라고 하나, Oracle에서 jdk를 받으려고 해도, console에서는 다운로드 받을 방법이 딱히 없는건지 모르는건지... 나쁘지 않은 것 같다.

아래 repository를 검색해 보니, 유해 해 보이지는 않지만... (잘 모르겠다! 보장 못함)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# add repository
sudo add-apt-repository ppa:openjdk-r/ppa
 
# update cache
sudo apt-get update
 
# install openjdk-8-jdk
sudo apt-get install openjdk-8-jdk
 
# At this time, if you check the version of java/javac,
# you will see the version of JAVA 7
# You need to update alternatives for java and javac
 
# You can find the new one for the java-8-openjdk-amd64
sudo update-alternatives --display javac
 
# Configure(select) the version of java & javac you want to use by interactive mode
sudo update-alternatives --config java
sudo update-alternatives --config javac
 
# Now you can see 1.8.0_171 for the version of java and javac
java -version
javac -version
   


Posted by 세월의돌
리눅스 & 안드로이드2016. 1. 22. 13:41

Input Device의 input event를 App.에서 직접 받아 볼 필요가 있어, NDK로 epoll을 이용해 구현 했던 내용을 정리 해 본다.

epoll 관련 설명은 The Event Poll Interface를 참고 하였다.


우선, device driver file의 fd를 사용해야 하기 때문에, 해당 device file을 열 수 있는 권한을 App.이 가지고 있어야 한다. (예를 들면 App.이 system 권한을 가지고 있어야 한다.)

아래 예제 소스 각각의 특징에 대해서, 간략하게만 정리 해 둔다. 구현 했던 걸, 생각나는 대로 다시 정리한 것이라서, 그대로 copy & paste 하면 제대로 빌드가 되지 않을 수는 있겠으나, 전체적인 맥락은 유효하니 나중에 필요할 때 다시 볼 수 있을 것으로 믿는다.ㅎㅎ


[Header]

  • epoll이나 device driver 파일을 열고나면, 열린 file descriptor를 복사한다는거 자체가 적절하지 않으므로, 복사/대입을 막아 두었다.
  • epoll로 이벤트를 받고 처리하기위해 thread를 하나 만들었으며, 전달 받은 이벤트를 container에 저장 해 두고 사용하기 위해서 mutex를 하나 두었다.
  • JNI에서 instance를 생성하고 사용해야 하므로, 간단하게 constructor에서 모든 초기화를 마치고, destructor에서 file descriptor등을 닫도록 처리 했다.

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
29
30
31
32
33
34
35
36
37
38
39
#ifndef __EPOLL_SAMPLE_H__
#define __EPOLL_SAMPLE_H__
 
#include <string>
#include <thread>
#include <mutex>
 
class EpollSample
{
private:
    const int EPOLL_HINT_SIZE = 1;
 
private:
    bool mInitialized;
    int mEpollFd;
    int mDeviceFd;
 
    bool mThreadDone;
    std::thread mEventThread;
    std::mutex mMutex;
 
public:
    explicit EpollSample(std::string const& devicePath);
    virtual ~EpollSample();
    EpollSample(EpollSample const&) = delete;
    EpollSample(EpollSample&&) = delete;
    EpollSample& operator=(EpollSample const&) = delete;
    EpollSample& operator=(EpollSample&&) = delete;
 
    bool isInitialized() const noexcept { return mInitialized; }
 
    int getEpollFd() const noexcept { return mEpollFd; }
    int getDeviceFd() const noexcept { return mDeviceFd; }
     
    bool isEventThreadAvilable() const noexcept { return !mThreadDone; }
    void terminateEventThread() noexcept;
};
 
#endif //__EPOLL_SAMPLE_H__


[Source]

  • threadHandler에서는 epoll_wait으로 이벤트를 무한정 대기한다.(timeout 시간을 지정할 수도 있음)
  • 정상적으로 이벤트를 받은 경우, epoll_wait이 이벤트의 개수를 반환한다. 이 개수 만큼, 대상 file descriptor를 통해 이벤트 데이터를 읽어 들인다.
  • 오류를 검사하고, input_event 구조체를 통해 이벤트 데이터를 활용한다.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <linux/input.h>
#include <sys/epoll.h>
#include <errno.h>
#include <EpollSample.h>
 
void threadHandler(EpollSample& instance)
{
    if (&instance == nullptr)
    {
        //("EpollSample instance is null!");
        return;
    }
     
    static int const EPOLL_MAX_EVENTS = 16;
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
 
    static int const EVENT_BUFFER_SIZE = 256;
    struct input_event eventBuffer[EVENT_BUFFER_SIZE];
 
    while (instance.isEventThreadAvilable()) {
 
        int const numEvents = epoll_wait(instance.getEpollFd(), eventItems,
                                    EPOLL_MAX_EVENTS, -1);
 
        if (numEvents < 0 && (errno == EBADF || errno == EINVAL))
        {
            //("epfd is not a valid file descriptor or a valid epoll instance");
            break;
        }
 
        for (auto i = 0; i < numEvents; ++i)
        {
            struct epoll_event& epollEvent = eventItems[i];
            if (epollEvent.events & EPOLLIN)
            {
                int const readSize = ::read(instance.getDeviceFd(), eventBuffer,
                    sizeof(struct input_event) * EVENT_BUFFER_SIZE);
 
                if (readSize <= 0)
                {
                    //("Could not get event, errno = %d", errno);
                    break;
                }
                else if (readSize % sizeof(struct input_event) != 0)
                {
                    //("Could not get event, wrong size = %d", readSize);
                    break;
                }
                else
                {
                    auto const numInputEvents = static_cast<std::size_t>(readSize)
                                         / sizeof(struct input_event);
                    for (auto j = 0; j < numInputEvents; ++j)
                    {
                        struct input_event& inputEvent = eventBuffer[j];
                        //Do something
                    }
                }
            }
            else if (epollEvent.events & EPOLLHUP)
            {
                //("The epoll hang-up event has been received");
            }
            else
            {
                //("Unexpected epoll event has been received, event = 0x%08x",
                     epollEvent.events);
            }
        }
    }
}
 
EpollSample::EpollSample(std::string const & devicePath)
    : mInitialized(false), mEpollFd(-1), mDeviceFd(-1), mThreadDone(false)
{
    mEpollFd = epoll_create(EPOLL_HINT_SIZE);
    if (mEpollFd < 0)
    {
        //("Could not create epoll instance!");
        return;
    }
 
    mDeviceFd = ::open(devicePath.c_str(), O_RDWR | O_CLOEXEC);
    if (mDeviceFd < 0)
    {
        //("Could not open virtual device to hook: %d", mDeviceFd);
        //("errno: %d", errno);
        return;
    }
 
    char buffer[80];
    if (ioctl(mDeviceFd, EVIOCGNAME(sizeof(buffer)-1), &buffer) < 1)
    {
        //("Could not get the device name");
    }
    else
    {
        buffer[sizeof(buffer) - 1] = '\0';
        //("The name of opened device = %s", buffer);
    }
 
    if (fcntl(mDeviceFd, F_SETFL, O_NONBLOCK)) {
        //("Error %d making device file descriptor non-blocking.", errno);
        return;
    }
 
    struct epoll_event evt;
    memset(&evt, 0, sizeof(evt));
    evt.events = EPOLLIN;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mDeviceFd, &evt))
    {
        //("Could not add device fd to epoll instance. errno=%d", errno);
        return;
    }
 
    mEventThread = std::thread(threadHandler, std::ref(*this));
 
    mInitialized = true;
}
 
EpollSample::~EpollSample()
{
    mInitialized = false;
 
    if (isEventThreadAvilable()) {
        terminateEventThread();
    }
 
    if (mEpollFd >= 0)
    {
        close(mEpollFd);
    }
 
    if (mDeviceFd >= 0)
    {
        close(mDeviceFd);
    }
}
 
void EpollSample::terminateEventThread() noexcept
{
    mThreadDone = true;
    mEventThread.join();
}


[JNI interface for JAVA]

  • App.에서 JAVA로 호출하게 될 native 함수 정의이다.
  • native도 복사/대입 금지를 하도록 되어 있으므로, JAVA interface도 singleton으로 구현하는 것이 적절하다고 판단 되므로, static으로 선언!
  • native instance의 pointer를 JAVA instance에서 보관하고 활용하는 방식으로 구현되어 있으므로, native interface를 추가하고 활용하기 위해서는, long 타입의 native instance pointer를 전달하는 것이 필요하다.
※ 참고로 native library를 동적으로 로드하기 위해 아래 코드가 JAVA layer에 추가되어 있어야 함.

static {
System.loadLibrary("epoll_sample");
}

1
2
private static native long nativeInit();
private static native void nativeFinalize(long ptr);


[JNI interface for C/C++]

  • App.이 native 초기화를 진행하면, native instance를 생성하면서 초기화를 진행하고, 문제가 없으면 instance pointer를 반환한다.
  • 현재는 device driver 파일경로를 직접 표시 했는데, android property 등의 환경변수나 다른 입력을 통해 전달 받도록 할 수 있겠다.

1
2
3
4
5
6
7
8
9
10
11
12
JNIEXPORT jlong JNICALL nativeInit(JNIEnv *, jclass)
{
    EpollSample* epollSample = new EpollSample("/dev/input/event3");
    assert(epollSample != nullptr);
    return reinterpret_cast<jlong>(epollSample);
}
 
JNIEXPORT void JNICALL nativeFinalize(JNIEnv *, jclass, jlong ptr)
{
    EpollSample* epollSample = reinterpret_cast<EpollSample*>(ptr);
    delete epollSample;
}


[Android.mk]

  • 일반적인 NDK makefile이며, C++11을 사용하기위해 -std=c++11을 추가함. (Application.mk에서와 중복되어 있다)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
 
LOCAL_CFLAGS := \
    -DLOG_NDEBUG=0 \
    -std=c++11
 
LOCAL_C_INCLUDES := \
    $(JNI_H_INCLUDE) \
    $(LOCAL_PATH)/include
 
LOCAL_SRC_FILES := \
    EpollSample.cpp
 
LOCAL_LDLIBS := \
    -llog
 
LOCAL_MODULE := libepoll_sample
 
include $(BUILD_SHARED_LIBRARY)


[Application.mk]

  • GCC 4.9와 STL 사용을 위해 명시적으로 추가 해 두었다.
  • platform이 32bit/64bit ABI를 사용하므로 두 종류 모두 빌드 할 수 있도록, armeabi-v7a, arm64-v8a를 추가 했다.

1
2
3
4
NDK_TOOLCHAIN_VERSION := 4.9
APP_STL := gnustl_shared
APP_ABI := armeabi-v7a arm64-v8a
APP_CPPFLAGS += -std=c++11


※ NDK로는 아무 문제없이 빌드가 되는데, Android platform에 추가해서 빌드를 해 보니 STL header(string 등등)의 path를 기본적으로 찾지 못했고, prebuilt에 포함된 NDK v9을 이용해 빌드 하면 컴파일은 가능하지만, arm64-v8a binary link를 진행하면서 unsupported ELF machine number 183 에러가 발생하였다. 구글링을 통해 google group이나 stack overflow의 글들을 찾아 보고, 적용해 볼만한건 다 해 봤지만 빌드가 되지 않았다.

해결 방법을 아시는 분은 덧글로 알려주시면 감사하겠습니다. (__)


Posted by 세월의돌
리눅스 & 안드로이드2016. 1. 19. 10:05

주변 사람들이 android 소스 볼 때는 vi를 사용해야 한다고 충고(조언?)을 하는데, 개인적으로 소스 분석에 Source Insight 만큼 편리한 도구가 없다고 생각한다. 특히나 소스의 규모가 크면 클수록 말이다.


그래서, AOSP 소스에서 필요한 파일들을 선택적으로 프로젝트 구성하여 사용하고 있는데, Source Insight에서 일부 source parsing에 문제가 발생해서 불편한 경우들이 있다. 이 문제를 해결하는 방법을 알게되어 정리 해 둔다.


대표적인(?) 예가, __BEGIN_DECLS 인데,

1
2
3
4
5
6
7
8
9
#if defined(__cplusplus)
#define __BEGIN_DECLS       extern "C" {
#define __END_DECLS     }
#define __static_cast(x,y)  static_cast<x>(y)
#else
#define __BEGIN_DECLS
#define __END_DECLS
#define __static_cast(x,y)  (x)y
#endif

위와 같이 정의가 되어 있고, (https://android.googlesource.com/platform/bionic/+/android-6.0.1_r10/libc/include/sys/cdefs.h), 아래와 같이 사용되고 있다. (http://androidxref.com/6.0.1_r10/xref/system/core/include/system/window.h)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <unistd.h>
 
#ifndef __UNUSED
#define __UNUSED __attribute__((__unused__))
#endif
#ifndef __deprecated
#define __deprecated __attribute__((__deprecated__))
#endif
 
__BEGIN_DECLS
 
/*****************************************************************************/
 
#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
    (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))


위와 같이 __BEGIN_DECLS 이후로는 parsing이 제대로 되지 않아, symbol 인식이 되지 않는다.


이 문제를 해결하는 방법은 간단하다. Project Source Directory (메뉴 Project > Project Settings... > Project Source Directory - the main location of your source files:)에 c.tom이라는 파일을 생성해서, parsing 과정에서 무시하고 넘어가도록 하고 싶은 macro를 한 줄에 하나씩 (아래와 같이) 추가 해 주면 된다.


__BEGIN_DECLS

__END_DECLS


위와 같이 c.tom 파일을 생성한 후에는 전체 프로젝트를 다시 parsing 해 주어야 한다. (메뉴 Project > Synchronize Files... > Force all files to be re-parsed)


참고로, 아래 링크에 이와 관련된 도움말이 존재한다 -0-

http://www.sourceinsight.com/docs35/af914775.htm

Posted by 세월의돌