Category Archives: gcc

ar ve binutils


Binutils

Binutils paketindeki programların büyük çoğunluğu, BFD, yani Binary File Descriptor kütüphanesini kullanır. Bu kütüphane, alt-seviyede manipülasyonlar yapmayı sağlar. Yine, çoğu program opcodes kütüphanesini kullanır. Bu kütüphane, makine komutlarını assemble ve disassemble etmeyi sağlar.

Binutils paketindeki kütüphaneler:

lifeinbeta@lifeinbeta:/usr/lib/ldscripts$ locate libbfd
/usr/lib/libbfd-2.20.1-system.20100303.so
lifeinbeta@lifeinbeta:/usr/lib/ldscripts$ locate libopcodes
/usr/lib/libopcodes-2.20.1-system.20100303.so

ar

ar utility, binutils‘deki utility‘lerden biridir.
Binutils‘in içeriği için, Linux From Scratch – Contents of Binutils‘e bakılabilir.

ar, Arşiv Kütüphaneleri/Statik Kütüphaneler üzerinde oluşturma, değiştirme, içindekileri çıkarma(extract) işlemleri yapmak için kullanılır.

man ar  

Description:(Kısaltılmıştır) `ar`, `s` *modifier*'ı ile birlikte kullanıldığında,
oluşturulacak olan arşivde bulunacak olan *relocatable object module*'lerin içinde bulunan *symbol*'lere bir *index* tablosu oluşturur.

Bir Object File‘ın Symbol tablosu, bir programın sembolik tanımlamalarını ve referanslarını locate ve relocate etmek için gerekli olan bilgileri tutar.

Bu index tablosunu listelemek için nm -sya da nm --print-armap kullanılır. Eğer bir arşiv dosyasında bu tablo yoksa, sadece bu tabloyu eklemek için ar utility‘nin içindeki ranlib kullanılabilir.

Şimdi, ar ile ilgili anlattıklarımın uygulamasını yapalım.

Arşiv Dosyasının – Statik kütüphanenin oluşturulması

lifeinbeta@lifeinbeta:~/CSWORKS/C/soexample$ ar -qcv libdummy.a countdown.o factorial.o
a - countdown.o  <- *Verbose* modda olduğumuz için,
a - factorial.o  <- yapılan işlem hakkında bilgiler veriliyor.
lifeinbeta@lifeinbeta:~/CSWORKS/C/soexample$ ls  <- libdummy.a gerçekten oluştu mu, görelim.
countdown.c  factorial.c  factorial.o  main    main.o
countdown.o  factorial.h  libdummy.a   main.c

Arşivdeki Index Tablosunun Görülmesi

lifeinbeta@lifeinbeta:~/CSWORKS/C/soexample$ nm -s libdummy.a

Archive index:  <- arşivdeki index table
countdown in countdown.o                  <- countdown.o'nun içinde countdown fonksiyonu var.
__i686.get_pc_thunk.bx in countdown.o     <- bu fonksiyonun ne yaptığını daha sonra açıklayacağım.[TODO]
countdown_by_adding in countdown.o        <- countdown.o'nun içinde countdown_by_adding fonksiyonu var.
countdown_with_modulo in countdown.o      <- countdown.o'nun içinde countdown_with_modulo fonksiyonu var.
fact in factorial.o                       <- factorial.o'nun içinde fact fonksiyonu var.
__i686.get_pc_thunk.bx in factorial.o     <- bu fonksiyonun ne yaptığını daha sonra açıklayacağım.[TODO]

countdown.o: <- Kütüphanedeki birinci parça, yani relocatable object module 1  <- aşağıda bu object modülündeki sembollere olan indexler gösteriliyor.
         U _GLOBAL_OFFSET_TABLE_    <- bir index entry ile GOT Tablosu belirtiliyor.
00000000 T __i686.get_pc_thunk.bx   <- bir index entry
00000000 T countdown                <- bir index entry ile countdown fonksiyonunu gösteren symbol belirtiliyor.
00000044 T countdown_by_adding      <- bir index entry ile countdown_by_adding fonksiyonunu gösteren symbol belirtiliyor.
0000008e T countdown_with_modulo    <- bir index entry ile countdown_with_modulo fonksiyonunu gösteren symbol belirtiliyor.
         U printf                   <- bir index entry ile printf fonksiyonunu gösteren symbol beliriliyor.

