2009-04-30 3 views
25

내가 본 적이있는 --whole-archive 링커 옵션의 유일한 실제 사용은 정적 라이브러리에서 공유 라이브러리를 만드는 것입니다. 최근에 나는 Makefile (들)을 방문했다.이 라이브러리는 집 정적 라이브러리와 링크 할 때 항상이 옵션을 사용한다. 이것은 물론 실행 파일이 참조되지 않은 개체 코드를 불필요하게 가져 오게합니다. 이것에 대한 나의 반응은 이것이 명백한 잘못이라는 것이 었습니다. 나는 여기서 뭔가를 놓치고 있습니까?ld 링커 질문 : --whole-archive 옵션

내가 가진 두 번째 질문은 전체 보관 옵션과 관련하여 읽지 만 상당히 구문 분석 할 수는 없습니다. 실행 파일이 정적 라이브러리와 동일한 객체 코드를 (부분적으로) 가진 공유 라이브러리와 연결되는 경우 정적 라이브러리와 연결하는 동안 --whole-archive 옵션을 사용해야하는 효과가 있습니다. 그것은 공유 라이브러리이고 정적 라이브러리는 오브젝트 코드 측면에서 중첩됩니다. 이 옵션을 사용하면 (사용 여부에 관계없이) 모든 심볼이 실행 파일에서 해결됩니다. 이것은 객체 코드의 중복을 피하기 위해서입니다. 혼란 스럽습니다. 심볼이 프로그램에서 심판을 받으면 링크 할 때 고유하게 해결되어야합니다. 중복에 대한이 비즈니스는 무엇입니까?

감사합니다 (이 단락은 꽤 명확 전형이 아닌 경우 용서)

답변

3

내가 실행 파일을 구축 할 전체적인 아카이브를 사용하여 당신으로 인해 불필요한 코드 연결에 (원하는 아마 아니라고 동의 부풀어 오른 소프트웨어 생성). 그들이 할 수있는 좋은 이유가 있다면, 이제는 추측하도록 남겨둔대로 빌드 시스템에서 문서화해야합니다.

두 번째 부분에 관해서. 실행 파일이 정적 라이브러리와 정적 라이브러리와 동일한 객체 코드 인 (부분적으로)을 모두 연결하는 경우 -whole-archive은 정적 라이브러리의 코드가 링크 타임에 적합하도록 보장합니다 . 이것은 정적 링크를 할 때 보통 원하는 것입니다.

50

실행 파일을 정적 라이브러리와 연결할 때 --whole-archive의 정당한 사용이 있습니다.

main.cc

typedef void (*handler)(const char *protocol); 
typedef map<const char *, handler> M; 
M m; 

void register_handler(const char *protocol, handler) { 
    m[protocol] = handler; 
} 
int main(int argc, char *argv[]) 
{ 
    for (int i = 1; i < argc-1; i+= 2) { 
     M::iterator it = m.find(argv[i]); 
     if (it != m.end()) it.second(argv[i+1]); 
    } 
} 

http.cc (libhttp.a의 일부)

: 한 가지 예는 글로벌 인스턴스가 자신의 생성자 (: 테스트되지 않은 코드 경고)에 자신을 "등록"C++ 코드를 구축하고있다
class HttpHandler { 
    HttpHandler() { register_handler("http", &handle_http); } 
    static void handle_http(const char *) { /* whatever */ } 
}; 
HttpHandler h; // registers itself with main! 

http.cc에는 main.cc의 기호가 없습니다. 당신이

g++ main.cc -lhttp 

로 이것을 연결하면 당신은 주요 실행 파일에 링크 HTTP 처리기를하지 것이며, handle_http()를 호출 할 수 없습니다.

g++ main.cc -Wl,--whole-archive -lhttp -Wl,--no-whole-archive 

같은 "자체 등록"스타일은 일반 C, 예를 들어도 가능하다 : 당신이로 연결할 때 발생하는 명암이 GNU 확장자는 __attribute__((constructor))입니다.

+1

Russion libhttp.a를 빌드 할 수있는 경우 register_handler 함수가 libhttp.a에 있음을 증명합니다. 그렇다면이 함수는 main.cc의 register_handler를 어떻게 참조 할 수 있습니까? 따라서이 경우 우리는 당신의 아이디어를 구현하기 위해 다른 방법을 사용해야합니다. – longbkit

9

--whole-archive의 또 다른 정당한 사용은 툴킷 개발자가 여러 기능이 포함 된 라이브러리를 단일 정적 라이브러리에 배포하는 것입니다. 이 경우 공급자는 소비자가 라이브러리의 어느 부분을 사용할 것인지 전혀 모르기 때문에 모든 것을 포함해야합니다.

+4

s/공유/정적 / – Igor

1

오래된 질문이지만 처음 질문 ("왜")에서, 전적으로 - 해당 라이브러리 간의 순환 참조를 회피하기 위해 내부 라이브러리에도 사용되었습니다. 도서관의 열악한 건축 양식을 숨기기 쉽기 때문에 추천하지 않습니다. 그러나 빠른 시험 작동을 얻는 빠른 방법입니다.

두 번째 쿼리의 경우 공유 객체와 정적 라이브러리에 동일한 심볼이있는 경우 링커는 먼저 충족하는 라이브러리로 참조를 충족시킵니다.
공유 라이브러리와 정적 라이브러리가 코드를 정확히 공유하면이 모두가 제대로 작동 할 수 있습니다. 그러나 공유 라이브러리와 정적 라이브러리가 동일한 심볼에 대해 다른 구현을 갖는 경우 프로그램은 여전히 ​​컴파일되지만 라이브러리 순서에 따라 다르게 동작합니다.

정적 라이브러리에서 모든 심볼을 강제로로드하는 것은 어디에서로드되었는지 혼동을 제거하는 한 가지 방법입니다. 그러나 일반적으로 이것은 잘못된 문제를 푸는 것과 같습니다. 대부분 다른 라이브러리에서 같은 기호를 원하지 않을 것입니다.

0

--whole-archive이 잘 사용되는 추가 시나리오는 정적 라이브러리 증분 링크를 처리 할 때 유용합니다.

은 우리가 그 가정하자 :

  1. libAa()b() 기능을 구현합니다.
  2. 프로그램의 일부는 libA과 연결되어야합니다 (예 : libA).

    : --wrap를 사용하여 일부 기능 배치로 인해
  3. libCc() 기능을 실현하고, 최종 프로그램 될 수 a()c()

증분 연결 방법을 사용 a()

  • 사용 (고전 예 malloc이다)
    ld -r -o step1.o module1.o --wrap malloc --whole-archive -lA 
    ld -r -o step2.o step1.o module2.o --whole-archive -lC 
    cc step3.o module3.o -o program 
    

    삽입하지 못했습니다. --whole-archive는 기능을 제거합니다. c() w hich는 program에 의해 사용되어 올바른 컴파일 과정을 방해합니다.

    물론 이것은 모든 모듈에서 모든 호출을 malloc으로 바꾸지 않도록 점진적 연결을 수행해야하는 특별한 경우입니다. 그러나 이것은 --whole-archive에 의해 성공적으로 지원되는 경우입니다.