답변:
(보다 정교한 텍스트를 얻으려면이 답변의 기록을 참조하십시오.하지만 독자가 실제 명령 줄을 보는 것이 더 쉽다고 생각합니다).
아래의 모든 명령이 공유하는 공통 파일
$ cat a.cpp
extern int a;
int main() {
return a;
}
$ cat b.cpp
extern int b;
int a = b;
$ cat d.cpp
int b;
$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o
$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order
링커는 왼쪽에서 오른쪽으로 검색하고 확인할 수없는 기호를 메모합니다. 라이브러리가 심볼을 해석하면 해당 라이브러리의 오브젝트 파일을 사용하여 심볼을 해석합니다 (이 경우 libb.a에서 둘 다).
정적 라이브러리의 서로에 대한 종속성은 동일하게 작동합니다. 즉, 기호가 필요한 라이브러리가 먼저 있어야하고, 그런 다음 기호를 해석하는 라이브러리가되어야합니다.
정적 라이브러리가 다른 라이브러리에 의존하지만 다른 라이브러리가 다시 이전 라이브러리에 의존하는 경우주기가 있습니다. 당신은에 의해 주기적으로 종속 라이브러리를 묶어이 문제를 해결할 수 -(
와 -)
같은 -( -la -lb -)
(당신은 같은 괄호 탈출해야 할 수도 -\(
와 -\)
). 그런 다음 링커는 동봉 된 lib를 여러 번 검색하여 순환 종속성이 해결되도록합니다. 또는 라이브러리를 여러 번 지정할 수 있으므로 각각이 서로 앞에 -la -lb -la
있습니다.
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!
$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order
여기에서도 동일합니다. 라이브러리는 프로그램의 오브젝트 파일을 따라야합니다. 정적 라이브러리와 비교했을 때의 차이점은 동적 라이브러리가 종속성을 스스로 정렬 하기 때문에 라이브러리의 종속성에 대해 신경 쓰지 않아도된다는 것 입니다.
최근의 일부 배포판은 기본적으로 --as-needed
링커 플래그 를 사용 하여 프로그램의 객체 파일이 동적 라이브러리보다 우선합니다. 해당 플래그가 전달되면 링커는 실제로 실행 파일에 필요하지 않은 라이브러리에 링크하지 않습니다 (왼쪽에서 오른쪽으로 감지). 최근의 아치 리눅스 배포판은 기본적 으로이 플래그를 사용하지 않으므로 올바른 순서를 따르지 않아도 오류가 발생하지 않았습니다.
의 의존성 생략 올바르지 않습니다 b.so
에 대한 d.so
이전을 만들 때입니다. 링크 할 때 라이브러리를 지정해야 a
하지만 a
실제로 정수 b
자체 는 필요하지 않으므로 b
자체 종속성 을 신경 쓰지 않아야합니다 .
다음은 종속성을 지정하지 않은 경우의 의미에 대한 예입니다. libb.so
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)
$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"
바이너리가 어떤 의존성을 가지고 있는지 살펴보면 바이너리 자체는 libd
단지 libb
뿐만 아니라에 의존 한다는 것을 알 수 있습니다. libb
이 방법으로 나중에 다른 라이브러리에 의존하는 경우 바이너리를 다시 연결해야합니다 . 그리고 누군가 가 런타임에 플러그인을 동적으로 로드하는 것을 libb
사용하여 dlopen
로드하면 호출도 실패합니다. 따라서 "right"
정말로 있어야합니다 wrong
.
lorder
+ 가하는 tsort
일입니다. 그러나 순환 참조가있는 경우 때로는 순서가 없습니다. 그런 다음 모든 것이 해결 될 때까지 라이브러리 목록을 순환해야합니다.
GNU ld 링커는 소위 스마트 링커입니다. 이전 정적 라이브러리에서 사용되는 함수를 추적하여 조회 테이블에서 사용되지 않은 함수를 영구적으로 버립니다. 결과적으로 정적 라이브러리를 너무 일찍 링크하면 나중에 해당 라이브러리의 함수를 더 이상 링크 라인의 정적 라이브러리에서 사용할 수 없게됩니다.
일반적인 UNIX 링커는 왼쪽에서 오른쪽으로 작동하므로 모든 종속 라이브러리를 왼쪽에 놓고 해당 종속성을 만족하는 라이브러리를 링크 라인의 오른쪽에 두십시오. 일부 라이브러리는 다른 라이브러리에 의존하고 다른 라이브러리는 다른 라이브러리에 의존한다는 것을 알 수 있습니다. 여기가 복잡해집니다. 순환 참조와 관련하여 코드를 수정하십시오!
정적 라이브러리가 관련된 경우 GCC와 함께 작동하는 방식을 명확하게 보여주는 예는 다음과 같습니다 . 다음 시나리오가 있다고 가정 해 봅시다.
myprog.o
-포함하는 main()
기능libmysqlclient
libmysqlclient
-예제를 위해 정적입니다 (물론 libmysqlclient
거대한 공유 라이브러리를 선호합니다 ). 에서 /usr/local/lib
; 그리고 물건에 의존libz
libz
(동적)이것을 어떻게 연결합니까? (참고 : gcc 4.3.4를 사용하여 Cygwin에서 컴파일 한 예)
gcc -L/usr/local/lib -lmysqlclient myprog.o
# undefined reference to `_mysql_init'
# myprog depends on libmysqlclient
# so myprog has to come earlier on the command line
gcc myprog.o -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# we have to link with libz, too
gcc myprog.o -lz -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# libz is needed by libmysqlclient
# so it has to appear *after* it on the command line
gcc myprog.o -L/usr/local/lib -lmysqlclient -lz
# this works
-Xlinker 옵션을 사용할 수 있습니다.
g++ -o foobar -Xlinker -start-group -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a -Xlinker -end-group
ALMOST는
g++ -o foobar -Xlinker -start-group -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a -Xlinker -end-group
조심해!
링크 순서는 적어도 일부 플랫폼에서 중요합니다. 라이브러리와 연결된 응용 프로그램이 잘못된 순서로 충돌하는 것을 보았습니다.
나는 이것을 많이 보았습니다. 우리 모듈 중 일부는 100 개의 라이브러리와 시스템 및 타사 라이브러리를 초과하여 연결됩니다.
다른 링커 HP / Intel / GCC / SUN / SGI / IBM / etc에 따라 일부 플랫폼에서 라이브러리를 두 번 나열해야하는 미해결 함수 / 변수 등을 얻을 수 있습니다.
대부분의 경우 라이브러리, 코어, 플랫폼, 다른 추상화 계층 구조 계층을 사용하지만 일부 시스템의 경우 여전히 link 명령에서 순서를 따라야합니다.
솔루션 문서에 부딪 치면 다음 개발자가 다시 해결할 필요가 없습니다.
예전 강사는 " 높은 응집력과 낮은 커플 링 " 이라고 말 했지만 오늘날에도 마찬가지입니다.
gcc
이 최근에보다 엄격한 동작으로 변경되었습니다.