factorial.o: <- Kütüphanedeki ikinci parça, relocatable object module 2
         U _GLOBAL_OFFSET_TABLE_
00000000 T __i686.get_pc_thunk.bx
00000000 T fact

Yukarıda archive index table‘ı görüntüledik.

Index Table‘daki entry‘lerin object module‘ler içindeki symbol‘lere referans verdiğini söyledim. Peki, relocatable objecet file‘lardaki bu sembolleri görelim.

Relocatable Object Module/File‘lardaki Sembol Tablolarının Görülmesi

Bunun için objdump utility‘si, -t parametresi ile kullanılabilir.

lifeinbeta@lifeinbeta:~/CSWORKS/C/soexample$ objdump -t libdummy.a
In archive libdummy.a:

countdown.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*  00000000 countdown.c
00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l    d  .rodata    00000000 .rodata
00000000 l    d  .text.__i686.get_pc_thunk.bx   00000000 .text.__i686.get_pc_thunk.bx
00000000 l    d  .note.GNU-stack    00000000 .note.GNU-stack
00000000 l    d  .comment   00000000 .comment
00000000 l    d  .group 00000000 .group
00000000 g     F .text  00000044 countdown     <- bir sembol
00000000 g     F .text.__i686.get_pc_thunk.bx   00000000 .hidden __i686.get_pc_thunk.bx  <- bir sembol
00000000         *UND*  00000000 _GLOBAL_OFFSET_TABLE_  <- UND a dikkat!
00000000         *UND*  00000000 printf                 <- UND a dikkat!
00000044 g     F .text  0000004a countdown_by_adding  <- diğer bir sembol
0000008e g     F .text  00000054 countdown_with_modulo <- diğer bir sembol

factorial.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*  00000000 factorial.c
00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l    d  .text.__i686.get_pc_thunk.bx   00000000 .text.__i686.get_pc_thunk.bx
00000000 l    d  .note.GNU-stack    00000000 .note.GNU-stack
00000000 l    d  .comment   00000000 .comment
00000000 l    d  .group 00000000 .group
00000000 g     F .text  00000035 fact  <- bir sembol
00000000 g     F .text.__i686.get_pc_thunk.bx   00000000 .hidden __i686.get_pc_thunk.bx  <- diğer bir sembol
00000000         *UND*  00000000 _GLOBAL_OFFSET_TABLE   <- UND'a dikkat!

Görüldüğü gibi, her relocatable object module‘ün bir sembol tablosu var.

Arşiv başlıklarının Görülmesi

Ayrıca, binutils‘deki diğer bir utility olan objdump‘ı -a parametresi ile kullanarak arşiv dosyasındaki relocatable object module‘lerin adları ve formatlarını görebiliriz.

lifeinbeta@lifeinbeta:~/CSWORKS/C/soexample$ objdump -a libdummy.a
In archive libdummy.a:

countdown.o:     file format elf32-i386
rw-r--r-- 1000/1000   1460 Jun  5 00:04 2011 countdown.o

factorial.o:     file format elf32-i386
rw-r--r-- 1000/1000   1028 Jun  5 00:04 2011 factorial.o

Yukarıdaki, -a parametresi, --archive-headers, Displays archive header information anlamındadır.

ar utility‘sinin açıklamasına devam edelim…

Aşağıda, Synopsis‘i kısaltarak yazdım.

SYNOPSIS: ar [-]p[mod] archive member...

Buradaki parametreler:

p: çalıştırılacak olan işlemi belirtir. Burada, bunun için q‘yu kullandım.

mod: Yapılacak olan işlem hakkındaki detaylar belirtilir. Burada, bunun için c ve v‘yi kullandık.

-c: Create, aşiv dosyasını oluşturur.

-v: Verbose, işlem yapılırken verbose modunda yapılmasını ister. Yani, yapılan işlemler hakkında özet bilgi gösterilir.

