시작하면서..


    유닉스란
무엇인가?
 
유닉스는
거대한 AT&T
부속 Bell 연구소에서
개발되었다. 1970년대에
Degital Equipment PDP 컴퓨터를
위해 개발된 유닉스는 멀티 프로세서 서버와 슈퍼
컴퓨터를 능가하는 PC
워크스테이션으로부터 다양한 하드웨어 플랫폼을
포함하여 매우 인기있는 다중 사용ㅈ,
다중 작업 운영체제가 되었다.
 
엄밀히
유닉스는 X/Open
의해 관리되는 상표이며,
X/Open
설명서인 XPG4.2
표준에 따르는 컴퓨터 운영체제이다.
또한 이 문서는 SPEC1170으로
알려져 있으며 유닉스 운영체제 기능들의 명칭,인터페이스,
작동등을 규정하고 있다.

    리눅스란
무엇인가?
 
리눅스는
헬싱키 대학의 리누즈 토발즈와,
인터넷을 통한 유닉스 프로그래머들의 참여로
개발되었다. 그리고
리눅스는 소규모 유닉스는 Andy
Tanenbaum
의 미닉스에 영감을 얻어 취미로 시작되었으나
점차 규모가 커져 그 자체만으로도 완벽한 유닉스
시스템이 되었다. 또한
리눅스 커널은 AT&T
다른 어떤 업체의 소스 코드도 사용하지 않았다.

    배포판
 
사실상 리눅스는 커널을 가리키는 말이다.
모든 사람들은 커널 소스를 얻어 컴파일할 수
있고 설치할 수 있으며 그런 이후에 자유롭게 배포된
다양한 소프트웨어들을 설치해 완벽한 유닉스 시스템으로
만들 수 있다. 커널과
그 이외의 다양한 프로그램으로 이루어져 있는 것을
리눅스 시스템이라 부른다.
이 대부분의 유틸리티들은 FSF
GNU 프로젝트로부터
만들어진 것이다.

    리눅스
프로그래밍
 
광대한
범위의 프로그래밍 언어가 유닉스에서 사용 가능하며,
또한 그 대부분을 자유롭게 CD-ROM이나
인터넷상의 FTP에서
구할 수 있다.

    유닉스
프로그래밍
 
유닉스
응용 프로그래밍은 실행 파일과 스크립트,
두 가지의 파일 현태로 구분된다.
실행 파일은 컴퓨터가 즉시 실행이 가능한 프로그램을
말하며 DOS.EXE
파일에 대응된다.
스크립트는 며영 해석기 같은 것으로 다른 프로그램을
수행하는 명령어의 집합이며,
DOS
.BAT 파일이나,
BASIC
프로그램을 인터프리터 하는 것에 대응한다.


        개발 시스템

    프로그램
 
프로그램은
보통 어떠한 목적에 따라 구분된 디렉토리에 저장된다.
시스템에서 일반적인 목적으로 제공되는 프로그램은
/usr/bin 에서 찾아볼
수 있다. 물론,
개발 툴들도 포함이 되어 있다.
또한, 특정
호스트 컴퓨터나 지역 네트워크에서 사용되는 프로그램은
시스템 관리자에 의해 /usr/local/bin
에 추가된다.
/usr/local
은 보통 벤더가 제공하는 파일과 나중에
추가하는 파일을 시스템이 제공하는 프로그램과 구별하기
위해 사용된다. /usr
이런 관점에서 관리하면,
나중에 운영체제를 업그레이드 할 때,
/usr/local
만 예약하면 되므로 편리하다.
프로그램을 컴파일하거나 바이너리를 사용할 때
/usr/local 아래를
사용하기를 권한다.
다른 추가 패키지와 프로그래밍 시스템에는 그들
고유의 디렉토리 구조와 프로그램 디렉토리가 있다.
GNU
컴파일러 시스템의 핵심 운영 프로그램인
gcc /usr/bin
또는 /usr/local/bin
있지만, gcc 는 다른
위치에 있는 다양한 컴파일러 지원 프로그램을 수행할
것이다. 이러한
위치는 컴파일러를 컴파일할 때 지정되며,
호스트 컴퓨터의 형태에 따라 다를 수 있다.
리눅스 시스템에서 이 위치는
/usr/lib/gcc-lib/i486-unknown-linux/2.7.2
정도가 될 것이다.
GNU C/C++
GNU 지정
헤더 파일은 여기에 저장되어 있다.

  헤더파일
