c++ 참조 동일한 라이브러리를 두 번 연결하여 순환 종속성을 해결 하시겠습니까?




c++ 다른 프로젝트 참조 (3)

우리는 정적 라이브러리로 분리 된 코드 기반을 가지고 있습니다. 불행히도 라이브러리에는 순환 종속성이 있습니다. 예를 들어, libfoo.alibfoo.a 의존하고 그 반대도 마찬가지입니다.

나는 이것을 처리하는 "정확한"방법이 링커의 --start-group--end-group 옵션을 사용하는 --end-group 있다.

g++ -o myApp -Wl,--start-group -lfoo -lbar -Wl,--end-group

그러나 기존의 Makefile에서 문제는 일반적으로 다음과 같이 처리됩니다.

g++ -o myApp -lfoo -lbar -lfoo

(복잡한 상호 의존성이있는 ~ 20 개의 라이브러리로 확장 한 것을 상상해보십시오.)

나는 Makefile을 통해 두 번째 형식을 처음부터 바 꾸었습니다.하지만 이제는 동료들이 왜 저에게 묻습니다 ... 그리고 "더 깨끗 해졌기 때문에"와 다른 형태가 위험하다는 모호한 감각 이외에, 나는 그렇지 않습니다. 좋은 대답을해라.

그래서 같은 라이브러리를 여러 번 링크하면 문제가 생길 수 있습니까? 예를 들어, 동일한 .o가 두 번 입력되면 다중 정의 기호로 링크가 실패 할 수 있습니까? 아니면 동일한 정적 객체의 사본 두 장을 가지고 미묘한 버그를 만들 수있는 위험이 있습니까?

기본적으로, 같은 라이브러리를 여러 번 연결하는 데 링크 시간 또는 런타임 오류가 발생할 가능성이 있는지 알고 싶습니다. 그렇다면 트리거하는 방법. 감사.


Answer #1

문제는

g++ -o myApp -lfoo -lbar -lfoo

libfoo 를 통한 두 패스와 libbar 를 통한 한 패스로 충분하다는 보장이 없다는 것입니다.

Wl,--start-group ... -Wl,--end-group 으로 접근하는 것이 더 튼튼하기 때문에 더 낫습니다.

다음 시나리오를 고려하십시오 (모든 기호가 다른 오브젝트 파일에 있음).

  • myApplibfoo 정의 된 심볼 fooA 필요로합니다.
  • 기호 fooA barB 정의 된 기호 fooA 필요합니다.
  • 기호 barBlibfoo 정의 된 기호 barB 필요합니다. 이것은 -lfoo -lbar -lfoo 로 처리 할 수있는 순환 종속성입니다.
  • 기호 fooC barD 정의 된 기호 fooC 필요합니다.

위의 경우에 빌드하려면 -lfoo -lbar -lfoo -lbar 를 링커에 전달해야합니다. 왜?

  1. 링커는 처음에는 libfoo 를보고 심볼 fooA 는 정의하지만 fooA 는 정의하지 않습니다. 왜냐하면 지금까지 fooC 도 바이너리에 포함 할 필요성을 fooC 못하기 때문입니다. 그러나 링커는 barB 정의를 찾기 시작합니다. 그 정의가 fooA 가 작동하는 데 필요하기 fooA 입니다.
  2. 링커는 -libbar 보고 -libbar (그러나 barD )의 정의를 포함하고 barB 정의를 fooC .
  3. fooC 의 정의는 libfoo 에서 두 번째로 처리 될 때 발견됩니다. 이제는 barD 의 정의가 필요하다는 것이 분명해졌습니다.하지만 너무 늦게 명령 줄에 libbar 가 없어 libbar !

위의 예는 임의의 의존성 깊이까지 확장 될 수 있습니다 (그러나 이것은 실제 생활에서는 드물게 발생합니다).

따라서

g++ -o myApp -Wl,--start-group -lfoo -lbar -Wl,--end-group

링커가 필요에 따라 라이브러리 그룹을 자주 통과하므로 패스가 심볼 테이블을 변경하지 않은 경우에만 링커가 명령 행의 다음 라이브러리로 이동합니다.

그러나 약간의 성능 저하가 있습니다. 첫 번째 예에서 -lbar 는 수동 명령 줄 -lfoo -lbar -lfoo 와 비교하여 한 번 더 검색되었습니다. 그것을 언급 할 가치가 있는지 / 생각할 가치가 있는지 확신 할 수 없습니다.


Answer #2

레거시 응용 프로그램이므로 라이브러리의 구조가 더 이상 중요하지 않은 배열에서 상속받으며, 더 이상 필요없는 다른 제품을 만드는 데 사용되는 것이 좋습니다.

상속 된 라이브러리 구조에 여전히 구조적인 이유가 남아 있더라도 거의 확실하게 기존의 배열에서 하나 이상의 라이브러리를 구축하는 것이 허용 될 수 있습니다. 20 개의 라이브러리에있는 모든 모듈을 새로운 라이브러리 liballofthem.a 됩니다. 그렇다면 모든 단일 응용 프로그램은 단순히 g++ -o myApp -lallofthem ...


Answer #3

제가 제공 할 수있는 것은 반례가 없다는 것입니다. 나는 실제로 첫번째 폼을 보지 못했지만 (분명히 더 낫지 만) 항상 두 번째 폼으로 해결 된 것을 보았고, 결과적으로 문제를 보지 못했습니다.

그렇다고하더라도 특정 방식으로 작동하는 링커에 의존하는 것이 아니라 라이브러리 간의 관계를 명확하게 보여주기 때문에 첫 번째 형식으로 변경하는 것이 좋습니다.

즉, 공통 라이브러리를 추가 라이브러리로 가져 오도록 코드를 리팩토링 할 가능성이 있는지 적어도 생각해보아야합니다.





circular-dependency