|
지난 수년 간 C++가 진화를 거듭하면서 컴파일러가 사용하는ABI(Application Binary Interface)도 새롭게 변화하는 언어 기능을 지원할 수 있도록 변경되어야 했습니다. 프로그래머들은 모든 컴파일러 릴리즈에서 모든 바이너리를 재컴파일할 수 있기를 기대했습니다. 불안정한 ABI는 바이너리 공유라는 Solaris의 기본 철학에 어긋났으며 바이너리와 미들웨어 벤더에게는 악몽과도 같습니다. 1998년 C++ 표준이 등장함에 따라 Solaris 플랫폼 상의 안정된 C++ ABI에 대한 새로운 기대감이 형성되기 시작했습니다. 이 자료는 Sun C++이 가진 이러한 문제점들을 비롯해 Solaris상의 구현 언어로서 C++을 사용할 때 기대할 수 있는 이점에 대해 다루고 있습니다.
들어가는 글
프로그래밍 언어 구현 시 ABI는 각각 별도로 컴파일된 모듈이 함께 연동될 수 있도록 지원하는 상세 사양입니다. 안정된 ABI가 없다면 프로그램의 모든 부분을 같은 버전의 동일 컴파일러로 컴파일해야 합니다. 이 경우 분산 프로젝트를 수행하는 경우, 특히 바이너리 라이브러리 공급자는 유지 보수에 상당한 어려움을 겪게 됩니다. 초기에는 C++ 프로그래밍 언어가 빠르게 진화를 거듭했기 때문에 안정된ABI를 제공하는 것이 어려웠습니다. 1998년 C++ 국제 표준[ISO/IEC 14882:1998 Programming Languages - C++]이 등장함에 따라 최소한 특정 C++ 구현에서 안정된 C++ ABI를 제공할 수 있게 되었습니다. 여기에서는 Solaris 운영 환경을 위한 Sun C++ 컴파일러의 안정성 문제에 대해 다루기로 하겠습니다.
C ABI
C가 표준 Unix 구현 언어이기 때문에 Solaris ABI는 C ABI이기도 합니다. C ABI는 다음을 지정할 수 있습니다:
- 사전 정의된 유형(문자, 정수, 부동소수점 등)의 크기 및 레이아웃
- 복합 유형(어레이 및 구조)의 레이아웃
- 로그래머가 정의한 이름의 외부(링커가 볼 수 있는) 철자
- 기계 코드 함수 호출 시퀀스
- 스택 레이아웃
- 레지스터 사용
C++ ABI
C가 표준 Unix 구현 언어이기 때문에 Solaris ABI는 C ABI이기도 합니다. C ABI는 다음을 지정할 수 있습니다:
- 기본 클래스(base class), 가상 기본 클래스 등과 같은 계층형 클래스 객체의 레이아웃
- 포인터 투 멤버(pointer-to-member)의 레이아웃
- 숨겨진 함수 매개변수(예: this) 전달
- 가상 함수 호출 방법
- vtable 컨텐트 및 레이아웃
- vtables에 대한 포인터의 객체 내 위치
- 이 포인터에 대한 조정 찾기
- 기반 클래스 오프셋(offset) 찾기
- 포인터 투 멤버를 통한 함수 호출
- 템플릿 인스턴스 관리
- 외부 철자가 혼합된 이름("이름 변경(name mangling)")
- 정적 객체의 생성 및 소멸
- 예외 발생 및 포착
- 표준 라이브러리에 대한 상세 내역
- 정의된 적용의 상세 내역
- typeinfo 및 런타임 유형 정보
- 멤버에 대한 인라인(inline) 함수 액세스
이름 변경(name mangling)
C++에서는 서로 다른 함수가 동일한 이름을 가질 수 있으며 동일한 이름을 가진 여러 글로벌 엔티티를 선언할 수 있는 무제한 수의 범위(scope)를 허용합니다. 예:
int f(int);
float f(float);
class T {
int f(int);
int f(char*);
class U {
int f(int);
};
};
namespace N {
class T {
int f(int);
};
}
이 예에는 T로 명명는 2개의 클래스와 f로 명명된 6개의 함수가 있으며, 일부는 동일한 범위 내에 있습니다. 모든 함수는 외부 연결을 가지고 있습니다. 동일한 이름을 가진 엔티티를 구별하기 위해 C++ 구현에서는 이들 함수에 대한 참조가 고유하도록 해야 합니다. 다른 모듈에서 나온 동일 엔티티에 대한 참조를 올바르게 해독하기 위해서는 고유의 참조를 갖도록 하는 방법을 사용할 수 있습니다.
일반적인 구조에서는 매개변수 유형 및 함수의 리턴 유형과 더불어 범위 이름의 인코딩을 통한 엔티티 이름 변경이 수행됩니다. 따라서, 이름은 복잡하게 "혼합"된 것처럼 보입니다. 예를 들어, 위 6개 함수의 이름은 Sun C++ 컴파일러에 의해 다음과 같이 인코딩할 수 있습니다:
변경된 함수 이름의 예:
| 함수 | 변경된 이름 |
|---|---|
| float f(float) | __1cBf6Ff_f_ |
| int f(int) | __1cBf6Fi_i_ |
| int T::f(int) | __1cBTBf6Mi_i_ |
| int T::f(char*) | __1cBTBf6Mpc_i_ |
| int T::U::f(int) | __1cBTBUBf6Mi_i_ |
| int N::T::f(int) | __1cBNBTBf6Mi_i_ |
C++은 이름이 변경되지 않도록 C 코드에서 이름에 액세스할 수 있도록 지정하는 방법도 제공합니다.
이름 변경 및 ABI
이름 변경 알고리즘은 컴파일러가 프로그램 엔티티에 대한 외부 참조와 정의를 생성하는 방법을 정의한다는 점에서 ABI의 일부라고 할 수 있습니다. 2개의 컴파일러 또는 컴파일러 버전이 동등한 선언을 동일한 방법으로 변경하지 않는다면 2개의 컴파일러에서 컴파일된 부분을 포함하고 있는 프로그램이 올바르게 연결되지 않습니다.
계층형 레이아웃
Smalltalk 및 Java와 마찬가지로 C++은 클래스 유형 계층에 대한 사용자 정의를 지원하며 여기에서 "파생(derived)" 클래스는 상속된 클래스의 모든 데이터 및 함수를 기본적으로 포함합니다. 정상적인 기본 클래스는 완전 객체의 시작부터 고정 오프셋에서 클래스 유형의 멤버와 마찬가지로 객체로 레이아웃되어 있습니다. 예:
class Base {
...
};
class Derived : public Base {
int i, j;
};
class Composed {
Base b;
int i, j;
};
많은 C++ 구현에서 Derived 및 Composed 클래스의 레이아웃이 동일합니다.
완전 객체에 대한 포인터는 기반 클래스 가운데 하나에 대한 포인터로 변환될 수 있지만 포인터가 표시하는 주소를 완전 객체 내에 있는 기본 클래스의 오프셋을 통해 조정해야 합니다.
Smalltalk나 Java와 달리 C++ 클래스는 1개 이상의 직접(immediate) 기본 클래스를 가질 수 있으며 이를 다중 상속(multiple inheritance)이라고 합니다.
클래스 A와 B가 각기 기본 클래스 Z를 가지고 있을 경우, A 및 B에서 파생된 클래스 C는 Z에 대해 2개의 복사본을 가질 수 있습니다. C가 Z에 대해 2개의 독립된 복사본을 갖도록 하는 것이 적합한 경우도 있습니다. 그렇지 않은 경우 Z는 오직 1개의 복사본만 갖도록 자원을 표시합니다.
계층형 객체에서 기본 클래스에 대한 복사본이 오직 1개만 존재하도록 지정하기 위해 기본 클래스를 “가상(virtual)"으로 선언할 수 있습니다.
직접 클래스와 관련된 가상 기본 클래스의 오프셋은 전체 계층에 종속됩니다. 예:
class Z {
...
};
class A : virtual public Z {
...
};
class B : virtual public Z {
...
};
class C : public A, public B {
...
};
객체 A에서는 Z 부분이 오프셋 OA에 있고 객체 B에서는 오프셋 OB에 있다고 가정해 봅시다. 객체 C에는 오직 1개의 Z 복사본이 있습니다. 복사본은 A 부분의 오프셋 OA와 B 부분의 오프셋 OB에 동시에 있을 수는 없습니다. 전체 객체가 C 유형일 때 이들 오프셋 중 최소한 1개는 달라야 합니다.
A에 대한 포인터가 있는 경우, 객체 A는 C 같이 좀더 복잡한 유형의 하위 객체로 바뀌기 때문에 하위 객체 Z의 위치를 컴파일 시점에서 결정할 수 없습니다. 런타임 시스템이 완전 객체의 유형을 동적으로 결정할 수 있도록 해야만 다른 객체의 오프셋이 결정될 수 있습니다.
C++ 구현은 일반적으로 vtable이라고 불리는 보조 테이블에 각 객체 유형에 대해 오프셋 정보를 저장합니다. 각 유형별로 1개의 vtable만 필요하며 해당 유형의 모든 객체가 이를 공유하게 됩니다. 그런 다음, vtable을 요구한 객체는 vtable에 대한 포인터를 포함하게 됩니다. 또한, vtable은 포인터나 참조에 의해 참조되는 실제 객체를 토대로 동적 함수 디스패치(dispatch)를 수항할 수 있도록 가상 함수의 주소도 포함하고 있습니다.
C++ 표준 라이브러리
C++ 표준은 라이브러리에 대한 프로그래밍 인터페이스를 비롯해서 라이브러리에서 유형 및 함수의 이름 및 속성을 정의합니다. 따라서, 사양에 작성된 소스 코드는 호환 구현 간에 포팅할 수 있습니다. 하지만, 바이너리 인터페이스는 약간 다릅니다.
C++ 표준은 프로그래밍 인터페이스가 영향을 받지 않는 한도 내에서 구현 상세 정보에서의 변수를 어느 정도 허용합니다. 이러한 구현 상세 정보의 대다수, 특히 클래스 객체의 크기 등은 ABI의 일부로 포함됩니다.
성능 향상을 위해서는 표준 라이브러리의 많은 부분을 인라인 함수를 통해 구현하는 것이 가장 바람직합니다. C의 매크로(macro) 등 일부는 인라인 함수에 대한 호출이 함수 코드로 대체됩니다. 함수가 표준 라이브러리에 정의된 클래스 멤버에 액세스하면 클래스 멤버의 위치가 인라인 함수를 사용하는 애플리케이션 프로그램의 코드에 자동으로 포함됩니다. 따라서, 인라인 함수가 참조한 모든 것은 C++ ABI의 일부입니다.
표준 라이브러리에 대한 향상 또는 버그 수정이 프로그래밍 인터페이스에 영향을 미치지 않는다 하더라도 라이브러리에 정의된 클래스의 크기 또는 레이아웃이 변경됐다면 이러한 변경 사항이 ABI에 영향을 미칠 수 있습니다.
ABI 불안정의 원인
새로운 언어 기능이나 변경된 언어 기능의 경우, ABI에 대한 단순한 확장이 아닌 변경이 필요할 수 있습니다. 아래에 그 2가지 예가 제시되어 있습니다:
-
C++ 표준은 오버라이드(override) 하는 함수와 다른 리턴 유형을 갖도록 오버라이딩 가상 함수를 지원합니다. 포인터나 참조 유형이 리턴 유형이 될 수 있으며, 파생된 클래스에 있는 함수의 리턴 유형은 오버라이드한 함수가 참조한 유형에서 파생된 함수를 뜻합니다. 예:
class Base { virtual Base* clone(); }; class Derived : public Base { virtual Derived* clone(); }; void f(Base* p) { Base* copy = p->clone(); }PRE>컴파일러는 클론(clone)에 대한 호출이 파생된 유형에 대한 포인터 또는 Base*를 리턴하는지 여부를 알 수 없습니다. ABI는 리턴되는 유형에 관계없이 올바른 포인터 조정을 수행할 수 있는 방법을 제공해야 합니다. 여기에 필요한 메커니즘은 구형 ABI에서는 제공되지 않습니다.
-
템플릿 함수 특성화와 이름 및 유형이 같은 비(non) 템플릿 함수를 고려하십시오.
template<class T> T min(T, T) { ... } int min<int>(int, int); // old specialization syntax int min(int, int); // non-template이전의 언어 규칙에서는 템플릿 함수로서 같은 이름 및 유형을 가진 비 템플릿 함수는 템플릿의 특성화(specialization)로 간주되었습니다. 따라서, 이러한 함수 및 해당되는 특성화는 동일한 변경된 이름을 가져야 합니다.
하지만, C++ 표준 규칙의 경우 이는 별도의 함수로서 서로 다른 변경된 이름을 가져야 합니다. 새로운 규칙 하에서는 최소한 1개 함수의 외부 이름이 변경되어야 합니다.
일부 버그를 교정하기 위해서는 ABI 변경이 필요합니다. 아래에 그 2가지 예가 제시되어 있습니다:
-
초기 C++ 컴파일러 대부분은 일부 환경에서 파생된 클래스의 생성자(constructor) 또는 소멸자(destructor)에서 가상 기본 클래스의 함수 호출을 지원할 수 없었습니다. 결국 이 문제에 대한 비용 효율적인 솔루션이 등장하기는 했지만, 여기에는 다른 vtable 구성과 다른 방식의 생성자 및 소멸자 호출이 요구되었습니다.
-
썬이 공급하는 컴파일러는 등가로 가정되는 일부 함수 선언에 대해 서로 다른 변경된 이름을 생성합니다. 버그 교정을 위해서는 일부 기존 함수에서 다른 변경된 이름을 획득하는 방법 즉 ABI 변경이 필요합니다.
ABI 불안정의 결과
ABI가 서로 다르면 서로 다른 컴파일러의 객체 파일을 연결할 수 없으며 연결이 가능하다 하더라도 제대로 실행되지 않습니다. (서로 다른 ABI에 대해 생성된 코드가 실수로 연결되지 않도록 서로 다른 컴파일러 구현은 일반적으로 서로 다른 이름 변경 체계를 사용합니다.)
언어가 급속하게 진화하던 C++ 초기에는 ABI가 자주 변경되었습니다. C++ 프로그래머들은 컴파일러를 업데이트할 때마다 모든 것을 재컴파일하는 데 익숙했습니다.
어떤 애플리케이션이 A라는 벤더의 ORB 라이브러리와 B라는 벤더의 데이터베이스 라이브러리를 사용하고 있다고 가정하면, 벤더들은 소스 코드의 배포를 원하지 않기 때문에 바이너리 라이브러리를 제공합니다. 두 벤더의 애플리케이션 코드 및 라이브러리 모두 동일한 ABI를 사용해야 합니다.
모든 컴파일러 릴리즈가 서로 다른 ABI를 가지고 있을 경우, 애플리케이션 프로그래머는 빈번한 컴파일러 업그레이드를 원치 않을 것입니다. 따라서, 프로젝트에서 모든 개발자 간에 업그레이드를 조정하고 공식적인 업그레이드 설치 일자에 모든 것을 재컴파일해야 합니다.
벤더 A와 벤더 B가 수많은 클라이언트를 지원해야 하고 그 각각이 서로 다른 컴파일러 릴리즈를 사용하고 있는 경우에는 각 컴파일러 버전에 대해 라이브러리를 출시 및 지원해야 합니다. 이러한 경우는 자원 비용이 너무 클 뿐만 아니라 일반적으로 실현 가능성도 없습니다. 이 시나리오에서는 벤더가 소스 코드를 출시하고 클라이언트가 자체적으로 라이브러리를 구축하게 됩니다. 하지만, 서로 다른 클라이언트가 서로 다른 툴 세트를 사용하고 생성 스크립트가 로컬 실행을 준수하도록 구성되어야 한다는 점에서 새로운 지원 문제가 발생합니다.
위 시나리오에서는 공유 라이브러리에 대한 Solaris의 비전이 제대로 지원되지 않습니다. 따라서, 지원되는 모든 ABI 변형에 대해 다른 버전의 C++ 공유 라이브러리를 생성해야 합니다. 컴파일러가 더 이상 지원되지 않는 경우에도 프로그램은 공유 라이브러리 사용에 의존하면서 필드에 존재할 수 있습니다. 오래된 라이브러리 버전도 계속해서 장기간 제공되어야 합니다.
제품으로서 라이브러리, 특히 공유 라이브러리의 성공적 배포를 위해서는 안정된 ABI를 갖춰야 합니다.
Sun C++ ABI의 역사
썬의 주요 C++ 컴파일러 릴리즈는 릴리즈 번호에 대한 엔지니어링 분류 체계에 따라 지금까지 비호환 ABI를 사용해 왔습니다. 새로운 주요 버전 번호는 비호환 릴리즈를 표시하고 있습니다.
C++ 3.0을 시작으로 썬은 C++ ABI에 일부 안정성을 도입하기 위해 노력했습니다. C++ 런타임 지원 라이브러리는 Solaris와 함께 제공되는 공유 라이브러리인 libC.so.3가 되었습니다.
하지만, C++은 여전히 진화를 거듭하고 있었고 C++ 표준에서 일부 중요한 상세 정보의 변경을 야기하는 작업이 진행되고 있었다는 것도 알 수 있었습니다. 이에 따라, 썬은 썬 소프트웨어 제품이 C++ 인터페이스를 익스포트할 수 있도록 한다는 정책을 수립했습니다. 익스포트된 C++ 인터페이스가 없으면 ABI 변경 시 “모든 것의 재컴파일”이 불가피합니다.
1993년 출시된 C++ 4.0은 새로운 비호환 ABI를 도입했습니다. 이 ABI는 안정성이 목적이었습니다. C++ 개발팀은 주요 썬 클라이언트, 심지어 ABI 설계 경쟁업체에게까지 의견을 구했고 외부의 몇 가지 제안을 받아들였습니다. ABI는 공용 문서로 발표되었습니다. 새로운 C++ 지원 라이브러리인 libC.so.5가 Solaris와 함께 출시되었습니다.
시간이 지남에 따라 일부 버그는 이름 변경 과정에서 약간의 변경이 필요하다는 사실을 알게 되었습니다. 이러한 버그는 교정되었고 사용자에게는 기존 코드의 연결이 필요할 경우 이전의 실행 방식으로 복원할 수 있는 방법이 제공되었습니다. 1996년에 발표된 C++ 4.2는 이러한 ABI의 대표적인 최종 버전이었습니다.
이 ABI에는 “ABI 불안정의 원인” 부분에서 설명한 가상 기본 클래스 문제 같이 잘 알려진 버그가 포함되었습니다. 뿐만 아니라, C++ 표준에 대한 작업도 거의 완료 단계에 접어들었으며 다른 ABI를 필요로 하는 기능이 포함된다는 사실도 알려졌습니다. ”ABI 불안정의 원인” 부분에서 설명한 템플릿 의미의 변경은 ABI에 영향을 미친 몇 가지 변경 사항 중 하나입니다.
진화하고 있는 C++ 표준을 추적하려는 노력으로 인해 ABI가 계속해서 변경되는 문제를 해결하기 위해 C++ 개발팀은 C++ 4.2에서 안정성을 유지한다고 가정하고 ABI 변경이 필요하지 않은 기능만 구현하는 전략을 채택했습니다. 썬은 C++ 기능 측면에서 지연을 감수하는 대신 고객에게 안정된 ABI를 제공했습니다.
런타임 라이브러리
초기 C++ 런타임 라이브러리는 "iostreams"라는 I/O 라이브러리와 힙(heap) 메모리 할당 지원, 예외 처리 및 동적 유형 정보를 포함한 컴파일러를 위한 런타임 "helper" 함수로 구성되었습니다.
C++ 표준에 지정된 라이브러리는 strings, iostreams, numerics, "STL" 같은 포괄적인 템플릿 클래스 및 함수 세트를 포함하고 있습니다.
시간적 압박으로 인해 C++ 컴파일러의 5.0 버전에는 C++ 표준의 모든 기능이 구현되지 못했습니다. 예를 들어, 표준 라이브러리 정의에는 클래스 멤버로서 템플릿이 포함되는데 C++ 5.0에서는 이 기능이 지원되지 않습니다. 컴파일러와 함께 제공된 라이브러리에서는 이러한 부분이 누락되었거나 약간 다르게 구현되었습니다.
이러한 이유로 라이브러리 구현은 2가지 부분으로 나누어졌습니다:
- 힙 메모리 할당 지원, 예외 처리 및 동적 유형 정보를 포함한 컴파일러 helper 함수로 구성된 libCrun .
- C++ 표준 라이브러리의 나머지 부분으로 구성된 libCstd
너무나도 많은 ABI
썬 정책에서는 C++ 표준에 대한 준수나 심지어 정확성보다도 지속적 호환성이 더욱 중요한 것으로 간주되고 있습니다. libCstd는 기준 미달이었으며 이름 변경에서 일부 버그가 발견되었음에도 불구하고 이러한 문제점은 이후 릴리즈에서도 계속되었습니다.
libCstd는 바이너리 호환성을 유지하고 있기 때문에 공유 라이브러리로 제공될 수 있었습니다. C++ 5.2는 라이브러리 옵션으로 libCstd.so.1을 함께 제공했고 C++ 5.3은 Solaris 패키지의 일부로 libCstd.so.1을 제공했습니다. 보다 많은 C++ 표준 라이브러리 기능은 요구하지만 바이너리 호환성은 요구하지 않는 고객을 지원하기 위해 C++ 5.4는 C++ 표준 라이브러리의 오픈 소스 STLport [http://www.stlport.org] 구현도 함께 제공했습니다.
ABI의 현황(2002년 5월)
현재 제공되고 있는 컴파일러는 Sun ONE Studio 7, Compiler Collection(이전 Forte Developer 7)의 컴포넌트인 C++ 5.4입니다.
모든C++ 5.x 컴파일러는 C++ 4.2와 호환되는 모드와 C++ 표준을 지원하는 기본 모드를 제공합니다. 2개의 모드가 서로 다른 2개의 ABI를 표시합니다. 각 모드에서 모든 5.x 컴파일러는 바이너리 호환 코드를 생성합니다.
썬의 호환성 정책에도 불구하고 일부 고객들은 프로그램 작동을 방해하는 ABI 버그를 교정하기를 원합니다. 이들 고객의 요구를 충족하기 위해 컴파일러는 정확하지만 호환되지 않는 ABI를 생성하는 문서화되지 않은 옵션을 가지고 있습니다. 타사 라이브러리를 이용하지 않는 고객들은 이 옵션을 이용해 모든 코드를 신중하게 컴파일하도록 올바른 ABI를 사용할 수 있습니다. C++ 컴파일러와 함께 제공되는 라이브러리는 ABI 버그를 트리거(trigger)하지 못하기 때문에 이들 라이브러리의 별도 버전을 요구하지 않습니다.
완벽하게 표준을 준수하는 라이브러리를 원하는 고객들을 위해 컴파일러는 STLport에서 나온 오픈 소스 라이브러를 함께 제공합니다. 또한, 컴파일러는 컴파일러와 함께 제공되는 라이브러리를 대신해 타사 표준 라이브러리를 사용할 수 있도록 지원합니다. 특히, Rogue Wave[http://www.roguewave.com] 및 Dinkumware[http://www.dinkumware.com]에서 출시한 라이브러리가 여기에 적합합니다.
향후 전망
현재 사용되고 있는 2개의 C++ ABI를 몇 년 동안은 계속 지원해야 한다는 데는 이견이 없습니다. 따라서, 라이브러리에 대한 호환 버전과 함께 2개의ABI 모두를 생성하는 컴파일러를 제공해야 합니다.
하지만 고객들은 이와 함께 표준 준수도 요구하고 있습니다. 이를 위해서는 제3의 ABI를 지원할 수 있어야 합니다. ABI의 안정성은 어느 정도의 수준일까요? 보다 많은 ABI 버그가 발견된 경우라면 어떨까요? C++ 표준이 다시 변경되면 어떻게 될까요?
마지막 질문은 단순히 이론적인 것만은 아닙니다. C++ 위원회는 표준 라이브러리에 대한 바이너리 비호환 변경을 포함해 표준에 대한 Technical Corrigendum 발표를 앞두고 있습니다. 이 위원회에 참석한 썬 대표자는 바이너리 호환성이 요구사항의 하나라는 사실에 대해 다른 회원들의 동의를 얻지 못했습니다.
따라서, 제3의 ABI가 제2의 ABI 보다 안정성이 향상되지는 않을 것입니다. 썬 뿐만 아니라 썬 고객에게도 지원되는 ABI의 확산은 실용적인 옵션이 아닙니다.
C++ 개발팀은 향후 컴파일러에서 옵션으로 “실험적” ABI를 제공하는 방안을 구상 중에 있습니다. ABI는 릴리즈 간 안정성은 보장되지 않지만 정확성은 높을 것입니다. 정확성을 요구하는 반면 호환성은 요구하지 않는 고객들은 선택에 따라 이를 사용할 수 있습니다. 이러한 고객들이 사용한다는 것은 ABI가 향후 지원 ABI로서 사용될 가능성이 있다는 것을 입증하는데 도움이 될 것입니다.
"개발자코너" 카테고리의 다른 글
- DTrace를 사용하여 유저가 조정하는 애플리케이션 크래쉬 데이타 정보 모으기 (댓글 1개 / 트랙백 0개) 2006/08/23
- D 스크립트 배우기 (댓글 0개 / 트랙백 0개) 2009/11/23
- C++ 표준 라이브러리인 libCstd와 libstlport 비교하기 (댓글 1개 / 트랙백 0개) 2006/07/23
- 썬 스튜디오: VIS 명령을 사용하여 중요한 루틴의 속도를 향상시키기 (댓글 1개 / 트랙백 0개) 2006/02/23
- 썬 스튜디오 dbx 를 이용한 AMD64 명령어 레벨의 디버깅 (댓글 0개 / 트랙백 0개) 2007/12/14
- 솔라리스에서의 유저 인증: Part 1 (댓글 0개 / 트랙백 0개) 2007/10/21
- C++ ABI의 안정성: 프로그래밍 언어의 진화 (댓글 1개 / 트랙백 0개) 2006/02/23
- 솔라리스 디바이스 드라이버 작성을 원하십니까? (댓글 1개 / 트랙백 0개) 2008/09/18
- DLight 소개 (댓글 0개 / 트랙백 0개) 2009/06/29
- Dmalloc 을 솔라리스, 썬 스튜디오 컴파일러와 사용하기 (댓글 6개 / 트랙백 0개) 2007/06/13
댓글을 달아 주세요
좋은 정보 감사해요~
2007/09/19 04:47