Я работаю над большим проектом на C ++ в Visual Studio 2008, и там много файлов с ненужными #include
директивами. Иногда #include
s - это просто артефакты, и все будет нормально компилироваться с их удалением, а в других случаях классы могут быть объявлены вперед, а #include может быть перемещен в .cpp
файл. Есть ли какие-нибудь хорошие инструменты для обнаружения обоих этих случаев?
источник
PC Lint отлично подходит для этого, и он также находит для вас множество других глупых проблем. У него есть параметры командной строки, которые можно использовать для создания внешних инструментов в Visual Studio, но я обнаружил, что с надстройкой Visual Lint легче работать. Даже бесплатная версия Visual Lint помогает. Но попробуйте PC-Lint. Настройка его так, чтобы он не выдавал слишком много предупреждений, займет немного времени, но вы будете поражены тем, что он появится.
источник
Для этого есть новый инструмент на основе Clang, include-what-you-use .
источник
!! ОТКАЗ !! Я работаю над коммерческим инструментом статического анализа (не PC Lint). !! ОТКАЗ !!
Есть несколько проблем с простым подходом без синтаксического анализа:
1) Наборы перегрузки:
Возможно, что перегруженная функция имеет объявления из разных файлов. Может случиться так, что удаление одного файла заголовка приведет к выбору другой перегрузки, а не к ошибке компиляции! Результатом будет незаметное изменение семантики, которое потом будет очень трудно отследить.
2) Специализации шаблона:
Как и в примере с перегрузкой, если у вас есть частичные или явные специализации для шаблона, вы хотите, чтобы они все были видны при использовании шаблона. Возможно, специализации для основного шаблона находятся в разных файлах заголовков. Удаление заголовка со специализацией не вызовет ошибки компиляции, но может привести к неопределенному поведению, если эта специализация была бы выбрана. (См .: Видимость шаблонной специализации функции C ++ )
Как указывает msalters, выполнение полного анализа кода также позволяет анализировать использование классов. Проверяя, как класс используется через определенный путь к файлам, возможно, что определение класса (и, следовательно, все его зависимости) могут быть полностью удалены или, по крайней мере, перемещены на уровень ближе к основному источнику во включении. дерево.
источник
Я не знаю таких инструментов, и я думал о написании одного в прошлом, но оказалось, что это трудная проблема для решения.
Скажем, ваш исходный файл включает ah и bh; ah содержит,
#define USE_FEATURE_X
а bh использует#ifdef USE_FEATURE_X
. Если#include "a.h"
закомментировано, ваш файл все еще может компилироваться, но может не делать то, что вы ожидаете. Обнаружить это программно - нетривиально.Независимо от того, какой инструмент это делает, необходимо также знать вашу среду сборки. Если а выглядит так:
Then
USE_FEATURE_X
определяется только в том случае, еслиWINNT
он определен, поэтому инструменту необходимо знать, какие директивы генерируются самим компилятором, а также какие из них указаны в команде компиляции, а не в файле заголовка.источник
Как и Тиммерманс, я не знаком ни с какими инструментами для этого. Но я знал программистов, которые написали сценарий Perl (или Python), чтобы попытаться закомментировать каждую строку включения по одной, а затем скомпилировать каждый файл.
Похоже, что теперь у Эрика Раймонда есть инструмент для этого .
В cpplint.py Google есть правило «включать то, что вы используете» (среди многих других), но, насколько я могу судить, нет «включать только то, что вы используете». Тем не менее, это может быть полезно.
источник
Если вы в целом интересуетесь этой темой, вы можете попробовать Lakos ' Large Scale C ++ Software Design . Это немного устарело, но связано с множеством проблем «физического дизайна», таких как поиск абсолютного минимума заголовков, которые необходимо включить. Я действительно нигде не видел, чтобы подобные вещи обсуждались.
источник
Дайте Включить представитель палаты в согласительном комитете конгресса попробовать. Он легко интегрируется в Visual Studio и визуализирует ваши пути включения, что помогает вам находить ненужные вещи. Внутри он использует Graphviz, но есть еще много интересных функций. И хотя это коммерческий продукт, у него очень низкая цена.
источник
Вы можете построить граф включений с помощью C / C ++ Include File Dependencies Watcher и визуально находить ненужные включения .
источник
Если ваши файлы заголовков обычно начинаются с
(в отличие от использования #pragma один раз) вы можете изменить это на:
А поскольку компилятор выводит имя компилируемого файла 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
директивы и удалите эти ненужные зависимости.источник
Начните с каждого включаемого файла и убедитесь, что каждый включаемый файл включает только то, что необходимо для его компиляции. Любые включаемые файлы, которые отсутствуют в файлах C ++, можно добавить в сами файлы C ++.
Для каждого включаемого и исходного файла закомментируйте каждый включаемый файл по одному и посмотрите, компилируется ли он.
Также рекомендуется отсортировать включаемые файлы в алфавитном порядке, а если это невозможно, добавьте комментарий.
источник
Добавление одного или обоих из следующих #define исключает часто ненужные файлы заголовков и может существенно улучшить время компиляции, особенно если код не использует функции Windows API.
См. Http://support.microsoft.com/kb/166474
источник
Если вы еще этого не сделали, использование предварительно скомпилированного заголовка, включающего все, что вы не собираетесь изменять (заголовки платформы, внешние заголовки SDK или статические уже завершенные части вашего проекта), значительно изменит время сборки.
http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx
Кроме того, хотя для вашего проекта может быть уже слишком поздно, хорошей практикой является организация вашего проекта по разделам, а не объединение всех локальных заголовков в один большой основной заголовок, хотя это требует небольшой дополнительной работы.
источник
Если вы будете работать с Eclipse CDT, вы можете попробовать http://includator.com, чтобы оптимизировать структуру включения. Однако Includator может не знать достаточно о предопределенных включениях VC ++, и настройка CDT для использования VC ++ с правильными включениями еще не встроена в CDT.
источник
Последняя версия Jetbrains IDE, CLion, автоматически показывает (серым цветом) включения, которые не используются в текущем файле.
Также можно получить список всех неиспользуемых включений (а также функций, методов и т. Д.) Из IDE.
источник
Некоторые из существующих ответов утверждают, что это сложно. Это действительно так, потому что вам нужен полноценный компилятор для обнаружения случаев, в которых будет уместно предварительное объявление. Вы не можете разобрать C ++, не зная, что означают символы; грамматика слишком двусмысленна для этого. Вы должны знать, является ли определенное имя именем класса (может быть объявлено вперед) или переменной (нельзя). Кроме того, вам нужно знать пространство имен.
источник
Возможно, немного поздно, но однажды я нашел Perl-скрипт WebKit, который делал именно то, что вы хотели. Думаю, потребуется некоторая адаптация (я не очень разбираюсь в perl), но это должно помочь:
http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes
(это старая ветка, потому что в стволе больше нет файла)
источник
Если есть определенный заголовок, который, по вашему мнению, больше не нужен (например, string.h), вы можете закомментировать его, а затем поместить его под всеми включениями:
Конечно, заголовки вашего интерфейса могут использовать другое соглашение #define для записи их включения в память CPP. Или без соглашения, и в этом случае этот подход не сработает.
Затем восстановите. Есть три возможности:
Строится нормально. string.h не критичен для компиляции, и включение для него можно удалить.
Ошибка #error. string.g каким-то образом был включен косвенно. Вы все еще не знаете, требуется ли string.h. Если это необходимо, вы должны напрямую #include (см. Ниже).
У вас другая ошибка компиляции. string.h был необходим и не включается косвенно, поэтому включение было правильным с самого начала.
Обратите внимание, что в зависимости от косвенного включения, когда ваш .h или .c напрямую использует другой .h, почти наверняка это ошибка: вы фактически обещаете, что ваш код будет требовать только этот заголовок, если этого требует какой-то другой заголовок, который вы используете, что, вероятно, не то, что вы имели в виду.
Предостережения, упомянутые в других ответах о заголовках, которые изменяют поведение, а не объявляют вещи, вызывающие сбои сборки, также применяются здесь.
источник