EnderUNIX Yazılım Geliştrime Takımı
Yazılım Geliştiricisi
<ozkan@enderunix.org>
Telif Hakkı © 2005 Bu doküman GFDL (GNU Free Documentation License) ile lisanslıdır. Kaynak belirtilmek şartı ile kopyalanabilir
Bu dokümanda GNU AutoTools (autoheader, autoconf, automake) araçlarının ne olduğu, nerelerde ve nasıl kullanıldığı anlatılacaktır. Yazar, sisteminize gelebilecek hiçbir zararın sorumluluğunu kabul etmemektedir.
Günümüzde bir çok yazılım paketi doğrudan autoconf, automake ve autoheader ile çalışmaktadır. Dolaylı olarak da m4 macro işlemcisi, make (GNU veya BSD make) ve aclocal yazılımlarını kullanır.

Yukarıdaki şekilde hangi yazılımın hangi dosyaları giriş olarak kullandığı ve hangi dosyaları yarattığı anlatılmıştır.
Öncelikle automake, Makefile.am dosyasını inceler ve buna uygun olarak Makefile.in dosyasını yaratır.
Ardından autoheader, configure.in dosyasını inceleyerek burada tanımlanan ve config.h dosyasında olması gereken ifadeleri toplayıp config.h.in dosyasını oluşturur.
autoheader'dan sonra autoconf, yine configure.in dosyasını inceler ve configure scriptini yaratır.
Son olarak configure çalıştırılır. Uzantısı .in olan dosyalar genellikle configure tarafından girişi dosyası olarak kullanılır. configure bu dosyalar üzerinde gereken işlemleri yaptıktan sonra .in uzantısını kaldırıp yeni bir dosya olarak kaydeder. Bu sayede Makefile.in dosyasından Makefile oluşur. config.h.in dosyasından config.h oluşur.
configure işleminden sonra Makefile oluşur ve make komutu çalıştırılarak program derlenir.
Kısacası bütün dosyalarınızı hazırladıktan sonra paketinizi aşağıdaki şekilde hazır hale getirebilirsiniz:
# aclocal && autoheader
# automake --add-missing
# autoconf
Yukarıdaki işlemlerle Makefile dosyası ve config.h dosyası hazır hale geliyor. Sisteminizde kurulu olması gereken yazılımlar:
autoconf
automake
autoheader
FreeBSD'de bu yazılımları kurmak için Port Kolleksiyonu'na başvuruyoruz.
# cd /usr/ports/devel/automake19
# make install clean
...
...
#
Port Kolleksiyonu, automake ile birlikte autoconf ve autoheader'i da kuracaktir.
Birçok Linux dağıtımında GNU autotools standart olarak gelmektedir.
autoconf'u daha iyi anlayabilmek için automake aşamasını atlayacağız.
autoconf, configure.in dosyası inceleyerek, orada tanımlanan işleri yapabilecek configure scriptini yaratır. configure scripti ise configure.inde belirlediğiniz, uzantısı .in olan giriş dosyalarını inceleyerek @degisken@ biçimde olan ifadeleri eğer tanımlanmışsa değerleri ile değiştirir. Çıkış dosyasından .in uzantısı kaldırılır.
-- configure.in --
...
...
program_klasoru="/usr/local/deneme"
AC_SUBST(program_klasoru)
AC_OUTPUT[deneme.h]
------------------
-- deneme.h.in --
#define KLASOR @program_klasoru@
-----------------
# autoconf
# ./configure
...
...
...
--- deneme.h ---
#define KLASOR "/usr/local/deneme"
----------------
Yukarıda autoconf ve configure'ün çalışma prensibine basit bir örneğe yer verdik. Burada AC_ ile başlayan makrolardan Kısım 4.2 de bahsedilecektir.
Daha geniş kapsamlı bir örnek;
--- deneme.c ---
#include <stdio.h>
#include "config.h"
int main(int argc, char **argv) {
printf("Bu programin sürümü %s\n", SURUM);
return 0;
}
----------------
--- config.h.in ---
#define SURUM @surum@
-------------------
--- configure.in ---
AC_INIT(deneme.c)
dnl C derleyicisini bul ve test et
AC_PROG_CC
AC_LANG_C
dnl surum degiskenini tanimla ve giris dosyalarinda incelenmek uzere gerekenleri yap
surum="0.1"
AC_SUBST(surum)
dnl Makefile.in dosyasını oku ve Makefile'i yarat
dnl config.h.in dosyasını oku ve config.h'i yarat
AC_OUTPUT([
Makefile
config.h
])
--------------------
--- Makefile.in ---
CC = @CC@
CFLAGS = @CFLAGS@
all: deneme-bin
deneme-bin: deneme.c
$(CC) $(CFLAGS) deneme.c -o deneme
clean:
rm -f deneme
distclean:
rm -f config.h Makefile
-------------------
Yukarıdaki mini projeyi aşama aşama uygulayalım:
# ls
Makefile.in config.h.in configure.in deneme.c
# autoconf
# ./configure
...
...
# ls
Makefile Makefile.in config.h config.h.in configure.in deneme.c
# make
...
...
# ls
Makefile Makefile.in config.h config.h.in configure.in deneme deneme.c
İlk başlangıçta autoconf çalıştırılarak, configure.in dosyasından configure scripti oluşturuluyor. configure scripti ile Makefile.in ve config.h.in dosyalarının içerisinde @...@ biçiminde yeralan ifadelerin değerleri yerine konuluyor ve Makefile ve config.h oluşturuluyor. make komutu ile derleme işlemi gerçekleştiriliyor.
Bu bölümde autoconf ta kullanabileceğiniz öntanımlı makrolara yer vereceğiz
AC_INIT(sourcefile)
autoconf'u hazırlar, configure.in dosyasında çağrılan ilk makro olmalıdır. sourcefile ifadesi yerine main fonksiyonunu içeren kaynak kod dosyasının adını yazın.
Örnek:
AC_INIT(deneme.c)
AC_PROG_CC
Kullanılacak olan C derleyicisini bulur ve CC değişkenine atar. Eğer CFLAGS değişkeni daha önceden tanımlanmamışsa bu değişkeni de tanımlar.
AC_PROG_CXX
Kullanılacak olan C++ derleyicisini bulur ve CXX değişkenine atar. Eğer CXXFLAGS değişkeni daha önceden tanımlanmamışsa bu değişkeni de tanımlar.
AC_LANG_C
C derleyicisini test eder.
AC_LANG_CPLUSPLUS
C++ derleyicisini test eder.
AC_PROG_INSTALL
INSTALL değişkenine BSD uyumlu install yazılımının tam yolunu atar.
AC_PATH_X
X Window sisteminin başlık dosyalarını ve kütüphanelerini bulmaya çalışır. x_includes ve x_libraries değişkenlerine ilgili klasörleri atar.
AC_PATH_PROG(a, b [,c [,d]])
a=değişken adı
b=aranılan program adı
c=program bulunamazsa değişkenin alacağı değer
d=programı aramak istediğiniz klasor
Örnek:
AC_PATH_PROG(ifconfig_path, ifconfig, FALSE, $PATH:/usr/obj)
AC_OUTPUT(dosyalar)
Hangi dosyaların giriş olacağı burada belirlenir. Giriş dosyaları buraya yazılan dosya isimlerinin sonuna .in uzantısı getirilerek belirlenir. Dosyalar üzerinde gerekli değiştirme işlemleri uygulandıktan sonra çıkış dosyaları yaratılır.
Örnek:
AC_OUTPUT(Makefile spec)
Yukarıdaki kullanımda Makefile.in dosyası
incelenir ve Makefile yaratılır. Aynı
şekilde spec.in dosyası incelenip, spec dosyası yaratılır. AC_CONFIG_HEADER(header_dosyalari)
Burada belirlenen header dosyaları AC_OUTPUT tarafından otomatik olarak işleme alınır. Genellikle dosya adı config.h olarak seçilir. Burada belirlenen dosya AC_OUTPUT tarafından işlem göreceği için config.h.in dosyasına ihtiyaç vardır. Bu dosyayı Bölüm 5 de anlatılan autoheader sizin için otomatik olarak oluşturur.
AC_CHECK_FUNCS(a, [,b [,c]])
a=Aradığınız fonksiyonların listesi (boşluklarla ayırın)
b=Fonksiyon bulunduğu zaman yapılacak işlem
c=Fonksiyon bulunamadığı zaman yapılacak işlem
Örnek:
AC_CHECK_FUNCS(dup2 inet_ntoa memset realpath strchr, [], \
[AC_MSG_ERROR(temel fonksiyonlar bulunamadi)])
AC_CHECK_LIB(a, b, [,c [,d]])
a=Fonksiyonun aranacağı kütüphane adı
b=Aranan fonksiyon adı
c=Fonksiyon bulunursa yapılacak işlem
d=Fonksiyon bulunamazsa yapılacak işlem
Örnek:
AC_CHECK_LIB(crypt,crypt, [], \
[AC_MSG_ERROR(crypt kütüphanesi bulunamadı)])
AC_CHECK_HEADERS(a, [,b [,c]])
a=Aranılan başlık(header) dosyaları (boşlukla ayrılmış)
b=Başlık dosyası bulunduğu zaman yapılacak işlem
c=Başlık dosyası bulunamadığı zaman yapılacak işlem
Örnek:
AC_CHECK_HEADERS(arpa/inet.h sys/socket.h sys/time.h, [], \
[AC_MSG_ERROR(Başlık dosyaları bulunamadı)])
AC_HEADER_STDC
stdlib.h, stdarg.h, string.h ve float.h başlıklarının olup olmadığını kontrol eder. Eğer bulabilirse STDC_HEADERS değişkenini tanımlar.
AC_DEFINE(a, b, [,c])
a=Tanımlanacak sabit'in adı
b=Sabit'in alacağı değer. (değişken kullanmayın çünkü bu makro Full Quoted'dir. Sabit'e değişken bir değer atayacaksanız AC_DEFINE_UNQUOTED makrona bakınız.)
c=Bu parametre, başlık dosyanızda bu sabit'in açıklaması olarak kullanılacaktır.
Örnek:
AC_CONFIG_HEADER(config.h)
AC_CHECK_LIB(crypt, crypt, AC_DEFINE(CRYPT_VARMI, 1, [Crypt fonkiyonu varmi]), \
AC_DEFINE(CRYPT_VARMI, 0, [Crypt fonksiyonu varmi]))
--- config.h.in ---
/*Crypt fonksiyonu var mi*/
#undef CRYPT_VARMI
----------------
# ./configure
...
...
--- config.h ---
/*Crypt fonksiyonu var mi*/
#define CRYPT_VARMI 1
----------------
Yukarıdaki örnekte crypt
fonksiyonunun bulunduğu kabul ettik. AC_DEFINE_UNQUOTED(a, b, [,c])
a=Tanımlanacak sabit'in adı
b=Sabit'in alacağı değer. (Değişken kullanabilirsiniz. Bu makro unquoted'dir.
c=Bu parametre, başlık dosyanızda bu sabit'in açıklaması olarak kullanılacaktır.
Örnek:
AC_CHECK_HEADER(config.h)
organizasyon="EnderUNIX"
AC_DEFINE(ORGANIZATION, "$organizasyon", [Organizasyon Adi])
# ./configure
...
...
--- config.h ---
/*Organizasyon Adi*/
#define ORGANIZASYON "$organizasyon"
----------------
Yukarıdaki örnekte görüdüğü gibi ifade olduğu gibi
alınmıştır (Full Quoted). Şimdi de AC_DEFINE_UNQUOTED
örneğini inceleyelim.
Örnek:
AC_CHECK_HEADER(config.h)
organizasyon="EnderUNIX"
AC_DEFINE_UNQUOTED(ORGANIZATION, "$organizasyon", [Organizasyon Adi])
# ./configure
...
...
--- config.h ---
/*Organizasyon Adi*/
#define ORGANIZASYON "EnderUNIX"
----------------
Son örnekte ise alıntı yapılmamış (unQoted) değişkenin
değeri yerine konulmuştur. AC_SUBST(degisken_adi)
Önceden tanımlanmış olan degisken_adi isimli degiskeni AC_OUTPUT ta tanımlanan dosyaların içerisinde arar. Orada tanimlanan dosyalarda @degisken_adi@ seklinde gecen ifadelerin yerine değerlerini yazar.
surum="0.1"
AC_SUBST(surum)
AC_OUTPUT(Makefile)
--- Makefile.in ---
VERSION=@surum@
...
...
-------------------
# ./configure
...
...
--- Makefile ---
VERSION=0.1
...
...
----------------
AC_MSG_ERROR(mesaj)
Kullanıyıcıyı tanımladığınız mesaj ile uyarır ve configure scriptinden çıkış değeri (exit code) 0(sıfır) olmayan bir şekilde çıkar. Genelde bir kütüphane veya başlık dosyasını bulamadığınızda bu fonksiyona ihtiyaç duyulur.
AC_CHECK_HEADERS(stdio.h sys/socket.h, [], \
AC_MSG_ERROR(Basliklar bulunamadi))
AC_MSG_WARNING(mesaj)
Kullanıcıyı tanımladığınız mesaj ile uyarır, ancak configure'den çıkmaz. Genelde opsiyonel bir kütüphane bulunamadığında kullanıcıyı bilgilendirmek için kullanılır.
AC_ARG_ENABLE(a, b, [,c [,d]])
a=Opsiyon adı (--enable-opsiyon)
b=./configure --help çalıştırıldığına bu opsiyon için gösterilecek açıklama
c=Bu opsiyon varsa yapılacak işlem
d=Bu opsiyon yoksa yapılacak işlem
Örnek:
AC_ARG_ENABLE(ssl, [SSL'i destekle], SSL_KULLAN="EVET", SSL_KULLAN="HAYIR")
AC_CANICAL_HOST
İşletim sistemini tespit eder ve bu değeri host_os değişkenine atar.
Örnek:
AC_CANONICAL_HOST
case "$host_os" in
linux*)
AC_DEFINE(LINUX, 1, [Linux kullaniliyor])
;;
freebsd*)
AC_DEFINE(FREEBSD, 1, [FreeBSD Kullaniliyor])
;;
*)
AC_MSG_ERROR([Desteklenmeyen işletim sistemi: $host_os.])
;;
esac
autoheader, configure.in de yazılı olan AC_CONFIG_HEADER makrosu ile belirlenmiş olan dosya için include dosyasını yaratır.
Örnek:
AC_CONFIG_HEADER(config.h)
# autoheader
Bu işlemden sonra config.h.in dosyası
yaratılır. config.h.in içeriğinde ise AC_DEFINE ve AC_DEFINE_UNQUOTED ile belirlediğiniz
tanımlamaların #undef olarak yer
aldığını görebilirsiniz. configure, yukarıdaki örneğimize göre config.h.in dosyasını prototip olarak alacak ve topladığı verilere göre config.h'ı yaratacaktır.
--- configure.in ---
AC_INIT(deneme.c)
AC_CONFIG_HEADER(config.h)
AC_PROG_CC
AC_LANG_C
AC_HEADER_STDC
AC_CHECK_FUNCS(atol)
AC_DEFINE(DENEME, 1, [Ornek define])
AC_OUTPUT(Makefile)
--------------------
# autoheader
--- config.h.in ---
/* config.h.in Generated automatically from configure.in by autoheader */
/* Define if you have the ANSI C header files */
#undef STDC_HEADERS
/* Define if you have the atol function */
#undef HAVE_ATOL
/* Ornek define */
#undef DENEME
-------------------
# ./configure
...
...
--- config.h ---
/* config.h Generated automatically by configure */
/* config.h.in Generated automatically from configure.in by autoheader */
/* Define if you have the ANSI C header files */
#define STDC_HEADERS 1
/* Define if you have the atol function */
#define HAVE_ATOL 1
/* Ornek define */
#define DENEME 1
----------------
Programınızda bu tanımlamaları kullanabilmek için #include "config.h" işlemini yapmayı unutmayın.
Autoconf bölümünde (Bkz. Bölüm 4) verdiğimiz Makefile.in dosyasında "install","uninstall" hedefleri yoktu. Tarball'un içinde olması gereken README, INSTALL ve Lisans dosyaları gibi dosyalar yok.
Bütün bunların bir araya getirilmesini sağlayan yazılım automaketir. automake, Makefile.am dosyasını inceleyerek gerekli hedefleri (install, uninstall, dist, clean gibi) yazılımınıza göre hazırlar ve bunun sonucunda Makefile.in dosyasını üretir. Üretilen bu dosyayı configure kullanacağı için, automake'in configure'den önce çalıştırılması gerekmektedir.
Automake kullanırken, configure.in dosyasındaki bazı autoconf makrolarını (AC_*), automake makrolarıyla (AM_*) değiştirmek gerekiyor.
AC_INIT makrosundan hemen sonra AM_INIT_AUTOMAKE(package,version) makrosu çağrılmalıdır. AC_CONFIG_HEADER yerine de AM_CONFIG_HEADER makrosu kullanılmalı.
-- configure.in --
AC_INIT(deneme.c)
AM_INIT_AUTOMAKE(deneme,0.1)
AM_CONFIG_HEADER(config.h)
...
...
...
------------------
Örnek olarak aşağıdaki Makefile.am dosyasını inceleyelim
-- Makefile.am --
bin_PROGRAMS = deneme
deneme_SOURCES = deneme.c
noinst_HEADERS = deneme.h config.h
man_MANS = deneme.8
EXTRA_DIST = deneme.jpg
---------------------------
bin_PROGRAMS
Derlenip, yüklenecek olan programları, bu alana boşluklarla ayırarak yazıyoruz. Bu bölümde ismi geçen programlar @prefix@/bin klasörüne install edilir.
deneme_SOURCES
_SOURCES takısından önce belirlenen progarm için gerekli kaynak kod dosyalarının listesidir. bin_PROGRAMS bölümündeki her program için ayrı bir _SOURCES bölümü olmalıdır.
noinst_HEADERS
Tarball'da olması gereken, ancak @prefix@/include klasörüne yüklenmesi gerekmeyen başlık (header) dosyalarının listesi.
man_MANS
Yüklenecek man sayfalarının listesi
EXTRA_DIST
Tarball'da olması gereken diğer dosyaların listesi. Örneğin scriptler, resim dosyaları, data dosyaları vb.
Bu bölümde Makefile.am dosyasında yer alabilecek başlıca ifadelere değineceğim.
SUBDIRS
Proje dosyalarınızı klasörlere ayırmışsanız, bu değişken ile belirlediğiniz klasörlerin içindeki Makefile.am dosyasının da işleme tabii tutulmasını sağlıyoruz.
SUBDIRS = src images doc
Her alt klasör kendi Makefile.am dosyasını içermelidir.
bin_PROGRAMS
Derlenip, yüklenecek olan programları, bu alana boşluklarla ayırarak yazıyoruz. Bu bölümde ismi geçen programlar @prefix@/bin klasörüne install edilir.
sbin_PROGRAMS
Derlenip, yüklenecek olan programları, bu alana boşluklarla ayırarak yazıyoruz. Bu bölümde ismi geçen programlar @prefix@/sbin klasörüne install edilir.
*_SOURCES
_SOURCES takısından önce belirlenen progarm için gerekli kaynak kod dosyalarının listesidir. *_PROGRAMS bölümündeki her program için ayrı bir _SOURCES bölümü olmalıdır.
include_HEADERS
Hem Tarball'a dahil edilecek hem de install işlemi esnasında @prefix@/include klasörüne yüklenecek olan başlık (header) dosyalarının listesi
noinst_HEADERS
Tarball'da olması gereken, ancak @prefix@/include klasörüne yüklenmesi gerekmeyen başlık (header) dosyalarının listesi.
bin_SCRIPTS
Derlenmeden, rwx r-x r-x haklarıyla @prefix@/bin klasörüne yüklenecek scriptlerin listesi
sbin_SCRIPTS
Derlenmeden, rwx r-x r-x haklarıyla @prefix@/sbin klasörüne yüklenecek scriptlerin listesi
pkgdata_DATA
@prefix@/share/program klasörüne r-x r-x r-x haklarıyla yüklenecek olan dosyaların listesi
man_MANS
Yüklenecek man sayfalarının listesi
EXTRA_DIST
Tarball'da olması gereken diğer dosyaların listesi. Örneğin scriptler, resim dosyaları, data dosyaları vb.
Makefile.am
SUBDIRS = src data pkgdata_DATA = \ README\ COPYING\ AUTHORS\ ChangeLog\ NEWS\ TODO EXTRA_DIST = $(pkgdata_DATA)
configure.in
AC_INIT(src/testdaemon.c)
AM_INIT_AUTOMAKE(testdaemon, 0.1)
AM_CONFIG_HEADER(src/config.h)
if test "x${prefix}" = "xNONE"; then
prefix=${ac_default_prefix}
fi
AC_CANONICAL_HOST
AC_MSG_CHECKING([for supported operating system])
case "$host_os" in
linux*)
AC_DEFINE([LINUX], 1, [Define for the Linux operating system.])
;;
freebsd*)
AC_DEFINE([FREEBSD], 1, [Define for the freebsd operating system.])
;;
*)
AC_MSG_ERROR([Non supprted operating system: $host_os. exiting.])
;;
esac
AC_MSG_RESULT($host_os)
AC_DEFINE_UNQUOTED(OS, "$host_os", [Operating System])
AC_PROG_INSTALL
AC_LANC_C
AC_PROG_CC
AC_HEADER_STDC
AC_CHECK_HEADERS(ctype.h sys/time.h unistd.h,,AC_MSG_ERROR([Gerekli Header Dosyalari bulunamadı]))
AC_OUTPUT([
Makefile
src/Makefile
data/Makefile
])
src/Makefile.am
sbin_programs = testdaemon bin_programs = testpasswd testdaemon_SOURCES = testdaemon.c testctl_SOURCES = testpasswd.c noinst_HEADERS = testdaemon.h testpasswd.h
data/Makefile.am
sbin_SCRIPTS = testctl man_MANS = testdaemon.8 EXTRA_DIST = $(sbin_SCRIPTS) $(man_MANS)