Инструменты статического анализа включения заголовочного файла? - PullRequest
26 голосов
/ 14 июля 2011

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

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

ОБНОВЛЕНИЕ

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

Ответы [ 8 ]

24 голосов
/ 14 июля 2011

Вывод gcc -w -H <file> может быть полезен (если вы проанализируете его и введете некоторые значения), -w существует для подавления всех предупреждений, с которыми может быть неудобно иметь дело.

Изgcc docs:

-H

Печать имени каждого используемого файла заголовка в дополнение к другим обычным действиям.Каждое имя имеет отступ, чтобы показать, насколько глубоко оно находится в стеке #include.Предварительно скомпилированные заголовочные файлы также печатаются, даже если они признаны недействительными;неверный предварительно скомпилированный заголовочный файл печатается с ...x, а действительный с ...!.

Вывод выглядит так:

. /usr/include/unistd.h
.. /usr/include/features.h
... /usr/include/bits/predefs.h
... /usr/include/sys/cdefs.h
.... /usr/include/bits/wordsize.h
... /usr/include/gnu/stubs.h
.... /usr/include/bits/wordsize.h
.... /usr/include/gnu/stubs-64.h
.. /usr/include/bits/posix_opt.h
.. /usr/include/bits/environments.h
... /usr/include/bits/wordsize.h
.. /usr/include/bits/types.h
... /usr/include/bits/wordsize.h
... /usr/include/bits/typesizes.h
.. /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stddef.h
.. /usr/include/bits/confname.h
.. /usr/include/getopt.h
. /usr/include/stdio.h
.. /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stddef.h
.. /usr/include/libio.h
... /usr/include/_G_config.h
.... /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stddef.h
.... /usr/include/wchar.h
... /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stdarg.h
.. /usr/include/bits/stdio_lim.h
.. /usr/include/bits/sys_errlist.h
Multiple include guards may be useful for:
/usr/include/bits/confname.h
/usr/include/bits/environments.h
/usr/include/bits/predefs.h
/usr/include/bits/stdio_lim.h
/usr/include/bits/sys_errlist.h
/usr/include/bits/typesizes.h
/usr/include/gnu/stubs-64.h
/usr/include/gnu/stubs.h
/usr/include/wchar.h
3 голосов
/ 14 июля 2011

несколько вещей-

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

  • использовать предварительно скомпилированные заголовки.

  • gcc имеет параметры -verbose и --trace, которые также отображают полное дерево включения, MSVC имеет параметр / showInclude, который можно найти на странице свойств Advanced C ++

Также Отображение иерархии #include для файла C ++ в Visual Studio

3 голосов
/ 14 июля 2011

Если вы используете gcc / g ++, опция -M или -MM выведет строку с информацией, которую вы ищете. (Первый будет включать системные заголовки, а второй - нет. Существуют другие варианты; см. Руководство.)

$ gcc -M -c foo.c
foo.o: foo.c /usr/include/stdint.h /usr/include/features.h \
  /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
  /usr/include/bits/wchar.h

Вам нужно будет удалить foo.o: foo.c в начале, но остальное - это список всех заголовков, от которых зависит файл, поэтому не составит труда написать сценарий для их сбора и суммирования.

Конечно, это предложение полезно только в Unix и только в том случае, если у кого-то нет идеи получше. : -)

1 голос
/ 23 июля 2011

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

  1. Отключите ваши методы класса.
  2. После того, как вы удалите их, повторно изучите включенные операторы и попытайтесь удалить их. Обычно полезно удалить их и начать заново.
  3. Предпочитаю использовать форвардные объявления максимально. Если вы деинлайн-методы в заголовочных файлах, вы можете сделать это много.
  4. Разбейте большие заголовочные файлы на более мелкие. Если класс в файле используется чаще, чем большинство, поместите его в заголовочный файл сам по себе.
  5. 1000 переводческих единиц - это не очень много на самом деле. У нас между 10-20 тысячами. :)
  6. Получите Incredibuild, если время компиляции все еще слишком велико.
1 голос
/ 14 июля 2011

У «Большого масштаба C ++ Software Design» Джона Лакоса были инструменты, которые извлекали зависимости времени компиляции среди исходных файлов.

К сожалению, их хранилище на сайте Аддисона-Уэсли исчезло (вместе с самим сайтом AW), но я нашел тарбол здесь: http://prdownloads.sourceforge.net/introspector/LSC-rpkg-0.1.tgz?download

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

Кстати, если вы не читали книгу Лакоса, похоже, ваш проект принесет пользу. (Текущее издание немного устарело, но я слышал, что у Лакоса есть еще одна книга, выходящая в 2012 году.)

1 голос
/ 14 июля 2011

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

Посетите справочную страницу для получения дополнительной информации. Есть несколько вариантов -M.

0 голосов
/ 03 ноября 2015

GCC Имеет флаг (-save-temps), с помощью которого вы можете сохранять промежуточные файлы. Это включает в себя файлы .ii, которые являются результатами препроцессора (так до компиляции). Вы можете написать скрипт для его анализа и определения веса / стоимости / размера того, что включено, а также дерева зависимостей.

Я написал скрипт Python для этого (общедоступно здесь: https://gitlab.com/p_b_omta/gcc-include-analyzer).

0 голосов
/ 20 декабря 2012

Я слышал, что есть некоторые инструменты, но я ими не пользуюсь.

Я создал какой-то инструмент https://sourceforge.net/p/headerfinder, может быть, это полезно. К сожалению, это инструмент "HOME MADE" со следующими проблемами,

  • Разработано в Vb.Net
  • Исходный код нужно скомпилировать
  • Очень медленно и потребляет память.
  • Справка недоступна.
...