Autoconf - Написание тестов
Go to the first, previous, next, last section, table of contents.
Написание тестов
@anchor{Writing Tests}
Если существующие тесты делают не то, что вам надо, то вы можете написать собственные тесты. Эти макросы являются строительными блоками для этих тестов. Они предоставляют другим макросам возможность проверить доступность различных свойств и сообщить о результатах.
Эта глава содержит некоторые пожелания и описание того, почему существующие тесты написаны так, а не иначе. Вы также можете научиться тому, как писать тесты Autoconf, разглядывая существующие тесты. Если в одном или нескольких тестах Autoconf что-нибудь пойдет не так, то эта информация может помочь вам понять предположения, которые стоят за ними, что, в свою очередь, может помочь вам определить наилучший способ решения проблемы.
Эти макросы проверяют вывод системного компилятора C. Они не кэшируют результаты тестов для последующего использования (see section Кэширование результатов), поскольку для генерации имени переменной кэша они не имеют достаточно информации о том, что они проверяют. Также по некоторым причинам они не печатают никаких сообщений. Проверки отдельных свойств компилятора С вызывают эти макросы и кэшируют свои результаты, а также выводят сообщения о том, что они проверяют.
Когда вы пишете тест свойства, который может быть применим для более чем одного пакета программного обеспечения, то лучше всего будет описать его как новый макрос. Для того, чтобы узнать, как это делается See section Создание макросов.
Исследование деклараций
@anchor{Examining Declarations}
Макрос AC_TRY_CPP
используется для проверки существования
конкретных заголовочных файлов. You can check for one at a time, or
more than one if you need several header files to all exist for some
purpose.
- Macro: AC_TRY_CPP (includes, [action-if-true [, action-if-false]])
-
includes содержит директивы
#include
языков C или C++, а также объявления, над которыми выполняются подстановки переменных командного процессора, обратных кавычек и обратных слэшей. (В действительности, includes может быть любой программой на C, но другие выражения, вероятно, бесполезны). Если препроцессор не выдает сообщений об ошибках в течении обработки директивы, то выполняется код командного процессора action-if-true. В противном случае выполняется код action-if-false.Этот макрос использует переменную
CPPFLAGS
, а неCFLAGS
, поскольку `-g', `-O' и т. п. не являются правильными ключами для многих препроцессоров C.
Вот как узнать, содержит ли конкретный заголовочный файл определенное
объявление, например, объявление типа, структуры, члена структуры или
функции. Используйте макрос AC_EGREP_HEADER
вместо прямого
запуска команды grep
для заголовочного файла; в некоторых
системах символ может быть объявлен в другом заголовочном файле, а не в
том, который вы проверяете в `#include'.
- Macro: AC_EGREP_HEADER (pattern, header-file, action-if-found [, action-if-not-found])
-
Если вывод препроцессора, запущенного для системного заголовочного файла
header-file соответствует регулярному выражению
egrep
pattern, то выполняются команды командного процессора action-if-found, в противном случае выполняются команды action-if-not-found.
Для проверки символов препроцессора C, определенных в заголовочном
файле, либо предопределенных препроцессором C, используйте макрос
AC_EGREP_CPP
. Вот пример последнего:
AC_EGREP_CPP(yes, [#ifdef _AIX yes #endif ], is_aix=yes, is_aix=no)
- Macro: AC_EGREP_CPP (pattern, program, [action-if-found [, action-if-not-found]])
-
program является текстом программы на C или C++, для которой
выполняются подстановки переменных командного процессора, обратных
кавычек и обратных слэшей. Если вывод препроцессора, обрабатывавшего
program, соответствует регулярному выражению команды
egrep
pattern, то выполняется код командного процессора action-if-found, иначе выполняется action-if-not-found.Этот макрос вызывает
AC_PROG_CPP
илиAC_PROG_CXXCPP
(в зависимости от того, какой из языков является текущим, see section Выбор языка), если эти макросы еще не вызывались.
Проверка синтаксиса
@anchor{Examining Syntax}
Для проверки синтаксических возможностей компиляторов C, C++ или Fortran
77, например, распознавания определенных ключевых слов, используется
макрос AC_TRY_COMPILE
, который пробует откомпилировать маленькую
программу, которая использует заданную возможность. Вы также можете
использовать этот макрос для проверки структур и полей структур, которые
присутствуют не во всех системах.
- Macro: AC_TRY_COMPILE (includes, function-body, [action-if-found [, action-if-not-found]])
-
Создает тестовую программу на C, C++ или Fortran 77 (в зависимости от того,
какой язык является текущим, see section Выбор языка), для того, чтобы
убедиться, что функция, чье тело состоит из function-body может
быть скомпилирована.
Для C и C++, includes является любыми директивами
#include
, в которых нуждается код в function-body (параметр includes будет проигнорирован, если текущим языком является Fortran 77). Этот макрос при компиляции помимо переменнойCPPFLAGS
также использует переменныеCFLAGS
илиCXXFLAGS
, если текущим языком является C или C++. ПеременнаяFFLAGS
будет использована при компиляции, если текущим языком является Fortran 77.Если файл компилируется нормально, то выполняются команды action-if-found, иначе выполняется action-if-not-found.
Этот макрос не пытается выполнить компоновку программы -- для этого вам придется использовать макрос
AC_TRY_LINK
(see section Проверка библиотек).
Проверка библиотек
@anchor{Examining Libraries}
Для проверки библиотеки, функции или глобальной переменной скрипт
configure
попытается скомпилировать и скомпоновать
небольшую программу, которая использует тестируемые возможности. Этим
Autoconf отличается от Metaconfig, который обрабатывает файлы
библиотеки C, используя nm
или ar
, чтобы определить,
какие функции
доступны. Попытка скомпоновать программу с функцией -- более надежный
вариант, поскольку он избавляет от необходимости обрабатывать различные
ключи командной строки и форматы выдачи результатов
программ nm
и ar
, а также выяснять расположение
стандартных библиотек. Этот подход также позволяет конфигурировать
кросс-компиляцию, а также проверять поведение функции во время
выполнения. С
другой стороны, этот подход может оказаться значительно более медленным, чем однократное
сканирование библиотек.
Компоновщики в нескольких существующих системах не возвращают статус
ошибки, если не могут найти какие-либо символы при компоновке. Эта ошибка делает
невозможным использование на таких системах скриптов настройки, созданных
Autoconf. Однако, некоторым из них могут быть заданы ключи, которые
позволяют получить правильный статус завершения работы.
Эту проблему в настоящий момент Autoconf не может обработать
автоматически. Если пользователь столкнется с таким, то он может
решить эту проблему установкой переменной среды LDFLAGS
,
передавая компоновщику необходимые ключи командной строки (например,
`-Wl,-dn' на MIPS RISC/OS).
Макрос AC_TRY_LINK
используется для компиляции тестовой программы
для проверки функций и глобальных переменных. Он также используется
макросом AC_CHECK_LIB
для проверки библиотек
(see section Файлы библиотек), временно добавляя проверяемую библиотеку в
переменную LIBS
и пытаясь скомпоновать маленькую программу.
- Macro: AC_TRY_LINK (includes, function-body, [action-if-found [, action-if-not-found]])
-
В зависимости от текущего языка (see section Выбор языка), создается
тестовая программа, для того чтобы выяснить, может ли быть
скомпилирована и скомпонована функция, чье тело состоит из аргумента
function-body.
Для C и C++, includes является любыми директивами
#include
, в которых нуждается код в function-body (параметр includes будет проигнорирован, если текущим языком является Fortran 77). Этот макрос при компиляции помимо переменнойCPPFLAGS
также использует переменныеCFLAGS
илиCXXFLAGS
, если текущим языком является C или C++. ПеременнаяFFLAGS
будет использована при компиляции, если текущим языком является Fortran 77. Однако в любом случае при компоновке будут использованы переменныеLDFLAGS
иLIBS
.Если файл компилируется и компонуется, то выполняются команды action-if-found, в противном случае --- action-if-not-found.
- Macro: AC_TRY_LINK_FUNC (function, [action-if-found [, action-if-not-found]])
-
В зависимости от текущего языка see section Выбор языка), создается тестовая
программа для того, чтобы убедиться, что программа, чье тело состоит их
прототипа и вызова function, может быть скомпилирована и
скомпонована.
Если файл компилируется и компонуется без ошибок, то выполняется код action-if-found, в противном случае выполняется action-if-not-found.
- Macro: AC_TRY_LINK_FUNC (function, [action-if-found [, action-if-not-found]])
- Этот макрос пробует скомпилировать и скомпоновать маленькую программу, которая компонуется с function. Если файл компилируется и компонуется без ошибок, то запускается код командного процессора action-if-found, в противном случае выполняется action-if-not-found.
- Macro: AC_COMPILE_CHECK (echo-text, includes, function-body, action-if-found [, action-if-not-found])
-
Этот макрос является устаревшей версией
AC_TRY_LINK
. Он отличается тем, что выдает сообщение `checking for echo-text' в поток стандартного вывода, в том случае, если аргумент echo-text не является пустым. Вместо этого макроса для выдачи сообщений используйтеAC_MSG_CHECKING
иAC_MSG_RESULT
(see section Выдача сообщений).
Проверка поведения во время выполнения
@anchor{Run Time}
Иногда вам необходимо определить, как система работает во время выполнения программы, например, имеет ли заданная функция определенные возможности или ошибки. Старайтесь выполнять такие проверки непосредственно во время выполнения программы, а не во время конфигурирования. Такие вещи, как расположение байтов в памяти машины также следует проверять при инициализации программы.
Если вам действительно необходимо протестировать поведение программы во
время выполнения при конфигурировании, то вы можете написать тестовую программу
для определения результатов, откомпилировать и запустить ее с помощью
макроса AC_TRY_RUN
. Если возможно, избегайте запуска тестовых программ,
поскольку их использование мешает пользователям
настраивать ваш пакет для кросс-компиляции.
Запуск тестовых программ
@anchor{Test Programs}
Используйте нижеописанный макрос, если вам нужно при конфигурировании протестировать поведение системы во время исполнения.
- Macro: AC_TRY_RUN (program, [action-if-true [, action-if-false [, action-if-cross-compiling]]])
-
Аргумент program является текстом программы на языке C, для
которой выполняются подстановки переменных командного процессора, а
также обратных кавычек и обратных слэшей. Если она компилируется и
компонуется, и при выполнении возвращает код завершения 0, то
выполняется код командного процессора action-if-true. В противном
случае выполняются команды action-if-false; код завершения
тестовой программы доступен в переменной командного процессора
`$?'. При компиляции этот макрос использует переменные
CFLAGS
илиCXXFLAGS
,CPPFLAGS
,LDFLAGS
иLIBS
.Если используемый компилятор C не создает исполняемых файлов, которые запускаются на той же системе, где выполняется скрипт
configure
, то тестовая программа не запускается. Если задан аргумент action-if-cross-compiling, то вместо программы запускается код, заданный в этом аргументе. В противном случаеconfigure
выдает сообщение об ошибке и прекращает работу.
Постарайтесь сделать значения по умолчанию пессимистическими, если
кросс-компиляция не позволяет проверить поведение времени выполнения.
Это можно сделать, передав макросу AC_TRY_RUN
необязательный
последний аргумент. autoconf
выдает предупреждающее
сообщение при создании configure
каждый раз, когда встречается
вызов макроса AC_TRY_RUN
с незаданным аргументом
action-if-cross-compiling. Вы можете игнорировать это
предупреждение, хотя пользователи не смогут настроить ваш пакет для
кросс-компиляции. Несколько макросов, поставляемых в составе Autoconf,
выдают это предупреждающее сообщение.
Для конфигурирования для кросс-компиляции вы также можете выбрать значения параметров, основываясь на каноническом имени системы (see section Ручная настройка). В качестве альтернативы, вы можете установить правильное значение для целевой системы в кэш-файле с результатами тестов (see section Кэширование результатов).
Для задания значений по умолчанию для вызовов макроса AC_TRY_RUN
,
которые включены в другие макросы (включая те, которые поставляются с
Autoconf), вы можете вызвать макрос AC_PROG_CC
до их вызова.
Затем, если переменная командного процессора cross_compiling
имеет значение `yes', то используется альтернативный метод для
получения результатов, вместо вызова макросов.
Рекомендации по написанию тестовых программ
@anchor{Guidelines}
Тестовые программы не должны выдавать никаких сообщений на поток стандартного
вывода. Они должны возвращать значение 0 в случае удачи и ненулевое
значение --- в противном случае, так что удачное выполнение можно легко отличить
от выдачи дампа при крахе программы или другого неудачного
выполнения; нарушение доступа к памяти и другие сбои возвращают
ненулевой статус завершения. Тестовые программы должны завершать работу
с помощью вызова функции exit
, а не с помощью оператора
return
из подпрограммы main
, поскольку на некоторых
системах (по крайней мере, на старых машинах Sun) в подпрограмме
main
игнорируется аргумент оператора return
.
Тестовые программы могут использовать директивы #if
или
#ifdef
для проверки значений макросов препроцессора, определенных
уже проведенными тестами. Например, если вы вызовете
AC_HEADER_STDC
, то далее в `configure.in' можно
использовать тестовую программу, которая в зависимости от условия
включает заголовочные файлы ANSI C:
#if STDC_HEADERS # include <stdlib.h> #endif
Если тестовой программе нужно использовать или создать файл
данных, то задавайте этому файлу имя, которое начинаются с
`conftest', например, `conftestdata'. Скрипт configure
после выполнения тестовых программ а также в случае прерывания работы
скрипта
удаляет эти файлы с помощью команды `rm -rf conftest*'.
Тестовые функции
@anchor{Test Functions}
Объявления функций в тестовой программе должны быть с помощью условной компиляции объявлены как для компилятора C++, так и для компилятора C. На практике, однако, тестовые программы редко нуждаются в функциях, которым передаются аргументы.
#ifdef __cplusplus foo(int i) #else foo(i) int i; #endif
Функции, которые объявляются в тестовых программах, должны быть также объявлены с применением прототипов `extern "C"', для использования с компиляторами C++. Убедитесь, что вы не включаете заголовочные файлы, содержащие конфликтующие прототипы.
#ifdef __cplusplus extern "C" void *malloc(size_t); #else char *malloc(); #endif
Если тестовая программа вызывает функцию с неправильными параметрами
(просто чтобы убедиться, что такая существует), то организуйте
программу таким образом, чтобы эта функция никогда не была вызвана. Это
можно сделать путем вызова ее в другой функции, которая никогда не
вызывается. Вы не можете сделать это, поместив вызов функции после
вызова функции exit
, поскольку GCC версии 2 знает о том, что
функция exit
никогда не возвращается в точку вызова, и оптимизирует
любой код, который следует за ней в том же блоке.
Если вы включаете какой-либо заголовочный файл, то убедитесь, что
функции, находящиеся в этих файлах, вызываются с правильным числом
параметров, даже если все эти параметры равны нулю. Это нужно, чтобы
избежать ошибок компиляции из-за
несоответствия прототипов. GCC версии 2 имеет внутренние прототипы
нескольких функций, которые он встраивает в код автоматически; например,
к таким относится
memcpy
. Для того, чтобы избежать ошибок при их проверке, либо
передавайте этим функциям правильное количество аргументов, либо
повторно объявите эти функции с другим типом возвращаемого значения
(например, как char
).
Переносимое программирование на языке командного процессора
@anchor{Portable Shell}
Есть определенные техники программирования скриптов командного
процессора, которых вам следует избегать, чтобы ваш код был переносим.
Bourne shell и совместимые с ним процессора, такие как Bash и Korn,
развивались в течении многих лет, но для того, чтобы избежать
трудностей, не используйте возможностей, которые были добавлены после
выпуска UNIX версии 7, примерно в 1977 году. Вы не должны использовать
функции командного процессора, псевдонимы (aliases), отрицательные классы
символов и другие возможности, которые присутствуют не во всех версиях
командных процессоров, совместимых с процессором Bourne; ограничьте себя
общим знаменателем. Даже unset
не поддерживается всеми командными
процессорами! При указании интерпретатора ставьте пробел после символов
`#!', например,
#! /usr/bin/perl
Если вы уберете пробел перед путевым именем, то системы типа 4.2BSD, такие как Sequent DYNIX, будут просто игнорировать эту строку, поскольку они интерпретируют `#! /' как 4-х байтовое магическое число.
Набор внешних программ, которые можно запускать из скрипта
configure
, довольно мал. See section `Utilities in Makefiles' in GNU Coding Standards,
ниже приведен список этих программ.
Это ограничение позволяет пользователям начать с небольшого количества
программ, постепенно компилируя остальные, и избежать слишком большого
числа зависимостей между пакетами.
Многие такие внешние утилиты обладают общим подмножеством переносимых
возможностей;
например, не полагайтесь на то, что команда ln
имеет ключ
`-f', а cat
вообще имеет какие-либо ключи. Скрипты sed
не
должны содержать комментариев или использовать метки длиннее 8
символов. Не используйте `grep -s' для запрещения вывода, поскольку
`grep -s' на System V не запрещает вывод, а запрещает только
сообщения об ошибках. Вместо этого ключа лучше перенаправьте стандартные
потоки вывода и сообщений об ошибках (сообщения о несуществующих файлах)
программы grep
на устройство `/dev/null'. Проверяйте код
возврата grep
, чтобы узнать, произошло ли совпадение.
Тестирование значений и файлов
@anchor{Testing Values and Files}
Скрипты configure
должны проверять различные свойства разных
файлов и строк. Вот небольшой список проблем с переносимостью, которых
нужно избегать при написании проверок.
Программа test
используется для выполнения многих проверок файлов
и строк. Она часто запускается альтернативным способом, через имя
`[', но использование этого имени в коде Autoconf приведет к
ошибкам, потому что этот символ является символом кавычек в m4
.
Если вам необходимо выполнить несколько проверок, используя команду
test
, то объединяйте их с помощью операторов командного
процессора `&&' и `||', а не используйте операторы программы
test
`-a' и `-o'. На System V приоритеты операторов
`-a' и `-o' неправильно соотносятся с приоритетами унарных
операторов; из-за этого POSIX не определяет эти операторы, так что их использование
приводит к непереносимому коду. Если вы в одном выражении используете как
`&&', так и `||', то помните, что они имеют одинаковый
приоритет.
Скрипты configure
, поддерживающие
кросс-компиляцию, не должны не делать ничего, что тестирует свойства
системы, на которой выполняется скрипт. Но иногда вам может понадобиться
проверить, существует ли определенный файл. Чтобы сделать это
используйте команды `test -f' или `test -r'. Не используйте
команду `test -x', поскольку 4.3BSD не поддерживает ее.
Другой непереносимой конструкцией программирования командного процессора является
var=${var:-value}
Она предназначена для установки значения переменной var равным
value, но только в тех случаях, когда переменная еще не имеет
значения. Если var уже было присвоено значение, даже равное
пустой строке, то оно остается неизменным. Старые командные процессоры
BSD, включая Ultrix-версию sh
, не воспринимают символ двоеточия,
выдают ошибку и прекращают работу. Переносимым эквивалентом данной
конструкции является
: ${var=value}
Множество вариантов
@anchor{Multiple Cases}
Некоторые операции выполняются несколькими разными способами в зависимости от используемого варианта UNIX. Их проверка требует "оператора выбора". Autoconf напрямую не обеспечивает такой оператор, однако достаточно легко эмулировать его, используя переменную командного процессора для запоминания, найден ли уже пригодный способ.
Вот пример, который использует переменную fstype
для отслеживания
того, остались ли варианты, которые необходимо проверить.
AC_MSG_CHECKING(как получить тип файловой системы) fstype=no # Порядок этих действий является важным. AC_TRY_CPP([#include <sys/statvfs.h> #include <sys/fstyp.h>], AC_DEFINE(FSTYPE_STATVFS) fstype=SVR4) if test $fstype = no; then AC_TRY_CPP([#include <sys/statfs.h> #include <sys/fstyp.h>], AC_DEFINE(FSTYPE_USG_STATFS) fstype=SVR3) fi if test $fstype = no; then AC_TRY_CPP([#include <sys/statfs.h> #include <sys/vmount.h>], AC_DEFINE(FSTYPE_AIX_STATFS) fstype=AIX) fi # (остальные варианты пропущены в этом примере) AC_MSG_RESULT($fstype)
Выбор языка
@anchor{Language Choice}
Пакеты, использующие одновременно и C, и C++, нуждаются в проверке
возможностей обоих компиляторов. Созданные Autoconf скрипты
configure
по умолчанию выполняют проверку возможностей
компилятора C. Нижеописанные макросы определяют, компилятор какого языка
будет использоваться в тестах, которые последуют за вызовом этого макроса в
`configure.in'.
- Macro: AC_LANG_C
-
Выполняет тесты компиляции, используя переменные
CC
иCPP
, а также используя расширение `.c' для тестовых программ. Устанавливает переменную командного процессораcross_compiling
в значение, вычисленное макросомAC_PROG_CC
, если он был запущен, и в пустое значение в противном случае.
- Macro: AC_LANG_CPLUSPLUS
-
Выполняет тесты компиляции, используя переменные
CXX
иCXXPP
, а также используя расширение `.C' для тестовых программ. Устанавливает переменную командного процессораcross_compiling
в значение, вычисленное макросомAC_PROG_CXX
, если он был запущен, и в пустое значение в противном случае.
- Macro: AC_LANG_FORTRAN77
-
Выполняет тесты компиляции, используя переменную
F77
, а также используя расширение `.f' для тестовых программ. Устанавливает переменную командного процессораcross_compiling
в значение, вычисленное макросомAC_PROG_F77
, если он был запущен, и в пустое значение в противном случае.
- Macro: AC_LANG_SAVE
-
Запоминает в стеке значение текущего языка (установленное макросами
AC_LANG_C
,AC_LANG_CPLUSPLUS
илиAC_LANG_FORTRAN77
). Не изменяет значение текущего языка. Используйте этот макрос иAC_LANG_RESTORE
в макросах, которым необходимо временно переключиться на конкретный язык.
- Macro: AC_LANG_RESTORE
-
Выбирает язык, который был сохранен на вершине стека, где он был
сохранен макросом
AC_LANG_SAVE
, и удаляет его со стека. Этот макрос эквивалентен вызовуAC_LANG_C
,AC_LANG_CPLUSPLUS
илиAC_LANG_FORTRAN77
, в зависимости от того, который из них действовал во время последнего вызова макросаAC_LANG_SAVE
.Не вызывайте этот макрос больше раз, чем было вызовов
AC_LANG_SAVE
.
- Macro: AC_REQUIRE_CPP
-
Убеждается, что препроцессор, который должен сейчас использоваться, был
найден. Вызывает макрос
AC_REQUIRE
(see section Требуемые макросы) с аргументом, равным либоAC_PROG_CPP
, либоAC_PROG_CXXCPP
, в зависимости от того, какой язык был выбран.
Go to the first, previous, next, last section, table of contents.