Простой пример
Дальше: Более сложный пример Вверх: Использование Autoconf Назад: Структура и основные принципы
Простой пример
Сначала приведем тривиальный пример. Пусть имеется проект, состоящий из четырех файлов -- foo.c, bar.c, main.h и main.c, и файлы соответственно содержат:
foo.c:
#include "main.h" void foo (void) { printf ("I am foo !\n"); }
bar.c:
#include "main.h" void bar (void) { printf ("I am bar !\n"); }
main.h:
#ifndef __MAIN_H__ #define __MAIN_H__ #include <stdio.h> extern void foo (void); extern void bar (void); #endif /* __MAIN_H__ */
main.c:
#include "main.h" int main (void) { foo (); bar (); return 0; }
Пусть также в проект входит Makefile-файл, который выглядит так:
CC=gcc CFLAGS=-Wall -O3 LDFLAGS= OBJECTS=main.o foo.o bar.o TARGET=prog RM=rm -f INSTALL=/usr/bin/install -c BINDIR=/usr/local/bin $(TARGET): $(OBJECTS) $(CC) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c $(CC) $(CFLAGS) -c $< foo.o: foo.c main.h bar.o: bar.c main.h main.o: main.c main.h clean: $(RM) $(OBJECTS) $(TARGET) install: $(TARGET) $(INSTALL) $(TARGET) $(BINDIR)
Теперь проиллюстрируем использование Autoconf. Зайдем в отдельную директорию, содержащую все файлы проекта и для начала посмотрим, что можно получить применением программы autoscan:
[user@host:homedir] cd prog-0.1 [user@host:prog-0.1] autoscan .
Так как проект очень маленький, выходной файл configure.scan получается не особенно содержательным:
dnl Process this file with autoconf to produce a configure script. AC_INIT(bar.c) dnl Checks for programs. AC_PROG_INSTALL dnl Checks for libraries. dnl Checks for header files. dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for library functions. AC_OUTPUT(Makefile)
(Символом ``dnl'', как можно догадаться, отмечаются комментарии -- они продолжаются до конца строки). Однако для иллюстрации принципов работы мы все-таки вставим несколько тестов: на наличие компилятора и проверку некоторых его возможностей, на наличие заголовочного файла stdio.h и на наличие функции printf(). Макрос AC_OUTPUT используем для генерации Makefile-файла из шаблона. Теперь файл configure.in будет выглядеть так:
dnl Process this file with autoconf to produce a configure script. AC_INIT(bar.c) dnl Checks for programs. AC_PROG_INSTALL AC_PROG_CC dnl Checks for libraries. dnl Checks for header files. AC_CHECK_HEADER(stdio.h,,exit 1) dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for library functions. AC_CHECK_FUNC(printf,,exit 1) AC_OUTPUT(Makefile)
Теперь в процессе конфигурации будет вышолнены следующие действия:
- определено местонахождение программы install и соответственно установлена переменная INSTALL, т.е. ее значение может быть замещено при генерации Makefile-файла из шаблона;
- проверена функциональность C-компилятора, и переменная CC будет инициализирована именем (названием выполняемого файла) компилятора;
- проверено наличие заголовочного файла stdio.h и, если таковой не будет обнаружен, процесс конфигурации завершится;
- проверено наличие функции printf (функция должна быть доступна при компиляции без указания дополнительных опций компилятору) и, если таковая не будет обнаружена (т.е. тестовая программа не слинкуется), процесс конфигурации завершится;
- сгенерируется Makefile.
Далее надо подготовить шаблон Makefile-файла, который по соглашению обычно называется Makefile.in. В нашем случае он легко получается из уже имеющегося Makefile-файла:
prefix = @prefix@ exec_prefix = @exec_prefix@ INSTDIR = @bindir@ CC=@CC@ CFLAGS=@CFLAGS@ OBJECTS=main.o foo.o bar.o TARGET=prog RM=rm -f INSTALL=@INSTALL@ $(TARGET): $(OBJECTS) $(CC) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c $(CC) $(CFLAGS) -c $< foo.o: foo.c main.h bar.o: bar.c main.h main.o: main.c main.h install: $(TARGET) $(INSTALL) $(TARGET) $(INSTDIR) clean: $(RM) $(OBJECTS) $(TARGET)
Этот шаблон отличается от исходного Makefile-файла тем, что при выполнении configure всем переменным, имена которых заключены в знаки @, будут присвоены значения, определенные во время конфигурации. Например, если будет указана команда
[user@host:prog-0.1] ./configure --prefix=/some/other/dir
то переменная prefix в созданном Makefile-файле будет иметь значение /some/other/dir, иначе будет установлено значение по умолчанию (обычно /usr/local).
Выполним команду configure и посмотрим, что же произойдет:
[user@host:prog-0.1] ./configure
creating cache ./config.cache checking for a BSD compatible install... /usr/bin/install -c checking for gcc... gcc checking whether the C compiler (gcc ) works... yes checking whether the C compiler (gcc ) is a cross-compiler... no checking whether we are using GNU C... yes checking whether gcc accepts -g... yes checking how to run the C preprocessor... gcc -E checking for stdio.h... yes checking for printf... yes updating cache ./config.cache creating ./config.status creating Makefile
Теперь посмотрим сгенерированный Makefile-файл:
# Generated automatically from Makefile.in by configure. prefix = /usr/local exec_prefix = ${prefix} INSTDIR = ${exec_prefix}/bin CC=gcc CFLAGS=-g -O2 OBJECTS=main.o foo.o bar.o TARGET=prog RM=rm -f INSTALL=/usr/bin/install -c $(TARGET): $(OBJECTS) $(CC) $(LDFLAGS) -o $@ $(OBJECTS) %.o: %.c $(CC) $(CFLAGS) -c $< foo.o: foo.c main.h bar.o: bar.c main.h main.o: main.c main.h install: $(TARGET) $(INSTALL) $(TARGET) $(INSTDIR) clean: $(RM) $(OBJECTS) $(TARGET)
Как можно видеть, переменным prefix, CC, CFLAGS и INSTALL присвоены значения по умолчанию. Используя опцию --help configure, можно получить список параметров, которые можно использовать для их изменения. Теперь можно набирать make или сразу make install.
Понятно, что ``интеллект'' конфигурационного скрипта целиком и полностью зависит от использованных макросов, и в принципе, имея достаточные навыки программирования на языке командного интерпретатора, можно создать какой угодно тест. Другое дело, что всего предусмотреть нельзя, и обычно ограничиваются некоторым разумным числом тестов.
Dmitry A. Antipov
1999-05-26