C ++ 11은 동적 / 공유 라이브러리 경계 사이에 std lib 객체를 전달하는 문제를 해결 했습니까? (즉, dll 등)?


34

C ++에 대한 나의 주요 불만 중 하나는 실제로 동적 라이브러리 (예 : dll / so) 경계 외부에서 std 라이브러리 객체를 전달하는 것이 얼마나 어렵다는 것입니다.

표준 라이브러리는 종종 헤더 전용입니다. 멋진 최적화를 수행하기에 좋습니다. 그러나 dll의 경우 std 라이브러리 컨테이너의 내부 구조 / 코드에 영향을 줄 수있는 다른 컴파일러 설정으로 빌드되는 경우가 많습니다. 예를 들어, MSVC에서 하나의 dll은 반복자 디버깅을 사용하여 빌드하고 다른 DLL은 그것을 해제하여 빌드 할 수 있습니다. 이 두 dll은 표준 컨테이너를 전달하는 데 문제가 발생할 수 있습니다. std::string내 인터페이스에 노출 되면 클라이언트가 사용하는 코드 std::string가 내 라이브러리와 정확히 일치 한다고 보장 할 수 없습니다 std::string.

이로 인해 문제, 두통 등을 디버그하기가 어렵습니다. 이러한 문제를 방지하기 위해 조직의 컴파일러 설정을 엄격하게 제어하거나 이러한 문제가없는보다 간단한 C 인터페이스를 사용합니다. 또는 클라이언트가 사용해야 할 예상 컴파일러 설정을 지정하십시오 (다른 라이브러리가 다른 컴파일러 설정을 지정하면 짜증납니다).

내 질문은 C ++ 11이 이러한 문제를 해결하기 위해 무엇을 시도했는지 여부입니다.


3
귀하의 질문에 대한 답변을 모르겠지만 귀하의 우려 사항이 공유되었다고 말할 수 있습니다. 잠재적 인 효율성의 모든 마지막주기를 짜는 것보다 ABI 안정성을 중요하게 생각하기 때문에 프로젝트에서 C ++을 사용하지 않는 이유에 대한 열쇠입니다.
Donal Fellows

2
구별하십시오. DLLs 사이가 어렵습니다 . 사이에서 SO그것은 항상 잘 작동했습니다.
Jan Hudec

1
엄밀히 말하면, 이것은 C ++만의 문제가 아닙니다. 다른 언어에서도이 문제가 발생할 수 있습니다.
MrFox

2
@ JanHudec 나는 SO가 당신이 나타내는 것처럼 거의 마술처럼 작동하지 않는다는 것을 보장 할 수 있습니다. 심볼 가시성 및 이름 변환이 자주 작동하는 방식을 고려할 때 문제에서 더 고립 될 수 있지만 다른 플래그 등으로 .so를 컴파일하고 다른 플래그와 함께 프로그램에서 링크 할 수 있다고 가정하면 재난의 원인이됩니다.
sdg

3
@ sdg : 기본 플래그와 기본 가시성으로 작동합니다. 당신이 그들을 변경하고 곤경에 처하면, 그것은 당신의 문제이며 다른 사람은 없습니다.
Jan Hudec

답변:


20

STL (실제로 템플릿 화 된 타사 라이브러리의 모든 것)은 모든 공용 C ++ API에서 피하는 것이 가장 좋습니다. http://www.ros.org/reps/rep-0009.html#definition 의 긴 규칙 목록을 따라 공개 C ++ API 프로그래밍을 방해하는 ABI 손상을 방지하려고합니다.

그리고 C ++ 11에 대한 대답은 아니오입니다.이 표준은 그것을 만지지 않습니다. 더 흥미로운 이유는 무엇입니까? 대답은 C ++ 17이 매우 감동적이기 때문에 C ++ 모듈을 구현하려면 템플릿을 내 보내야하고, 전체 AST를 디스크에 덤프 한 다음 clang과 같은 LLVM 유형 컴파일러가 필요합니다. 대규모 C ++ 프로젝트에서 많은 ODR 위반 사례를 처리하기 위해 발신자 종속 조회를 수행합니다. GCC 및 ELF 코드가 많이 포함되어 있습니다.

