Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: shooshОтветов: 12

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

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

  • См. Также: stackoverflow.com/questions/74326/ Eclipse 19.06.2009
  • Связанный вопрос, похоже, решает проблему только в Windows, в частности с использованием Visual Studio. D'Nabre 07.11.2014
  • Голосование за повторное открытие, поскольку дубликат, в частности, касается использования Visual Studio. Drew Dormann 14.05.2015

cc++dependenciesrefactoringinclude

Ответы

Ответ 1 · рейтинг 42 · Community

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

Ответ 2 · рейтинг 187 · Josh Kelley

Cppclean от Google (ссылки на: загрузить, documentation) может найти несколько категорий проблем C ++, а теперь может найти лишние #includes.

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

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

Ответ 3 · рейтинг 71 · Tzafrir

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

Ответ 4 · рейтинг 26 · JaredPar

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

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

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

Ответ 5 · рейтинг 15 · itsmatt

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

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

Ответ 6 · рейтинг 7 · Diomidis Spinellis

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

Ответ 7 · рейтинг 5 · Gilad Naor

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

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

Иногда просто срабатывает брутфорс :-)


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

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

Ответ 8 · рейтинг 5 · Dan

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

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

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

Ответ 9 · рейтинг 5 · Dan Olson

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

Ответ 10 · рейтинг 4 · Ben Martin

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

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

Руководящие указания

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

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

Ответ 11 · рейтинг 4 · PeterSom

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

Ответ 12 · рейтинг 2 · Steve Gury

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы