Substituir sinalizadores de compilação para arquivos únicos

109

Eu gostaria de usar um conjunto global de sinalizadores para compilar um projeto, o que significa que no meu arquivo CMakeLists.txt de nível superior eu especifiquei:

ADD_DEFINITIONS ( -Wall -Weffc++ -pedantic -std=c++0x )

No entanto, para um arquivo específico (digamos "foo.cpp") em um subdiretório, quero mudar os sinalizadores de compilação para não aplicar -Weffc ++ (biblioteca comercial incluída, não posso mudar). Para simplificar a situação de usar apenas -Wall, tentei:

 SET_SOURCE_FILES_PROPERTIES( foo.cpp PROPERTIES COMPILE_FLAGS -Wall )
 ADD_EXECUTABLE( foo foo.cpp )

, que não funcionou. Eu também tentei

SET_PROPERTY( SOURCE foo.cpp PROPERTY COMPILE_FLAGS -Wall )
ADD_EXECUTABLE( foo foo.cpp )

e

ADD_EXECUTABLE( foo foo.cpp )
SET_TARGET_PROPERTIES( foo PROPERTIES COMPILE_FLAGS -Wall )

, em que nenhum funcionou.

Por fim, tentei remover esta definição:

REMOVE_DEFINITIONS( -Weffc++ )
ADD_EXECUTABLE( foo foo.cpp )
ADD_DEFINITIONS( -Weffc++ )

, que também não funcionou (ou seja, recebo muitos avisos de estilo sobre a biblioteca comercial). (** Nota: Os avisos SÃO suprimidos se eu NÃO incluir novamente a diretiva -Weffc ++ após o executável ser compilado.)

Também tentei remover temporariamente os sinalizadores de compilação: http://www.cmake.org/pipermail/cmake/2007-June/014614.html , mas isso não ajudou.

Não existe uma solução elegante para isso?

JB Brown
fonte
1
Espere, se sua última tentativa funcionar, mas somente depois de construída, isso não pode ser um problema de cache? Tente excluir CMakeCache depois de fazer suas alterações.
Cameron
Relacionado, consulte Como alterar um sinalizador do compilador para apenas um executável no CMake? A resposta de Andre mostra o que parece ser uma maneira de substituir as opções existentes por novas opções.
jww

Respostas:

126

Suas tentativas acima estão adicionando mais sinalizadores ao seu arquivo / destino, em vez de sobrescrever como você parece esperar. Por exemplo, nos documentos de Propriedades nos arquivos de origem - COMPILE_FLAGS :

Esses sinalizadores serão adicionados à lista de sinalizadores de compilação quando este arquivo de origem for construído.

Você deve ser capaz de contra-ordenar o -Weffc++ ordenar bandeira para foo.cpp fazendo

set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -Wno-effc++)

Isso deve ter o efeito de adicionar -Wno-effc++após-Weffc++ no comando do compilador, e a última configuração vence. Para ver o comando completo e verificar se este é realmente o caso, você pode fazer

make VERBOSE=1

À parte, um dos mantenedores da Biblioteca Padrão GNU C ++ apresenta uma opinião bastante negativa sobre -Weffc++em esta resposta .

Outro ponto é que você está usando mal add_definitions usando no sentido de que está usando isso para sinalizadores de compilador em vez das definições de pré-processador pretendidas.

Seria preferível usar add_compile_options

add_compile_options(-Wall -Weffc++ -pedantic -std=c++0x)

ou para versões do CMake <3.0 para fazer algo mais como:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Weffc++ -pedantic -std=c++0x")

Em resposta a outras perguntas nos comentários abaixo, acredito que seja impossível remover de forma confiável um sinalizador em um único arquivo. O motivo é que, para qualquer arquivo de origem, ele tem o COMPILE_OPTIONSeCOMPILE_FLAGS 1 de seu destino aplicado, mas eles não aparecem em nenhuma das propriedades desse arquivo de origem.

Você pode tentar retirar o sinalizador de problema do alvo COMPILE_OPTIONS , em seguida, aplicá-lo a cada uma das origens do destino individualmente, omitindo-o do arquivo de origem específico conforme necessário.

No entanto, embora isso possa funcionar em muitos cenários, há alguns problemas.