C
나 다른 언어로 프로그래밍을 하려면,
상수가 정의되어 있으며 시스템을 위한 라이브러리
함수 호출이 선언되어 있는 헤더 파일이 필요하다.
C
에서 필요한 대부분의 헤더파일은 /usr/include
에 위치한다. 특정
리눅스나 리눅스에 의존적인 헤더파일은
/usr/include/sys
/usr/include/linux 에서
찾을 수 있다.
다른
프로그래밍 시스템에 필요한 헤더 파일은 보통 컴파일러가
자동으로 검색 가능한 디렉토리에 저장되어 있다.
예를 들자면, X
윈도우의 include
디렉토리는 /usr/include/X11
이며, GNU C++
include 디렉토리는
/usr/include/g++ 이다.
하위 디렉토리나 표중이 아닌 디렉토리에 있는
헤더 파일은 C 컴파일러에
-I 옵션을 주어
사용하면 된다.

gcc -I~/Desktop test.c

컴파일러는 즉시 표준 장소인
~/Desktop 에서 헤더
파일을 찾아서 test.c
삽입한다.

    라이브러리
파일

  라이브러리란 재사용 가능하게
작성된 함수들을 미리 컴파일하여 모아놓은 것이며,
일반적으로 연관된 작업을 수행하기 윟나 함수들로
구성되어 있다. 예를
들면 입출력 함수로서 stdio
라이브러리가 있으며,
데이터베이스 사용 루틴이 들어있는 dbm
라이브러리 등이 있다.

 표준 시스템 라이브러리는 보통
/lib /usr/lib
에 저장되어 있다.
C
컴파일러(정확히
이야기하면 링커)
어떤 라이브러리를 찾을 것인지 알려주기를 원하며,
기본적으로는 표준 C
라이브러리만을 검색한다.
이것은 컴퓨터가 느리고 CPU
가 고가였던 시대의 유물이다.
라이브러리를 표준 디렉토리에 넣고서 컴파일러가
그것을 찾아주기를 바라는 것만으로는 충분하지 않다.
라이브러리는 명칭에 관한 특별한 규정을 따라야
하며, 명령행에서도
언급하여야 한다.

 라이브러리 이름은 항상 lib
로 시작한다. 그리고
각 부분별로 무슨 라이브러리인지를 표시한다(c
C 라이브러리,
m
은 수학라이브러리).
마지막 부분은 “.”
으로 시작되는데,
이 뒷부분에서는 라이브러리의 형태를 지정한다.

  .a    전통적인
정적 라이브러리

.so, .sa 공유
라이브러리

  일반적으로 라이브러리는 정적
형태와 공유 형태의 두 종류가 존재한다.
ls /usr/lib
하면 볼 수 있을 것이다.
사용자는 -l 플래그를
사용하거나 또는 라이브버리의 전체 이름을 적어서
컴파일러가 라이브러리를 찾도록 알려줄 수 있다.

cc -o fred fred.c
/usr/lib/libm.a

  fred.c
를 컴파일하기 위해서 컴파일러를 호출하며,
표준 C 라이브러리
이외에 수학 라이브러리를 검색한다.
다음과 같이 해도 같은 결과를 얻는다.

cc -o fred fred.c -lm

  -lm(l
m 사이에
공백이 없다)은 표준
라이브러리 디렉토리(여기서는
/usr/lib)에서 libm.a
를 불러주는 줄임 형식의 표현이다(줄임
형식은 유닉스에서 상당히 유용하다).
-lm
표기법의 추가적 이점은 컴파일러가 자동으로
공유 라이브러리가 있을 경우 선택 한다는 것이다.

  비록 라이브러리가 일반적으로
헤더 파일과 마찬가지로 표준 장소에서 발견된다고는
하지만 -L 옵션으로
디렉토리를 정해 줄 수도 있다.
예를 들어

cc -o x11fred
-L/usr/openwin/lib x11fred.x -LX11

  x11fred
프로그램을 /usr/openwin/lib
에 있는 libX11
라이브러리와 링크하는 것이다.
만약 -o name 옵션을
사용하지 않았다면,
a.out(
어셈블러 결과를 의미)이라는
프로그램을 생성한다.
프로그램을 컴파일 했는데 실행 파일을 찾지
못하였을 경우에는 a.out
찾아보기 바란다.

    정적(static)
라이브러리

  라이브러리의 가장 간단한
