it-swarm-vi.tech

Làm cách nào để phát hiện các tệp #incoide không cần thiết trong dự án C ++ lớn?

Tôi đang làm việc với một dự án C++ lớn trong Visual Studio 2008, và có rất nhiều tệp không cần thiết #include chỉ thị. Đôi khi #includes chỉ là các tạo phẩm và mọi thứ sẽ biên dịch tốt khi chúng bị xóa và trong các trường hợp khác, các lớp có thể được chuyển tiếp và #include có thể được chuyển sang .cpp tập tin. Có công cụ nào tốt để phát hiện cả hai trường hợp này không?

93
shambolic

Mặc dù nó sẽ không tiết lộ các tệp không cần thiết, Visual studio có cài đặt /showIncludes (nhấp chuột phải vào một .cpp tập tin, Properties->C/C++->Advanced) sẽ xuất ra một cây gồm tất cả các tệp được bao gồm trong thời gian biên dịch. Điều này có thể giúp xác định các tệp không cần được đưa vào.

Bạn cũng có thể xem thành ngữ pimpl để cho phép bạn thoát khỏi với các phụ thuộc tệp tiêu đề ít hơn để dễ dàng nhìn thấy hành trình mà bạn có thể loại bỏ.

47
Eclipse

PC Lint hoạt động khá tốt cho việc này và nó cũng tìm thấy tất cả các loại vấn đề ngớ ngẩn khác cho bạn. Nó có các tùy chọn dòng lệnh có thể được sử dụng để tạo Công cụ bên ngoài trong Visual Studio, nhưng tôi thấy rằng Visual Lint addin dễ làm việc hơn. Ngay cả phiên bản miễn phí của Visual Lint cũng giúp. Nhưng hãy cho PC-Lint một phát súng. Việc cấu hình nó để nó không cung cấp cho bạn quá nhiều cảnh báo mất một chút thời gian, nhưng bạn sẽ ngạc nhiên về những gì nó xuất hiện.

29
Joe

Có một công cụ dựa trên Clang mới, bao gồm-những gì bạn sử dụng , nhằm mục đích này.

28
Josh Kelley

!! TUYÊN BỐ TỪ CHỐI !! Tôi làm việc trên một công cụ phân tích tĩnh thương mại (không phải PC Lint). !! TUYÊN BỐ TỪ CHỐI !!

Có một số vấn đề với cách tiếp cận không phân tích cú pháp đơn giản:

1) Bộ quá tải:

Có thể một hàm quá tải có các khai báo đến từ các tệp khác nhau. Có thể là việc xóa một tệp tiêu đề dẫn đến tình trạng quá tải khác nhau được chọn thay vì lỗi biên dịch! Kết quả sẽ là một sự thay đổi thầm lặng trong ngữ nghĩa có thể rất khó theo dõi sau đó.

2) Mẫu chuyên ngành:

Tương tự như ví dụ quá tải, nếu bạn có các chuyên môn một phần hoặc rõ ràng cho một mẫu bạn muốn tất cả chúng được hiển thị khi mẫu được sử dụng. Có thể là các chuyên môn cho mẫu chính nằm trong các tệp tiêu đề khác nhau. Xóa tiêu đề với chuyên môn hóa sẽ không gây ra lỗi biên dịch, nhưng có thể dẫn đến hành vi không xác định nếu chuyên môn đó đã được chọn. (Xem: Hiển thị chuyên môn hóa mẫu của chức năng C++ )

Như được chỉ ra bởi 'msalters', thực hiện phân tích đầy đủ mã cũng cho phép phân tích việc sử dụng lớp. Bằng cách kiểm tra cách một lớp được sử dụng mặc dù một đường dẫn cụ thể của tệp, có thể định nghĩa của lớp (và do đó tất cả các phụ thuộc của nó) có thể được loại bỏ hoàn toàn hoặc ít nhất là được chuyển đến một mức gần với nguồn chính trong bao gồm cây.

26
Richard Corden

Tôi không biết về bất kỳ công cụ nào như vậy và tôi đã nghĩ về việc viết một công cụ trong quá khứ, nhưng hóa ra đây là một vấn đề khó giải quyết.

Nói tệp nguồn của bạn bao gồm a.h và b.h; a.h chứa #define USE_FEATURE_X và b.h sử dụng #ifdef USE_FEATURE_X. Nếu #include "a.h" được nhận xét, tệp của bạn vẫn có thể biên dịch, nhưng có thể không làm những gì bạn mong đợi. Phát hiện điều này theo chương trình là không tầm thường.