마지막으로, 많은 MSVC 증오와 친 GCC 의견이 있습니다. ELF의 GCC는 근본적으로, 그리고 틀림없이 유효하고 정확한 C ++ 코드를 생성 할 수 없습니다. ELF의 GCC는 Boost.Python을 사용하여 작성된 Python 확장을 Boost.Python을 기반으로 한 둘 이상의 확장이 Python에로드되는 경우 안전하게 Python 확장을 생성 할 수 없습니다. PE와 MachO 및 실제로 제안 된 C ++ 모듈 사양은 모두 모듈 당 기호 테이블을 사용하는 반면, 결국 C ++ 테이블 전역의 ELF는 segfault를 유발하는 ODR 위반을 방지하여 설계 할 수 없기 때문입니다. 그리고 더 많은 문제가 있습니다. 최근에 대답 한 StackOverflow를 참조하십시오.예를 들어 C ++ 예외 발생이 ELF에서 근본적으로 회복 될 수없는 경우 (예 : https://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055)

마지막 요점 : 서로 다른 STL의 상호 운용과 관련하여, 이는 많은 대기업 사용자가 일부 STL 구현에 긴밀하게 통합 된 타사 라이브러리를 혼합하려고 시도하는 데 큰 어려움입니다. 유일한 해결책은 C ++이 STL interop을 처리 할 수있는 새로운 메커니즘이며,이를 사용하는 동안 컴파일러 interop도 수정하여 MSVC, GCC 및 clang 컴파일 된 객체 파일을 혼합 할 수 있습니다. . 나는 C ++ 17 노력을보고 앞으로 몇 년 안에 무엇이 나올지 볼 것입니다. 아무것도하지 않으면 놀랐습니다.


큰 반응! Clang이 Windows 호환성을 향상시키고 좋은 기본 표준 컴파일러를 설정하기를 바랍니다. C ++의 텍스트 포함 / 헤더 시스템은 끔찍합니다. 모듈이 C ++ 코드 구성을 단순화하고 컴파일 시간을 신속하게 가속화하며 ODR 위반 캐치와의 컴파일러 상호 운용성을 향상시키는 날을 기대합니다.
Alessandro Stamatto

3
개인적으로 필자는 실제로 컴파일러 시간 이 크게 증가 할 것으로 예상하고 있습니다. 인트라 모듈 AST를 빠르게 탐색하는 것은 매우 어렵습니다. 아마도 메모리 내 공유 메모리 캐시가 필요할 것입니다. 그러나 나쁜 것들은 거의 모두 나아집니다. BTW, 헤더 파일은 확실히 유지되고 있으며 현재 C ++ 모듈에는 인터페이스 파일이 일대일 헤더 파일로 매핑되어 있습니다. 또한 자동 생성 된 인터페이스 파일은 유효한 C ++이므로 레거시 헤더는 C 매크로를 필터링하여 인터페이스 파일로 스 패트 아웃합니다. 어?
Niall Douglas

시원한! 모듈에 대해 너무 많은 의심이 있습니다. 모듈 시스템이 텍스트 포함 대 기호 포함을 고려합니까? 현재 include 지시문을 사용하면 컴파일러는 모든 소스 파일에 대해 수만 줄의 코드를 반복해서 다시 컴파일해야합니다. 모듈 시스템이 앞으로 선언하지 않고 언젠가 코드를 허용합니까? 빌딩 도구를 개선 / 쉬울 것인가?
Alessandro Stamatto

2
모든 타사 템플릿이 의심스러운 경우 -1입니다. 구성 변경은 구성중인 항목이 템플릿인지 여부와 관계가 없습니다.
DeadMG

1
@Alessandro : 제안 된 C ++ 모듈은 C 매크로를 명시 적으로 비활성화합니다. 템플릿을 사용하거나 지금 사용할 수 있습니다. 제안 된 인터페이스는 합법적 인 C ++이며, 자동 생성되며, 재분석 속도를 위해 선택적으로 사전 컴파일 할 수 있습니다. 즉, 기존의 사전 컴파일 된 헤더보다 속도가 향상되지 않을 것으로 예상됩니다. 마지막 두 가지 질문, 나는 실제로 모른다 : 그것은 달려있다 :)
Niall Douglas

