it-swarm.com.ru

Обнаружение лишних #include в C/C++?

Я часто нахожу, что секция заголовков файла постоянно увеличивается и увеличивается, но она никогда не уменьшается. На протяжении всей жизни исходного файла классы могли перемещаться и подвергаться рефакторингу, и вполне возможно, что существует довольно много #includes, которые больше не нужны и больше. Оставив их там, можно только продлить время компиляции и добавить ненужные зависимости компиляции. Попытка выяснить, что еще нужно, может быть довольно утомительной.

Есть ли какой-нибудь инструмент, который может обнаружить лишние директивы #include и предложить, какие из них я могу безопасно удалить?
Может ли это сделать Линт?

246
shoosh

Это не автоматически, но doxygen создаст диаграммы зависимостей для файлов #included. Вам придется просматривать их визуально, но они могут быть очень полезны для получения изображения того, что и что использует.

39
anon

Google cppclean (ссылки на: скачать , документацию ) может найти несколько категорий проблем C++, и теперь он может найти лишние #include.

Есть также инструмент на основе Clang, include-what-you-use , который может сделать это. include-what-you-use может даже предложить предварительные объявления (так что вам не нужно так много включать #include) и при желании очистить ваши #include для вас. 

Текущие версии Eclipse CDT также имеют встроенную функциональность: перейдя в меню «Источник» и щелкнув «Организовать включения», вы расположите в алфавитном порядке ваши # включения, добавьте любые заголовки, которые, по вашему мнению, использует Eclipse, без непосредственного их включения, и закомментируйте любые заголовки, которые вам не нужны. Однако эта функция не на 100% надежна.

148
Josh Kelley

Также проверьте include-what-you-use , который решает аналогичную проблему. 

57
Tzafrir

Проблема с обнаружением лишних включений заключается в том, что это не может быть просто проверка зависимости типа. Избыточное включение - это файл, который не предоставляет ничего полезного для компиляции и не изменяет другой элемент, от которого зависят другие файлы. Существует много способов, которыми файл заголовка может изменить компиляцию, например, путем определения константы, переопределения и/или удаления использованного макроса, добавления пространства имен, которое изменяет поиск имени каким-либо образом вниз по строке. Чтобы обнаружить такие элементы, как пространство имен, вам нужно гораздо больше, чем препроцессор, на самом деле вам нужен почти полный компилятор. 

Lint - это скорее средство проверки стиля, и, конечно, у него не будет такой полной возможности. 

Я думаю, вы найдете единственный способ обнаружить лишнее включение - это удалить, скомпилировать и запустить пакеты. 

24
JaredPar

Я думал, что PCLint сделает это, но прошло несколько лет с тех пор, как я на это посмотрел. Вы можете проверить это.

Я просмотрел этот блог , и автор немного рассказал о настройке PCLint для поиска неиспользуемых включений. Может стоит посмотреть.

15
itsmatt

Браузер CScout refactoring может обнаруживать лишние директивы include в коде C (к сожалению, не C++). Вы можете найти описание того, как это работает, в этом журнальной статье.

7
Diomidis Spinellis

Вы можете написать быстрый скрипт, который удаляет одну директиву #include, компилирует проекты и записывает имя в #include и файл, из которого он был удален, в случае, если не возникло ошибок компиляции.

Дайте ему поработать ночью, и на следующий день у вас будет 100% правильный список включаемых файлов, которые вы можете удалить.

Иногда грубой силы просто работает :-)


Правка: а иногда это не так :-). Вот немного информации из комментариев:

  1. Иногда вы можете удалить два заголовочных файла по отдельности, но не оба вместе. Решение состоит в том, чтобы удалить заголовочные файлы во время выполнения, а не вернуть их обратно. Это позволит найти список файлов, которые вы можете безопасно удалить, хотя может быть решение с большим количеством файлов для удаления, которое этот алгоритм не найдет. (это жадный поиск по пространству включаемых файлов для удаления. Он найдет только локальный максимум)
  2. В поведении могут быть незначительные изменения, если некоторые макросы переопределяются по-разному в зависимости от некоторых #ifdefs. Я думаю, что это очень редкие случаи, и модульные тесты, являющиеся частью сборки, должны уловить эти изменения.
6
Gilad Naor

Я никогда не нашел полноценного инструмента, который бы выполнял то, что вы просите. Самым близким, что я использовал, является IncludeManager , который отображает ваше дерево включения заголовков, чтобы вы могли визуально определять такие вещи, как заголовки, включенные только в один файл, и включения круглых заголовков.

5
Dan Olson

Извините (пере) опубликовать здесь, люди часто не расширяют комментарии.

Посмотрите мой комментарий к crashmstr, FlexeLint/PC-Lint сделает это за вас. Информационное сообщение 766. Это обсуждается в разделе 11.8.1 моего руководства (версия 8.0).

Кроме того, и это важно, продолжайте итерацию, пока сообщение не исчезнет . Другими словами, после удаления неиспользуемых заголовков, перезапустите lint, больше файлов заголовков, возможно, стали «ненужными», как только вы удалите некоторые ненужные заголовки. (Это может звучать глупо, читайте это медленно и разбирайте, это имеет смысл.)

5
Dan

Если вы используете Eclipse CDT, вы можете попробовать http://includator.com , которая бесплатна для бета-тестеров (на момент написания этой статьи) и автоматически удаляет лишние #include или добавляет отсутствующие. Для тех пользователей, у которых есть FlexeLint или PC-Lint и которые используют Elicpse CDT, можно выбрать http://linticator.com (также бесплатно для бета-тестирования). Хотя он использует анализ Lint, он предоставляет быстрые исправления для автоматического удаления лишних операторов #include.