-q: Quick Append, beliritilen member‘ları yani dosyaları, arşive ekle demek içindir.

Advertisements

Leave a comment

Filed under C, disassembling, gcc

C – Linker ve Nesne Dosyaları


Header Dosyalarının yerleri ve Search Path Ayarları yazısının girişinde sorduğum sorulardan;

  • Bir Header dosyasının belirttiği bir object file nasıl bulunur? Linker bunu nerede arar?

sorularını burada cevaplayacağım. Bunu yaparken, Linker ve Linker parametrelerinden söz edeceğim.

Object File

Stackoverflow‘da Why compile to an object file first? sorusuna verilen cevaplarda önce object code‘a derleme konusunda aşağıdaki noktalara değiniliyor.

Bu olaya, separate compilation denir.

  • Aynı anda, farklı object file‘larda birden fazla kişi çalışabilir.
  • Daha hızlı derleme, aynı dosyaları tekrar tekrar derlemene gerek yoktur.
  • object file‘lar farklı dillerden derlenerek oluşturulmuş olabilir. Daha sonra, Linker ile birleştirilebilirler.
  • separate compilation birçok sistem geneli library‘nin dağıtımını kolaylaştırır. Bunlar static ya da shared library‘ler olabilir. Mesela; işletim sistemi kütüphaneleri, dillerin standart kütüphaneleri, ya da üçüncü parti kütüphaneler.

Yukarıda anlatılanlardan, Make vs. Ant – Build araçları ile konfigürasyon yönetimi yazısında bahsetmiştim. Burada, object file‘ları birleştirmek Linker‘ın işidir.

gcc ile Link işlemini, çeşitli parametreler kullanarak yapabiliriz. Ayrıca, binutils den biri olan ld ile de bu işlemi linker adımı içerisinde yapabiliriz.

GCC ve Linker Parametreleri

Options for Linking‘de link aşamasında kullanılabilecek olan parametreler açıklanıyor.

gcc -c file1.c file2.c

Yukarıdaki yapıdaki -c, compile demektir, bu parametre Derleyicinin kullandığı bir parametredir.  Belirtilen kaynak kodların object filelarını oluşturur. linker bu parametreyi, -S ve -E parametrelerinden biriyle işlem yapıldığında görmezden gelir.

gcc -o exe_dosya file1.o file2.o

Yukarıdaki yapıda, -o (output) parametresi belirtildiği için, belirtilen object file‘lar, Linker tarafından Link edilerek executable oluşturulur. Dolayısıyla, Linker‘ın en temel parametresi, .o uzantılı object file‘dır. Ama çoğu zaman tek başına .o lar ile işlem yapılmaz. Kütüphaneler(shared->.so ya da static->.a) ile işlem yapılır.

C ile LIBC’yi Kullanmadan Program Yazmak yazısında bahsettiğim -nostdlib‘e de değinmek isterim.

gcc -nostdlib -o hello hello.c

-nostdlib Linker‘a, .c dosyası derlendikten sonra oluşan .o dosyasını libc kütüphanesiyle link etmemesini söylüyor. Yoksa bu .o, .c dosyasında #include <stdio.h>, #include <stdlib.h> ... ifadeleri belirtilmemiş bile olsa standart kütüphaneyle link edilirdi. Bu parametre ile .o dosyasına link edilmeyecek olan libc kütüphanesi,

/usr/lib/gcc/i486-linux-gnu/4.4/libgcc.a

dir.

Bununla birlikte hazır bakmışken libgcc ile ilgili başka nerelerde neler var onlara da bakalım.

