헤더 전용 라이브러리의 이점은 무엇이며 구현을 별도의 파일에 넣는 것과 반대되는 방식으로 작성하는 이유는 무엇입니까?
헤더 전용 라이브러리의 이점은 무엇이며 구현을 별도의 파일에 넣는 것과 반대되는 방식으로 작성하는 이유는 무엇입니까?
답변:
헤더 전용 라이브러리가 유일한 옵션 인 상황이 있습니다 (예 : 템플릿을 처리 할 때).
헤더 전용 라이브러리가 있다는 것은 라이브러리가 사용될 수있는 다른 플랫폼에 대해 걱정할 필요가 없음을 의미합니다. 구현을 분리 할 때 일반적으로 구현 세부 정보를 숨기고 라이브러리를 헤더 및 라이브러리 ( lib
, dll
'또는 .so
파일) 의 조합으로 배포합니다 . 물론 지원을 제공하는 모든 운영 체제 / 버전에 맞게 컴파일해야합니다.
구현 파일을 배포 할 수도 있지만 이는 사용자에게 추가 단계 (사용하기 전에 라이브러리 컴파일)를 의미합니다.
물론 이것은 사례 별로 적용됩니다 . 예를 들어 헤더 전용 라이브러리는 때때로 증가합니다.코드 크기 및 컴파일 시간.
헤더 전용 라이브러리의 이점 :
헤더 전용 라이브러리의 단점 :
더 큰 개체 파일. 일부 소스 파일에서 사용되는 라이브러리의 모든 인라인 메서드는 해당 소스 파일에 대해 컴파일 된 개체 파일에서 약한 기호, 라인 외부 정의를 가져옵니다. 이로 인해 컴파일러 속도가 느려지고 링커 속도도 느려집니다. 컴파일러는 모든 팽창을 생성해야하며 링커는이를 필터링해야합니다.
더 긴 컴파일. 위에서 언급 한 팽창 문제 외에도 헤더가 컴파일 된 라이브러리보다 헤더 전용 라이브러리에서 본질적으로 더 크기 때문에 컴파일 시간이 더 오래 걸립니다. 이러한 큰 헤더는 라이브러리를 사용하는 각 소스 파일에 대해 구문 분석해야합니다. 또 다른 요소는 헤더 전용 라이브러리의 헤더 파일 #include
이 인라인 정의에 필요한 헤더와 라이브러리가 컴파일 된 라이브러리로 빌드 된 경우 필요한 헤더를 가져야 한다는 것입니다.
더 복잡한 컴파일. 헤더 전용 라이브러리에 #include
필요한 추가 요소 때문에 헤더 전용 라이브러리를 사용하면 더 많은 종속성을 얻을 수 있습니다. 라이브러리에서 일부 주요 기능의 구현을 변경하면 전체 프로젝트를 다시 컴파일해야 할 수도 있습니다. 컴파일 된 라이브러리의 소스 파일을 변경하면 하나의 라이브러리 소스 파일을 다시 컴파일하고 컴파일 된 라이브러리를 새 .o 파일로 업데이트 한 다음 응용 프로그램을 다시 연결하기 만하면됩니다.
인간이 읽기가 더 어렵습니다. 최고의 문서가 있더라도 라이브러리 사용자는 종종 라이브러리의 헤더를 읽어야합니다. 헤더 전용 라이브러리의 헤더는 인터페이스를 이해하는 데 방해가되는 구현 세부 정보로 채워집니다. 컴파일 된 라이브러리를 사용하면 인터페이스와 구현이 수행하는 작업에 대한 간략한 설명 만 볼 수 있으며 일반적으로 원하는 모든 것입니다. 그게 정말 당신이 원하는 전부입니다. 라이브러리 사용 방법을 알기 위해 구현 세부 사항을 알 필요는 없습니다.
detail
입니다.
이것이 오래된 스레드라는 것을 알고 있지만 아무도 ABI 인터페이스 또는 특정 컴파일러 문제를 언급하지 않았습니다. 그래서 그렇게 생각했습니다.
이것은 기본적으로 사람들에게 배포 할 헤더가있는 라이브러리를 작성하거나 헤더에 모든 것을 포함하는 대신 자신을 재사용한다는 개념을 기반으로합니다. 헤더와 소스 파일을 재사용하고 모든 프로젝트에서 재 컴파일 할 생각이라면 실제로 적용되지 않습니다.
기본적으로 C ++ 코드를 컴파일하고 하나의 컴파일러로 라이브러리를 빌드하면 사용자가 다른 컴파일러 또는 동일한 컴파일러의 다른 버전에서 해당 라이브러리를 사용하려고하면 바이너리 비 호환성으로 인해 링커 오류 또는 이상한 런타임 동작이 발생할 수 있습니다.
예를 들어 컴파일러 공급 업체는 종종 버전간에 STL 구현을 변경합니다. 라이브러리에 std :: vector를 받아들이는 함수가있는 경우 해당 클래스의 바이트가 라이브러리가 컴파일 될 때 정렬 된 방식으로 정렬 될 것으로 예상합니다. 새 컴파일러 버전에서 공급 업체가 std :: vector의 효율성을 개선 한 경우 사용자의 코드는 다른 구조를 가질 수있는 새 클래스를보고 새 구조를 라이브러리로 전달합니다. 모든 것이 거기에서 내려갑니다 ... 이것이 라이브러리 경계를 넘어 STL 객체를 전달하지 않는 것이 권장되는 이유입니다. CRT (C 런타임) 유형에도 동일하게 적용됩니다.
CRT에 대해 이야기하는 동안 라이브러리와 사용자의 소스 코드는 일반적으로 동일한 CRT에 연결되어야합니다. Visual Studio에서 다중 스레드 CRT를 사용하여 라이브러리를 빌드하지만 사용자가 다중 스레드 디버그 CRT에 대해 링크하면 라이브러리가 필요한 기호를 찾지 못할 수 있으므로 링크 문제가 발생합니다. 어떤 기능인지 기억이 나지 않지만 Visual Studio 2015의 경우 Microsoft는 하나의 CRT 기능을 인라인으로 만들었습니다. 갑자기 CRT 라이브러리가 아닌 헤더에 있었기 때문에 링크 타임에 찾을 것으로 예상했던 라이브러리가 더 이상 할 수 없었고 이로 인해 링크 오류가 발생했습니다. 그 결과 이러한 라이브러리는 Visual Studio 2015로 다시 컴파일해야했습니다.
Windows API를 사용하지만 라이브러리 사용자에 대해 다른 유니 코드 설정으로 빌드하는 경우에도 링크 오류 또는 이상한 동작이 발생할 수 있습니다. 이는 Windows API에 유니 코드 또는 ASCII 문자열을 사용하는 함수와 프로젝트의 유니 코드 설정에 따라 올바른 유형을 자동으로 사용하는 매크로 / 정의가 있기 때문입니다. 잘못된 유형 인 라이브러리 경계를 넘어서 문자열을 전달하면 런타임에 문제가 발생합니다. 또는 프로그램이 처음에 연결되지 않음을 알 수 있습니다.
이러한 사항은 다른 타사 라이브러리 (예 : Eigen 벡터 또는 GSL 행렬)에서 라이브러리 경계를 넘어 객체 / 유형을 전달하는 경우에도 적용됩니다. 타사 라이브러리가 라이브러리를 컴파일하고 사용자가 코드를 컴파일하는 사이에 헤더를 변경하면 문제가 발생합니다.
기본적으로 안전을 위해 라이브러리 경계를 넘어 전달할 수있는 유일한 것은 유형과 POD (Plain Old Data)에 내장되어 있습니다. 이상적으로 모든 POD는 자체 헤더에 정의 된 구조체에 있어야하며 타사 헤더에 의존하지 않아야합니다.
헤더 전용 라이브러리를 제공하면 모든 코드가 동일한 컴파일러 설정 및 동일한 헤더에 대해 컴파일되므로 이러한 많은 문제가 해결됩니다 (사용자와 사용자가 사용하는 세 번째 라이브러리의 버전이 API 호환 가능).
그러나 컴파일 시간 증가와 같은 위에서 언급 한 부정적 요소가 있습니다. 또한 비즈니스를 운영하고 있으므로 사용자 중 한 명이 훔치는 경우 모든 소스 코드 구현 세부 정보를 모든 사용자에게 전달하고 싶지 않을 수 있습니다.
인라인은 LTO (Link Time Optimization)로 수행 할 수 있습니다.
헤더 전용 라이브러리의 두 가지 주요 이점 중 하나 인 "인라인으로 처리 할 헤더에 대한 정의가 필요합니다."라는 두 가지 주요 이점 중 하나의 값을 감소시키기 때문에 이것을 강조하고 싶습니다.
이에 대한 최소한의 구체적인 예는 링크 시간 최적화 및 인라인에 나와 있습니다.
따라서 플래그를 전달하기 만하면 리팩토링 작업없이 개체 파일 전체에서 인라인을 수행 할 수 있습니다. 더 이상 헤더에 정의를 유지할 필요가 없습니다.
그러나 LTO에도 단점 이있을 수 있습니다. 링크 시간 최적화 (LTO)를 사용하지 않는 이유가 있습니까?