Ar (유닉스)
1. 개요
ar (유닉스)는 유닉스 계열 운영체제에서 사용되는 아카이브 파일 형식 및 관련 유틸리티를 의미한다. 주로 여러 오브젝트 파일들을 묶어 정적 라이브러리를 생성하고 관리하는 데 사용된다. ar 파일은 파일 형식과 파일 헤더를 가지며, BSD와 System V(GNU) 두 가지 주요 변형이 존재한다. GNU/Linux 환경에서 정적 라이브러리를 생성하고 관리하는 데 널리 활용되며, 링커를 통해 오브젝트 파일을 추출하여 프로그램을 컴파일하는 데 사용된다.
-
유닉스 프로그래밍 도구 -
펄
펄은 래리 월이 개발한 텍스트 조작에 강점을 가진 다목적 프로그래밍 언어이며, 1987년 펄 1.0이 처음 공개된 이후 여러 버전 업데이트를 거쳐 객체 지향 프로그래밍과 유니코드 지원 기능을 추가했고, 현재 펄 5가 널리 사용되며 CPAN을 통해 방대한 모듈 생태계를 제공한다. -
유닉스 프로그래밍 도구 -
GNU 컴파일러 모음
GNU 컴파일러 모음(GCC)은 리처드 스톨먼이 1987년 처음 출시한 자유 소프트웨어 컴파일러 시스템으로, C, C++, Fortran, Ada, Go 등 다양한 프로그래밍 언어를 지원하며 여러 명령어 집합 아키텍처와 플랫폼에서 널리 사용된다. -
표준 유닉스 프로그램 -
AWK
AWK는 1977년에 개발된 텍스트 처리 및 프로그래밍 언어로, 유닉스 환경에서 텍스트 처리를 위해 설계되었으며 정규 표현식 처리 기능을 통해 텍스트 분석, 데이터 추출, 보고서 생성 등 다양한 작업을 수행한다. -
표준 유닉스 프로그램 -
Rm (유닉스)
유닉스 명령어 `rm`은 파일을 삭제하는 데 사용되며, 옵션을 통해 삭제 동작을 제어하고 디렉터리를 재귀적으로 삭제할 수 있지만, 잘못 사용하면 시스템에 심각한 손상을 초래할 수 있어 주의가 필요하며 안전 장치나 휴지통 기능 등의 대안이 존재한다. -
유닉스 보관 및 압축 관련 유틸리티 -
Gzip
gzip은 DEFLATE 알고리즘을 기반으로 데이터를 압축하는 파일 형식으로, 매직 넘버, 헤더, 압축된 페이로드 등을 포함하며, 단일 파일 압축에 주로 사용되고 HTTP 압축 및 다양한 응용 분야에서 활용된다. -
유닉스 보관 및 압축 관련 유틸리티 -
Bzip2
Bzip2는 줄리안 세워드가 개발한 자유 소프트웨어로, 버로우즈-휠러 변환, MTF 변환, 허프만 부호화 등의 압축 기법을 사용하여 gzip이나 ZIP보다 높은 압축률을 제공하지만 압축 속도가 느린 블록 정렬 압축 알고리즘이다.
2. 파일 형식
ar 파일 형식은 표준화된 적이 없으며, 현대 아카이브는 BSD와 System V(GNU, ELF, 윈도우에서도 사용됨)의 두 가지 주요 변형을 가진 일반적인 형식을 기반으로 한다. 데비안 ".deb" 아카이브는 일반 형식을 사용한다.
ar 파일은 전역 헤더로 시작하며, 그 뒤에 ar 파일 내에 저장된 각 파일에 대한 헤더와 데이터 섹션이 온다. 각 데이터 섹션은 2바이트 정렬되며, 홀수 오프셋으로 끝나면 개행 문자('\n', 0x0A)가 채움 문자로 사용된다.
2.2. 파일 헤더
ar 파일은 전역 헤더로 시작하며, 그 뒤에 각 파일의 헤더와 데이터 섹션이 이어진다. 각 데이터 섹션은 2바이트로 정렬되며, 홀수 오프셋으로 끝나면 개행 문자('\n', 0x0A)가 채움 문자로 사용된다.
각 파일 헤더는 파일 정보를 담고 있으며, ASCII 텍스트로 저장되어 가독성이 높다. 헤더 정보는 다음과 같다.
파일 이름 길이와 형식의 제한으로 인해 GNU 및 BSD 파생형은 긴 파일 이름을 저장하는 다양한 방법을 사용한다. (자세한 내용은 하위 섹션 참조)
2.2.1. BSD 변형
BSD ar은 ASCII 공백으로 오른쪽 정렬된 파일 이름을 저장하는데, 이는 파일 이름에 공백이 포함될 경우 문제를 발생시킨다. 4.4BSD ar은 이 문제를 해결하기 위해 파일 이름 필드에 "#1/" 문자열과 파일 이름 길이를 차례로 배치하고, 데이터 섹션 앞에 실제 파일 이름을 저장하는 방식으로 확장 파일 이름을 지원한다.
BSD ar 유틸리티는 전통적으로 전역 심볼 조회 테이블 구축을 별도의 유틸리티인 ranlib에 위임했다. ranlib는 아키텍처별 파일 `__.SYMDEF`를 첫 번째 아카이브 멤버로 삽입하여 심볼 테이블을 생성했다. 일부 후손 버전에서는 정렬된 버전을 나타내기 위해 이름 뒤에 공백과 "SORTED"를 추가하기도 했다. 다윈에는 64비트 변형인 `__.SYMDEF_64`도 존재한다.
그러나 POSIX에서 ranlib를 대체하는 ``(s) 옵션 요구 사항이 추가된 후, 새로운 BSD ar 구현은 해당 기능을 포함하도록 다시 작성되었다. 특히 FreeBSD는 SYMDEF 테이블 형식을 버리고 System V 스타일 테이블을 채택했다.
2.2.2. System V (GNU) 변형
System V ar는 파일 이름의 끝을 표시하기 위해 '/' 문자(0x2F)를 사용한다. 이렇게 하면 확장된 파일 이름을 사용하지 않고도 공백을 사용할 수 있다. 그런 다음 "//"라는 이름의 파일의 데이터 섹션에 여러 개의 확장된 파일 이름을 저장하며, 이 레코드는 이후 헤더에서 참조된다. 헤더는 확장된 파일 이름 데이터 섹션에서 "/" 다음에 확장된 파일 이름의 시작 부분까지의 십진수 오프셋을 저장하여 확장된 파일 이름을 참조한다. 이 "//" 파일 자체의 형식은 단순히 긴 파일 이름 목록이며, 각 파일 이름은 하나 이상의 LF 문자로 구분된다. 십진수 오프셋은 "//" 파일 내의 줄 또는 문자열 번호가 아닌 문자 수이다. 일반적으로 파일의 두 번째 항목이며, 항상 첫 번째 항목인 심볼 테이블 다음에 온다.
System V ar는 특수 파일 이름 "/"을 사용하여 다음 데이터 항목에 ar 라이브러리에서 액세스 속도를 높이는 데 사용되는 심볼 조회 테이블이 포함되어 있음을 나타낸다. 이 심볼 테이블은 세 부분으로 구성되며 연속된 데이터로 함께 기록된다.
# 테이블의 항목 수를 나타내는 32비트 빅 엔디안 정수.
# 32비트 빅 엔디안 정수 집합. 각 심볼에 대해 하나씩, 이 심볼을 포함하는 파일의 헤더 내 아카이브 위치를 기록한다.
# 널 종료 문자열 집합. 각 항목은 심볼 이름이며, 2부의 위치 목록과 동일한 순서로 나타난다.
일부 System V 시스템은 심볼 조회 테이블에 대해 위에 설명된 형식을 사용하지 않는다. HP-UX 11.0과 같은 운영 체제의 경우 이 정보는 SOM 파일 형식을 기반으로 하는 데이터 구조에 저장된다.
특수 파일 "/"은 특정 시퀀스로 종료되지 않는다. 마지막 심볼 이름을 읽으면 끝이라고 가정한다.
4 GiB 파일 크기 제한을 극복하기 위해 솔라리스 11.2 및 GNU와 같은 일부 운영 체제는 변형된 조회 테이블을 사용한다. 32비트 정수 대신 64비트 정수가 심볼 조회 테이블에 사용된다. 문자열 "/SYM64/"는 "/" 대신 이 테이블의 식별자로 사용된다.
GNU ar는 '/'를 파일명의 종단으로 인식한다. 즉, 이것을 이용하면 확장 파일명을 이용하지 않고, 공백을 사용할 수 있다.
GNU ar는 특수한 파일명 "/"를 이용하여, 그 직후의 데이터 엔트리에 ar 라이브러리의 액세스 속도를 향상시키는데 이용되는 심볼 룩업 테이블을 포함할 수 있다. 이 심볼 테이블은 인접 데이터로서 동시에 기록되는 이하 3개의 부분으로 구성된다.
# 32비트 빅 엔디안 정수로 주어지는 테이블상의 엔트리 수
# 32비트 빅 엔디안 정수의 집합. 각 심볼마다, 심볼을 포함하는 파일용 헤더의 아카이브 내의 위치를 하나씩 기록한다.
# 종단이 0인 문자열의 집합. 각각 심볼명이며, 두 번째 데이터에 있는 위치의 리스트로서, 동일한 순서로 구성된다.
특수한 파일 "/"는, 특정 종단 문자열을 가지지 않는다. 마지막 심볼명이 일단 읽히면, 거기서 종료한다고 가정된다.
다른 커맨드로서 `ranlib`라는 것이 있다. 이것은 `ar s`를 실행한 경우와 완전히 등가이다. 즉 심볼 룩업 테이블을 추가하는 커맨드이다.
3. 사용 예시
`class1.o`, `class2.o`, `class3.o` 파일들로부터 아카이브를 하나 만들려면 다음 명령어를 사용한다.
```
ar rcs libclass.a class1.o class2.o class3.o
```
유닉스 링커는 일반적으로 C 컴파일러 `cc`를 통해 호출되며, `ar` 파일을 읽고 거기에서 오브젝트 파일을 추출할 수 있다. 따라서 `libclass.a`가 `class1.o`, `class2.o` 및 `class3.o`를 포함하는 아카이브인 경우 다음 명령어들은
```
cc main.c libclass.a
```
또는 (libclass.a가 `/usr/local/lib`와 같은 표준 라이브러리 경로에 배치된 경우)
```
cc main.c -lclass
```
또는 (링크하는 동안)
```
ld ... main.o -lclass ...
```
다음과 같다.
```
cc main.c class1.o class2.o class3.o
```
`class1.o`, `class2.o`, 및 `class3.o`에 의존하는 프로그램을 컴파일하려면 다음을 실행한다.
```
cc main.c libclass.a
```
위는 정적 링크 방법이지만, 다음과 같이 라이브러리를 생성하지 않고 프로그램으로 컴파일하는 경우도 많다.
```
cc main.c class1.o class2.o class3.o
5. 한국에서의 사용 및 윈도우 호환성
한국에서는 주로 리눅스 배포판 환경에서 GNU ar를 사용한다. 윈도우의 라이브러리 파일(.lib)도 내부적으로 ar 형식을 사용하고 있지만, 파일 헤더 및 심볼 테이블 형식의 차이로 인해 GNU ar와의 직접적인 호환성은 제한적이다.
6. GNU/리눅스 환경에서의 활용
GNU/리눅스 환경에서 `ar` 명령어는 주로 정적 라이브러리(`.a`)를 만들고 관리하는 데 사용된다. 예를 들어, `class1.o`, `class2.o`, `class3.o` 파일들로부터 `libclass.a`라는 정적 라이브러리를 생성하려면 다음과 같은 명령어를 사용한다.
```
ar rcs libclass.a class1.o class2.o class3.o
```
유닉스 링커는 `ar` 파일을 읽고 오브젝트 파일들을 추출할 수 있다. `libclass.a`가 `class1.o`, `class2.o`, `class3.o`를 포함하는 아카이브인 경우, 다음과 같이 `cc` (C 컴파일러)를 통해 호출하여 프로그램을 컴파일할 수 있다.
```
cc main.c libclass.a
```
또는 `libclass.a`가 `/usr/local/lib`와 같은 표준 라이브러리 경로에 있다면 다음과 같이 사용할 수도 있다.
```
cc main.c -lclass
```
이는 정적 링크 방식이며, 다음과 같이 라이브러리를 생성하지 않고 직접 컴파일하는 방법도 존재한다.
```
cc main.c class1.o class2.o class3.o
```
정적 라이브러리는 컴파일 시점에 프로그램에 포함되므로 실행 파일의 크기가 커지지만, 배포가 용이하고 외부 의존성 문제를 줄여 프로그램의 안정성을 높일 수 있다는 장점이 있다.