Primeiro - as propriedades dos arquivos de origem não incluem COMPILE_OPTIONS, apenas COMPILE_FLAGS. Isso é um problema porque o COMPILE_OPTIONSde um destino pode incluir expressões geradoras , masCOMPILE_FLAGS não as suporta. Portanto, você teria que acomodar expressões geradoras enquanto procurava por seu sinalizador e, de fato, talvez até tivesse que "analisar" expressões geradoras se seu sinalizador estivesse contido em um ou mais para ver se deveria ser reaplicado ao restante Arquivos Fonte.

Segundo - desde CMake v3.0, os destinos podem especificar INTERFACE_COMPILE_OPTIONS. Isso significa que uma dependência do seu alvo pode adicionar ou substituir a do seu alvo por COMPILE_OPTIONSmeio de seu INTERFACE_COMPILE_OPTIONS. Portanto, você ainda teria que iterar recursivamente por meio de todas as dependências do seu destino (não é uma tarefa particularmente fácil, pois a lista de LINK_LIBRARIESpara o destino também pode conter expressões geradoras) para encontrar qualquer uma que esteja aplicando o sinalizador de problema e tente removê-la daquelas alvos ' INTERFACE_COMPILE_OPTIONStambém.

Neste estágio de complexidade, gostaria de enviar um patch ao CMake para fornecer a funcionalidade de remover um sinalizador específico incondicionalmente de um arquivo de origem.


1: Observe que, ao contrário da COMPILE_FLAGSpropriedade nos arquivos de origem, a COMPILE_FLAGSpropriedade nos destinos está obsoleta.

Fraser
fonte
6
Mas como você realmente define os sinalizadores de compilação para arquivos separadamente sem anexá-los. Por exemplo, quero usar sinalizadores de compilação diferentes para o destino resultante e não para os arquivos, mas, como eles estão anexados, eu teria que removê-los manualmente. Não há nenhuma propriedade que não acrescenta, mas realmente os define apenas para o arquivo / destino especificado?
Baradé
2
O que podemos fazer quando -fno-flag não está disponível (e o -fflag está definido)?
gnzlbg
@ Baradé Você não pode - não para um arquivo de origem.
Fraser
@gnzlbg Mais uma vez, estamos praticamente presos. Atualizei minha resposta para fornecer um pouco mais de informação (e uma possível solução alternativa que provavelmente funcionaria em alguns cenários).
Fraser de
Não há realmente nenhuma solução alternativa para a configuração das opções de compilação de arquivo único? Eu tenho que desabilitar a geração de cobertura do gcc para alguns arquivos que estão travando o gcov.
Lothar
5

Apenas adicionando a resposta correta de @Fraser.

Caso você queira adicionar o sinalizador especial a pastas específicas, você pode fazer:

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_property(SOURCE ${SPECIAL_SRC_FILES} PROPERTY COMPILE_FLAGS -Wno-effc++)

ou

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_source_files_properties(${SPECIAL_SRC_FILES} PROPERTIES COMPILE_FLAGS -Wno-effc++)

Observe que não é recomendado usar GLOB conforme discutido aqui

Levon
fonte
0

Usando a resposta @Fraser, criei o seguinte para lidar com o Qt includes porque a variável inclui vários caminhos separados por ponto-e-vírgula. Isso significa que primeiro tive que adicionar um foreach()loop e criar os sinalizadores de inclusão manualmente . Mas isso me permite ter uma exceção: foo.cpp (aquele arquivo usa Qt por enquanto, mas a longo prazo eu quero remover essa dependência e quero ter certeza de que o Qt não se infiltrará em nenhum outro lugar).

find_package(Qt5Core REQUIRED)
set(QT_INCLUDE_PROPERTIES "")
foreach(DIR ${Qt5Core_INCLUDE_DIRS})
    set(QT_INCLUDE_PROPERTIES "${QT_INCLUDE_PROPERTIES} -isystem ${DIR}")
endforeach()
set_source_files_properties(foo.cpp PROPERTIES
    COMPILE_FLAGS
        ${QT_INCLUDE_PROPERTIES}
)

Observe também que eu uso o em -isystemvez de -Ipara evitar alguns avisos que os cabeçalhos Qt geram (tenho muitos avisos ativados).

Alexis Wilke
fonte