8

사양에는이 문제가 없었습니다. 그 이유는 "하나의 정의 규칙"이라는 개념을 가지고 있기 때문입니다.이 개념은 각 심볼이 실행중인 프로세스에서 정확히 하나의 정의를 갖도록 요구합니다.

Windows DLL은이 요구 사항을 위반합니다. 그렇기 때문에 이러한 모든 문제가 있습니다. 따라서 C ++ 표준화위원회가 아니라 문제를 해결하는 것은 Microsoft의 책임입니다. 공유 라이브러리는 다르게 작동하고 기본적으로 하나의 정의 규칙을 준수하기 때문에 Unix는이 문제를 겪지 않았습니다.

Windows DLL은 다음과 같은 이유로 하나의 정의 규칙을 위반합니다.

  • 정적 링크 시간 동안 어떤 동적 라이브러리에서 심볼을 사용할지 하드 코딩하고이를 정의하는 라이브러리 내에서 심볼을 정적으로 확인합니다. 따라서 단일 프로세스에서 사용되는 것보다 동일한 약한 심볼이 여러 공유 라이브러리 및 해당 라이브러리에서 생성되면 동적 링커에서 해당 심볼을 병합 할 기회가 없습니다. 일반적으로 이러한 기호는 템플릿 인스턴스의 정적 멤버 또는 클래스 impedimenta이며 다른 DLL의 코드간에 인스턴스를 전달할 때 문제를 발생시킵니다.
  • 컴파일 중에 이미 동적 라이브러리에서 심볼을 가져올 지 여부를 하드 코딩합니다. 따라서 일부 라이브러리와 정적으로 링크 된 코드는 동일한 라이브러리와 동적으로 링크 된 코드와 호환되지 않습니다.

ELF 형식 내보내기를 사용하는 Unix는 첫 번째 문제를 피하기 위해 내 보낸 모든 기호를 내재적으로 가져오고 두 번째를 피하기 위해 정적 링크 시간까지 정적 및 동적으로 해결 된 기호를 구분하지 않습니다.


다른 문제는 컴파일러 플래그입니다. 이 문제는 여러 컴파일 단위로 구성된 모든 프로그램에 존재하며 동적 라이브러리가 필요하지 않습니다. 그러나 Windows에서는 훨씬 더 나쁩니다. 유닉스에서는 정적으로 또는 동적으로 링크하는지 여부는 중요하지 않으며, 아무도 표준 런타임을 정적으로 링크하지 않습니다 (Linux에서는 불법 일 수도 있음). 특별 디버그 런타임이 없으므로 하나의 빌드로 충분합니다. 그러나 Microsoft가 정적 및 동적 연결, 디버그 및 릴리스 런타임 및 기타 옵션을 구현 한 방식은 필요한 라이브러리 변형의 조합 폭발을 일으켰습니다. C ++ 언어 문제가 아닌 플랫폼 문제입니다.


2
@DougT .: GCC는 아무 관련이 없습니다. ABI 플랫폼. 대부분의 Unices에서 사용하는 객체 형식 인 ELF에서 공유 라이브러리는 보이는 모든 심볼을 내보내고 내보내는 모든 심볼을 가져옵니다. 따라서 여러 라이브러리에서 무언가가 생성되면 동적 링커는 모두에 대한 첫 번째 정의를 사용합니다. 단순하고 우아하며 작동합니다.
Jan Hudec

1
@MartinBa : 병합 할 것이 없지만, 동일하고 처음에 병합되지 않는 한 중요하지 않습니다. 예, ELF 플랫폼에서 호환되지 않는 컴파일러 설정을 사용하면 어디에서나 동일한 엉망이됩니다. 공유 라이브러리를 사용하지 않더라도 여기서는 다소 주제가 다릅니다.
Jan Hudec

