@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.
#include
языков C или C++, а также
объявления, над которыми выполняются подстановки переменных командного
процессора, обратных кавычек и обратных слэшей. (В действительности, includes
может быть любой программой на C, но другие выражения, вероятно, бесполезны).
Если препроцессор не выдает сообщений об ошибках в
течении обработки директивы, то выполняется код командного процессора
action-if-true. В противном случае выполняется код
action-if-false.
Этот макрос использует переменную CPPFLAGS
, а не CFLAGS
,
поскольку `-g', `-O' и т. п. не являются правильными ключами
для многих препроцессоров C.
Вот как узнать, содержит ли конкретный заголовочный файл определенное
объявление, например, объявление типа, структуры, члена структуры или
функции. Используйте макрос AC_EGREP_HEADER
вместо прямого
запуска команды grep
для заголовочного файла; в некоторых
системах символ может быть объявлен в другом заголовочном файле, а не в
том, который вы проверяете в `#include'.
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)
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
, который пробует откомпилировать маленькую
программу, которая использует заданную возможность. Вы также можете
использовать этот макрос для проверки структур и полей структур, которые
присутствуют не во всех системах.
Для 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
и пытаясь скомпоновать маленькую программу.
Для 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.
Если файл компилируется и компонуется без ошибок, то выполняется код 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}
Используйте нижеописанный макрос, если вам нужно при конфигурировании протестировать поведение системы во время исполнения.
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'.
CC
и CPP
,
а также используя расширение `.c' для тестовых программ. Устанавливает
переменную командного процессора cross_compiling
в значение,
вычисленное макросом AC_PROG_CC
, если он был запущен, и в пустое
значение в противном случае.
CXX
и
CXXPP
, а также используя расширение `.C' для тестовых
программ. Устанавливает переменную командного процессора
cross_compiling
в значение, вычисленное макросом
AC_PROG_CXX
, если он был запущен, и в пустое значение в противном
случае.
F77
, а также используя
расширение `.f' для тестовых программ. Устанавливает переменную
командного процессора cross_compiling
в значение, вычисленное
макросом AC_PROG_F77
, если он был запущен, и в пустое значение в
противном случае.
AC_LANG_C
, AC_LANG_CPLUSPLUS
или
AC_LANG_FORTRAN77
). Не изменяет значение текущего
языка. Используйте этот макрос и AC_LANG_RESTORE
в макросах,
которым необходимо временно переключиться на конкретный язык.
AC_LANG_SAVE
, и удаляет его со стека. Этот
макрос эквивалентен вызову AC_LANG_C
,
AC_LANG_CPLUSPLUS
или AC_LANG_FORTRAN77
, в зависимости от
того, который из них действовал во время последнего вызова
макроса AC_LANG_SAVE
.
Не вызывайте этот макрос больше раз, чем было вызовов
AC_LANG_SAVE
.
AC_REQUIRE
(see section Требуемые макросы)
с аргументом, равным либо AC_PROG_CPP
, либо
AC_PROG_CXXCPP
, в зависимости от того, какой язык был выбран.
Go to the first, previous, next, last section, table of contents.