Commutazione tra GCC e Clang / LLVM usando CMake


269

Ho un certo numero di progetti realizzati con CMake e vorrei poter passare facilmente dall'uso di GCC o Clang / LLVM per compilarli. Credo (per favore correggimi se sbaglio!) Che per usare Clang devo impostare quanto segue:

    SET (CMAKE_C_COMPILER             "/usr/bin/clang")
    SET (CMAKE_C_FLAGS                "-Wall -std=c99")
    SET (CMAKE_C_FLAGS_DEBUG          "-g")
    SET (CMAKE_C_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
    SET (CMAKE_C_FLAGS_RELEASE        "-O4 -DNDEBUG")
    SET (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")

    SET (CMAKE_CXX_COMPILER             "/usr/bin/clang++")
    SET (CMAKE_CXX_FLAGS                "-Wall")
    SET (CMAKE_CXX_FLAGS_DEBUG          "-g")
    SET (CMAKE_CXX_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
    SET (CMAKE_CXX_FLAGS_RELEASE        "-O4 -DNDEBUG")
    SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")

    SET (CMAKE_AR      "/usr/bin/llvm-ar")
    SET (CMAKE_LINKER  "/usr/bin/llvm-ld")
    SET (CMAKE_NM      "/usr/bin/llvm-nm")
    SET (CMAKE_OBJDUMP "/usr/bin/llvm-objdump")
    SET (CMAKE_RANLIB  "/usr/bin/llvm-ranlib")

Esiste un modo semplice per alternare tra queste e le variabili GCC predefinite, preferibilmente come una modifica a livello di sistema piuttosto che specifica del progetto (ovvero non aggiungendole semplicemente al CMakeLists.txt di un progetto)?

Inoltre, è necessario utilizzare i llvm-*programmi anziché i valori predefiniti del sistema durante la compilazione usando clang invece di gcc? Qual è la differenza?

Risposte:


342

CMake onora le variabili di ambiente CCe CXXal rilevamento del compilatore C e C ++ per utilizzare:

$ export CC=/usr/bin/clang
$ export CXX=/usr/bin/clang++
$ cmake ..
-- The C compiler identification is Clang
-- The CXX compiler identification is Clang

I flag specifici del compilatore possono essere sovrascritti inserendoli in un file CMake a livello di sistema e puntando la CMAKE_USER_MAKE_RULES_OVERRIDEvariabile su di esso. Creare un file ~/ClangOverrides.txtcon i seguenti contenuti:

SET (CMAKE_C_FLAGS_INIT                "-Wall -std=c99")
SET (CMAKE_C_FLAGS_DEBUG_INIT          "-g")
SET (CMAKE_C_FLAGS_MINSIZEREL_INIT     "-Os -DNDEBUG")
SET (CMAKE_C_FLAGS_RELEASE_INIT        "-O3 -DNDEBUG")
SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")

SET (CMAKE_CXX_FLAGS_INIT                "-Wall")
SET (CMAKE_CXX_FLAGS_DEBUG_INIT          "-g")
SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT     "-Os -DNDEBUG")
SET (CMAKE_CXX_FLAGS_RELEASE_INIT        "-O3 -DNDEBUG")
SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")

Il suffisso _INITfarà inizializzare CMake la *_FLAGSvariabile corrispondente con il valore dato. Quindi invocare cmakenel modo seguente:

$ cmake -DCMAKE_USER_MAKE_RULES_OVERRIDE=~/ClangOverrides.txt ..

Infine, per forzare l'uso delle binutils LLVM, imposta la variabile interna _CMAKE_TOOLCHAIN_PREFIX. Questa variabile è onorata dal CMakeFindBinUtilsmodulo:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

Mettendo insieme tutto questo è possibile scrivere un wrapper shell che imposta le variabili di ambiente CCe CXXquindi richiama cmakecon le sostituzioni variabili citate.


1
Ho seguito la tua risposta e tutto tranne le CMAKE_USER_MAKE_RULES_OVERRIDEopere. Sembra che il file venga ignorato (ovvero, nonostante CMAKE_C_FLAGS_RELEASEsia impostato su -O4nel file di sostituzione, mostra il valore predefinito -O3 -DNDEBUGin in cmake).
Rezzie,

18
Si noti che molte di queste informazioni sono memorizzate nella cache nel file CMakeCache.txt nel livello superiore dell'albero di compilazione. Per passare da gcc a clang, dovresti avere due alberi di build completamente separati, e semplicemente cd avanti e indietro per "cambiare" i compilatori. Una volta generato un albero di compilazione con un determinato compilatore, non è possibile cambiare il compilatore per quell'albero di compilazione.
DLRdave,

@DLRdave Usare due alberi di costruzione separati è un'idea sensata; uno che non avevo considerato. Oops :) Tuttavia, anche eseguendolo in una nuova src/build-clangdirectory, le sostituzioni vengono ignorate.
Rezzie,

1
@Rezzie I flag in ClangOverrides.txt devono essere definiti con il suffisso _INIT. Vedi la risposta aggiornata.
Sakra,

8
Nota per i lettori. Se hai problemi con CMake che non rispetta le variabili CCe CXX, potrebbe essere perché devi prima eliminare tutti i file dalla directory di compilazione. rm CMakeCache.txtpotrebbe non essere intelligente.
John Dibling,

128

Modifica C ++ a livello di sistema su Ubuntu:

sudo apt-get install clang
sudo update-alternatives --config c++

Stamperà qualcosa del genere:

  Selection    Path              Priority   Status
------------------------------------------------------------
* 0            /usr/bin/g++       20        auto mode
  1            /usr/bin/clang++   10        manual mode
  2            /usr/bin/g++       20        manual mode

Quindi basta selezionare clang ++.


3
Grazie, non lo sapevo! Anche se immagino che dipenda da dove cmake sta cercando un compilatore, giusto?
Ibrahim,

1
@Ibrahim Questa configurazione imposta il collegamento simbolico "c ++" sul compilatore scelto e cmake controlla "c ++" per impostazione predefinita, non "g ++". Quindi, a meno che la configurazione di cmake non sia molto specifica, questo dovrebbe funzionare bene (e funziona per me).
Zoomulator

2
Ottengo una risposta che "Esiste una sola alternativa nel gruppo di collegamenti c ++". Espandi la tua risposta per includere come aggiungere clang a questo elenco
vedant

3
Fai attenzione a questa alternativa in quanto può portare a effetti collaterali con il tuo sistema. Ho già avuto problemi con pacchetti come il driver nvidia che ricompila alcuni moduli del kernel durante l'installazione e non è compatibile con clang.
Falco,

2
Se si desidera installare clang-3.5, clang-3.6, ecc usare questo per impostare il valore predefinito stackoverflow.com/a/30742451/1427533 altrimenti si otterràThere is only one alternative in link group cc (providing /usr/bin/cc): /usr/bin/gcc
miguel.martin

23

È possibile utilizzare il comando opzione:

option(USE_CLANG "build application with clang" OFF) # OFF is the default

e quindi avvolgi le impostazioni del compilatore clang in if () s:

if(USE_CLANG)
    SET (...)
    ....
endif(USE_CLANG)

In questo modo viene visualizzato come opzione cmake negli strumenti di configurazione della GUI.

Per renderlo a livello di sistema, puoi ovviamente usare una variabile d'ambiente come valore predefinito o rimanere con la risposta di Ferruccio.


È così che attualmente l'ho impostato, ma ovviamente deve essere fatto in base al progetto. Speravo che ci fosse un comando simile cmake -DCMAKE_COMPILER_DEFINITIONS=MyLlvmDefinitions.cmake.
Rezzie,

1
Ora capisco cosa stai cercando di realizzare. Non so se quel comportamento sia fornito da cmake, ma potresti provare l'opzione -C che sembra caricare uno script prima di iniziare a eseguire CMakeLists.txt. Non l'ho provato però.
Tobias Schlegel,

18

Cambio C di sistema su Ubuntu:

sudo update-alternatives --config cc

Modifica C ++ a livello di sistema su Ubuntu:

sudo update-alternatives --config c++

Per ognuna delle opzioni precedenti, premere il numero di selezione (1) e Invio per selezionare Clang:

  Selection    Path            Priority   Status
------------------------------------------------------------
* 0            /usr/bin/gcc     20        auto mode
  1            /usr/bin/clang   10        manual mode
  2            /usr/bin/gcc     20        manual mode
Press enter to keep the current choice[*], or type selection number:

7
Se hai installato manualmente il tuo clang e messo in un posto non standard, potrebbe non apparire con --config. Ad esempio, se è presente, /opt/clang-llvm-3.5/installa prima una nuova alternativa: sudo update-alternatives --install /usr/bin/c++ c++ /opt/clang-llvm-3.5/bin/clang++ 30
CodeKid

16

A tale scopo è possibile utilizzare il meccanismo del file toolchain di cmake, vedere ad esempio qui . Scrivi un file di toolchain per ogni compilatore contenente le definizioni corrispondenti. Al momento della configurazione, esegui ad es

 cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/clang-toolchain.cmake ..

e tutte le informazioni del compilatore verranno impostate durante la chiamata project () dal file della toolchain. Sebbene nella documentazione sia menzionato solo nel contesto della compilazione incrociata, funziona anche per diversi compilatori sullo stesso sistema.


4
Sono ancora stupito di come le risposte giuste possano essere trovate solo in fondo a una discussione qui a SO.
Slava,

10

Sicuramente non è necessario utilizzare i vari programmi llvm-ar etc:

SET (CMAKE_AR      "/usr/bin/llvm-ar")
SET (CMAKE_LINKER  "/usr/bin/llvm-ld")
SET (CMAKE_NM      "/usr/bin/llvm-nm")
SET (CMAKE_OBJDUMP "/usr/bin/llvm-objdump")
SET (CMAKE_RANLIB  "/usr/bin/llvm-ranlib")

Questi sono fatti per funzionare sul formato interno llvm e come tali non sono utili per la compilazione della tua applicazione.

Come nota -O4 invocherà LTO sul tuo programma che potresti non voler (aumenterà notevolmente il tempo di compilazione) e clang di default in modalità c99 in modo che il flag non sia necessariamente necessario.


7

Se il compilatore predefinito scelto da cmakeè gcce lo hai installato clang, puoi utilizzare il modo semplice per compilare il tuo progetto con clang:

$ mkdir build && cd build
$ CXX=clang++ CC=clang cmake ..
$ make -j2

5

Secondo l'aiuto di cmake:

-C <initial-cache>
     Pre-load a script to populate the cache.

     When cmake is first run in an empty build tree, it creates a CMakeCache.txt file and populates it with customizable settings for the project.  This option may be used to specify a  file  from
     which to load cache entries before the first pass through the project's cmake listfiles.  The loaded entries take priority over the project's default values.  The given file should be a CMake
     script containing SET commands that use the CACHE option, not a cache-format file.

Puoi essere in grado di creare file simili gcc_compiler.txte clang_compiler.txtincludere tutta la relativa configurazione nella sintassi di CMake.

Esempio di Clang (clang_compiler.txt):

 set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE string "clang compiler" FORCE)

Quindi eseguilo come

GCC:

cmake -C gcc_compiler.txt XXXXXXXX

clang:

cmake -C clang_compiler.txt XXXXXXXX

3

È possibile utilizzare la sintassi: $ENV{environment-variable}in your CMakeLists.txtper accedere alle variabili di ambiente. È possibile creare script che inizializzano un set di variabili di ambiente in modo appropriato e che contengano riferimenti a tali variabili nei CMakeLists.txtfile.


Per favore, potresti approfondire un po 'di più? Intendi uno script di shell per esportare le variabili di ambiente prima di avviare cmake? Quali variabili dovrebbero essere impostate? O intendi uno script / alias che chiama semplicemente cmake con -DCMAKE_C_COMPILER ...etc?
Rezzie,

Intendo uno script che esporta solo le variabili d'ambiente appropriate. Dovresti creare le tue variabili di ambiente e farle riferimento nel file CMakeLists.txt.
Ferruccio,

Ahh; Capisco cosa vuoi dire. L'unica cosa è che richiederebbe di esaminare CMakeLists.txttutti i progetti e di interrogare le nuove variabili. Speravo che ci sarebbe stato un modo conveniente per farlo a livello di sistema, senza dover modificare alcun file di progetto. Simile al passaggio a CMAKE_TOOLCHAIN_FILE.
Rezzie,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.