1
@ 1 월-답변과 관련이 있습니다. "... 하나의 정의 규칙 ... Windows DLL이이 요구 사항을 위반합니다 ... 공유 라이브러리가 [UNix에서] 다르게 작동합니다 ..."그러나 std-lib 관련 문제 (헤더에 정의 됨)와 관련된 질문 유닉스에 문제가없는 이유는 SO 대 DLL과 관련이 없지만 Unix에는 표준 라이브러리의 호환되는 버전이 하나 뿐이지 만 Windows MS에서는 호환되지 않는 (디버그) 버전을 선택했기 때문입니다. (확장 검사 등).
Martin Ba

1
@MartinBa : 아니요, Windows에 문제가있는 주된 이유는 Windows에서 사용되는 내보내기 / 가져 오기 메커니즘이 모든 경우에 템플릿 클래스의 정적 멤버와 클래스 impedimenta를 올바르게 병합 할 수없고 정적으로 동적으로 링크 된 심볼을 병합 할 수 없기 때문입니다. 여러 라이브러리 변형으로 인해 훨씬 ​​더 악화되었지만, 주된 문제는 C ++에 Windows 동적 링커에없는 링커의 유연성이 필요하다는 것입니다.
Jan Hudec

4
DLL 사양이 손상되어 Msft가 '수정'해야한다는 해당 요구가 잘못되었다고 생각합니다. DLL이 C ++의 특정 기능을 지원하지 않는다는 사실은 DLL 사양의 결함이 아닙니다. DLL은 언어 중립적이며 벤더 중립적 패키징 메커니즘이며 ABI는 진입 점을 머신 코드 ( '함수 호출') 및 데이터 블롭에 노출합니다. 특정 언어의 고급 기능을 기본적으로 지원하기위한 것이 아닙니다. Msft 또는 DLL 사양의 결함이 아니므로 일부 사람들은 다른 사람들이 원하는 것을 원하지 않습니다.
Euro Micelli

6

아니.

헤더 시스템을 대체하기 위해 많은 작업이 진행 중입니다.이 기능은 모듈이라고하며 이것에 영향을 줄 수는 있지만 큰 것은 아닙니다.


2
헤더 시스템이 이것에 영향을 미치지 않을 것이라고 생각합니다. 문제는 Windows DLL이 하나의 정의 규칙을 위반한다는 것 (C ++ 사양을 따르지 않으므로 C ++위원회는 이에 대해 아무것도 할 수 없음)과 Windows에는 표준 런타임 변형이 너무 많아서 C ++위원회가 할 수 있다는 것입니다. t에 대해 아무것도하지 마십시오.
Jan Hudec

1
아닙니다. 그것들이 어떻게, 사양은 그런 종류의 것을 언급하지도 않습니다. 그 외에는 (Windows) 프로그램이 Windows dll과 연결될 때 ODR이 충족됩니다. 보이는 모든 (내 보낸) 심볼은 ODR을 준수해야합니다.
Paul Michalik

@PaulMichalik C ++은 연결 (9 단계)을 다루며 적어도 DLL / SO의로드 타임 연결은 9 단계에 해당하는 것으로 보입니다. 즉, 외부 연결이있는 심볼 (내 보낸지 여부에 관계없이)이 연결되어 있어야합니다. ODR. LoadLibrary / dlopen과의 동적 연결은 분명히 이러한 요구 사항에 포함되지 않습니다.
bames53

@ bames53 : IMHO, 사양이 너무 약해서 그런 진술을 할 수 없습니다. 된 .dll / .so를하는 것은 그 자체로는 "프로그램"으로 볼 수있다. 보다 규칙이 만족되었습니다. 런타임에 다른 "프로그램"을로드하는 것과 같은 것은 표준에 의해 너무 많이 지정되어 있지 않으므로 이에 관한 진술은 임의적입니다.
Paul Michalik

@PaulMichalik 실행 파일에로드 타임 링크가 필요한 경우로드 타임 링크 전에 외부 엔터티가 확인되지 않고 실행에 필요한 정보가 없습니다. LoadLibrary와 dlopen은 사양을 벗어 났지만로드 타임 링크는 9 단계에 포함되어야합니다.
bames53
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.