Bất cứ công cụ nào làm điều này cũng cần phải biết môi trường xây dựng của bạn. Nếu a.h trông như:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

Sau đó USE_FEATURE_X chỉ được xác định nếu WINNT được xác định, vì vậy công cụ sẽ cần biết những lệnh nào được tạo bởi chính trình biên dịch cũng như những lệnh nào được chỉ định trong lệnh biên dịch thay vì trong tệp tiêu đề.

10
Graeme Perrow

Giống như Timmermans, tôi không quen thuộc với bất kỳ công cụ nào cho việc này. Nhưng tôi đã biết các lập trình viên đã viết một tập lệnh Perl (hoặc Python) để thử nhận xét từng dòng bao gồm một dòng và sau đó biên dịch từng tệp.


Có vẻ như bây giờ Eric Raymond có một công cụ cho việc này .

Google cpplint.py có quy tắc "bao gồm những gì bạn sử dụng" (trong số nhiều người khác), nhưng theo như tôi có thể nói, không "chỉ bao gồm những gì bạn sử dụng. " Mặc dù vậy, nó có thể hữu ích.

9
Max Lybbert

Nếu bạn quan tâm đến chủ đề này nói chung, bạn có thể muốn xem Lakos ' Thiết kế phần mềm quy mô lớn C++ . Nó hơi cũ, nhưng đi vào rất nhiều vấn đề "thiết kế vật lý" như tìm ra tiêu đề tối thiểu tuyệt đối cần được đưa vào. Tôi đã không thực sự thấy loại điều này được thảo luận ở bất cứ nơi nào khác.

5
Adrian

Đưa ra Bao gồm Trình quản lý một lần thử. Nó tích hợp dễ dàng trong Visual Studio và trực quan hóa các đường dẫn bao gồm của bạn giúp bạn tìm thấy những thứ không cần thiết. Bên trong nó sử dụng Graphviz nhưng có nhiều tính năng thú vị hơn. Và mặc dù nó là một sản phẩm thương mại nhưng nó có giá rất thấp.

4
Alex

Bạn có thể xây dựng một biểu đồ bao gồm bằng cách sử dụng C/C++ Bao gồm Trình theo dõi phụ thuộc tệp và tìm thấy không cần thiết bao gồm trực quan.

4
Vladimir

PC-Lint thực sự có thể làm điều này. Một cách dễ dàng để làm điều này là cấu hình nó để phát hiện các tệp bao gồm không sử dụng và bỏ qua tất cả các vấn đề khác. Điều này khá đơn giản - để chỉ kích hoạt thông báo 766 ("Tệp tiêu đề không được sử dụng trong mô-đun"), chỉ cần bao gồm các tùy chọn -w0 + e766 trên dòng lệnh.

Cách tiếp cận tương tự cũng có thể được sử dụng với các thông báo liên quan như 964 ("Tệp tiêu đề không được sử dụng trực tiếp trong mô-đun") và 966 ("Tệp tiêu đề được bao gồm gián tiếp không được sử dụng trong mô-đun").

FWIW Tôi đã viết về điều này chi tiết hơn trong một bài đăng trên blog vào tuần trước tại http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318 .

3
Anna-Jayne Metcalfe

Nếu các tệp tiêu đề của bạn thường bắt đầu bằng

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif

