Pergunta

Eu sei PC-Lint Pode falar sobre cabeçalhos que estão incluídos, mas não usados. Existem outras ferramentas que podem fazer isso, de preferência no Linux?

Temos uma grande base de código que, nos últimos 15 anos, viu muitas funcionalidades se mover, mas raramente as sobras #include Diretivas são removidas quando a funcionalidade se move de um arquivo de implementação para outro, deixando -nos com uma boa bagunça neste ponto. Obviamente, posso fazer a coisa meticulosa de remover todas as diretivas #include e deixar o compilador me dizer quais reincludes, mas prefiro resolver o problema ao contrário - encontre os não utilizados - em vez de reconstruir uma lista de usados.

Foi útil?

Solução

AVISO LEGAL: Meu trabalho diário está trabalhando para uma empresa que desenvolve ferramentas de análise estática.

Eu ficaria surpreso se a maioria (se não todas) ferramentas de análise estática não tivesse alguma forma de verificação de uso do cabeçalho. Você poderia usar isto Página da Wikipedia para obter uma lista de ferramentas disponíveis e, em seguida, envie um email para as empresas para perguntar.

Alguns pontos que você pode considerar ao avaliar uma ferramenta:

Para sobrecargas de funções, você deseja que todos os cabeçalhos contendo sobrecargas sejam visíveis, não apenas o cabeçalho que contém a função que foi selecionada por resolução de sobrecarga:

// f1.h
void foo (char);

// f2.h
void foo (int);


// bar.cc
#include "f1.h"
#include "f2.h"

int main ()
{
  foo (0);  // Calls 'foo(int)' but all functions were in overload set
}

Se você adotar a abordagem de força bruta, primeiro remova todos os cabeçalhos e depois os adie até que ela se compile, se 'F1.h' for adicionado primeiro, o código será compilado, mas a semântica do programa foi alterada.

Uma regra semelhante se aplica quando você tem especializações parciais. Não importa se a especialização é selecionada ou não, você precisa garantir que todas as especializações sejam visíveis:

// f1.h
template <typename T>
void foo (T);

// f2.h
template <>
void foo (int);

// bar.cc
#include "f1.h"
#include "f2.h"


int main ()
{
  foo (0);  // Calls specialization 'foo<int>(int)'
}

Quanto ao exemplo de sobrecarga, a abordagem de força bruta pode resultar em um programa que ainda compila, mas tem um comportamento diferente.

Outro tipo de análise relacionado que você pode procurar é verificar se os tipos podem ser encaminhados. Considere o seguinte:

// A.h
class A { };

// foo.h
#include "A.h"
void foo (A const &);

// bar.cc
#include "foo.h"

void bar (A const & a)
{
  foo (a);
}

No exemplo acima, a definição de 'a' não é necessária e, portanto, o arquivo de cabeçalho 'foo.h' pode ser alterado para que tenha uma declaração a seguir apenas para 'a':

// foo.h
class A;
void foo (A const &);

Esse tipo de verificação também reduz as dependências do cabeçalho.

Outras dicas

Aqui está um script que faz isso:

#!/bin/bash
# prune include files one at a time, recompile, and put them back if it doesn't compile
# arguments are list of files to check
removeinclude() {
    file=$1
    header=$2
    perl -i -p -e 's+([ \t]*#include[ \t][ \t]*[\"\<]'$2'[\"\>])+//REMOVEINCLUDE $1+' $1
}
replaceinclude() {
   file=$1
   perl -i -p -e 's+//REMOVEINCLUDE ++' $1
}

for file in $*
do
    includes=`grep "^[ \t]*#include" $file | awk '{print $2;}' | sed 's/[\"\<\>]//g'`
    echo $includes
    for i in $includes
    do
        touch $file # just to be sure it recompiles
        removeinclude $file $i
        if make -j10 >/dev/null  2>&1;
        then
            grep -v REMOVEINCLUDE $file > tmp && mv tmp $file
            echo removed $i from $file
        else
            replaceinclude $file
            echo $i was needed in $file
        fi
    done
done

Dê uma olhada em Dehydra.