4
PeterSom

Чтобы закончить это обсуждение: препроцессор c ++ завершен. Это семантическое свойство, является ли включение избыточным. Следовательно, из теоремы Райс следует, что неразрешимо, является ли включение избыточным или нет. НЕ МОЖЕТ быть программа, которая (всегда правильно) определяет, является ли включение лишним.

2
Algoman

Существует бесплатный инструмент «Встраивать зависимости от файлов» , который можно интегрировать в визуальную студию. Он показывает лишние #include красным.

2
Vladimir

В этой статье объясняется техника удаления #include с помощью анализа Doxygen. Это всего лишь скрипт на Perl, поэтому его довольно просто использовать.

2
Steve Gury

Я пытался использовать Flexelint (Unix-версия PC-Lint) и получил несколько смешанные результаты. Это вероятно потому, что я работаю над очень большой и запутанной кодовой базой. Я рекомендую внимательно изучить каждый файл, который указан как неиспользованный.

Основное беспокойство - ложные срабатывания. Несколько включений одного и того же заголовка сообщаются как ненужный заголовок. Это плохо, поскольку Flexelint не сообщает вам, в какую строку включен заголовок или где он был включен ранее.

Один из способов, которым автоматизированные инструменты могут ошибиться:

В A.hpp:

class A { 
  // ...
};

В B.hpp:

#include "A.hpp

class B {
    public:
        A foo;
};

В C.cpp:

#include "C.hpp"  

#include "B.hpp"  // <-- Unneeded, but lint reports it as needed
#include "A.hpp"  // <-- Needed, but lint reports it as unneeded

Если вы будете слепо следить за сообщениями от Flexelint, вы испортите свои зависимости #include. Есть больше патологических случаев, но в основном вам нужно будет самостоятельно проверить заголовки для достижения наилучших результатов.

Я настоятельно рекомендую эту статью на Физическая структура и C++ из блога Игры изнутри. Они рекомендуют комплексный подход к устранению путаницы #include:

Методические рекомендации

Вот несколько рекомендаций из книги Лакоса, которые сводят к минимуму количество физических зависимостей между файлами. Я использую их годами и всегда был очень доволен результатами.

  1. Каждый файл cpp сначала включает свой собственный заголовочный файл. [Надрез]
  2. Заголовочный файл должен включать все заголовочные файлы, необходимые для его анализа. [Надрез]
  3. Заголовочный файл должен иметь минимальное количество заголовочных файлов, необходимых для его анализа. [Надрез]
2
Ben Martin

Вот простой грубый способ идентификации лишнего заголовка включает в себя . Это не идеально, но устраняет «очевидные» ненужные включения. Избавление от них имеет большое значение для очистки кода.

Доступ к scripts можно получить непосредственно на GitHub.

1
ap-osd

Может быть, немного поздно, но однажды я нашел Perl-скрипт WebKit, который делал именно то, что вы хотели. Я думаю, что потребуется некоторая адаптация (я не очень хорошо разбираюсь в Perl), но это должно сработать:

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

(это старая ветка, потому что в стволе больше нет файла)

1
rubenvb

Существует два типа лишних файлов #include:

  1. Файл заголовка фактически не нужен Модулю (.c, .cpp) вообще 
  2. Файл заголовка требуется модулем , Но включается более одного раза, прямо или косвенно.

В моем опыте есть 2 способа, которые хорошо подходят для его обнаружения:

  • gcc -H или cl.exe/showinclude (решить проблему 2)

    В реальном мире Вы можете экспортировать CFLAGS = -H перед make, , Если все параметры Makefile не переопределяют CFLAGS. Или, как я использовал, вы Можете создать оболочку cc/g ++, чтобы принудительно добавлять опции -H К каждому вызову $ (CC) и $ (CXX). и добавьте каталог wrapper в переменную $ PATH , тогда ваш make будет все вместо этого использует вашу команду wrapper. Of Конечно, ваша обертка должна вызывать компилятор Real gcc. Этот трюк Нужно изменить, если ваш Makefile напрямую использует Gcc. вместо $ (CC) или $ (CXX) или по подразумеваемым правилам.

    Вы также можете скомпилировать один файл, настроив его из командной строки. Но если вы хотите очистить заголовки для всего проекта. Вы можете захватить весь вывод:

    очистить

    сделать 2> & 1 | tee result.txt

  • PC-Lint/FlexeLint (решить проблему .__ 1 и 2)

    убедитесь, что добавили опции + e766, это предупреждение о: неиспользуемых заголовочных файлах.

    pclint/flint -vf ...

    Это приведет к выводу pclint включенных заголовочных файлов, вложенные заголовочные файлы будут иметь соответствующие отступы.

1
zhaorufei

PC Lint Gimpel Software может сообщать, когда включаемый файл был включен более одного раза в модуль компиляции, но он не может найти включаемые файлы, которые не нужны так, как вы ищете.

Правка: Оно может. См. Itsmatt's answer

0
crashmstr

CLion , C/C++ IDE от JetBrains, обнаруживает избыточные включения «из коробки». Они недоступны в редакторе, но есть также функции для оптимизации включений в текущий файл или весь проект .

Я обнаружил, что вы платите за эту функцию, хотя; CLion требуется время для сканирования и анализа вашего проекта при первой загрузке.

0
congusbongus