lifeinbeta@lifeinbeta:/$ sudo find / -name libgcc*
/opt/lampp/lib/libgcc_s.so.1
/usr/share/lintian/overrides/libgcc1
/usr/share/doc/libgcc1
/usr/lib/ure/lib/libgcc3_uno.so
/usr/lib/gcc/i486-linux-gnu/4.4/libgcc_s.so
/usr/lib/gcc/i486-linux-gnu/4.4/libgcc.a
/usr/lib/gcc/i486-linux-gnu/4.4/libgcc_eh.a
/usr/lib/libgccpp.so.1
/usr/lib/libgccpp.so.1.0.2
/var/lib/dpkg/info/libgcc1.md5sums
/var/lib/dpkg/info/libgcc1.shlibs
/var/lib/dpkg/info/libgcc1.postrm
/var/lib/dpkg/info/libgcc1.symbols
/var/lib/dpkg/info/libgcc1.postinst
/var/lib/dpkg/info/libgcc1.list
/lib/libgcc_s.so.1

-llib: Linker, belirtilen object file‘ı, burada belirtilen library ile link eder.

UNIX’te bir kütüphanenin ismi, “liblibrary_name(.ar | .so)” şeklindedir. Link edilmesi istenen kütüphane, -llibname şeklinde değil, -lname şeklinde belirtilmelidir.

gcc parametreleri belirtilirken, -l parametresinin hangi sırada belirtildiği önemlidir. Eğer, foo.o -lname zoo.o şeklinde bir ifade varsa, zoo.o, name kütühanesindeki gerekli .o ile link edilmez. Çünkü, Linker, object file‘ları ve kütüphaneleri, gcc komutunda bunların belirtildiği noktaya gelince arar ve sadece o noktada işlem yapar. Yukarıda, -lname, bütün object file‘lardan sonra belirtilmiş olsaydı, Linker, önce object file‘ları işleyecekti sonra en sonda belirtilen kütüphaneyi arayacaktı ve bulduğunda bunu, önceden farkettiği object file‘lar ile link edebilecekti.

Peki, yukarıda sadece library ismini belirttik. UNIX üzerinde yüzlerce dizin olduğunu hesaba katarsak, Linker belirtilen kütüphaneyi hangi dizinde bulacak? Linker, gerekli olan bir kütüphaneyi, bir standart dizin listesindeki dizinlerde arar. Daha sonra bu kütüphanenin içinden gerekli olan object file‘ın nasıl alınarak nasıl link edildiğini Loaders yazısında anlatacağım.

Library Search Path = Link Path = Load Path

setting search paths‘te ve When should i set LD_LIBRARY_PATH‘te belirtildiği gibi;

Linker, kütüphaneleri sırasıyla /usr/lib/ ve /usr/local/lib/ dizinlerinde arar. Bu dizinler, link edilecek dosyaların aranması için kullanılan, varsayılan dizinlerdir. Bu dizinlere, library search path ya da link path ya da load path denir. Standart C Kütüphanesi olan libgcc, /usr/lib/ altında bulunur ve varsayılan olarak her zaman link edilir. Link işleminde kullanılması gereken harici bir kütüphanenin bu dizin listesine eklenmesi gerekir.

Load Path‘e yeni bir dizin, LD_LIBRARY_PATH ortam değişkeni aracılığıyla eklenebilir(Ancak bu, güvenlik nedeniyle, tavsiye edilmez). Bu değişken, varsayılan dizinleri tutmaz, sadece harici olarak eklenmiş dizinleri tutar. Ortam değişkenine eklemekle, yeni eklenen dizin başka link işlemlerinde de aranması için kalıcı hale getirilmiş olur. Sadece uygulamaya göre, Linker tarafından içinde kütüphane aranacak olan, dizin belirtmek için(tavsiye edilen) -Ldizin parametresi kullanılmalıdır.

Ancak, -L parametresiyle link path‘e her link işlemi için dizin belirtmek istemeyiz. Aynı şekilde, -l parametresiyle link edilmesini istediğimiz library‘leri belirtirken de tekrar tekrar bu işi yapmak istemeyiz. Bunlara alternatif olarak, makefile kullanabiliriz. Aşağıda örnek bir Makefile var.

CC = gcc -Wall
SOURCE = hello.c
FLAGS = -lglut
BINARY = hellogl

all:
        $(CC) $(SOURCE) -o $(BINARY) $(FLAGS)

clean:
        @echo Temizleniyor...
        @rm $(BINARY)
        @echo Temiz!

freeglut3 Kurulumu

Şimdi, freeglut3‘ü sistemimize yükleyelim.

