Visual Studio 2008에서 대규모 C ++ 프로젝트를 작업 중이며 불필요한 #include
지시문 이있는 파일이 많이 있습니다 . 때로는 #include
s는 아티팩트 일 뿐이며 모든 것이 제거되면 잘 컴파일되며 다른 경우에는 클래스를 앞으로 선언하고 #include를 .cpp
파일 로 이동할 수 있습니다 . 이 두 경우를 모두 감지 할 수있는 좋은 도구가 있습니까?
답변:
불필요한 포함 파일을 표시하지는 않지만 Visual Studio에는 컴파일 타임에 포함 된 모든 파일의 트리를 출력하는 설정 /showIncludes
( .cpp
파일을 마우스 오른쪽 버튼으로 클릭 Properties->C/C++->Advanced
)이 있습니다. 이는 포함 할 필요가없는 파일을 식별하는 데 도움이 될 수 있습니다.
또한 pimpl 관용구를 살펴보면 더 적은 헤더 파일 종속성을 제거하여 제거 할 수있는 내용을 쉽게 확인할 수 있습니다.
PC Lint 는 이것에 대해 아주 잘 작동하며 다른 모든 종류의 구피 문제도 찾습니다. Visual Studio에서 외부 도구를 만드는 데 사용할 수있는 명령 줄 옵션이 있지만 Visual Lint 추가 기능을 사용하는 것이 더 쉽다 는 것을 알았 습니다. Visual Lint의 무료 버전도 도움이됩니다. 그러나 PC-Lint를 시도해보십시오. 너무 많은 경고가 표시되지 않도록 구성하려면 약간의 시간이 걸리지 만 표시되는 내용에 놀랄 것입니다.
이를위한 새로운 Clang 기반 도구 인 include-what-you-use가 있습니다 .
!!부인 성명!! 저는 상용 정적 분석 도구 (PC Lint가 아님)로 작업합니다. !!부인 성명!!
간단한 비 파싱 접근 방식에는 몇 가지 문제가 있습니다.
1) 과부하 세트 :
오버로드 된 함수에 다른 파일에서 온 선언이있을 수 있습니다. 하나의 헤더 파일을 제거하면 컴파일 오류가 아닌 다른 오버로드가 선택 될 수 있습니다! 그 결과 나중에 추적하기가 매우 어려울 수있는 의미 체계의 조용한 변경이 발생합니다.
2) 템플릿 전문화 :
오버로드 예제와 유사하게, 템플릿에 대한 부분적 또는 명시 적 전문화가있는 경우 템플릿이 사용될 때 모두 표시되기를 원합니다. 기본 템플릿의 전문화가 다른 헤더 파일에있을 수 있습니다. 전문화가있는 헤더를 제거해도 컴파일 오류가 발생하지 않지만 해당 전문화가 선택되었을 경우 정의되지 않은 동작이 발생할 수 있습니다. (참조 : C ++ 함수의 템플릿 전문화 가시성 )
'msalters'가 지적했듯이 코드를 전체적으로 분석하면 클래스 사용도 분석 할 수 있습니다. 파일의 특정 경로를 통해 클래스가 사용되는 방식을 확인하면 클래스의 정의 (및 모든 종속 항목)를 완전히 제거하거나 적어도 포함의 기본 소스에 더 가까운 수준으로 이동할 수 있습니다. 나무.
그런 도구에 대해 잘 모르고 과거에 하나를 작성하는 것에 대해 생각해 보았지만 이것이 해결하기 어려운 문제라는 것이 밝혀졌습니다.
소스 파일에 ah 및 bh가 포함되어 있다고 가정합니다. 아 포함 #define USE_FEATURE_X
하고 bh 사용합니다 #ifdef USE_FEATURE_X
. #include "a.h"
주석 처리 된 경우 파일이 여전히 컴파일 될 수 있지만 예상 한대로 수행되지 않을 수 있습니다. 이를 프로그래밍 방식 으로 감지하는 것은 중요하지 않습니다.
어떤 도구를 사용하든 빌드 환경도 알아야합니다. 아의 경우 :
#if defined( WINNT )
#define USE_FEATURE_X
#endif
그런 다음 USE_FEATURE_X
이 정의 된 경우에만 정의 WINNT
되므로 도구는 컴파일러 자체에 의해 생성 된 지시문과 헤더 파일이 아닌 컴파일 명령에 지정된 지시문을 알아야합니다.
Timmermans와 마찬가지로 나는 이것에 대한 도구에 익숙하지 않습니다. 하지만 필자는 Perl (또는 Python) 스크립트를 작성하여 한 번에 하나씩 각 포함 줄을 주석 처리 한 다음 각 파일을 컴파일하는 프로그래머를 알고 있습니다.
이제 Eric Raymond 가이를위한 도구를 가지고있는 것으로 보입니다 .
Google의 cpplint.py 에는 "사용하는 항목 만 포함"규칙이 있지만, 내가 말할 수있는 한 " 사용하는 항목 만 포함"은 없습니다 . 그래도 유용 할 수 있습니다.
일반적으로이 주제에 관심이 있다면 Lakos의 대규모 C ++ 소프트웨어 디자인 을 확인해보십시오 . 약간 구식이지만 포함되어야하는 헤더의 절대 최소값을 찾는 것과 같은 많은 "물리적 설계"문제에 직면합니다. 나는 다른 곳에서 이런 종류의 논의를 실제로 본 적이 없습니다.
C / C ++ Include File Dependencies Watcher를 사용하여 포함 그래프를 빌드하고 불필요한 포함을 시각적으로 찾을 수 있습니다.
헤더 파일이 일반적으로
#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif
(#pragma를 한 번 사용하는 것과는 반대로) 다음과 같이 변경할 수 있습니다.
#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else
#pragma message("Someheader.h superfluously included")
#endif
그리고 컴파일러는 컴파일되는 cpp 파일의 이름을 출력하기 때문에 적어도 어떤 cpp 파일이 헤더를 여러 번 가져 오는지 알 수 있습니다.
A.h
와 B.h
모두에 달려 있다고 C.h
당신은 포함 A.h
하고 B.h
당신이 모두 필요하기 때문에, 당신은 것 등 C.h
두 번,하지만 컴파일러는 그것을 두 번째 시간을 건너 뛸 수 있기 때문에 즉, 괜찮아요 당신이하지 않은 경우, 기억해야 할 것 항상 C.h
이전에 포함 A.h
하거나 B.h
훨씬 더 쓸모없는 포함으로 끝납니다.
PC-Lint는 실제로 이것을 할 수 있습니다. 이를 수행하는 한 가지 쉬운 방법은 사용하지 않는 포함 파일 만 감지하고 다른 모든 문제를 무시하도록 구성하는 것입니다. 이것은 매우 간단합니다. 메시지 766 ( "모듈에 헤더 파일이 사용되지 않음") 만 활성화하려면 명령 줄에 -w0 + e766 옵션을 포함하기 만하면됩니다.
964 ( "모듈에서 직접 사용되지 않는 헤더 파일") 및 966 ( "모듈에서 사용되지 않는 간접적으로 포함 된 헤더 파일")과 같은 관련 메시지에도 동일한 접근 방식을 사용할 수 있습니다.
FWIW 지난주 http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318 의 블로그 게시물에서 이에 대해 자세히 썼습니다 .
#include
빌드 시간을 줄이기 위해 불필요한 파일 을 제거하려는 경우 cl.exe / MP , make -j , Xoreax IncrediBuild , distcc / icecream 등을 사용하여 빌드 프로세스를 병렬화하는 데 시간과 돈을 쓰는 것이 좋습니다 .
물론, 이미 병렬 빌드 프로세스가 있고 여전히 속도를 높이려는 경우, 반드시 #include
지시문을 정리하고 불필요한 종속성을 제거하십시오.
다음 #defines 중 하나 또는 둘 다를 추가하면 종종 불필요한 헤더 파일이 제외되고 특히 Windows API 함수를 사용하지 않는 코드의 경우 컴파일 시간이 크게 향상 될 수 있습니다.
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
아직 변경하지 않은 경우 미리 컴파일 된 헤더를 사용하여 변경하지 않을 모든 항목 (플랫폼 헤더, 외부 SDK 헤더 또는 프로젝트의 이미 완료된 정적 부분)을 포함하면 빌드 시간이 크게 달라집니다.
http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx
또한 프로젝트에 너무 늦을 수 있지만 프로젝트를 섹션으로 구성하고 모든 로컬 헤더를 하나의 큰 메인 헤더로 묶지 않는 것이 좋습니다. 그러나 약간의 추가 작업이 필요합니다.
Eclipse CDT로 작업 할 경우 http://includator.com 을 사용하여 포함 구조를 최적화 할 수 있습니다. 그러나 Includator는 VC ++의 사전 정의 포함에 대해 충분히 알지 못할 수 있으며 올바른 포함으로 VC ++를 사용하도록 CDT를 설정하는 것은 아직 CDT에 내장되어 있지 않습니다.
최신 Jetbrains IDE 인 CLion은 현재 파일에서 사용되지 않는 포함 항목을 회색으로 자동 표시합니다.
IDE에서 사용하지 않는 모든 포함 (함수, 메소드 등)의 목록을 가질 수도 있습니다.
기존 답변 중 일부는 어렵다고 말합니다. 순방향 선언이 적절한 경우를 감지하려면 완전한 컴파일러가 필요하기 때문에 사실입니다. 기호의 의미를 모르면 C ++를 구문 분석 할 수 없습니다. 문법은 너무 모호합니다. 특정 이름이 클래스 (앞으로 선언 될 수 있음) 또는 변수 (불가능)를 명명하는지 알아야합니다. 또한 네임 스페이스를 인식해야합니다.
조금 늦었을지 모르지만 한 번 당신이 원하는 것을 수행하는 WebKit perl 스크립트를 발견했습니다. 내가 믿는 약간의 적응이 필요하지만 (나는 펄에 정통하지 않다) 트릭을해야한다.
(트렁크에 더 이상 파일이 없기 때문에 이것은 오래된 분기입니다)
더 이상 필요하지 않다고 생각하는 특정 헤더 (예 : string.h)가있는 경우 포함을 주석 처리 한 다음 모든 포함 아래에 넣을 수 있습니다.
#ifdef _STRING_H_
# error string.h is included indirectly
#endif
물론 인터페이스 헤더는 다른 #define 규칙을 사용하여 CPP 메모리에 포함 된 내용을 기록 할 수 있습니다. 또는 규칙이없는 경우이 방법은 작동하지 않습니다.
그런 다음 재건하십시오. 세 가지 가능성이 있습니다.
괜찮습니다. string.h는 컴파일에 중요하지 않았으며 포함을 제거 할 수 있습니다.
#error 트립. string.g가 어떻게 든 간접적으로 포함되었습니다. string.h가 필요한지 여전히 알 수 없습니다. 필요한 경우 직접 #include해야합니다 (아래 참조).
다른 컴파일 오류가 발생합니다. string.h가 필요했고 간접적으로 포함되지 않았으므로 포함은 처음부터 정확했습니다.
.h 또는 .c가 다른 .h를 직접 사용할 때 간접 포함에 따라 거의 확실하게 버그입니다. 실제로 사용중인 다른 헤더가 필요로하는 한 코드에 해당 헤더 만 필요하다고 약속하는 것입니다. 아마도 당신이 의미 한 것이 아닐 것입니다.
빌드 실패를 일으키는 사항을 선언하는 것보다 동작을 수정하는 헤더에 대한 다른 답변에서 언급 한 경고도 여기에도 적용됩니다.