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

Поэтому у меня возникла идея написать скрипт, который автоматически будет проверять зависимости от хедеров и убирать ненужные. Сканируя все входные файлы, он последовательно пытается убрать все строки, содержащие подстроку "#include", и скомпилировать результат. Если make завершается успешно, скрипт считает, что удалённая строка не нужна.

Скрипт написан на bash и требует от исходников двух вещей:
1) Программа собирается с помощью утилиты make.
2) В данный момент программа успешно компилируется.

#!/bin/bash

function del {
FILE=$1
TEMP_FILE=$FILE".tmp"
BAK_FILE=$FILE".bak"
LINE=$2

echo -n "$LINE..." | tr -d \\r
grep -v "$LINE" "$FILE" > $TEMP_FILE 2>/dev/null
cp $FILE $BAK_FILE
cp $TEMP_FILE $FILE

#cat $FILE
sleep 1
touch -m $FILE
make >/dev/null 2>&1 && echo "YES" || ( cp $BAK_FILE $FILE; echo "NO" )
rm -rf $BAK_FILE $TEMP_FILE
}

function check {
FILE=$1
echo "---------- $FILE ----------"

grep '#include' $FILE | \
while read LINE;
do
del $FILE "$LINE"
done
}

until [ -z "$1" ]
do
check $1
shift
done


Скрипт иногда может работать не совсем корректно:
1) Если A.cpp напрямую зависит от B.h и C.h, а B.h в свою очередь зависит от C.h, то скрипт удалит зависимость A.cpp от C.h. Это не всегда правильно, т.к. зависимость B.h от C.h может измениться без участия A.cpp. Причём такие зависимости могут меняться при смене платформы или компилятора.
2) Если в хедерах есть некая хитрая макроподстановка. Например, файл, содержащий только строки типа #define USE_SOME_FEATURE. Без них программа будет компилироваться, но будет компилироваться не так, как нам хочется.

Также скрипт работает довольно долго: (количество директив #inlcude + время компиляции одного модуля + время линковки) секунд. Это вызвано необходимостью добавления в скрипт строки «Sleep 1», т.к. make проверяет время изменения файлов с точностью до секунды, а частота запуска make больше одного раза в секунду.

Тем не менее, для небольших по сложности проектов скрипт работает вполне сносно.