Bunun için, OpenGL Utility Toolkit(freeglut3) ü kurduktan sonra aşağıdaki işlemi yaptım.

lifeinbeta@lifeinbeta:/$ sudo find / -name freeglut*
/usr/share/doc/freeglut3
/var/cache/apt/archives/freeglut3_2.6.0-0ubuntu2_i386.deb
/var/lib/dpkg/info/freeglut3.postinst
/var/lib/dpkg/info/freeglut3.list
/var/lib/dpkg/info/freeglut3.postrm
/var/lib/dpkg/info/freeglut3.shlibs
/var/lib/dpkg/info/freeglut3.md5sums

Henüz .h ve .so dosyları yok. Daha sonra, development libraries and headers for GLUT(freeglut-dev)i kurdum ve aşağıdaki işlemi yaptım.

lifeinbeta@lifeinbeta:/$ sudo find / -name freeglut*
/usr/share/doc/freeglut3
/usr/share/doc/freeglut3-dev
/usr/share/doc/freeglut3-dev/freeglut.html
/usr/share/doc/freeglut3-dev/freeglut_user_interface.html
/usr/share/doc/freeglut3-dev/freeglut_logo.png
/usr/include/GL/freeglut_std.h
/usr/include/GL/freeglut.h
/usr/include/GL/freeglut_ext.h
/var/cache/apt/archives/freeglut3_2.6.0-0ubuntu2_i386.deb
/var/cache/apt/archives/freeglut3-dev_2.6.0-0ubuntu2_i386.deb
/var/lib/dpkg/info/freeglut3-dev.list
/var/lib/dpkg/info/freeglut3.postinst
/var/lib/dpkg/info/freeglut3.list
/var/lib/dpkg/info/freeglut3.postrm
/var/lib/dpkg/info/freeglut3.shlibs
/var/lib/dpkg/info/freeglut3-dev.md5sums
/var/lib/dpkg/info/freeglut3.md5sums

Header dosyaları, /usr/include/ içinde /GL/ dizini oluşturularak buraya konuldu. Neden buraya konduğu konusunda bkz. Header dosyalarının yerleri ve Search Path ayarları. Ancak hala kütüphaneler ortada yok. development libraries … dediğine göre yüklenmiş olmalılar, ama bulamadım. 🙂 How to install freeglut?‘dan bakarak bu kütüphanelerin libglut isminde olduğunu gördüm.

Aşağıdaki işlemi yaptığımda bu dosyaları görebildim.

lifeinbeta@lifeinbeta:/$ sudo find / -name libglut*
/usr/share/doc/libglut3-dev
/usr/lib/libglut.so.3
/usr/lib/libglut.so
/usr/lib/libglut.so.3.9.0
/usr/lib/libglut.a
/var/cache/apt/archives/libglut3-dev_3.7-25_all.deb
/var/lib/dpkg/info/libglut3-dev.list
/var/lib/dpkg/info/libglut3-dev.md5sums

Linkler

Leave a comment

Filed under build, C, gcc, linker

Header Dosyalarının Yerleri ve Search Path Ayarları


Bu yazıda şu sorular üzerinden gideceğim:

  • C’de Header dosyalarının varsayılan yerleri neresidir. Kullanıcının header dosyaları nerelerde olabilir?
  • Header dosyaları nasıl bulunur?
  • Header dosyasının belirttiği object file nasıl bulunur?
  • Object File‘ların oluşturduğu kütüphaneler(.so, .dll) nasıl bulunur ve burada gerekli olan bir bileşen belleğe nasıl yüklenir?

Header dosyaları

GCC Dökümantasyonunda Libc – Using the Library – Header Files kısmından alıntı yaparak başlayalım:

C Programları tarafından kullanılan kütüphaneler iki kısımdan oluşur. Bunlar: tipleri, makroları, değişken ve fonksiyon bildirimlerini(declaration) içeren header dosyaları ile fonksiyonların ve değişkenlerin tanımlamalarını içeren(definition) gerçek kütüphane veya arşivlerdir.

