2011-10-28 13 views
7

Como dice el tema, quiero poder ejecutar un comando específico durante la compilación, y su resultado será la definición de una macro de preprocesador.con xcode, ¿cómo definir macros de preprocesador a partir de la salida de un comando?

En este momento, tienen varias variables definidas por el usuario (en project.pbxproj) y soy capaz de utilizar sus valores para llenar definiciones de macro, como sigue:

GCC_PREPROCESSOR_DEFINITIONS = (
"stringify (x) = @ # x ",
" _MACRO = STRINGIFY ($ {MACRO}) ",
);
MACRO = foo;

Puedo establecer MACRO a un valor diferente por esquema (por ejemplo, depuración frente a versión) que es muy útil. Pero no puedo entender cómo configurarlo ejecutando un comando.

Respuesta

11

puedo pensar en 3 opciones:

Variable de entorno: Si se construye desde la línea de comandos que puede exportar una variable (export ENVMACRO=superfoo) antes de invocar el comando de generación y utilizarlo en un archivo de configuración Xcode OTHER_CFLAGS=-DMACRO=$(ENVMACRO). Necesita configurar el destino con el archivo .xcconfig.

Run Script Build Phase: secuencia de comandos personalizada que genera un archivo de encabezado.

MACROVALUE=$(run-command-to-obtain-value) 
echo "#define MACRO ($MACROVALUE)" > $(SRCROOT)/path/to/header.h 

En mis pruebas necesita un archivo de encabezado vacío para poder compilar correctamente. Hay otras opciones, como modificar un archivo existente usando sed o cualquier otro comando.

regla de compilación personalizada: secuencia de comandos personalizada que procesa un archivo de entrada y crea un archivo de salida. Similar a Ejecute la secuencia de comandos pero será un poco mejor porque ejecutará la secuencia de comandos solo cuando se haya modificado el archivo de entrada. Por ejemplo, cree un archivo .macro y trátelo para actualizar un archivo de encabezado.

En Xcode> Target> Build rules, agregue una nueva regla personalizada.

Proceso: *.macro

secuencia de personalización:

HEADER="${SRCROOT}/Config.h" 
cd ${SRCROOT} 
echo "// Do not edit" > $HEADER 
cat "${INPUT_FILE_PATH}" | while read line 
do 
    macro="`echo $line | cut -d= -f1`" 
    cmd="`echo $line | cut -d= -f2-`" 
    value=$($cmd) 
    echo "#define ${macro} @\"${value}\"" >> $HEADER 
done 
echo "// Updated on "`date` >> $HEADER 

Los archivos de salida: $(SRCROOT)/Project.h

Project.macro contiene pares MACRO=one-liner-command.Al igual que estos dos ejemplos sin sentido:

COMMIT=git log --pretty=format:%h -n 1 
BUILDYEAR=date +%Y 

archivo generado se verá así:

// Do not edit 
#define COMMIT @"c486178" 
#define BUILDYEAR @"2011" 
// Updated on Sat Oct 29 14:40:41 CEST 2011 

Cada vez Project.macro cambios, se actualizará la cabecera generada.

+0

gracias - la segunda opción es esencialmente lo que he ido - en mi caso, quería que el comando se ejecutara en cada compilación. el único inconveniente es que no escribo en el archivo de encabezado actual si sus contenidos no son idénticos a los contenidos recién generados (para evitar el cambio de dependencia). Aunque me gusta especialmente la tercera opción también. – michael

0

Si alguien tiene curiosidad, la solución que he usado es agregar una nueva fase de compilación que ejecute una secuencia de comandos que genere manualmente un archivo de encabezado con las macros que quiero. No es elegante, y aún preferiría algo mejor, pero funciona.

+1

Felicidades por la solución. Asegúrese de marcar su respuesta como 'aceptada' para que otros puedan aprender de su éxito. Saludos ~ –

0

creo que una mejor solución sería declarar sólo una macro de preprocesador en la configuración de generación de proyecto (por ejemplo DEBUG de depuración, RELEASE para la liberación) y luego en su Prefix.pch archivo que se pueda comprobar si el valor con el fin de decidir qué otras macros definir, p. ej .:

// Use NSLOG and NSASSERT so that they are only output in debug mode 
#ifdef DEBUG 

//#warning You are running in Debug mode 
#define NSLOG NSLog 
#define NSASSERT NSAssert 
#define NSASSERT1 NSAssert1 

#else 

#define NSLOG if(false)NSLog 
#define NSASSERT(X, Y) \ 
if(!(X)) {   \ 
NSLogOkay(Y);  \ 
}     
#define NSASSERT1(X, Y, Z) \ 
if(!(X)) {    \ 
NSLogOkay(Y, Z);  \ 
}      

#endif 
Cuestiones relacionadas