형태는 사용 가능한 오브젝트 파일을 함께 모아둔 것이
될 것이다. 프로그램에서
라이브러리에 포함된 함수를 사용하려면 함수가 선언된
헤더 파일을 포함시키기만 하면 된다.
컴파일러와 링커는 프로그램과 라이브러리를
결합시켜 하나의 실행 가능한 프로그램으로 만든다.

  정적 라이브러리는 archives
라고도 불리며,
통상적으로 .a
끝나는 파일 이름을 가진다.
예를 들면, 표준
C 라이브버리인
/usr/lib/libc.a X11
라이브러리인 /usr/X11/lib/libX11.a
등이 있다.

  ar
프로그램을 이요하면 매우 쉽게 정적 라이브러리를
만들고 유지할 수 있다.
cc -c
명령을 사용하면 필요한 함수들을 따로따로
컴파일하여 오브젝트 파일을 만들 수 있다.
가능하다면 함수를 분리된 소스로 유지하는 것이
좋다. 만약에 함수에서
공통적인 데이터 접근이 필요하다면,
같은 소스 파일 안에 해당 데이터를 둘 수 있으며,
같은 파일에 static
변수로 선언하여 사용할 수도 있다.

   공유 라이브러리
 정적 라이브러리의 단점은 동시에 여러 프로그램을 띄웠을 경우 이들이 모두 같은 라이브러리의 함수들을 사용함으로써 메모리에 같은 함수들을 여러 번 복사하고, 프로그램 파일에도 같은 라이브러리를 여러 번 복사를 한다는 것이다. 이는 메모리 욘량과 디스크 용량을 많이 소모한다. 많은 유닉스 시스템에서는 이러한 불편함을 극복할 수 있도록 공유 라이브러리를 제공한다.
 공유 라이브러리는 정적 라이브러리와 같은 곳에 저장되어 있지만 확장자가 다르다. 전형적인 리눅스 시스템에서 표준 C 라이브러리의 공유 라이브러리 버전은 /lib/libc.so.N 이다. 여기서 N 은 대부분 메이저 버전 숫자를 나타내며 현재는 6이다.
 프로그램이 공유 라이브러리를 사용할 때, /usr/lib/libc.sa 라는 stub 라이브러리에 링크된다. 이 라이브러리는 그 자체로는 함수 코드를 포함하고 있지 않는 특별한 라이브러리이다. 하지만 실행 시간에 포함할 공유 라이브러리를 참조한다.
 프로그램이 실행을 위해 메모리에 적재될 때, 함수에 대한 참조 부분이 분석되어 공유 라이브러리의 적재가 가능하게 되며, 필요할 경우에 공유 라이브러리는 메모리상에 적재된다.
 이 경우에 시스템은 많은 응용 프로그램들로 하여금 한 번에 하나의 공유 라이브러리 복사본만 사용하도록 할 수 있다. 아울러 한 부의 공유 라이브러리만이 디스크에 저장된다.
 공유 라이브러리는 이것에 의존하는 프로그램과 상관없이 독립적으로 갱신할 수 있는 부가적인 이점도 있다. 마이너 버전 번호의 수정은 클라이언트 프로그램에는 별 영향을을 주지 않는다.
 리눅스 시스템에서 공유 라이브러리의 적재를 관리하며,  클라이언트 프로그램의 함수 참조를 분석하는 일은 ld.so 또는 ld-linux.so 가 맡고 있다. 공유 라이브러리 검색 디렉토리는 /etc/ld.so.conf 에 설정된다. /etc/ld.so.conf 파일에 변경이 있었다면 ldconfig 를 수행해야 한다. 하나의 예로, X11 공유 라이브러리 디렉토리가 추가되었을 경우를 들 수 있다.
 ldd 유틸리티를 이용하면 해당 프로그램에서 어떠한 공유 라이브러리를 요구하는지 알아볼 수 있다.


pchero@MyNote:~/Desktop/Study/Programming/ETC/linux/gmtime$ ldd gmtime
        linux-gate.so.1 =>  (0xffffe000)
        libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e0f000)
        /lib/ld-linux.so.2 (0xb7f6b000)

 위와 같은 경우 표준 C 라이브러리(libc)가 공유(DLL)되고 있음을 알 수 있다. 다른 유닉스 시스템에서도 공유 라이브러리에 대한 접근 방법은 이와 비슷하다.

 공유 라이브러리는 마이크로소프트에서 사용되는 동적 링크 라이브러리와 많은 부분에서 비슷하다. .so 라이브러리는 .DLL 과 대응되며 .sa 라이브러리는 .LIB 와 비슷하다.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.