GNU C Kütüphanesindeki bileşenleri kullanabilmek için, programların kaynak kodlarının, ilgili bileşene referans veren header dosyalarını içerdiğinden emin olmamız gerekir. Compiler, derleme aşamasında bu referansları işler. Program derlendikten sonra, Linker, bu referansları arşiv dosyalarının birinde bulunan gerçek tanımlamalar(.o dosyası) ile değiştirir(çözümler – resolve).

NOT: Yukarıdaki cümleden şunları çıkarabiliriz:

  • Header dosyalarının yerlerini bulan C Preprocessor programıdır. (Dolaylı olarak yaptığım bir çıkarım.)
  • Header dosyalarının belirttiği object file‘ların yerini bulup derlenecek olan kaynak kodun üreteceği object file ile birleştiren ise Linker programıdır.

GNU CPP Manual‘de Header Files kısmında yazılı açıklamalardan gidersek;

Header dosyalarının iki amacı vardır:

  • User Header Files, kullanıcının bir programını oluşturan kaynak kodlar arasındaki arayüzlerdir. #include "file" yapısı kullanılır.
  • System Header Files, işletim sistemi parçalarına arayüz belirtir. Bunları ekleyerek, sistem çağrısı yapabilmek ya da bu çağrılarla ilgili C Kütüphane bileşenlerini çağırabilmek için gerekli bildirim ve tanımlamaları kodumuzda belirtmiş oluruz. #include <file> yapısı kullanılır. file ismiyle belirtilen dosyayı, sistem dizinleri listesinde arar. Bu liste bir standarttır. Bu listeye yeni bir dizin eklemek için -I bayrağı kullanılabilir.

NOT: Burada bir listeden ve -I bayrağından(parametresinden) bahsediliyor. Böylelikle yazının başında sorduğum ilk iki soruya cevap almaya başladık.

Bu sistem dizinleri listesindeki dizinler ve -I bayrağı ile belirtilerek eklenen dizinler, search path kavramını ortaya çıkarır. Buna ileride değineceğim.

Devam edelim,

-I parametrenin nasıl kullanılacağını anlatan Invocation kısmına referans veriliyor. Burada,

Genelde, C Preprocessor‘unu özellikle çağırmazsınız; C Compiler‘ını çağırdığınızda, derleme aşamasına geçmeden önce zaten otomatik olarak çağrılır. Ancak, C Preprocessor‘unu bazen kendi başına çağırmak da gerekebilir.

diye söze giriliyor. Buradan, daha önce de belirttiğim gibi, header dosyalarının yerlerini C Preprocessor‘un bulduğunu anlarız. C Preprocessor‘unu çağırmak için cpp kullanılır.

Preprocessor‘u gcc ya da cpp ile çağırırsanız, öncelikle derleyici sürücüsü(compiler driver) çalıştırılır. Bu programın amacı, parametreler ile birlikte girilecek olan komutu, bu komutta belirtilen gerçek işi yapacak olan program çağrılarına dönüştürmektir.

cpp için belirtilen komut parametrelerinin hepsi gcc için de kullanılabilir ve aynı anlamdadır. Ancak, C Compiler‘ı, çıktı dosyasını(output file) belirtmek için farklı kurallar kullanır.
C Preprocessor‘ı iki argümana sahiptir. Bu argümanlar, sırasıyla infile ve outfile‘ı belirtir. infile‘da belirtilen dosyalar include dosyalarıdır. Bu dosyalar birleştirilerek belirtilen outfile‘a yazılır.

Parametre Yapısı

-I parametresinden sonra yazılacak olan argümanlar -Ifoo şeklinde birleştirilerek ya da -I foo şeklinde ayrı belirtilerek yazılabilir.
Birçok parametre birden fazla harften oluşabilir (-undef gibi). Bu nedenle ayrı parametreler(mesela -d -M) gruplanarak yazılamaz (-dM gibi).

Search Path

GNU GCC Manual Search Path‘te yazılı bilgilerden devam edelim:

GCC -dolaylı olarak cpp denmek isteniyor- , header dosyaları için çeşitli farklı yerleri arar.

