lenguaje - funcion preprocesador en c++
CMake preprocesador condicional definir en código (3)
Estoy migrando un proyecto de makefile a CMake. La persona que escribió el makefile la primera vez había hecho un módulo para escribir ciertos valores en un archivo de inclusión.
Hay un archivo principal config.h que incluye un config_in.h. El archivo config.h contiene algo como esto:
#ifndef USE_FEATURE_A
#define USE_FEATURE_A 0
#endif
#ifndef USE_FEATURE_B
#define USE_FEATURE_B 0
#endif
En el archivo make hay un objetivo falso como with_feature_a
que escribe en config_in.h
#define USE_FEATURE_A 1
De esta manera alguien puede escribir
make with_feature_a
make
para obtener la compilación correcta.
Quiero replicar algo como esto usando este código base pero usando CMake. Intenté un par de enfoques sugeridos en la red, pero no logré que funcionara.
set_target_properties(with_feature_a PROPERTIES COMPILE_DEFINITIONS
"WITH_FEATURE_A=1"
)
Esto no funciona porque si corro
make with_feature_a
No veo with_feature_a
en la línea de comandos del preprocesador.
El segundo intento que hice fue escribir un archivo directamente con el contenido configurado a lo que quisiera, pero no entendía cómo conectar el comando file()
a mi destino.
Coloqué esto en mi CMakeLists.txt
file(WRITE
local/config_in.h
"#define WITH_FEATURE_A 1"
)
pero esto no se ejecuta cada vez y no sé cómo configurarlo en un solo objetivo.
Cualquier ayuda es apreciada. Gracias por leer todas estas cosas. Lo siento por la larga historia :)
ACTUALIZAR
La solución proporcionada here es una gran mejora en el camino hacia la solución. El problema es que no se permiten definiciones recursivas. Os muestro un ejemplo:
en CMakeLists.txt coloqué:
if (WITH_FEATURE_A)
MESSAGE(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
add_definitions(-DWITH_FEABURE_B=1)
endif()
if (WITH_FEABURE_B)
MESSAGE(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_D=1)
endif()
if (WITH_FEABURE_C)
MESSAGE(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_D=1)
endif()
if (WITH_FEABURE_D)
MESSAGE(STATUS "WITH_FEATURE_D")
endif()
en este caso, si ejecuto cmake con -DWITH_FEATURE_A = 1, me encantaría ver en la salida:
WITH_FEATURE_A
WITH_FEATURE_B
WITH_FEATURE_D
en realidad este código de impresión solo
WITH_FEATURE_A
Me topé con esta pregunta y pensé que compartía otra opción: TARGET_COMPILE_DEFINITIONS
. Podría tener dos destinos en su archivo CMakeLists.txt, uno por configuración, y tener algo como esto
ADD_EXECUTABLE (versionA, ...)
TARGET_COMPILE_DEFINITIONS (versionA, PUBLIC -DWITH_FEATURE_A=1 -DWITH_FEATURE_B=0)
ADD_EXECUTABLE (versionB, ...)
TARGET_COMPILE_DEFINITIONS (versionB, PUBLIC -DWITH_FEATURE_A=0 -DWITH_FEATURE_B=1)
Esto le indica a cmake que agregue las definiciones de preprocesadores de las macros WITH_FEATURE_A
y WITH_FEATURE_B
(con el valor adecuado), como si las hubiera definido en sus archivos * pp. Entonces puedes decir qué versión compilar:
make versionA
make versionB
Parece que quieres introducir relaciones entre tus opciones. Esto será más fácil si separas los pasos. Primero resuelva las relaciones, luego establezca las definiciones de C en los resultados. Recuerde que WITH_FEATURE_A es una variable cmake, y USE_FEATURE_A es el conjunto de definiciones del preprocesador C con ADD_DEFINITIONS:
# Specify the inter-feature dependencies
if (WITH_FEATURE_A)
# A requires B because <somereason>
set(WITH_FEATURE_B ON)
endif()
if (WITH_FEATURE_B)
set(WITH_FEATURE_D ON)
endif()
if (WITH_FEATURE_C)
set(WITH_FEATURE_D ON)
endif()
# Now generate the C defines for passing the options to the compiler
if (WITH_FEATURE_A)
MESSAGE(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
endif()
if (WITH_FEATURE_B)
MESSAGE(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_B=1)
endif()
if (WITH_FEATURE_C)
MESSAGE(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_C=1)
endif()
if (WITH_FEATURE_D)
MESSAGE(STATUS "WITH_FEATURE_D")
add_definitions(-DUSE_FEATURE_D=1)
endif()
Puede simplificar las cosas evitando crear los objetivos ficticios y eliminando el archivo de configuración. En cambio, si pasa los requisitos a través de la línea de comandos cuando invoca CMake (o a través de la interfaz gráfica de usuario de CMake), puede ejecutar make solo una vez.
Por ejemplo, podría agregar lo siguiente a su CMakeLists.txt:
option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)
if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B)
endif()
De forma predeterminada, si simplemente ejecuta CMake, establecerá la variable CMake WITH_FEATURE_A
en ON
que, en consecuencia, agrega USE_FEATURE_A
como una definición de preprocesador a la compilación. USE_FEATURE_B
no está definido en el código.
Esto sería equivalente a hacer #define USE_FEATURE_A
en su código.
Si realmente necesitas el equivalente de
#define USE_FEATURE_A 1
#define USE_FEATURE_B 0
Luego en tu CMakeLists.txt puedes hacer:
option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)
if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A=1)
else()
add_definitions(-DUSE_FEATURE_A=0)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B=1)
else()
add_definitions(-DUSE_FEATURE_B=0)
endif()
Para cambiar estos valores predeterminados desde la línea de comando, simplemente haga (por ejemplo):
cmake . -DWITH_FEATURE_A=OFF -DWITH_FEATURE_B=ON
make
Una vez que una variable se ha configurado a través de la línea de comandos de esta manera, se almacena en caché y se mantendrá sin cambios hasta que se sobrescriba con un valor diferente en la línea de comandos, o elimine el archivo CMakeCache.txt en su raíz de compilación.
Respuesta a actualizar:
Como señaló @Peter, parece que estás mezclando las variables CMake (las WITH_FEATURE...
) y las definiciones del preprocesador (las USE_FEATURE...
). Usted puede, como se sugiere, resolver todas las dependencias entre las opciones primero, luego configurar las definiciones de preprocesador resultantes, o en este caso donde el flujo es bastante sencillo, solo hágalo todo de una vez:
if(WITH_FEATURE_A)
message(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
set(WITH_FEATURE_B ON)
endif()
if(WITH_FEATURE_B)
message(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_B=1)
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_C)
message(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_C=1)
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_D)
message(STATUS "WITH_FEATURE_D")
add_definitions(-DUSE_FEATURE_D=1)
endif()