(trái ngược với việc sử dụng #pragma một lần), bạn có thể thay đổi điều đó thành:

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else 
#pragma message("Someheader.h superfluously included")
#endif

Và vì trình biên dịch xuất ra tên của tệp cpp đang được biên dịch, điều đó sẽ cho bạn biết ít nhất tệp cpp nào đang khiến tiêu đề được đưa vào nhiều lần.

3
Sam

Nếu bạn đang tìm cách xóa các tệp #include Không cần thiết để giảm thời gian xây dựng, thời gian và tiền bạc của bạn có thể được sử dụng tốt hơn song song với quá trình xây dựng của bạn bằng cách sử dụng cl.exe/MP , tạo -j , Xoreax IncrediBuild , distcc/ icecream , v.v.

Tất nhiên, nếu bạn đã có quy trình xây dựng song song và bạn vẫn đang cố gắng tăng tốc nó, thì bằng mọi cách, hãy dọn sạch các chỉ thị #include Của bạn và loại bỏ các phụ thuộc không cần thiết đó.

2
bk1e

Bắt đầu với mỗi tệp bao gồm và đảm bảo rằng mỗi tệp bao gồm chỉ bao gồm những gì cần thiết để tự biên dịch. Bất kỳ tệp bao gồm nào bị thiếu cho các tệp C++, có thể được thêm vào chính các tệp C++.

Đối với mỗi tệp bao gồm và tệp nguồn, hãy nhận xét từng tệp bao gồm một tệp một lần và xem liệu nó có biên dịch không.

Nó cũng là một ý tưởng tốt để sắp xếp các tập tin bao gồm theo thứ tự abc, và nếu điều này là không thể, hãy thêm một bình luận.

2
selwyn

Thêm một hoặc cả hai #defines sau đây sẽ loại trừ các tệp tiêu đề không cần thiết và có thể cải thiện đáng kể thời gian biên dịch, đặc biệt nếu mã không sử dụng các hàm API của Windows.

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

Xem http://support.Microsoft.com/kb/166474

1
Roger Nelson

IDE Jetbrains mới nhất, CLion, tự động hiển thị (màu xám) bao gồm không được sử dụng trong tệp hiện tại.

Cũng có thể có danh sách tất cả những thứ không được sử dụng bao gồm (và cả các hàm, phương thức, v.v ...) từ IDE.

1

Nếu bạn sẽ làm việc với Eclipse CDT, bạn có thể thử http://includator.com để tối ưu hóa cấu trúc bao gồm của bạn. Tuy nhiên, Bao gồm có thể không biết đủ về bao gồm được xác định trước của VC++ và thiết lập CDT để sử dụng VC++ với bao gồm chính xác chưa được tích hợp vào CDT.

1
PeterSom

Có thể hơi muộn, nhưng tôi đã từng tìm thấy một kịch bản WebKit Perl đã làm đúng những gì bạn muốn. Tôi sẽ cần một số điều chỉnh mà tôi tin (tôi không rành về Perl), nhưng nó nên thực hiện thủ thuật:

http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes

(đây là một nhánh cũ vì thân cây không có tệp nữa)

0
rubenvb

Nếu có một tiêu đề cụ thể mà bạn nghĩ không còn cần thiết nữa (giả sử chuỗi.h), bạn có thể nhận xét bao gồm sau đó đặt tiêu đề này bên dưới tất cả bao gồm:

#ifdef _STRING_H_
#  error string.h is included indirectly
#endif

Tất nhiên, các tiêu đề giao diện của bạn có thể sử dụng quy ước #define khác để ghi lại sự bao gồm của chúng trong bộ nhớ CPP. Hoặc không có quy ước, trong trường hợp phương pháp này sẽ không hiệu quả.

Sau đó xây dựng lại. Có ba khả năng:

  • Nó xây dựng ok. chuỗi.h không được biên dịch quan trọng và có thể loại bỏ bao gồm cho nó.

  • Các chuyến đi #error. string.g được đưa vào một cách gián tiếp bằng cách nào đó Bạn vẫn không biết nếu chuỗi.h là bắt buộc. Nếu được yêu cầu, bạn nên trực tiếp #incolee nó (xem bên dưới).

  • Bạn nhận được một số lỗi biên dịch khác. chuỗi.h là cần thiết và không được đưa vào một cách gián tiếp, do đó, bao gồm là chính xác để bắt đầu.

Lưu ý rằng tùy thuộc vào sự bao gồm gián tiếp khi .h hoặc .c của bạn trực tiếp sử dụng .h gần như chắc chắn là một lỗi: bạn thực sự hứa rằng mã của bạn sẽ chỉ yêu cầu tiêu đề đó miễn là một số tiêu đề khác bạn đang sử dụng yêu cầu, mà có lẽ không phải là ý bạn.

Những cảnh báo được đề cập trong các câu trả lời khác về các tiêu đề sửa đổi hành vi thay vì tuyên bố những điều gây ra lỗi xây dựng cũng được áp dụng ở đây.

0
Britton Kerin

Một số câu trả lời hiện có nói rằng nó khó. Điều đó thực sự đúng, bởi vì bạn cần một trình biên dịch đầy đủ để phát hiện các trường hợp trong đó một tuyên bố chuyển tiếp sẽ phù hợp. Bạn không thể phân tích C++ mà không biết ý nghĩa của các ký hiệu; ngữ pháp đơn giản là quá mơ hồ cho điều đó. Bạn phải biết liệu một tên nhất định đặt tên cho một lớp (có thể được khai báo chuyển tiếp) hoặc một biến (không thể). Ngoài ra, bạn cần phải nhận thức không gian tên.

0
MSalters