Buradan sonra ilk iki sorunun cevabına daha çok yaklaşıyoruz;

Normal bir UNIX Sisteminde, aksi belirtilmedikçe, #include <file>‘da belirtilen bir file, aşağıdaki dizinlerde aranır:

/usr/local/include
*libdir*/gcc/*target*/version/include
/usr/*target*/include
/usr/include

Yani, bu dizinler header dosylarının varsayılan dizinleri, sistem dizinleridir.
GCC, kurulu olduğu sisteme göre derlenmek üzere ayarlanmıştır. Yukarıdaki, target, bu sistemi belirtir. Kullandığım sistemde, bu, i486-linux-gnu.
Yukarıdaki, libdir, Standard C Library’nin kurulu olduğu dizindir. Kullandığım sistemde(ubuntu), lifeinbeta@lifeinbeta:~$ locate /gcc diye aratarak /usr/lib/gcc‘de olduğunu buldum.

Search path ile ilgili parametreler öncelikle -I, -nostdinc, -include, -isystem ve -iquote dir. Bunlara sırayla bakalım:

  • -I *dir* ve -iquote *dir*: Bundan zaten bahsetmiştim. Kullanıcının kendi kütüphanelerini oluşturmak için yazdığı header dosyaları için belirtilir. Sistem dizinleri listesinden önce belirtilen dizinlerde arama yapılır. Bu, hem #include <file> hem de #include "file" ile belirtilen dosyalar için bu anlama gelirken; -iquote ile , adından da anlışılacağı gibi, kodda sadece #include "file" ile belirtilen dosyalar için belirtilen dizinde arama yapılır. #include <file> dosyaları için bu parametreyle search path‘e eklenen dizinde arama yapmaz.
  • -isystem *dir*: -I ile belirtilen dizinleri standart sistem dizinlerinden biriymiş gibi göstermek amacıyla kullanılır. GCC Manual System Headers kısmında açıklanan amaçlardan ve nedenlerden dolayı böyle bir şeye ihtiyaç duyulabilir. İşletim sistemi ve libc arasında arayüz belirten header dosyarı normal header dosyalarından farklıdır. GCC, standart sistem header‘larına farklı davranır.
  • -nostdinc: cpp‘ye Header dosylarının bulunduğu sistem dizinlerinde(varsayılan dizinler) arama yapmamasını söyler. Sadece -I ya da -iquote parametreleri ile belirtilen dizinlerde arama yapılır. Libc olmadan program yazmak yazısında -nostdlib den bahsetmiştim. Bu parametre Linker yani ld‘nin kullandığı bir parametreydi. Bu parametre ise daha cpp aşamasında iken libc‘nin include dosyalarının dikkate alınmamasını söylemek için kullanılır. Bu yüzden bu seçenek, işletim sistemi kernel‘ını derlerken kullanılabilir ya da standart C kütüphanesini kullanmayan programları yazarken kullanılabilir.
  • -include *file*: Kodda, #include "file" şeklinde yazılmış gibi .c dosyasının başına ekler. #include "file"‘da belirtilen file aranmaya başlanırken önce .c‘nin bulunduğu dizin aranır eğer burada bulunamazsa varsayılan dizinlere bakılır. Bu parametre ile önce varsayılan dizinlere bakılır sonra .c‘nin bulunduğu dizine bakılır.

Uygulama ve Açıklamalar

