Autoconf ve Automake Kullanımı
Önceki GNU Paket Yapılandırma Sistemi Sonraki
Autoconf ve Automake Kullanımı
GNU Paket Kurgulama Sistemi iki temel amacın gerçekleştirilebilmesi için geliştirilmiştir: Programları platformlar arası daha rahat taşınabilir hale getirmek ve kaynak koddan program kurulumlarını mümkün olduğu kadar basite indirgeyebilmek.
Taşınabilir kod yazmak gerçekten oldukça zahmetli bir iştir. Hedef mimarinin ayrıntılı olarak özelliklerinin bilinmesi çoğu zaman mümkün değildir. Bir önceki bölümde örnek olarak yazdığımız Makefile dosyasında mkdir -p /usr/local/bin/test komutunu kullanmıştık. Oysa mkdir komutunun -p seçeneği tüm Unix sistemlerde aynı şekilde çalışmaz. Bu ve bunun gibi pek çok farklılık yüzünden her Unix sisteminde çalışabilecek bir Makefile yazmak çok zor iştir. Kullanılan kütüphanelerin sistemler arasındaki farklılıkları ise apayrı bir konudur. İşte GNU Paket Kurgulama Sistemi tüm bu zorlukların üstesinden gelebilmek için oluşturulmuştur. Kdevelop gibi programlar yeni proje oluşturduğunuzda b sistemi de otomatik olarak oluşturmaktadırlar. Ancak oluşan dosyalar fazlasıyla karışık olduğundan bu bölümde çok daha basit örneklerle yapıyı anlatmaya çalışacağım. Buradaki temel bilgilerden yararlandıktan sonra Kdevelop gibi programların ürettiği veya örütbağdan indirmiş olduğunuz herhangi bir uygulamanın kaynak kodu içerisinde gezinerek farklı kullanımları inceleyebilirsiniz.
Gerekli Araçlar
GNU Paket Kurgulama Sistemi için gerekli araçlar ve kullanım alanları aşağıdaki gibidir:
  1. autoconf yapılandırma için kullanılacak configure betiğini üretir. Kodun taşınabilir olmasını etkileyecek özellikleri, üzerinde çalıştığı platform için denetler. Elde ettiği değerleri, daha önceden belirtilmiş şablonlara uygun şekilde birleştirerek özelleştirilmiş Makefile, başlık dosyaları vb. oluşturur. Bu sayede programı derleyecek kullanıcı tek tek elle bu değişiklikleri yapmak zahmetinden kurtulur.
  2. automake, autoconf için kullanılacak Makefile şablonlarını (Makefile.in) temel alarak Makefile.am dosyalarını üretir. automake tarafından üretilen Makefile dosyaları GNU makefile standartlarına uygun olup, kullanıcıyı elle Makefile dosyası oluşturma zahmetinden kurtarır. autoconf'un çalışabilmesi için öncelikle automake'in düzgün olarak çalışması gereklidir.
  3. libtool özellikle paylaşımlı kütüphanelerin taşınabilir bir yapıda oluşturulabilmesi için gereken pek çok ayrıntıyı kullanıcıdan soyutlar. Kullanımı için autoconf veya automake gerekli değildir, tek başına da kullanılabilir. automake ise libtool'u destekler ve onunla birlikte çalışabilir.
  4. Autotools GNU kodlama standartlarına uygun, taşınabilir kod üretmede yardımcı olur.
GNU Paket Kurgulama Sistemi tarafından gerçekleştirilen temel görevler şunlardır:
  1. Çok sayıda alt dizin içeren kaynak kodlardan uygulamaları üretebilir. Her bir dizin için ayrıca make komutunu çağırmak zahmetinden geliştiriciyi kurtarır. Bu sayede tüm kaynak kodları aynı dizinde bulundurmak yerine aşamaları daha belirgin bir dizin yapısı kullanabilirsiniz.
  2. Yapılandırma işlemini otomatik olarak yapar. Kullanıcıların Makefile dosyalarını düzenlemelerine gerek kalmaz.
  3. Makefile dosyalarını otomatik olarak üretir. Makefile yazımı büyük projelerde sürekli tekrar gerektirir ve aynı zamanda hata yapmaya elverişli bir yapıdır. GNU Paket Kurgulama Sistemi için sadece Makefile.am şablonunun yazımı yeterlidir. Bu sayede hata yapma olasılığı azalır ve yönetimi kolay hale gelir.
  4. Hedef platform için özel testler yapabilme imkanı sunar. Makefile.am dosyasına eklenecek bir kaç satırla hedef platformda programın derlenebilesi için aranan özelliklerin var olup olmadığı kontrol edilebilir.
  5. Paylaşımlı kütüphanelerin oluşturulması statik kütüphanelerin oluşturulması kadar kolay hale gelir.
