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

241

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

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

  • 1
    Смотрите также: stackoverflow.com/questions/74326/…
  • 1
    Похоже, что связанный вопрос решает проблему только в Windows, в частности с использованием Visual Studio.
Показать ещё 1 комментарий
Теги:
dependencies
include
refactoring

19 ответов

38
Лучший ответ

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

  • 5
    Это отличный способ увидеть цепочки .. видя, что A -> B -> C -> D и A -> D сразу обнаруживает избыточность.
  • 3
    Как вы заставили Doxygen показывать диаграммы зависимостей?
Показать ещё 1 комментарий
134

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

Там также есть инструмент, основанный на Clang, include-what-you-use, который может это сделать. include-what-you-use может даже предлагать передовые декларации (так что вам не нужно так много #include) и, возможно, очистите свои #includes для вас.

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

  • 2
    Это сейчас. Я только начинаю его использовать. Смотрите мою заметку здесь. stackoverflow.com/questions/1301850/...
  • 0
    @ Шанс: Обновлено. Благодарю.
Показать ещё 9 комментариев
56

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

  • 6
    ИМХО, этот ответ нуждается в гораздо большем количестве голосов, так как после того, как изломы проработаны, инструмент IWYU от Google станет окончательным инструментом для этой задачи.
  • 4
    sudo apt-get установить iwyu
Показать ещё 3 комментария
22

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

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

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

  • 7
    Ничего из этого не будет проблемой, если включаемые файлы выложены правильно. Если вам когда-нибудь понадобится включить файл A перед файлом B, вы делаете это неправильно (и я работал над проектами, где они делали это неправильно).
  • 7
    @ Дэвид, да, но это зависит от лет разработчиков, прежде чем ты сделаешь это правильно. Я могу с большой уверенностью сказать, что вероятность того, что это произойдет, благоприятствует дому, а не вам :(
Показать ещё 4 комментария
15

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

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

  • 0
    Хорошая находка! Я должен использовать это.
  • 1
    хороший. Жаль, что PC-линт не бесплатен ...
Показать ещё 3 комментария
7

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

5

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

5

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

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

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

  • 0
    Я точно знаю, что вы имеете в виду, и моя реакция была "Ewwww". Я ненавижу такой код.
5

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

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

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


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

  • Иногда вы можете удалить два файла заголовка отдельно, но не оба вместе. Решение состоит в том, чтобы удалить файлы заголовков во время прогона и не возвращать их обратно. Это найдет список файлов, которые можно безопасно удалить, хотя может быть решение с большим количеством файлов для удаления, которые этот алгоритм не найдет. (это жадный поиск по пространству включенных файлов для удаления. Он найдет только локальный максимум)
  • Могут быть незначительные изменения в поведении, если у вас есть некоторые макросы, переопределенные по-разному в зависимости от некоторых #ifdefs. Я думаю, что это очень редкие случаи, и тесты Unit, которые являются частью сборки, должны улавливать эти изменения.
  • 0
    Будьте осторожны с этим - скажем, есть два заголовочных файла, которые оба содержат определение чего-либо. Вы можете удалить либо, но не оба. Вы должны быть немного более тщательным в своем подходе грубой силы.
  • 0
    Возможно, это то, что вы имели в виду, но сценарий, который удаляет одно включение и оставляет последнее удаленное включение, если оно было успешно удалено, сработает.
Показать ещё 5 комментариев
4

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

  • 0
    Лицензия на это дополнение смешно 830 швейцарских франков !!!!
  • 0
    Причина в том, что наш бухгалтерский отдел не может выставлять меньшие суммы. Если вы посчитаете время, которое вы можете сэкономить, это не так уж и необоснованно. После того, как мы получили возможность принимать платежи по кредитным картам, мы можем значительно снизить цену. Другой вариант будет спонсором наших усилий по развитию. Наша модель финансирования требует от нас получения прибыли для финансирования нашей исследовательской работы. Я был бы рад продать лицензии намного дешевле, но не могу. Может быть, мы внесем это в CDT, и вы получите это бесплатно, но это я должен как-то финансировать. Я забыл, вы можете попробовать бесплатно!
2

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

  • 2
    Я попросил «всегда правильное» решение? Этот ответ не очень продуктивен для обсуждения.
  • 1
    Ну, были многочисленные посты, обсуждающие проблемы, с которыми столкнется такая программа. Мой пост дает окончательный и правильный ответ на эту часть обсуждения. И мне бы, например, не понравилось бы, если бы программа сказала мне, я мог бы безопасно удалить #include, и тогда мой код больше не компилируется. (или хуже - все еще компилируется, но делает что-то по-другому). Любая такая программа несет этот риск.
Показать ещё 14 комментариев
2

Существует бесплатный инструмент Включить Watcher Dependencies File, который можно интегрировать в визуальную студию. Он показывает лишние # включает красный.

  • 2
    Я только что попробовал, и ссылка была сломана для меня.
2

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

  • 0
    Сценарий находит некоторые включения для удаления, но он также дает множество включений, которые нельзя удалить. Кажется, что он не поддерживает перечисление классов, кажется, что он плохо работает с макросами, а иногда и с пространством имен.
2

Я пробовал использовать 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. Есть больше патологических случаев, но в основном вам нужно будет проверить заголовки самостоятельно для достижения наилучших результатов.

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

Руководство по

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

  • Каждый файл cpp сначала содержит свой заголовочный файл. [Надрез]
  • Заголовочный файл должен содержать все файлы заголовков, необходимые для его анализа. [Надрез]
  • Заголовочный файл должен иметь минимальное количество файлов заголовков, необходимых для его анализа. [Надрез]
  • 0
    Книга Лакоса отлично подходит для образования - кроме его устаревших наблюдений о технологии компиляции.
1

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

Скрипты могут быть доступны непосредственно на GitHub.

1

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

  • Файл заголовка, который фактически не нужен модуль (.c,.cpp) при всех
  • Файл заголовка необходим модулю но включается не один раз, прямо или косвенно.

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

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

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

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

    сделать чистым

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

  • PC-Lint/FlexeLint (проблема с разрешением и 1 и 2)

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

    pclint/flint -vf...

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

1

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

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

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

0

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

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

0

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

Изменить: Он может. См. его ответ

  • 0
    Вы уверены в этом? Я не использовал FlexeLint (такой же, как PCL) в течение нескольких лет для кода C ++, но даже недавно в коде C я мог поклясться, что видел пару сообщений (я думаю, что это код 766?) О неиспользуемых заголовочных файлах. Только что проверил (v8.0), см. Раздел 11.8.1. ручной.
  • 0
    Да, см. Мое редактирование, указывающее на обновленный ответ itmatt.
Сообщество Overcoder
Наверх
Меню