lifeinbeta@lifeinbeta:~$ cd /usr/lib/gcc
lifeinbeta@lifeinbeta:/usr/lib/gcc$ ls
aotcompile.py  aotcompile.pyc  classfile.py  classfile.pyc  i486-linux-gnu
lifeinbeta@lifeinbeta:/usr/lib/gcc$ cd i486-linux-gnu
lifeinbeta@lifeinbeta:/usr/lib/gcc/i486-linux-gnu$ ls
4.4  4.4.3
lifeinbeta@lifeinbeta:/usr/lib/gcc/i486-linux-gnu$ cd 4.4.3
lifeinbeta@lifeinbeta:/usr/lib/gcc/i486-linux-gnu/4.4.3$ ls
cc1          crtend.o       include        libgomp.a           libsupc++.a
cc1plus      crtendS.o      include-fixed  libgomp.so          SYSCALLS.c.X
collect2     crtfastmath.o  libgcc.a       libgomp.spec
crtbegin.o   crtprec32.o    libgcc_eh.a    libssp_nonshared.a
crtbeginS.o  crtprec64.o    libgcc_s.so    libstdc++.a
crtbeginT.o  crtprec80.o    libgcov.a      libstdc++.so
lifeinbeta@lifeinbeta:/usr/lib/gcc/i486-linux-gnu/4.4.3$ cd include
lifeinbeta@lifeinbeta:/usr/lib/gcc/i486-linux-gnu/4.4.3/include$ ls
ammintrin.h     float.h            mm_malloc.h  stdbool.h    wmmintrin.h
avxintrin.h     immintrin.h        nmmintrin.h  stddef.h     x86intrin.h
bmmintrin.h     iso646.h           omp.h        stdfix.h     xmmintrin.h
cpuid.h         mm3dnow.h          pmmintrin.h  tmmintrin.h
cross-stdarg.h  mmintrin-common.h  smmintrin.h  unwind.h
emmintrin.h     mmintrin.h         stdarg.h     varargs.h

Yukarıda, header dosyalarının bulunduğu standart sistem dizinlerinden biri olan *libdir*/gcc/*target*/version/include dizinin içeriği görünüyor. Buradaki header dosyaları, GCC – derleyici uygulamasının, kendi işlevleri için kullandığı kütüphanelere arayüz sağlayan dosyalardır. Burada ayrıca libc‘de standart olarak belirtilmeyen ama GNU‘nun libc‘yi gerçeklerken ek olarak koyduğu fonksiyonların gerçeklemelerine arayüz sağlayan header dosyaları da vardır. GCC, libc‘nin bütün header’larını kullanabilir. Detaylı bilgi için buraya bakılabilir.

lifeinbeta@lifeinbeta:/usr/local/include$ ls
lifeinbeta@lifeinbeta:/usr/local/include$ cd /usr
lifeinbeta@lifeinbeta:/usr$ ls
bin  games  include  lib  lib64  local  sbin  share  src
lifeinbeta@lifeinbeta:/usr$ cd include
lifeinbeta@lifeinbeta:/usr/include$ ls
aio.h           expat_external.h  libexslt         nl_types.h   sysexits.h
aliases.h       expat.h           libgen.h         nss.h        syslog.h
...
err.h           jpegint.h         netinet          stdio.h      xen
errno.h         jpeglib.h         netipx           stdlib.h     xlocale.h
error.h         langinfo.h        netiucv          string.h     xorg
...
...
...

Yukarıda, bahsettiğim standart sistem dizinlerinden sadece /usr/include da header dosyaları bulundu. Bu dosyaların bir özeti gösteriliyor.

Bu yazı yine uzadı gitti 🙂 Neyse ki markdown‘la kolayca yazabildim. 😛 Böylelikle, yıllarca(!) aklımın bir köşesinde takılı kalan bazı noktaları temizledim. Ayrıca, bu yazı sadece hobi olarak yazılmış bir yazı değil. Bir Nerd işi de değil. Sadece, herhangi büyük bir C uygulaması ile uğraşırken ya da harici bir C kütüphanesini kullanırken kafam rahat olsun diye 🙂 yazdığım bir yazı. Neyse, son iki soru kaldı. Onları bir sonraki yazımda, Linker‘dan bahsederken cevaplayacağım.

GCC Ortam Değişkenleri

CPATH
C_INCLUDE_PATH
CPLUS_INCLUDE_PATH
OBJC_INCLUDE_PATH

Yukarıdaki Ortam Değişkenlerinin değeri, terminalden;

lifeinbeta@lifeinbeta:~$ echo $C_INCLUDE_PATH

lifeinbeta@lifeinbeta:~$ echo $CPATH

lifeinbeta@lifeinbeta:~$ echo $OBJC_INCLUDE_PATH

şeklinde yazılarak görülebilir.


LİNKLER

1 Comment

Filed under gcc, linking