GNU Paket Kurgulama Sistemi için gerekli olan bu araçların sadece geliştirmenin yapıldığı sistemde kurulu olması yeterlidir. Bu programlar çalıştıktan sonra her platformda çalışabilecek betik programları üretirler. Bu sayede uygulamanızın kaynak kodunu indirip kurmak isteyen biri, autoconf, automake gibi araçları da sistemine kurmak zorunda kalmaz.
Basit Bir Autoconf, Automake Örneği
Şimdi aşağıdaki test programımız için GNU Paket Kurgulama Sistemini nasıl kullanacağımızı öğrenelim.
#include <stdio.h>

int main()
{
  printf("Çalışıyor\n");
  return 0;
Programımızı test.c olarak kaydedelim. Şimdi programın derlenmesi işlemlerini autoconf ve automake ile yapmaya başlayalım. Bunun için öncelikle aşağıdaki Makefile.am dosyasını oluşturalım:
in_PROGRAMS = test
test_SOURCES = test.c
Ardından aşağıdaki gibi bir configure.in dosyası oluşturalım:
AC_INIT(test.c)
AM_INIT_AUTOMAKE(test,0.1)
AC_PROG_CC
AC_PROG_INSTALL
AC_OUTPUT(Makefile)
Dosyaları oluşturup kaydettikten sonra şimdi aşağıdaki komutları çalıştıralım:
$ aclocal
$ autoconf
$ ls -l
total 88
-rw-r--r--    1 demirten demirten    16626 Haz 22 17:32 aclocal.m4
-rwxr-xr-x    1 demirten demirten    50233 Haz 22 17:32 configure
-rw-r--r--    1 demirten demirten       90 Haz 22 17:31 configure.in
-rw-r--r--    1 demirten demirten       43 Haz 22 17:29 Makefile.am
-rw-r--r--    1 demirten demirten       71 Haz 22 17:28 test.c
Gördüğünüz gibi aclocal ve autoconf uygulamaları çalıştıktan sonra aclocal.m4 ve configure dosyaları üretildi. Şimdi ise automake programını çalıştıracağız:
$ automake -a
automake: configure.in: installing `./install-sh'
automake: configure.in: installing `./mkinstalldirs'
automake: configure.in: installing `./missing'
automake: Makefile.am: installing `./INSTALL'
automake: Makefile.am: required file `./NEWS' not found
automake: Makefile.am: required file `./README' not found
automake: Makefile.am: installing `./COPYING'
automake: Makefile.am: required file `./AUTHORS' not found
automake: Makefile.am: required file `./ChangeLog' not found
automake: configure.in: installing `./depcomp'
automake ilk çalıştırıldığında öncelikle install-sh, mkinstalldirs ve missing dosyalarının daha önceden oluşturulup oluşturulmadığını kontrol eder. Eğer yoksa bu dosyaları oluşturur (Bendeki sistemde dosyaları oluşturmak yerine /usr/share/automake dizini altındaki asıllarına bağ veriyor). Bu dosyalar automake tarafından üretilen Makefile dosyaları için gereklidir. Ayrıca GNU kodlama standartlarına göre INSTALL, NEWS, COPYING, README, AUTHORS ve ChangeLog dosyalarının da bu dizinde bulunması gereklidir. Bu dosyalar olmadığı için automake uyarı vermektedir. make distcheck komutunun hata vermemesi için bu dosyaları oluşturalım, sonra içlerini nasıl olsa doldururuz. Bendeki sistemde automake ilk çalıştırıldığında INSTALL ve COPYING dosyalarını da bağ olarak oluşturduğu için önce onları siliyorum:
$ rm INSTALL COPYING
$ touch NEWS INSTALL README COPYING AUTHORS ChangeLog
automake programını bu dosyalardan varlığından haberdar edelim:
$ automake -a
$ ls
aclocal.m4  configure     depcomp     Makefile.am  mkinstalldirs  test.c
AUTHORS     configure.in  install-sh  Makefile.in  NEWS
ChangeLog   COPYING       INSTALL     missing      README
Bu dizin yapısı size tanıdık gelmiş olmalı. Kaynak paketimiz bu haliyle artık son kullanıcının karşısına çıkmaya hazır, hemen paketleyip dağıtabiliriz. Şimdi kendimizi bu programi Genel Ağ'dan indirip bilgisayarına kurmak isteyen birinin yerine koyalım. Yapmamız gerekenler aşağıdaki gibidir:
$ ./configure
creating cache ./config.cache
checking for a BSD compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for mawk... mawk
checking whether make sets ${MAKE}... yes
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 for style of include used by make... GNU
checking dependency style of gcc... gcc
checking for a BSD compatible install... /usr/bin/install -c
updating cache ./config.cache
creating ./config.status
creating Makefile
$ make
source='test.c' nesnect='test.o' libtool=no \
depfile='.deps/test.Po' tmpdepfile='.deps/test.TPo' \
depmode=gcc /bin/sh ./depcomp \
gcc -DPACKAGE=\"test\" -DVERSION=\"0.1\"  -I. -I. -g -O2 -c `test -f test.c
¬ || echo './'`test.c
gcc  -g -O2   -o test  test.o
$ ./test
Çalışıyor
Uyarı
Aşağıda programı nasıl sisteminize kuracağınız anlatılmaktadır. Öntanımlı olarak test uygulaması /usr/local/bin dizini altına kopyalanır. Ancak bu dizinde test adında bir uygulamanız zaten varsa ve bunu kaybetmek istemiyorsanız veya yanlışlıkla prefix vererek uygulamayı varolan /usr/bin/test üzerine kopyalamamak için dikkatli olunuz.
Bu noktada dilerseniz uygulamayı sisteme kurabilirsiniz. Bunun için root kullanıcı haklarına sahip olmalısınız.
$ make install
make[1]: Entering directory `/tmp/test'
/bin/sh ./mkinstalldirs /usr/local/bin
  /usr/bin/install -c test /usr/local/bin/test
make[1]: Nothing to be done for `install-data-am'.
make[1]: Leaving directory `/tmp/test'
Uygulamayı kaldırmak içinse make uninstall komutunu kullanabilirsiniz:
$ make uninstall
rm -f /usr/local/bin/test
Uygulamanızın artık hazır olduğuna inandığınızda make distcheck komutu ile onu paket haline getirebilirsiniz (Ekran çıktısı biraz uzun olduğundan burada listelenmemiştir). Bu komut işini tamamladığında bulunduğunuz dizinde test-0.1.tar.gz adında bir dosya oluşacaktır. Artık bu dosya ile programınızın dağıtımını yapabilirsiniz.
Şimdi biraz da yaptığımız bu örneği biraz daha açıklayalım. Makefile.am içerisinde mantıksal bir dil kullandık. Yazdığımız hiç bir satır çalıştırılmadı. Diğer yandan configure.in içerisinde kullandığımız dil prosedüreldir, yazdığımız her satır çalıştırılacak bir komutu göstermektedir. Makefile.am dosyası içerisindeki ilk satır programın ismini belirtirken ikinci satır programı oluşturan kaynak kodları belirtmektedir. Şimdi daha karışık olan configure.in içerisindeki komutlara sırasıyla bakalım:
  • AC_INIT komutu configure betiği için ilklendirmeleri yapar. Parametre olarak kaynak dosyaların adlarını alır.
  • AM_INIT_AUTOMAKE komutu, automake kullanacağımızı gösterir. Parametre olarak programın ismini ve sürümünü alır. Eğer Makefile.in dosyalarını elle hazırlayacak olsaydık bu komutu kullanmamıza da gerek olmayacaktı.
  • AC_PROG_CC komutu kullanılan C derleyicisinin ne olduğunu belirler.
  • AC_PROG_INSTALL komutu BSD uyumlu install uygulamasına sahip olup olmadığımızı denetler. Eğer yoksa bu işlem için install-sh'ı kullanır.
  • AC_OUTPUT komutu configure betik programının Makefile dosyalarını Makefile.in dosyalarından üretmesi gerektiğini belirtir.
Örneğimizdeki configure.in dosyası içerisinde yer almayan ama sıklıkla kullanacağımız bazı komutlar da şunlardır:
  • AC_PROG_RANLIB komutuyla bir kütüphane geliştiriyorsak ranlib'in sistemde nasıl kullanılacağını öğrenebiliriz.
  • AC_PROG_CXX komutuyla sistemdeki C++ derleyicisinin ne olduğunu öğrenebiliriz.
  • AC_PROG_YACC ve AC_PROG_LEX komutlarıyla kaynak kodlarımız lex veya yacc dosyaları içeriyorsa bu uygulamaların sistemde varlığını denetleyebiliriz.
  • Eğer alt dizinlerde başka Makefile dosyalarımız da olacaksa bunu
    AC_OUTPUT(Makefile         \
              dizin1/Makefile  \
              dizin2/Makefile  \
              )
    
    komutlarıyla belirtebiliriz.
Dosyaların içeriğinden bahsettikten sonra şimdi de biraz önce yaptığımız örnekte çalıştırdığımız komutlardan sonra neler olduğuna tekrar bakalım.
  • aclocal komutu çalıştıktan sonra aclocal.m4 dosyası üretilir. Bu dosya içerisinde autoconf tarafından kullanılacak olan makrolar yer almaktadır (kendi özel makrolarımızı nasıl hazırlayacağımıza ileride değinilecektir).
  • autoconf komutuyla aclocal.m4 ve configure.in dosyaları işlenerek configure betik programı oluşturulur.
  • automake komutu Makefile.am dosyasını temel alan bir Makefile.in oluşturur. Ayrıca GNU kodlama standartlarına göre eksik olan dosyalar için örnek birer kopya üretir.
  • ./configure komutuyla çalıştırılan betik programı daha önceden belirtilen özellikler için sistemimizi test eder ve Makefile.in dosyasını örnek alarak Makefile dosyalarını oluşturur. AC_OUTPUT() ile belirtilen tüm dosyalardaki @[email protected] şeklindeki kayıtları FOO için elde edilen değerlerle değiştirir (örneğin C derleyicisinin ne olduğu gibi).
Yapılandırma Başlık Dosyalarının Kullanımı
Çoğu zaman derleme anında bazı makrolar tanımlamak isteriz. -D seçeneği ile derleyiciye bildirilen bu değerleri programımız içerisinden kullanarak ilgili kod parçacığının çalışma şeklini değiştirebiliriz. autoconf kullandığımız bir uygulama için böylesi seçenekleri kullanmanın yolu yapılandırma başlık dosyası, config.h kullanmaktan geçmektedir.
config.h mantığını kullanabilmemiz için test.c programımızın en başına aşağıdaki üç satırı eklemeliyiz:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
Burada unutulmaması gereken önemli bir nokta, config.h dosyasının mutlaka ilk olarak include edilmesidir.
Program kaynak kodunu bu şekilde değiştirdikten sonra configure.in dosyasını da aşağıdaki duruma getirmeliyiz:
AC_INIT(test.c)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(test,0.1)
AC_PROG_CC
AC_PROG_INSTALL
AC_OUTPUT(Makefile)
Ve çalıştırdığımız komutlara bir yenisini aşağıdaki sırada ekleyelim:
$ aclocal
$ autoconf
$ touch NEWS README AUTHORS ChangeLog
$ autoheader
$ automake -a
Burada yaptıklarımızın bir önceki örneğimizden farkı autoheader programını da çalıştırmaktan ibarettir. autoheader, configure.in dosyasını tarayarak bir config.h.in şablon dosyası oluşturur. Bu dosyanın içerisine configure.in dosyasından öğrendiği, tanımlanabilecek değerleri ve açıklamalarını yerleştirir. Aynı zamanda kaynak kodumuzdan config.h dosyasının include edilebilmesi için gerekli -I seçeneklerini de derleyiciye geçirir. ./configure komutundan sonra ise gerçek config.h dosyası oluşur. Şimdi örneğimizde oluşan config.h dosyasına bir bakalım.
/* config.h.  Generated automatically by configure.  */
/* config.h.in. Generated automatically from configure.in by autoheader 2.13. */

/* Name of package */
#define PACKAGE "test"

/* Version number of package */
#define VERSION "0.1"
Automake ile ilgili ayrıntılar
Projemiz büyüdükçe kaynak kodların bulunduğu yerler gittikçe karışmaya başlar. Bunları düzenleyebilmek amacıyla daha hiyerarşik dizin yapıları kurarız. Ancak bu defa da her bir dizin için uygun Makefile dosyalarını üretmemiz gerekecektir. Bunun için bu bölümde Makefile.am dosyalarından daha ayrıntılı bir şekilde bahsedeceğiz.
Makefile.am dosyalarının genel biçimi değişken = değer şeklindedir. Ancak aynı zamanda, geleneksel Makefile mantığındaki gibi hedef ve soyut kural tanımlamalarını da destekler. Şimdi Makefile.am dosyalarında sıklıkla kullanacağımız satırlara bir bakalım.
INCLUDES = -I/usr/local/include -I/usr/custom/include ...
Nesne kodlarını oluştururken derleyiciye include edilen dosyaları hangi dizinlerde araması gerektiğini belirtir. Ayrıca proje kaynak kod yapısı içerisindeki bir dizin seçenek olarak verildi ise alt dizinlerde yer alan kaynak programların hepsinin bu dosyalara erişebilmelerini sağlamak amacıyla tanımlama INCLUDES = -I$(top_srcdir)/src/libxxx şeklinde yapılmalıdır. Buradaki $top_srcdir değişkeni kaynak kod yapısı içerisindeki en üst dizini tutar.
LDFLAGS = -L/usr/local/lib ...
Derleyici çalıştırılabilir dosyaları üretirken ihtiyaç duyduğu kütüphaneleri hangi dizinlerde araması gerektiğini bu tanımla öğrenecektir.
LDADD = test.o ... $(top_builddir)/lib/libfoo.a ... -lfoo ...
Tüm oluşacak çalıştırılabilir dosyalara sembolik bağlamak istediğiniz sisteme kurulu olan ve olmayan nesne dosyaları burada listelenir. Eğer listelenen nesne dosyası sistemde kurulu değilse dosyanı tam adresi verilmelidir ($top_builddir/lib/libfoo.a örneğindeki gibi).
EXTRA_DIST = dosya1 dosya2 ...
Kaynak kod paketinizde bulunmasınıistediğiniz her türlü dosyayı burada listeleyebilirsiniz.
SUBDIRS = dizin1 dizin2 ...
Bulunulan dizin için işlem yapmadan önce kuralların çalıştırılması gereken dizinlerdir. make uygulaması bulunulan dizinde işleme başlamadan önce, burada belirtilen dizinlerdeki Makefile kurallarını çalıştırır ve listelenen tüm dizinler için işlemleri bitirdikten sonra bu dizine geri döner.
bin_PROGRAMS = test test2 ...
make komutu çalıştıktan sonra üretilecek ve make install komutuyla belirli bir dizin altına kopyalanacak program adları burada listelenir.
lib_LIBRARIES = libfoo1.a libfoo2.a ...
make komutu çalıştıktan sonra üretilecek ve make install komutuyla belirli bir dizin altına kopyalanacak kütüphane dosyalarının adları burada listelenir.
check_PROGRAMS = program1 program2 ...
make komutunun çalışması esnasında üretilmeyip, sadece make check komutuyla üretilecek, programınızın tümünü veya bir kısmını test edecek uygulamaların çalıştırılabilir dosya adları listelenir.
TESTS = program1 program2 ...
make check komutu sonrasında test amaçlı çalıştırılacak dosya adlarını listeler. Çoğu durumda TEST = $(check_PROGRAMS) şeklinde bir tanımlama yapabilirsiniz.
include_HEADERS = foo1.h foo2.h ...
/prefix/include dizini altına kurulmasını istediğiniz başlık dosyalarını burada listelemelisiniz.
bin_PROGRAMS
Bu değişkende listelediğiniz her bir program için aşağıdaki tanımlamaları da yapmalısınız (program kelimesi yerine programın adını yazmalısınız):
program_SOURCES = test.c test1.c test2.c test.h test1.h test2.h ...
automake programı burada belirtmiş olduğunuz dosya adları için, C, C++ ve Fortran dillerine özgün soyut Makefile kurallarını oluşturur. Eğer başka bir dil kullanılıyorsa gerekli kuralları siz vermelisiniz.
program_LDADD = $(top_builddir)/lib/libfoo.a -lnsl ...
Burada programınızla ilintilenmesi gereken kütüphaneleri listelemelisiniz.
program_LDFLAGS = -L/dizin1 ...
program_LDADD ile belirttiğiniz kütüphanelerin hangi dizinlerde aranması gerektiği burada listelenir.
program_DEPENDENCIES = dep1 dep2 ...
Programınızın derlenebilmesi için bağımlı olduğu diğer hedefleri burada listelemelisiniz.
Önceki Üst Ana Başlık Sonraki
Makefile Kullanımı Başlangıç Yararlı Belgeler
Bir Linux Kitaplığı Sayfası