Como adiciono um vinculador ou sinalizador de compilação em um arquivo CMake?

220

Eu estou usando o arm-linux-androideabi-g++compilador. Quando tento compilar um simples "Olá, mundo!" programa compila bem. Quando eu testo adicionando um tratamento de exceção simples nesse código, ele também funciona (depois de adicionar -fexceptions... acho que está desativado por padrão).

Isto é para um dispositivo Android, e eu só quero usar o CMake, não ndk-build.

Por exemplo - first.cpp

#include <iostream>

using namespace std;

int main()
{
   try
   {
   }
   catch (...)
   {
   }
   return 0;
}

./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions

Funciona sem problemas ...

O problema ... Estou tentando compilar o arquivo com um arquivo CMake.

Quero adicionar o -fexceptionscomo uma bandeira. Eu tentei com

set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )

e

set ( CMAKE_C_FLAGS "fexceptions")

Ele ainda exibe um erro.

solti
fonte
No momento, estou tendo o mesmo problema e estou tentando coisas diferentes. Espere um pouco e eu posto uma resposta. Para sinalizadores de compilação, não é uma forma impura, mas fácil: add_definitions ( "- truc")
Offirmo
Para uma discussão mais atualizada sobre essa questão (especialmente se você estiver usando o CMake 3.x ou mais recente): Qual é o método moderno para definir sinalizadores de compilação gerais no CMake? .
ComicSansMS
Se os sinalizadores de link que você deseja tentar configurar rpath em seguida, ter um olhar para o específico CMake rpath comandos gitlab.kitware.com/cmake/community/wikis/doc/cmake/...
Gabriel Devillers

Respostas:

243

Suponha que você queira adicionar esses sinalizadores (melhor declá-los em uma constante):

SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS    "-lgcov")

Existem várias maneiras de adicioná-los:

  1. A mais fácil (não limpa, mas fácil e conveniente e funciona apenas para sinalizadores de compilação, C & C ++ de uma só vez):

    add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
  2. Anexando às variáveis ​​CMake correspondentes:

    SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
    SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
  3. Usando propriedades de destino, cf. doc CMake compila a propriedade de destino do sinalizador e precisa saber o nome do destino.

    get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
    if(TEMP STREQUAL "TEMP-NOTFOUND")
      SET(TEMP "") # Set to empty string
    else()
      SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
    endif()
    # Append our values
    SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
    set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )

Agora eu uso o método 2.

Offirmo
fonte
4
por que add_definitions () é impuro?
LeoD_natipaC
14
@leinaD_natipaC: A documentação oficial diz: Este comando pode ser usado para adicionar qualquer sinalizador, mas pretende adicionar definições de pré-processador . Eu acho que é por isso.
Benoit Blanchon
Embora esta seja a resposta aceita isso realmente mostrar muito estilo antigo CMAKE, referem-se a resposta por @vitaut por quanto qualquer novo código CMAKE deve ser estruturado em relação a parâmetros de tempo de compilação
Harald Scheirich
1
string(APPEND CMAKE_EXE_LINKER_FLAGS "new_value")é mais curto e limpo do queset(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} new_value")
sangrento
165

Nas versões mais recentes do CMake, você pode definir sinalizadores de compilador e vinculador para um único destino com target_compile_optionse target_link_librariesrespectivamente (sim, o último também define opções de vinculador):

target_compile_options(first-test PRIVATE -fexceptions)

A vantagem desse método é que você pode controlar a propagação de opções para outros destinos que dependem desse via PUBLIC e PRIVATE.

No CMake 3.13, você também pode usar target_link_optionspara adicionar opções de vinculador, o que torna a intenção mais clara.

vitaut
fonte
2
Eu tentei usá-lo: target_compile_options(main_static PRIVATE --static)mas não parece funcionar, alguma idéia do porquê?
Paweł Szczur 5/11
2
-staticprovavelmente é um vinculador, não uma opção do compilador. Tente passá-lo para target_link_libraries.
Vitaut
9
Ah, target_link_librarieseu perdi essa parte do documento: "Especifique bibliotecas ou sinalizadores para usar ao vincular um determinado destino". Obrigado.
Paweł Szczur 5/11
3
Uma adição recente: o CMake 3.13 apresenta target_link_optionscomo uma maneira mais limpa de especificar sinalizadores de vinculador. Você deve evitar o uso target_link_librariesde sinalizadores de vinculador no futuro e usá-lo target_link_options.
ComicSansMS
1
Há também add_compile_options - ver stackoverflow.com/questions/39501481/... e mais recentemente add_link_options
Bruce Adams
46

Tente definir a variável em CMAKE_CXX_FLAGSvez de CMAKE_C_FLAGS:

set (CMAKE_CXX_FLAGS "-fexceptions")

A variável CMAKE_C_FLAGS afeta apenas o compilador C, mas você está compilando código C ++.

Adicionar o sinalizador a CMAKE_EXE_LINKER_FLAGSé redundante.

sakra
fonte
Eu tentei isso, mas ainda dá erro. Está definido (CMAKE_CXX_FLAGS "-fexceptions") a única maneira de especificar o sinalizador do compilador.
Solti
3
Eu resolvi o problema, mas não de uma maneira boa, é uma solução alternativa ruim. Eu criei -DCMAKE_CXX_FLAGS = "-fexceptions" na linha de comando. por algum motivo, o cmake não está lendo sinalizadores do arquivo .cmake. :( .. obrigado sakra pela sua resposta ..
solti
8
-DCMAKE_CXX_FLAGS = "-fexceptions" NÃO deve haver um espaço entre o = e "
evandrix 5/12/12
Com relação ao que você disse: "por alguma razão, o cmake não está lendo sinalizadores do arquivo .cmake". Certifique-se de limpar o cache existente. Isso pode ser feito excluindo tudo do diretório de compilação antes do cmake novamente.
Zaizen
1

Você também pode adicionar sinalizadores de vinculador a um destino específico usando a LINK_FLAGSpropriedade:

set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")

Se você deseja propagar essa alteração para outros destinos, é possível criar um destino fictício ao qual vincular.

kaveish
fonte