tutorial que c++ cmake

c++ - que - cmake tutorial



Manera moderna de establecer indicadores de compilaciĆ³n en el proyecto cmake multiplataforma (4)

Abordar los dos primeros puntos, pero no el tercero:

  1. He leído varias veces que no se debe configurar manualmente CMAKE_CXX_FLAGS y variables similares en primer lugar, pero no estoy seguro de qué otro mecanismo usar.

El comando que desea es set_property . CMake admite un montón de propiedades, no todo, sino muchas, de una manera que le ahorra la molestia de hacer un trabajo específico del compilador. Por ejemplo:

set_property(TARGET foo PROPERTY CXX_STANDARD 17)

que para algunos compiladores resultará en --std=c++17 pero para los anteriores con --std=c++1z (antes de que se finalizara C ++ 17). o:

set_property(TARGET foo APPEND PROPERTY COMPILE_DEFINITIONS HELLO WORLD)

dará como resultado -DHELLO -DWORLD para gcc, clang y MSVC pero para compiladores extraños podría usar otros conmutadores.

¿No hay realmente ningún comando como append que me permita reemplazar set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo") con append(CMAKE_CXX_FLAGS "Foo")?

set_property se puede usar en modo set o en modo anexar (ver ejemplos anteriores).

target_compile_features embargo, no puedo decir si esto es preferible a add_compile_options o target_compile_features .

Quiero escribir un archivo cmake que establezca diferentes opciones de compilación para clang ++, g ++ y MSVC en las versiones de depuración y lanzamiento. Lo que estoy haciendo actualmente se parece a esto:

if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest /W4") # Default debug flags are OK set(CMAKE_CXX_FLAGS_RELEASE "{CMAKE_CXX_FLAGS_RELEASE} /O2") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z -Wall -Wextra -Werror") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} some other flags") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") else() # nothing special for gcc at the moment endif() endif()

Pero tengo un par de problemas con esto:

  1. Primero lo trivial: ¿no hay realmente ningún comando como appen que me permita reemplazar set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo") con append(CMAKE_CXX_FLAGS "Foo") ?
  2. He leído varias veces que no se debe configurar manualmente CMAKE_CXX_FLAGS y variables similares en primer lugar, pero no estoy seguro de qué otro mecanismo usar.
  3. Lo más importante: la forma en que lo hago aquí, necesito un directorio de compilación separado para cada compilador y configuración. Idealmente, me gustaría transformar eso en tener múltiples objetivos en el mismo directorio para poder llamar, por ejemplo, make foo_debug_clang .

Entonces mis preguntas son

  • a) ¿Hay una mejor manera de escribir el script de cmake que resuelva mis "puntos débiles"? solución a los puntos mencionados anteriormente?
  • b) ¿Hay algo así como una mejor práctica moderna y aceptada de cómo configurar tales proyectos?

La mayoría de las referencias que pude encontrar en Internet están desactualizadas o muestran solo ejemplos triviales. Actualmente estoy usando cmake3.8, pero si eso hace alguna diferencia, estoy aún más interesado en la respuesta para versiones más recientes.


Otra forma es usar archivos .rsp.

set(rsp_file "${CMAKE_CURRENT_BINARY_DIR}/my.rsp") configure_file(my.rsp.in ${rsp_file} @ONLY) target_compile_options(mytarget PUBLIC "@${rsp_file}")

lo que podría hacer que la inclusión de opciones múltiples y esotéricas sea más fácil de administrar.


Puede usar target_compile_options () para "agregar" opciones de compilación.


Su enfoque sería, como ha comentado @Tsyvarev, estar absolutamente bien, solo desde que solicitó el "nuevo" enfoque en CMake, esto es a lo que se traduciría su código:

cmake_minimum_required(VERSION 3.8) project(HelloWorld) string( APPEND _opts "$<IF:$<CXX_COMPILER_ID:MSVC>," "/W4;$<$<CONFIG:RELEASE>:/O2>," "-Wall;-Wextra;-Werror;" "$<$<CONFIG:RELEASE>:-O3>" "$<$<CXX_COMPILER_ID:Clang>:-stdlib=libc++>" ">" ) add_compile_options("${_opts}") add_executable(HelloWorld "main.cpp") target_compile_features(HelloWorld PUBLIC cxx_lambda_init_captures)

