Как сделать Autoconf для тестирования исходного кода из внешнего файла? - PullRequest
0 голосов
/ 18 января 2019

Мы используем GNUmakefile в качестве нашей основной системы сборки. Makefile выполняет тесты функций с использованием тестовых программ в исходных файлах:

$ ls TestPrograms/
dump2def.cxx         test_arm_sm4.cxx      test_x86_avx.cxx
test_32bit.cxx       test_cxx.cxx          test_x86_avx2.cxx
test_64bit.cxx       test_mixed_asm.cxx    test_x86_avx512.cxx
...

Тестовая программа - это то, что можно ожидать:

$ cat test_cxx.cxx
#include <string>
int main(int argc, char* argv[])
{
    unsigned int x=0;
    return x;
}

Мы поддерживаем автоинструменты для таких дистрибутивов, как Debian и Fedora. Мы хотим, чтобы Autotools использовал тестовые программы, такие как GNUmakefile и CMake. Документация Autools на AC_COMPILE_IFELSE здесь , но она, как обычно, жалкая. Здесь не обсуждаются темы и не приводятся примеры.

Получение ударов в темноте:

CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
   [AC_LANG_PROGRAM([TestPrograms/test_x86_sse2.cxx])],
   [AC_MSG_RESULT([yes])],
   [AC_MSG_RESULT([no])]
)

Результаты:

checking if g++ supports -msse2 and Foo Bar... no

И тот же результат с cat, помещающим файл в строку:

CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
   [AC_LANG_PROGRAM(`cat TestPrograms/test_x86_sse2.cxx`)],
   [AC_MSG_RESULT([yes])],
   [AC_MSG_RESULT([no])]
)

Результат неверен на машине Skylake. SSE2 является частью основного набора инструкций и всегда доступен:

$ g++ -msse2 TestPrograms/test_x86_sse2.cxx
$

Как мы скажем Autoconf скомпилировать тестовый файл?

1 Ответ

0 голосов
/ 18 января 2019

Документация по Autools на AC_COMPILE_IFELSE [...], как обычно, жалкая. Здесь не обсуждаются темы и не приводятся примеры.

Хотя эта отдельная страница не содержит подробных сведений, она является частью более крупного руководства, которое содержит более подробные сведения и некоторые соответствующие примеры в соседних разделах. Однако даже на этой странице предлагается AC_LANG_PROGRAM в качестве подходящего средства для создания параметра input для этого макроса, а документация для этого макроса дает разумное представление об общей форме, которую он создает - фактическая исходный код программы, а не имя файла.

Когда дело доходит до получения ответного удара, я предлагаю не быть преднамеренно в темноте. Даже если вы не находите документацию адекватной, по крайней мере, файл журнала configure (config.log) должен содержать много информации о том, что именно не удалось и как. В случае сбоя, он покажет вам полный источник программы тестирования, которую он использовал, команды, которые он выполнил, чтобы фактически выполнить тест, и любую выполненную диагностику.

Например, используя скрипт настройки, полученный из этого configure.ac, вдохновленного вашими примерами ...

AC_INIT([test_test], [0.0.1])
AC_CONFIG_SRCDIR([test_src/test_cxx.cxx])
AC_PROG_CXX
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
   [AC_LANG_PROGRAM([`cat test_src/test_cxx.cxx`])],
   [AC_MSG_RESULT([yes])],
   [AC_MSG_RESULT([no])]
)
AC_OUTPUT

... Я получаю результат ошибки с соответствующим выводом в журнале:

configure:2891: gcc -o conftest -g -O2   conftest.c  >&5
conftest.c:9:18: fatal error: string: No such file or directory
 #include <string>
                  ^
compilation terminated.
configure:2891: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "test_test"
| #define PACKAGE_TARNAME "test_test"
| #define PACKAGE_VERSION "0.0.1"
| #define PACKAGE_STRING "test_test 0.0.1"
| #define PACKAGE_BUGREPORT ""
| #define PACKAGE_URL ""
| /* end confdefs.h.  */
| #include <string>
| int main(int argc, char* argv[])
| {
|     unsigned int x=0;
|     return x;
| }
| int
| main ()
| {
| 
|   ;
|   return 0;
| }
configure:2895: result: no

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

  1. AC_LANG_PROGRAM предоставляет больше, чем вы хотите в этом случае (в соответствии с его документацией). На самом деле, вам это вообще не нужно, если вы предоставляете полный исходный текст для тестовой программы.

  2. Тестовая программа компилируется и связывается как программа C, но ее источником является C ++. Это значение по умолчанию задокументировано в руководстве .

Проблема (1) может быть решена просто путем подачи источника непосредственно к AC_LINK_IFELSE, без переноса его через AC_LANG_PROGRAM, но в этом случае Autoconf предупредит о невидимости AC_LANG_SOURCE. Разумное решение этой проблемы - использовать AC_LANG_SOURCE напрямую, а не AC_LANG_PROGRAM. Однако это добавит к указанному источнику некоторые дополнительные #defines, которые могут вас не устраивать. Если вы этого не хотите, то я думаю, что в этом случае будет безопасно игнорировать предупреждения.

Проблема (2) может быть решена с помощью макроса AC_LANG, чтобы сообщить Autoconf, что тест должен выполняться с использованием компилятора C ++ и соответствующих переменных Autotools для флагов C ++.

Таким образом, если я обновлю свой configure.ac до

AC_INIT([test_test], [0.0.1])
AC_CONFIG_SRCDIR([test_src/test_cxx.cxx])
AC_PROG_CXX
AC_LANG([C++])
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
   [AC_LANG_SOURCE([`cat test_src/test_cxx.cxx`])],
   [AC_MSG_RESULT([yes])],
   [AC_MSG_RESULT([no])]
)
AC_OUTPUT

тогда мой запуск конфигурации завершился успешно, и я вижу в журнале, что команда компиляции, которую он выполнил, успешно была

configure:2296: g++ -o conftest -msse2   conftest.cpp  >&5

. То есть он скомпилирован с использованием выбранного компилятора C ++, с использованием флагов, указанных в CXXFLAGS, и соответствующим образом назвал исходный файл теста для компиляции как C ++.

...