с помощью xcode, как определить макросы препроцессора из вывода команды? - PullRequest
7 голосов
/ 28 октября 2011

Как говорится в теме, я хочу иметь возможность запускать определенную команду во время сборки, и ее вывод будет определением макроса препроцессора.

Сейчас у меня есть несколько пользовательских переменных (в project.pbxproj), и я могу использовать их значения для заполнения определений макросов следующим образом:

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

Я могу установить для MACRO другое значение для каждой схемы (например, Debug vs. Release), что очень полезно. Но я не могу понять, как установить его, выполнив команду.

Ответы [ 3 ]

11 голосов
/ 29 октября 2011

Я могу придумать 3 варианта:

Переменная среды : если вы строите из командной строки, вы можете экспортировать переменную (export ENVMACRO=superfoo) перед вызовом команды построения и использовать ее в файле конфигурации Xcode OTHER_CFLAGS=-DMACRO=$(ENVMACRO). Вам необходимо настроить цель с помощью файла .xcconfig.

Этап запуска сценария сборки : Пользовательский сценарий, который создает файл заголовка.

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

В моих тестах вам нужен пустой заголовочный файл для правильной компиляции. Существуют и другие параметры, такие как изменение существующего файла с помощью sed или любой другой команды.

Правило пользовательской сборки : Пользовательский сценарий, который обрабатывает входной файл и создает выходной файл. Аналогично Run Script фаза сборки, но немного лучше, потому что он будет запускать скрипт только после изменения входного файла. Например, создайте файл .macro и обработайте его для обновления файла заголовка.

В Xcode> Target> Build rules добавьте новое пользовательское правило.

Процесс : *.macro

Пользовательский скрипт:

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

Выходные файлы : $(SRCROOT)/Project.h

Project.macro содержит пары MACRO=one-liner-command. Как эти два бессмысленных примера:

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

Сгенерированный файл будет выглядеть так:

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

Каждый раз, когда Project.macro изменяется, сгенерированный заголовок будет обновляться.

0 голосов
/ 29 октября 2011

Я думаю, что лучшим решением было бы объявить только один макрос препроцессора в настройках сборки проекта (например, DEBUG для отладки, RELEASE для выпуска), а затем в файле Prefix.pch вы можете проверить значение чтобы решить, какие другие макросы нужно определить, например:

// 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
0 голосов
/ 29 октября 2011

Если кому-то интересно, я использовал решение, чтобы добавить новую фазу сборки, которая запускает скрипт, который вручную генерирует заголовочный файл с нужными мне макросами. Это не элегантно, и я все равно предпочел бы что-нибудь получше, но это работает.

...