Toma add_compile_options() y - como @ Al.G. ha comentado - "usa las expresiones de generador sucio".

Hay algunas desventajas de las expresiones generadoras:

  1. La muy útil expresión $<IF:...,...,...> solo está disponible en la versión CMake> = 3.8
  2. Tienes que escribirlo en una sola línea. Para evitarlo, usé la string(APPEND ...) , que también puede usar para "optimizar" su set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ... llamadas.
  3. Es difícil de leer y entender. Por ejemplo, los puntos y comas son necesarios para convertirlo en una lista de opciones de compilación (de lo contrario, CMake lo citará).

Así que mejor use un enfoque más legible y compatible con versiones anteriores con add_compile_options() :

if(MSVC) add_compile_options("/W4" "$<$<CONFIG:RELEASE>:/O2>") else() add_compile_options("-Wall" "-Wextra" "-Werror" "$<$<CONFIG:RELEASE>:-O3>") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_compile_options("-stdlib=libc++") else() # nothing special for gcc at the moment endif() endif()

Y sí, ya no especifica explícitamente el estándar C ++, solo nombra la función C ++ de la que depende su código / destino con las llamadas target_compile_features() .

Para este ejemplo, he elegido cxx_lambda_init_captures que, por ejemplo, para un compilador GCC anterior daría el siguiente error (como ejemplo, qué sucede si un compilador no admite esta función):

The compiler feature "cxx_lambda_init_captures" is not known to CXX compiler "GNU" version 4.8.4.

Y debe escribir una secuencia de comandos de contenedor para crear varias configuraciones con un generador de archivos MAKE de "configuración única" o utilizar un IDE de "configuración múltiple" como Visual Studio.

Aquí están las referencias a ejemplos:

Así que probé lo siguiente con el soporte Open Folder Visual Studio 2017 CMake para combinar en este ejemplo los compiladores cl , clang y mingw :

CMakeSettings.json

{ // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file. "configurations": [ { "name": "x86-Debug", "generator": "Visual Studio 15 2017", "configurationType": "Debug", "buildRoot": "${env.LOCALAPPDATA}//CMakeBuild//${workspaceHash}//build//${name}", "buildCommandArgs": "-m -v:minimal", }, { "name": "x86-Release", "generator": "Visual Studio 15 2017", "configurationType": "Release", "buildRoot": "${env.LOCALAPPDATA}//CMakeBuild//${workspaceHash}//build//${name}", "buildCommandArgs": "-m -v:minimal", }, { "name": "Clang-Debug", "generator": "Visual Studio 15 2017", "configurationType": "Debug", "buildRoot": "${env.LOCALAPPDATA}//CMakeBuild//${workspaceHash}//build//${name}", "cmakeCommandArgs": "-T/"LLVM-vs2014/"", "buildCommandArgs": "-m -v:minimal", }, { "name": "Clang-Release", "generator": "Visual Studio 15 2017", "configurationType": "Release", "buildRoot": "${env.LOCALAPPDATA}//CMakeBuild//${workspaceHash}//build//${name}", "cmakeCommandArgs": "-T/"LLVM-vs2014/"", "buildCommandArgs": "-m -v:minimal", }, { "name": "GNU-Debug", "generator": "MinGW Makefiles", "configurationType": "Debug", "buildRoot": "${env.LOCALAPPDATA}//CMakeBuild//${workspaceHash}//build//${name}", "variables": [ { "name": "CMAKE_MAKE_PROGRAM", "value": "${projectDir}//mingw32-make.cmd" } ] }, { "name": "GNU-Release", "generator": "Unix Makefiles", "configurationType": "Release", "buildRoot": "${env.LOCALAPPDATA}//CMakeBuild//${workspaceHash}//build//${name}", "variables": [ { "name": "CMAKE_MAKE_PROGRAM", "value": "${projectDir}//mingw32-make.cmd" } ] } ] }

mingw32-make.cmd

@echo off mingw32-make.exe %~1 %~2 %~3 %~4

Por lo tanto, puede usar cualquier generador CMake desde Visual Studio 2017, hay algunas citas poco saludables (en septiembre de 2017, tal vez arregladas más tarde) que requieren el intermediario mingw32-make.cmd (eliminando las comillas).