A partir do site:

O DEYDRA é uma ferramenta de análise estática leve, scriptável e de uso geral capaz de análises específicas de aplicativos do código C ++. No sentido mais simples, o Dehydra pode ser considerado uma ferramenta semântica de grep.

Deveria ser possível criar um script que verifique os arquivos #include não utilizados.

Google's cppclean parece fazer um trabalho decente ao encontrar arquivos de cabeçalho não utilizados. Eu apenas comecei a usá -lo. Produz alguns falsos positivos. Geralmente, ele encontrará desnecessário inclui em arquivos de cabeçalho, mas o que ele não lhe dirá é que você precisa de uma declaração a seguir da classe associada e a inclusão precisa ser movida para o arquivo de origem associado.

Se você estiver usando o Eclipse CDT, pode tentar Incluindo que é gratuito para testadores beta (no momento da redação deste artigo) e remove automaticamente #includes supérfluos ou adiciona os ausentes.

Isenção de responsabilidade: trabalho para a empresa que desenvolve incluí -lo e a usa nos últimos meses. Funciona muito bem para mim, então tente :-)

Até onde eu sei, não há um (que não seja PC-Lint), o que é uma pena e surpreendente. Eu já vi a sugestão de fazer esse pedaço de pseudocódigo (que basicamente automatiza seu "processo meticuloso":

Para cada arquivo CPP
para cada cabeçalho incluir
Comente o Incluir
Compilar o arquivo CPP
if (compile_errors)
desativar o cabeçalho
senão
Remova o cabeçalho Incluir do CPP

Coloque isso em um cron noturno e deve fazer o trabalho, mantendo o projcet em questão livre de cabeçalhos não utilizados (você sempre pode executá -lo manualmente, obviamente, mas levará muito tempo para executar). O único problema é quando não incluir um cabeçalho não gera um erro, mas ainda produz código.

Eu fiz isso manualmente e vale a pena no curto (oh, é o prazo de longo prazo? - leva muito tempo) devido ao tempo reduzido de compilação:

  1. Menos cabeçalhos para analisar cada arquivo de CPP.
  2. Menos dependências - o mundo inteiro não precisa recarregar após uma alteração em um cabeçalho.

É também um processo recursivo - cada arquivo de cabeçalho que permanece na necessidade de examinar para ver se algum arquivo de cabeçalho isto inclui pode ser removido. Além disso, às vezes você pode substituir as declarações avançadas pelo cabeçalho.

Em seguida, todo o processo precisa repetir a cada poucos meses/ano para se manter no topo dos cabeçalhos restantes.

Na verdade, estou um pouco irritado com os compiladores C ++, eles devem poder dizer o que não é necessário - o compilador da Microsoft pode dizer quando uma alteração em um arquivo de cabeçalho pode ser ignorada com segurança durante a compilação.

Se alguém estiver interessado, acabei de colocar o SourceForge uma pequena ferramenta de linha Java Comand para fazer exatamente isso. Como está escrito em Java, é obviamente executável no Linux.

O link para o projeto é https://sourceforge.net/projects/chksem/files/chksem-1.0/

A maioria das abordagens para remover não utilizada inclui o trabalho melhor se você primeiro verifique se cada um dos seus arquivos de cabeçalho compila por conta própria. Fiz isso relativamente rapidamente da seguinte maneira (desculpas por erros de digitação - estou digitando isso em casa:

find . -name '*.h' -exec makeIncluder.sh {} \;

Onde makeIncluder.sh contém:

#!/bin/sh
echo "#include \"$1\"" > $1.cpp

Para cada arquivo ./subdir/classname.h, essa abordagem cria um arquivo chamado ./subdir/classname.h.cpp contendo a linha

#include "./subdir/classname.h"

Se seu makefile no . O diretório compila todos os arquivos de CPP e contém -I. , então apenas a recompilação testará que todo arquivo inclui pode compilar por conta própria. Compilar em seu IDE favorito com o BOTO-Error e corrija os erros.

Quando você acabar, find . -name '*.h.cpp' -exec rm {} \;

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top