UNIX OLANAKLARI
|
SERİ UÇ PROGRAMLAMA TEKNİKLERİ
· TERMİNALSİZ SERİ UÇLAR İÇİN PROGRAMLAR
Terminalsiz seri uçlar için yazılan programlar, UNIX ortamına program kontrolunda diğer çevre birimlerini bağlayabilme olanağı getirir. Yazılan program gün başında çok kullanıcılı ortama geçildikten sonra veya bir kullanıcı tarafından istenildiği zaman başlatılabilir. Bu yöntemle işletim sisteminin bir parçası olabilecek sürücü program olmadan, herhangi bir çevre birimini UNIX ortamına bağlamak mümkün olur.
o UNIX ortamında Seri Uçların tanımlanma biçimi
UNIX ortamında, işletim sistemi seri uçları iki biçimde tanımlar : Birincisi fiziksel seri uçlar; İkincisi ise pseudo seri uçlardır. Fiziksel seri uçlar kullanılan donanıma ilişkin seri uç sürücü programlarına bağımlı çevre birimi tanımlarıdır ama çoğu kez /dev/ttynn biçiminde tanımlanır.Pseudo seri uçlar gerçekte olmayan ancak TCP/IP ve telnet servisi tarafından üretilen sahte seri uçlardır.
Seri uçlara ait çevre birimi tanımlarının sahibi çoğu zaman "root" adlı kullanıcıdır. gettyprogramı bir kullanıcı sisteme girdikten sonra bu seri ucun erişim haklarını yalnız ilgili kullanıcıya yönlendirir ve diğer kullanıcıların bu seri uca erişimini kaldırır.
Seri uca bağlı bir terminal yoksa getty programı kullanılmamalıdır. Bu işlem en güzel,/etc/inittab kütüğündeki ilgili terminal bilgilerinde getty tanımının respawn özelliğini offkonumuna almaktır. Böylece aynı seri uca ileride bir terminal bağlanması söz konusu olduğunda /etc/inittab bilgileri bozulmadan off konumu respawn yapılarak terminalden logingörüntülenmesi sağlanmış olur.
Seri uca terminal bağlanmayacak ve buraya bir başka çevre birimi bağlanacaksa, bu çevre biriminde olması gereken en önemli özellik, gönderilen mesajları algılayan bir programın ilgili çevre birimi üzerinde çalışır durumda olabilmesidir.
UNIX üzerindeki program, ilgili seri ucu kullanabilmek için bu kütüğü open komutu ile açmalıdır. Seri uç kütüğü UNIX için /dev/ttynn biçiminde tanımlanır. Program bu kütüğü açarken hem OKUMA hem de YAZMA işlemi yapacak biçimde koşullandırılır. UNIX ortamında bu kütük daha önce mknod komutu ile yaratılmış olduğundan, kütüğün açılırken yoksa yaratılması söz konusu değildir. Çünkü bu tür kütükleri "root" adlı kullanıcı yaratabilir. Eğer kullanıcının kütüğe erişme yetkisi yoksa kütük açma işlemi başarı ile bitmez.
Kütük açarken dikkat edilmesi gereken konular :
1. Eğer seri uca bir modem bağlanmış ise, modemler telefon hattından karşı taraftaki modemi görmeden DTR ve CD sinyalini yakmazlar. Bu durumda program seri uca ait kütüğü açamayabilir. Bu gibi durumlar için open komutunda N_DELAY konumu kullanılmalı, modemle iletişim kurulup mesaj alış verişi tamamlandıktan sonra N_DELAY fcntl komutu ile kaldırılmalıdır.
2. Seri bağlantıda sistemde tanımlı RS-232 uçlardan TX,RX,CTS,DTR ve Toprak bağlantıları mutlaka bulunmalıdır. Eğer sistemde seri uç çoklayıcı donanım kullanılıyorsa ve bu donanıma ilişkin sürücünün parametrik bilgileri varsa UNIX ortamına uyumlu olmaması olasılığına karşın seri uçların tümünde protokol tanımı "NO PROTOCOL" biçiminde hazırlanmalıdır. Bu özellikler yoksa fcntl komutu ile seri uc, protokolsüz çalışacak biçimde düzenlenmelidir.
3. Seri uç donanımı UART kurallarına uygun ise seri uc iletişim hızı en çok 38400 olabilir. Bu hızın üzerinde iletişim kurmak söz konusu olduğunda, işletim sisteminin özel komutları varsa kullanılmalıdır. Unutulmaması gereken özellik seri uç iletişim hızı 9600, 19200 ve 38400 olabilir. Diğer ara hızlarda seri uç ile iletişim kurulamayabilir.
o Seri uç parametrelerini düzenleme
UNIX ortamında seri uçların kullanım biçimi terminal kullanımına göre düzenlenmiştir. BuradaBreak tuşu, yazılamayan karakteri çevirme özelliği gibi bazı tanımlar önceden terminal sürücü programı tarafından düzenlenmiş filitreler oluşturulmuştur. Bu düzenleme seri uçtan bir bilgi okuma veya seri uca bir bilgi yazma adımlarında istenilmeyen sonuçlar verebilir. Özellikle çevre birimini kontrol etmeyi amaçlayan karakterler (STX, ETX, NULL gibi), filitrelerden geçmeyebilir. Seri uç programları ham veri işleme konumunda iken işletim sistemi ve sürücü programlar tarafından düzenlenmiş filitrelerin parametrelerini değiştirmelidir. Parametre değiştirme işlemi fcntl komutu ile yapılır.
fcntl komutu için kullanılacak parametrik bilgilerin alabileceği değerler :
c_lflag = 0; c_iflag = IGNPAR | IXANY | IGNBRK; c_oflag = 0; for(a=0;a < NCCS;a++) c_cc[a] = 0; c_cc[4] = 1; /* karakter sayısı */ c_cc[5] = 1; /* zaman asımı bekleme süresi */ c_cflag = CLOCAL | CS8 | CREAD | baud_rate;
olarak tanımlanabilir.
o Ham bilgi okuma ve yazma kuralları
UNIX ortamında bir kütükten ham bilgi okuma read komutu, bir kütüğe ham bilgi yazmawrite komutu ile olur. Seri uçlara ham bilgi (donanım karakter tabanlı olduğu için), bir byte gönderme veya bir byte okuma biçimindedir. Tamponlanmış giriş/çıkış işlemi yapılmamalıdır. Hız açısından (özellikle bilgi gönderirken) tamponlanmış bilgi alış verişi yapılacaksa, tampon alan kontrol edilmeli, tampon alan dolduğunda gönderme durdurulmalı, boşalınca tekrar başlatılmalıdır. Terminal kullanımına ait olan XON/XOFF protokolü ham veri işleme konumunda kesinlikle kullanılmamalıdır. Çünkü bu bilgi (XON veya XOFF), gerçekte karşı taraftaki çevre birimine gitmesi gereken bir bilgi olabilir.
Bilgi okurken en çok bir byte bilgi tamponlanmalı, mümkünse tampon alan boyu 0 olmalıdır.
Bilgi okuma işleminde doğrudan read komutu kullanılacak olursa program, okuma işlemi yapılmadan bu komuttan çıkmaz. Ama çevre birimine bilgi gönderen ve çevre biriminden okuma yapan bu tür progamlara sistem içindeki bir başka işlemden bilgi akışı olabilir. Bu durumda çevre biriminden okunacak bilgi yoksa program bir başka işleve geçebilmeli, kendisine gelen bir başka bilgi veya mesaj olup olmadığını anlayabilmelidir.
UNIX ortamında kesinti (Interrupt) olanağı olmadığından, bu bilgi doğrudan işletim sistemi kontrolu altında olduğundan seri uç okuma programında read komutu yerine select komutu kullanılmalıdır. Bu komut ile açılmış kütüklere ait kütük numaralarından bir küme oluşturulur. Oluşturulan kümeden bilgi gelmesi beklenir. Eğer kümenin hiçbir elemanından bilgi gelmiyorsa belirtilen zaman aşımında işlev, hata kodu ile programa döner. Eğer bir bilgi gelmiş ise, kümedeki kütüğün numarası programa döner. Bu durumda program, ilgili kütükten gelen bilgiyi okur.
o Örnek program tanımı
Örnek olarak seri uçtan gelecek bilgi protokol gereği
biçiminde olsun. Program bu mesajı alınca önce LRC denetimi yapacak daha sonra mesaj doğru alındı ise ACK gönderecektir. Hata varsa NACK gönderecektir.
o Örnek program kodu
#define NACK 0x15 #define ACK 0x06 #define ETX 0x03 #define UPD_NFDS(x) if(nfds<(x))nfds=(x) main() { fd_set fdx; struct timeval tv; struct termios term; int nfds = 0; char c; int s, fd, sec, msec; fd = open("/dev/tty00",2); /* seri uc tanimlarini duzenleme */ tcgetattr(fp_prt,&term); term.c_lflag = 0; term.c_iflag = IGNPAR | IXANY | IGNBRK; term.c_oflag = 0; for(a=0;a < NCCS;a++) term.c_cc[a] = 0; /* karakter sayısı */ term.c_cc[4] = 1; /* zaman asımı bekleme süresi */ term.c_cc[5] = 1; term.c_cflag = CLOCAL|CS8|CREAD|B9600; tcsetattr(fp_prt,TCSANOW,&term); sec = 0; msec = 100; tv.tv_sec = sec; tv.tv_usec = msec; FD_ZERO(&fdx); FD_SET(fd,&fdx); UPD_NFDS(fd); while(1) { lrc = 0; s = select(nfds+1, &fdx, NULL, NULL, &tv); if(s >= 0) { /* STX okunur */ read(s,&c,1); /* mesajin kalani ETX dahil okunur ve LRC hesaplanir */ while(c != ETX) { read(s,&c,1); lrc = lrc ^ c; } /* LRC okumak icin */ read(s,&c,1); /* LRC hatasi varsa NACK gonder */ c = (c != lrc) ? NACK : ACK; write(s,&c,1); } } }
Bu örnek programda, kodlamayı kısaltmak için hattan gelen mesajın protokoldaki yapıda sonuna kadar hatasız geleceği varsayılmıştır.
· TERMİNALLER İÇİN TÜM EKRAN (FULL SCREEN)
PROGRAM YAZMA TEKNİKLERİ
Bu bölümde yer alan anlatım için kullandığınız UNIX program geliştirme ortamındaki curses kitaplığı yayınlarına bakmak, varsa diğer özel işlevleri de kullanmak gerekebilir.
o Karakter tabanlı ekranlarda tüm ekran kullanımı (curses)
UNIX ortamında karakter ekranlar satır satır kayan komundadır. Tüm ekranı (24 x 80) karakter biçiminde kullanmak. Yazılan her harfi anında algılayabilmek ancak ham bilgi alma ve yazma konumunda geçerlidir.
Ham bilgiyi ekrandan alma ve ekrana yazma işlemi UNIX program geliştirme ortamındacurses kitaplığı ile mümkündür.
curses gerçek anlamda bir ekranı ham veri işleme konumunda kullanan kitaplıktır. Bu kitaplıkta yer alan işlevlerle uygulama programları ekrandan bir karakter okur, ekrana bir karakter yazabilir. Halbuki komut konumunda yazılan bilgi UNIX tarafından Enter tuşuna basılmadan işleme alınmaz. Komut konumundaki bu mantığa tampon alandan okuma tekniği denir. Ham veri işleme konumunda ise program yazılan her tuşu anında algılar, tuşun gereği olan işlemi anında gerçekleştirir.
curses önce ekranı ham veri işleme konumuna alır. Daha sonra tüm ekranın iki kopya olarak bilgilerini saklar. Birinci kopya görüntülenen ekran, diğeri ise program tarafından günlenen ekran alanıdır. Her refresh komutu çalıştığında, curses iki kopya arasındaki farklı karakterleri belirler ve yalnız bu karakterleri ekrana gönderir. Bu nedenle curses ekran üzerindeki bir karakterin nereye yazılabileceğini bilmelidir. Her ekranın karakter görüntüleme komutları üretici firmalara göre değiştiğinden, ekran özellikleri termlib veya termcap veri tabanındaki tanımlardan alınır. curses kitaplığının doğru çalışması için kullanılan terminalin özellikleri termlib kitaplığına tanıtılmalıdır. Bu işlem için tic komutu kullanılır. curses UNIX kullanıcısının çevre değişkenlerinden TERM bilgisini kullanarak hangi terminal ile çalıştığını saptar ve ekrana bilgiyi bu terminalin özelliklerine göre gönderir.
o Ekran tanımlama
Bir ekranı ham veri işleme konumuna almak için curses kitaplığındaki initscr, cbreak,noecho, nonl işlevleri sıra ile kullanılır. Bu işlemler ekranı ham veri işleme konumuna alır.
Ekranı tekrar komut işleme konumuna almak için echo ve endwin işlevlerini çalıştırmak gerekir.
Ekran ham veri işleme konumuna alındığında curses kitaplığı bu ekran için bir gösterge tanımlar. Bu göstergenin adı stdscr olarak belirlenmiştir. Terminal, ham veri işleme konumuna alındığında tuş takımından girilen bilgi iki biçimde algılanabilir. Ya program tuş takımı bilgilerini de ham olarak okur uygulama içinde karakterlerin ne anlama geldiğini belirler, ya da curseskitaplığı basılan bir tuşun termlib kitaplığındaki karşılığını bulup ilgili tuş değerini çevirilmiş olarak programa döndürür. Bu işlem için keypad işlevi çalıştırılır.
Yukarıda tanımlanan işlevlerle ekran ham veri işleme konumuna alındığında move, getch,addch işlevleri kullanılarak bilgi, ekranın istenilen yerine yazdırılır veya tuş takımından okunur.
Bir ekrana istenilen bilginin çıkması için refresh işlevinin çalıştırılması gerekir.
o Pencere tanımlama
stdscr altında bir veya daha çok pencere açmak, pencerelere hareket ettirmek curseskitaplığı kullanımı ile mümkündür. Pencere açma işlevi newwin ile yapılır. Burada pencerenin ekrandaki (stdscr) başlangıç noktası ve boyutları belirtilir. Açılan pencere werease, delwingibi işlevlerle kapatılır.
Bir pencere kapatılınca ekrandan silinmesi için daha önce açılmış pencereler touch işlevi ile yenilenmeli, böylece kapanan pencerenin bıraktığı boşluk değir pencereler ile doldurulmalıdır.
o Pencereden bilgi okuma, pencereye bilgi yazma
Pencereye bilgi yazarken pencerenin içindeki imleç adreslemesi pencerenin sol üst kösesine göre (0,0) kabul edilerek hesaplanır. Böylece pencerenin hareket ettirilmesi, yerinin değişmesi programlarda yeniden hesaplama yapmayı gerektirmez.
Bir pencereden bilgi okurken wgetch işlevi kullanılır. Aynı pencereye bilgi yazmak içinwaddch işlevi kullanmak gerekir. move işlevi yerine imleç hareketi için wmove işlevi kullanılır.
|
ÖZDEVİNLİ (RECURSIVE) PROGRAMLAR
BİRAZ TARİHÇE
Bilgisayarların ilk yapıldığı yıllarda, program kodu ve veri aynı alanda saklanırdı. O zamanlar çok kullanıcı ortam yerine tek kullanıcılı ortamda çalışma olduğundan bu tür kodlama sorun çıkartmıyordu. İşletim Sistemleri gelişip çok kullanıcılı ortama geçiş başlayınca bellekte aynı programdan birkaç kopya bulunması zamanında en pahalı donanım olan belleğin lüzumsuz harcanmasına neden oluyordu. Bilimsel açıdan bakıldığında derleyicilerin ürettiği kod üç ana bölümden oluşuyordu. Program komutları, değişmez değerler ve kullanıcıya göre değişen bilgiler. Donanım bu yapıya göre gelişirken, yani bellek kesimlere bölünürken işletim sistemleri de programları belleğe yüklerken bu ayrımı göze aldı. Bir programın değişmeyen bölümlerinden yalnız bir kopya saklandı. Yalnızca değişen bölümler için aynı programı kullanan değişik kullanıcılara ayrı bellek kesimleri açıldı. Bu yapı derleyicilerde tekrar girilebilen (reentrant) program kodu üretilmesini zorunlu kıldı. Tekrar girilebilen program kodunda her kullanıcı için son yapılan işlem, program durum bilgisi (program status word) adlı bir alanda saklandı. Aynı kod paylaşımlı olarak birden çok kullanıcı tarafından kullanılabilir oldu. Her kullanıcı kendi verileri için açılan kesimde bilgilerini sakladı. İşletim Sistemlerinin bu olanağı kullanıcıların özdevinli (recursive) program yazmalarına olanak verdi.
ÖZDEVİNLİ PROGRAM
Özdevinli programlarda bir işlev çalışırken bitmeden kendisini çağırır. Çağırılan işlevin sonucu, çağıran işlevde kullanılır. Görünüşte karmaşık olan bu olay, aslında donanımın, işlemcinin "stack" bilgilerinin program içinde verimli bir biçimde kullanılmasını sağlar. Örneklemek gerekirse, Matematikte :
f(n) = f(n-1) + f(n-2)
biçiminde yazılan Fibonacci seri açılımı bu tür programların anlatımı için en kolay örnektir. Burada f(n) değerini hesaplamak için önce f(n-2) ve sonra f(n-1) değerlerini bilmek gerekir. Yazilan bir programda f işlevi aşağıdaki gibi kodlanırsa :
f(int n) { return (f(n-1) + f(n-2)); }
Bu işlev kendisini bir kez n-1 için bir kez de n-2 için çağırır. Aynı işlev n-1 değeri için kendisini bir kez n-2 ve bir kez de n-3 için çağırır. Burada her çağırma işleminde n değeri bir azalmaktadır. Sonunda n=0 ve n=1 değerlerine gelindiğinde işlev değişmez bir değer döndürmeli kendi çağırmayı durdurmalıdır. Yani
f(int n) { if(n == 0 || n == 1) return 1; return (f(n-1) + f(n-2)); }
Biçiminde kodlama değiştirilirse, işlev n=0 ve n=1 için kendini çağırmayı durdurur. Örneklemek açısından n=4 için işlevin durumunu göstermeye çalışalım :
f(4) (5) f(3) + f(2) (3) (2) f(2) + f(1) f(1) + f(0) (2) 1 1 1 f(1)+f(0) 1 1 ÖZDEVİNLİ PROGRAMLARDA DEĞİŞKENLER
Bu tür programlarda değişkenler otomatik değişken olmalıdır. İşlev dışında tanımlanan değişkenleri kullanmak istemeyen sonuçlar alınmasına neden olabilir. Özellikle işleve parametre olarak geçirilen değer, işlev dışında "global" tanımlanmamalı, "stack" üzerinde bulunan otomatik değişkenler olmalıdır. Bilindiği gibi otomatik değişkenler işlev bitince bellekten silinmektedir. Özdevinli işlevlerde, çağırılan işlevin sonucu bir önceki işleve geri dönecek biçimde bir otomatik değişkene atanmalı veya atama işlemini gerçekleştiren bir deyimde kullanılmalıdır.
UYGULAMADA ÖZDEVİNLİ İŞLEV KULLANIMI
Bir seriden her seferinde bir byte okuyup işleme almak bu tür programlar için güzel bir örnektir. Örneğin hattan gelen mesaj analizinde bu tür işlev kolaylıkla kullanılır. Özellikle mesaj boyu bilinmiyor ancak mesajın nasıl biteceği biliniyorsa özdevinli işlev kullanmak programın akışını kolaylaştırması açısından önemlidir.
Aşağıdaki örnek program okunan mesajın sonunda "newline" karakterini bulunca sonucu yazdırır.
#include main() { char buf[300]; mesaj_oku(buf); puts(buf); } mesaj_oku(char *p) { char c; if((c = getchar()) != '\n') { *p = c; mesaj_oku(++p); } else *p = '\0'; return; } |
LINUX VE KABUK PROGRAMLAMA (SHELL PROGRAMING) Bir programi kod safhasindan çalisabilir bir hale getirebilmek için ilk önce derlememiz gerekir. Derleyiciler o kodu üzerinde çalistigimiz isletim sistemine uyarlarlar. Fakat pazi program kodlari derleme islemi gerektirmez. Bunlar direk isletim sistemi tarafindan yorumlanabilen "Script" tabir ettigimiz kod parçaciklaridir. Bu bir HTML sayfasindaki JavaScript olabilir veya Linux üzerinde bir kabuk programi olabilir. Kabuk programlariyla isletim sistemi üzerinde zahmetli olacak bir çok islem kolayca yapilabilir. Kabuk programlarinin aslinda diger programlama dillerinden pek farki yoktur. Genelde diger dillerle ayni mantigi kullanir. Simdi bu kabuk programlarinin nasil yazildigina bakalim. Kabuk programlari da diger diller gibi degiskenler, döngüler, kosullu ifadeler vb. kullanabiliriz. Programi yazmaya baslarken ilk satirda ozel bir ifade kullaniriz. Bu isletim sisteminin hangi kabugunu kullanacagimizi belirtir. NOT: Kabuk isletim sistemi ve kullanici arasinda tercümanlik yapan bir kilavuzdur diyebiliriz. Kullanicinin komutlarini yorumlayarak isletim sistemine iletir. NOT2:Kaydettiginiz programi çalistirmak için dosya modunu 700 yapmaniz gerekir. Bunu yapmaniz için...: Linux:tEmEl~$ chmod 700 dosya_adi (veya ayni seyi diger bir yolla da yapabiliriz) Linux:tEmEl~$ chmod +x dosya_adi --> +x execute anlamina geliyor. Linux:tEmEl~$ dosya_adi --> bu da yazdiginiz programi çalistirmak için. DEGISKEN KULLANMA Linux'te degiskenlerin belirli bir tipi yoktur. Degiskenleri tanimlarken string, integer, float vb. olduklarini belirtmenize gerek yoktur. Isletim sistemi bunu sizin yerinize yapar. Mesela : ---------degisken.sh--------- #!/bin/bash deger ="Temel KARABACAK" sayi = 10 ---------degisken.sh--------- Simdi bu programin neler yaptiguna bir bakalim. Ilk satirdaki ifade bu programin çalistigi sürece "/bin/bash" kabugunu kullanmasini belirtiyor. Ikinci satirdaki ifade ise deger degiskenine "Temel KARABACAK" degerini atiyor. Üçüncü satirda ise sayi degiskenine 10 degeri ataniyor. EKRANA YAZDIRMA Bir önceki yazdigimiz program hiç bir islem yapmiyordu. Simdi bir takim islemler yapan bir program yazalim. Mesela ekrana bir seyler yazdirsin. -------yazdir.sh------------- #!/bin/bash echo "Temel KARABACAK" -------yazdir.sh------------- veya bunu farkli bir sekilde yapalim : -------yazdir1.sh------------- #!/bin/bash temel="Temel KARABACAK" echo "$temel Kondor'un bir uyesidir." -------yazdir1.sh------------- Yukardaki programin neler yaptigina bir gözatalim. Ilk iki satirin ne yaptigini daha önce ögrenmistik. Son satirda ise yeni bir komut var. "echo" komutu ekrana yazdirmak için kullanilan bir komuttur. Echo komutu ile ekrana bir degiskenin degerini yazdirmak istersek $temel diyerek bu sözcügün bas tarafina "$" isareti koyarak bir degisken oldugunu belirtiriz. PROGRAM IÇINE AÇIKLAMA SATIRLARI KOYMAK Linux'te açiklama satirlari koymak için # karakterinden yararlaniriz. Bu karakterin anlami bu satiri iptal et ve okumadan direk diger satira geç demektir. Yanliz ilk basta programa baslarken yazdigimiz "#!/bin/bash" ifadesi bir istisnadir. Örnegin...: --------------aciklama.sh--------------- #!/bin/bash #Bu satir sistem tarafindan hiç okunmayacak. #Asagidaki islem ismimi ekrana yazdiracak. echo "Temel" --------------aciklama.sh--------------- KOSULLU IFADELER(IF STATEMENTS) Diger programlama dillerinde oldugu gibi kabuk programcilarinda da karsilastirmalar yapabiliriz. Bu diger dillerdekine çok benzer. Simdi bununla ilgili küçük bir uygulama yapalim. ---------if.sh------------ #!/bin/bash deger1=1 deger2=100 #Eger deger1 ve deger2 esitse birinci islem gerçeklesir. if [ $deger1 -eq $deger2] then echo "Bu iki deger ayni" else echo "Bu iki deger farkli" fi ---------if.sh------------ Ilk üç satida yazanlari daha önceden biliyoruz. Dördüncü satirda ise if komutu basliyor. Linux'ta if komutu "if" ile baslar ve "fi" ile biter. If komutundan sonraki ifadeleri [] parantezler içine almalisiniz. Bu parantezlerin içindeki ifadeler mutlaka parantez kenarindan bir bosluk tusu kadar uzakta olmalidir. Yoksa yazdigimiz program çalismayabilir. Then ifadesi ise "if" ifadesinden sonraki kosulun gerçeklestigi zaman çalistirilacak komut veya komutlari belirtir. Else ifadesi ise if ifadesinden sonraki kosulun gerçeklesmemesi sonucu çalistirilacak komut veya komutlarin girildigi bölümdür. Simdi yukaridaki programda iki farkli degiskenin karsilastirilmasi var. deger1 ve deger2 degiskenleri karsilastiriliyor. Karsilastirma komutu için "=" ifadesi yerine ise "-eq" kullanilmis. Bu ifade iki degiskenin "equal" olup olmadigini kontrol ediyor. Linux'ta sayisal karsilastirmalar "-eq" gibi ifadelerle stirngsel yani kelime karsilastirmalari ise "=, !=" gibi ifadelerle yapilir. Diger kontrol degiskenlerini bölüm sonunda yazacagim. Eger ikisi de ayniysa ekrana "Bu iki sahis ayni kisi." Mesaji yazilacak. Fakat bizim programimizda bu iki degisken de birbirinden farkli. Programda iki degiskenin farkli olmasi durumunda ise ekrana "Bu iki sahis farkli kisi." Mesaji yazdirilacakti. Bu yüzden programimizin çiktisi else ifadesinden sonraki bölüm olacak. Simdi farkli bir deneme yapalim. --------if2.sh---------- #!/bin/bash #Buradaki $# parametre sayisi anlamina geliyor. if test $# -eq 0 then echo "Hiç parametre girmediniz." else #Birinci parametreyi ekrana yaz. Ikinci parametre olsa $2 olurdu. echo $1 fi --------if2.sh---------- Karsilastirma ifadeleri : -eq --> equal yani esit mi? -ne --> not equal yani esit degil -ge --> greater equal yani büyük esit -le --> little equal yani küçük esit -lt --> little yani küçük -gt --> greater yani büyük = --> string olarak esit != --> string olarak esit degil WHILE DÖNGÜSÜ Linux'te çesitli amaçlarla kullanilan döngüler yer alir. Diger dillerde oldugu gibi farkli bir döngüyle yaptigimiz isi bir baskasi ile de yapabiliriz. Fakat Linux'ta for döngüsünde biraz farklilik vardir ve eger sistem yöneticisi isek bu bizim çok isimize yarar. Simdi küçük bir örnekle while döngüsünü açiklayalim. -------while.sh---------- #!/bin/bash sayici=1 sayi=22 #while döngüsü basliyor while [ $sayici -lt $sayi ] do #Sayimizin degerini ekrana yazdiriyoruz. echo "Sayimizin degeri : $sayici" #sayici degiskeninin degerine 1 ekliyoruz. #bunu yapmazsak program sonsuz döngüye girer. sayici=`expr $sayi +1` done echo "Sayma islemi bitti." -------while.sh---------- Yukaridaki örnegi biraz açiklayalim. While satirinda sayici ve sayi degiskenlerinin degerleri karsilastiriliyor. Eger kosul dogruysa sayici degiskeninin degeri ekrana yazdiriliyor. Açiklamalardan sonraki satirda ise sayici degiskeninin degeri 1 artiriliyor. Buradaki "expr" ifadesi matematiksel bir islem yapilacagini belirtiyor. Müteakip satirda ise "done" ifadesi var. Linux'ta while döngüsü "do" ile devam eder ve "done" ile biter. "do" ifadesinden sonra yapilacak islemleri gireriz. While komutunun sona erdigini ise "done" ifadesi ile belirtiriz. UNTIL DÖNGÜSÜ Until komutu while döngüsünde oldugu gibi bir takim isleri tekrar etmemizi saglar. Simdi bu komutun yapisina bir göz atalim. ----------------repeat.sh---------------- #!/bin/bash deger1=0 deger2=10 #until komutu basliyor. until [ $deger1 -nq $deger2 ] do #yapilacak isleri buradan itibaren yazacagiz echo "$deger1 degeri : --> $deger1" deger1=`expr $deger1 +1` done #hepsi bu kadar iste! ----------------repeat.sh---------------- FOR DÖNGÜSÜ For döngüsü diger döngülerden mantik itibariyle farklidir. Bunu bir örnek üzerinde açiklayalim. ----------for.sh--------------- #!/bin/bash #for döngüsü için önceden degisken tanitmamiza gerek yok. #degiskenimizi döngü içinde tanimliyoruz. for deger in 1 2 3 4 5 6 7 8 9 0 do echo "deger degiskenimizin degeri --> $deger" done ----------for.sh--------------- yukarida klasik bir for döngüsü yazdik. Bu döngünün basinda deger degiskeninin her döngü için alabilecegi degiskenleri tanimladik. Buna göre deger degiskeni 1 2 3 4 5 6 7 8 9 0 degerlerini alabilirdi. Ve do-done arasinda da ise yapilacak islemleri tanimladik. Burada deger degiskeninin degeri her seferinde ekrana yaziliyor. Buraya kadar da görüldügü gibi döngü mantigi döngü_ismi-do-done seklinde. EXPR KOMUTU ILE YAPILACAK ISLEMLER Expr komutu ile matemetiksel islemler yapilabilecegi gibi stringsel islemler de yapilabilir. Simdi bunlari teker teker inceleyelim: Matemetiksel Islemler: * --> Çarpma / --> Bölme % --> Mod alma = --> Esit > --> Büyük < --> Küçük <= --> Küçük esit >= --> Büyük esit Stringsel islemler : 1) expr string1:string2 iki stringi karsilastiriyor. 2) expr length string string'in uzunlugunu buluyor. 3) a=batman expr substr $a 1 3 1 nci kelimeden sonra 3 karakter kopyaliyor. Deger burada "bat" olur. Expr substr $a 4 3 Buradaki deger ise "man" olurdu. 4) expr index $a m a degiskeni içinde "m" karakterinin yerini söylüyor. Dolayisiyla deger 4 olur. Simdilik bu kadar. Devami gelecek |
TCP/IP İLE PROGRAMLAMA
TCP/IP iletişimi hakkında kısa bir açıklamayı iletişim bölümünde daha önce anlatmıştım. Ayrıca dileyenler, INTERNET bağlantıları ve bilgisayarlar arasındaki mesaj trafiği hakkında bilgi edinmek için INTERNET ağlarıkonulu dökümanı da inceleyebilirler.
Burada TCP/IP iletişimi için C programlarında nasıl bir yöntem izlendiğine ve programlarda kullanılan komutların özelliklerine değineceğiz. Sonra örnek programlarla bu bilgileri nasıl kullandığımızı göstereceğiz.
KISA ÖN BİLGİ
TCP/IP genelde bir bilgisayar ortamında iki program arasında iletişim kurulması için kullanılan bir protokoldur. Burada programlar İşgören (sunucu) ve İşveren olarak iki ayrı konumda çalışır. Kısaca söylemek gerekirse programlardan biri gelen bilgiyi işleyip diğer programa göndermeyi gerçekleştirirken, bilgiyi alan program, işlenmiş bilgiyi görüntüleri ya da kullanır. Bu kavram bize iki değişik ortamda çalışan programlar yazma olanağı getirir.
Genelde kullanıcıların hepsinde yalnız kullanıcı arayüzü olan programlar çalışırken, merkezde veri tabanı erişimi, yazici paylaşımı ve dış dünya ile bağlantı için gereken programlar bulunur. Kullanıcı bilgilerinin ekrandan alınması sırasında kullanıcı bilgisayarında çalışan program merkezdeki programla bağlantı olmadığından tüm işlem yükü yalnız kullanıcı bilgisayarında kalır. Bu işlemler için merkez bilgisayar bir emek harcamaz. Bilgi tamamlanıp merkeze gönderildiğinde ilgili program, gelen bilgi üzerinde gereken işlemleri yapıp sonuçları kullanıcının bilgisayarına iletir. Aradaki iletişim sürekli değildir. İletişim yalnız mesaj alış verişi sırasında kurulur. Ancak aynı anda birden çok kullanıcı bir merkeze bağlantı kurabildiğinden merkezdeki bilgisayar yüksek işlem gücü ile donatılır. Kullanıcı bilgisayarları ise herkesin kullandığı PC'ler olabilir.
Bazı koşullarda tüm kullanıcılara her işi yapan yetki verilmez. Ancak kullandıkları programın veri tabanına ekler yapması, ya da verilerin bazılarını değiştirmesi gerekebilir. Bu durumda İşgören (Sunucu) tüm yetkilerle ile donatılır ve işveren program gerekli mesajı göndererek işlemin yapılmasını ister. Burada işgören ve işveren programlar aynı bilgisayarda çalışabilir. Örneğin bir java applet ile ekrandan girilen bilginin diske yazılması hakkı bir işgören programa mesaj gönderilerek yapılabilir. Burada java applet, bilgiyi alırken kullanıcının yetkisi olup olmadığını, güvenlik kuralları çerçevesinde kontrol eder (kullanıcı adı ve şifresi almak gibi) ve uygun güvenlik bilgilerini mesajla birlikte işgörene gönderir.
Bu nedenle TCP/IP iletişim programları kullanıcılara işveren ve işgören programlar yazarak uygulama alanlarını genişletme olanağı getirir.
Anlattığım ya da anlatacağım bazı temel kavramlar, TCP/IP hakkında teknik bilgileri içermektedir. Amaç, çeşitli uygulamalarda bu kavramları kullanarak iletişim programları yazılımını kolaylaştırmaktır.
Tanımlanmış IP protokolları
Bu tabloda yer alan IP protokollarının kullanım biçimleri TCP/IP iletişimi için önemlidir. Örneğin, programlarda kullanılan socket açma komutunun son parametresi aşağıdaki IP protokollarından biri olmalıdır.
TCP socket protokolları
TCP socket'lerinde bağlantılı türleri socketin özelliğine göre değişir. TCP iletişiminde iki ana kavram vardır. Biri bağlantılı, diğeri bağlantısız iletişim. Bağlantılı iletişimde socket'ten mesaj bekleyen (listen komutu ile socketi dinleyen) programa bağlantı, connect komutu ile yapılır. Bağlantı sağlandıktan sonra mesaj gönderme ve alma işlemi read ve write komutları ile gerçekleşir. Bağlantılı iletişimde kullanılan socket türü SOCK_STREAM olmalıdır. TCP/IP üzerinden iletişimde, hattın yoğunluğu ve kalitesine bağımlı olarak parçalanan TCP paketleri bu socket türü kullanıldığında alıcı socket altında sıralanır ve birleşirilerek TCP katmanına ulaştırılır. Bu durumda uygulama programı, bir read komutu ile tüm mesajı bir seferde okuyabilir.
Kısa mesajlar SOCK_DGRAM socket üzerinden iletilebilir. Bu tür mesajların parçalanması söz konusu olmadığından yukarıdaki sorun yaşanmaz. Bu tür mesajlarda mesaj boyu 256 byte ya da daha kısa olmalıdır. Ve mesajlar hep aynı uzunlukta olmalıdır. Bağlantısız iletişim ortamında kullanılır. Yani socket dinleyen program accept komutu kullanmaz, sockete bilgi gönderen de connect komutunu kullanmaz. Burada yalnızlisten komutu vardır. Programlar karşılıklı "read" ve "write" komutu ile haberleşir. İletişim açısından çok güvenli bir socket haberleşmesi değildir. Daha güvenli ve bağlantılı iletişimde (connected) DATA GRAM mesajları, SOCK_SEQPACKET tipi socket'ler üzerinde iletilmelidir.
Bir bilgisayar içindeki programlar arası iletişim SOCK_RAW tipi socket ile kurulabilir. Bu tür socket'lerde Data Gram tipi mesajlar iletilir.
TCP/IP İletişim Programları Mantığı
Bir sistemde TCP/IP program geliştirme modülleri varsa, programcının bu modülleri nasıl kullanacağı, kullanılmak istenilen socket türüne göre farklıdır. Eğer bağlantılı ve güvenli iletişimi içeren SOCK_STREAM kullanılıyorsa, yazılacak programın görevine göre iletişim komutları şöyle özetlenebilir :
İşveren (Client) Programı :
Bu program hangi bilgisayar ile bağlantı kuracağını belirledikten sonra socket komutu ile socket açar. Socket açıldıktan sonra ilk iş karşı taraftaki programla bağlantı kurmaktır. Bağlantı connect komutu ile kurulur. Bundan sonra işlem, mesaj gönderme ve cevap alma olarak devam eder. İşlem bittiğinde close komutu ile bağlantı kesilir.
İşgören Programı :
İşgören programı hangi bilgisayara hangi TCP portundan bilgi geleceğini bilmelidir. İşgören program her zaman bir TCP protunu dinler. İşgören programın dinlediği port birden çok IP adresi bulunan bir bilgisayarda bulunabilir. Bu durumda sunucu program yalnız bir bilgisayara gelen mesajları dinleyebilir. İstenirse sunucu program o bilgisayar gelen tüm mesajları da dinleyebilir.
İşgören program once socket komutu ile kullanacağı socket'i açmalıdır. İşgören programın bir porttan gelen mesajları dinlemesi icin bind komutunu başlatmış olması gerekir. listen komutuyla sunucu program, ilgili portu dinleyeceğini söyler. Bundan sonraki adım porttan bağlantı beklemektir. Porttan accept komutu ile bağlantı beklenir.
Porttan bağlantı mesajı geldiğinde sunucu program hemen kendini kopyalamalı, kopyalardan biri bağlantı kuran programla bilgi alış verişine başlarken diğer kopya yeni gelecek bağlantılar için portu dinlemeye devam etmelidir.
Mesaj alış verişi biten kopya bağlantı kapandığında çalışmasına son verir. Port dinleyen program bağlantı talebinin sayısına ve belleğin büyüklüğüne bağımlı olarak aynı anda birden çok kopya üretebilir ve aynı anda birden çok bağlantıya hizmet verebilir.
TCP/IP Komutları
gethostbyname : Bu komut verilen bir bilgisayar adına ilişkin yapı tanımını döndürür. Bu yapı tanımında bilgisayarın adresi ve TCP için kullanılan protokolun tanımı vardır. Bu komut kullanıldığında yazılan program INTRANET ya da INTERNET ortamında sorunsuz çalışır. Çünkü kullanılacak bilgisayar ilişkin yapı sistemdeki diğer programlar ve varsa name server tarafından hazırlanır.
socket : Bu komut iletişim için gerekli uç noktayı programa tanıtmak için kullanılır. Çeşitli socket kavramları aşağıda kısaca acıklanmıştır :
· SOCK_STREAM : Sıralanmış ve iki yönlü bağlantı sonrası kullanılabilecek güvenli byte dizileri için geçerli bir socket türüdür.
· SOCK_DGRAM : Kısa ve Sabit uzunluklu bağlantısız mesaj trafiğine elverişli, datagram tipi, çok güvenli olmayan bir socket türüdür.
· SOCK_RAW : Bir bilgisayar içindeki iletişim için kullanılır. Belitilen (ya da adlandırılmış) sendkomutları için DATAGRAM göndermekte kullanılır. UNIZ ortamında yalnız super-kullanıcı (root) bu tür socket'leri kullanabilir.
· SOCK_SEQPACKET : Bu tür socket datagram tipi kısa ve değişmez boylu mesajları bağlantıdan sonra kullanmaya yarar. Güvenli iletişim için gereklidir.
bind : Bu komut bir socket'i bir adrese bağlamak için kullanılır. Bu adres ya yerel bilgisayar adresi, ya da sıfır (0.0.0.0) adresi'dir. Bind komutu öncesinde socket komutu ile socket tanımlanmış olmalıdır.
listen : Bu komut gelen bağlantıları beklemek ve aynı anda gelen bağlantı isteklerini kuyruklamak için kullanılır. Bu komutta kaç tane isteğin kuruklanacağı da belirtilir. Bind komutundan sonra kullanılır.
accept : Bu komut ile socket'e gelecek bağlantı isteği beklenir. Bu komuttan önce socket komutu ile tanım yapılmış olmalı, bind komutu ile socket bir adrese bağlanmış olmalı ve listen komutu ile kuyruk boyu tanımlanmış olmalıdır. Bind, listen ve accept komutları hep bağlantı bekleyen program tarafından kullanılır. Diğer bir deyimle sunucu (iş gören) programı bu komutları kullanır.
connect : Bu komut, işveren programın socket tanımından sonra kullandığı komut olup, karşı tarafta bağlantı bekleyen programa, bağlantı isteğini iletmek için kullanılır. Eğer bağlantı bekleyen program çalışmıyorsa connect komutu hatalı bir biçimde sonlanır. Connect komutu ile accept komutu karşılıklı çalışan komutlardır.
write : Bağlantı kurulduktan sonra uygulama protokolu içinde hangi program bilgi gönderecekse "write" komutunu kullanırken karşı program "read" komutu ile gelecek bilgiyi bekler. Tüm iletişim programlarındaki genel kural ışığında "write" komutunu kullanan program mesajın gidip gitmediğini ancak karşı taraftan bir cevap aldığında anlar. Bu cevaba biz uygulama adımında "acknowledge" deriz. Yani, "write" komutunu kullanan bir program bu komutun peşinden "read" komutunu kullanarak karşı taraftaki programdan cevap bekler. Cevap alındıktan sonra yeni bir "write" komutu gönderilir. Ancak listen komutunda mesaj kuyruklama olanağı olduğundan uygulama sırasında her write komutundan sonra read beklemek aradaki iletişim hızını yavaşlatacağından, belirli sayıda "write" komutundan sonra bir kez "read" kullanmak iletişimi hızlandırır. Bu tür uygulamaya "windowing" adı verilmektedir.
Örneğin her yedi "write" komutundan sonra bir kez "read" komutu ile cevap beklemek, cevap geldiğinde yedi mesajın da karşı taraftaki program tarafından doğru alındığını belirttiği varsayılırsa gönderen program mesaj alındı yanıtını gönderilen her mesajdan sonra değil de yedi mesajdan sonra alması işlemi hızlandırır. Ancak cevap gelmemiş ise gönderen program aynı mesajları tekrar göndermek durumundadır. Çünkü karşı tarafın ne kadar mesajı aldığı bilinmemektedir. Bu nedenle "windowing" karvarı bozuk hatlarda iletişimi hızlandıracağına yavaşlatabilir. Dinamik "windowing" kullanmak, tekrarların sayısına göre "windowing" katsayısını değiştirmek iletişim programları açısından en olumlu ve verimli kullanım biçimidir.
select : read komutu karşı taraftan cevap gelinceye kadar sonsuz bu komutta bekleyen bir yapıya sahiptir. Bu ise iletişim açısından sakıncalıdır. En uygun yöntem belirli bir sürede karşı taraftan cevap gelmeyince "zaman aşımı" olduğunu varsaymak ve iletişimin aksadığına karar vermiş olmaktır. Zaman aşımını sağlamanın bir yöntemi select komutunu kullanmaktır. Select komutu yalnız zaman aşımını belirlemek için kullanılmaz. Aynı anda birden çok socket ya da seri uçtan hangisinden mesaj geldi ise onu algılamaya da yarar.
Bu özelliği ile select komutu, UNIX ortamında "Interrupt" bekleme işlemi gibi kullanılmış olur. Select komutu ile beraber kullanılan macro'lar aracılığı ile mesaj beklenecek socket ve seri uçlar önce bu komutun "Interrupt" vektörüne tanıtılır. Daha sonra bekleme süresi saptanır. Komut çalışmaya başladığında bekleme süresi içinde hangi socketten cevap geldi ise onun bilgisini programa iletir. Eğer hiç cevap gelmemiş ise komut programa "zaman aşımını" döndürür. Böylece select komutu ile bir program, birden çok socketten mesaj bekleyebilir ve bunun için socketler arasında "poll" işlemi yapmamış olur. Bilindiği gibi "polling" işletim sistemine ve işlemciye gereksiz işlem yükü getirmektedir. Sistemin verimliliği "poll" yapan programlar yüzünden azalabilir.
read : Select komutundan hemen sonra kullanılırsa sockette bekleyen mesajın okunması için gerekli olan komuttur. Bu biçimi ile kullanılınca iletişimin aksaması durumunda bile programın asılı kalması önlenmiş olur. Select kullanılmadan doğrudan "read" komutu kullanılmış ise program karşı taraftan mesaj gelmeden bir sonraki konuma geçemez. Bu şekilde read komutuna asılı kalan programlar ancak "kill" komutu ile dışarıdan yapılacak girişimle durdurulabilir.
close : Bu komut açılmış bir socket'i kapatmak icin kullanılır. Eğer program son bulmazsa ve close komutu kullanılmazsa, karsi taraf bağlantıyı kesse bile, socket kullanımda kalır, ancak program son bulunca serbest bırakılır.
|
PROGRAMLAMA
SOCKET NEDIR?
---------------------
Diger programlarla konu$abilmek icin bir yoldur(ya da IPC=Interprocess communication'nin temel ta$idir).
Bu i$ icin standart file descriptor'leri kullanilir.File descriptor'ler, int turunden olan temel I/O
object'leridir.Detaylari sonra orneklerle goreceksiniz.
Genel olarak programcilar icin ba$vurulan 3 tur socket vardir: (hepsi bu 3 tane degil, bizim de ilgileneceklerimiz bunlar)
1- stream socket (SPX) (SOCK_STREAM) telnet gibi, guvenli(o anlamda guvenli degil), cift yonlu, kontrollu paketler. TCP(Transmission Control Protocol) kullanir. Paketler 2 yonludur, eger A,B,C harflerini gonderirseniz kar$i taraf da A,B,C sirasiyla alir. www browserlarinin kullandigi HTTP(hyper text transfer protocol) protocolu de stream turunden socket kullanirlar. ornegin bir adrese telnet adres port:80 yapip GET pagename yaparsaniz HTML(hyper text mark-up language) text olarak aynen size gelir gibi gibi.
2- datagram socket (IPX) (SOCK_DGRAM)
paket sirasi kari$ik olabilir, bilgi aki$i TCP gibi guvenli olmayabilir. paketi gonderirsiniz, belki gitmeyebilir(karsi taraf ACK gonderene kadar).Giden paketler de sirali gitmeyebilir. tftp,bootp,windows'taki realplayer ya da bir cok trojan bunu kullaniyor. UDP(User datagram protocol) kullanir.
3- raw socket (SOCK_RAW)
(bir cok paket turunu degerlendirmek icin ya da ornegin birden cok protocole ayni zamanda eri$mek icin kullanilir)
bunlarin her birine ornek a$agida var.gelecegiz.
Simdi. ilk basta acayip gelebilecek fakat programlarimizda kullanacagimiz birkac ozellige bakalim.
Diger detaylari ornek programlarin icinde anlatmaya calistim. Please inspect them olayi ;P Burada bahsedilmeyenlerin detaylarini nerede bulacaksin? cevap: internet ;)
SOCKET() : File Descriptor Tanimlayalim
-----------------------------------------------------
evet..yanli$ okumadin..unix aleminde aslinda her $ey bir file'dir ;)
tipki dosya i$lemleri gibi, socket'ler de aslinda bir tur file'dir.
------------------------------------------------------
#include #include
int socket(int domain, int type, int protocol);
domain: AF_INET
type: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW gibi turlerden biri olacak. protocol: $imdilik 0(sifir) olsun.daha sonra bununla orneklerde goreceksin.
$imdi, programlarimiz icin gerekli olabilecek struct'lara ornek olsun diyerek bakalim.
---------------------------------------------------------------------------
struct sockaddr { unsigned short sa_family; /* addres turu, AF_xxx */ char sa_data[14]; /* 14 bytelik protocol addresi */ }; --------------------------------------------------------------------------- bu structure, bir cok turden socket icin socket adreslerini tutar. sa_family : AF_INET gibi. sa_data :socket icin destination adresi ve port noyu icerir.
programcilar, i$i internet tarafina ta$imak icin $u structure'i yazmi$lar:
--------------------------------------------------------------------------- struct sockaddr_in { short int sin_family; /* Addres turu */ unsigned short int sin_port; /* Port no */ struct in_addr sin_addr; /* Internet addresi */ unsigned char sin_zero[8]; /* struct sockaddr ile ayni buyuklukte */ }; --------------------------------------------------------------------------- bunlari birazdan kullanacagiz, hepsi butunle$ecek.biraz sabir.
baska structure yok mu? var ..
diger structure'larin kullanimlarini ornekteki dosyalardan bakabilirsiniz. tum structure'lar o kadar mi? hayir..senin Linux'ta hepsinin detaylari var..bkz..*.h files gibi.
BIND() : socketi bir porta baglayalim.
--------------------------------------------- Bir socketimiz olduktan sonra baglanti icin bir port belirlemeliyiz(stream.udp).
#include
#include
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
sockfd: yukarida bahsettigimiz socket file desciptor.
struct sockaddr *my_addr : port ve IP adresimizi belirtecek bolum. addrlen: sockaddr buyuklugu,basitce $unu kullan: sizeof(struct sockaddr)
ORNEKLER : Vakit geldi.
---------------------------------
bu programlari denedikten sonra kurcalayabilirsin..al hepsi senin olsun ;)
internette artik search engine'lerdeki kutulara "socket programming" and linux gibi yazmanin zamani geldi de mi?
NOT: ASAGIDAKI PRGLARDA COMPILE SIRASINDA HATA VERIRSE : MAIL TO ME PLEASE.
buraya aktardiktan sonra biraz daha elledim orasina burasina, ondan diyorum. PRG'LARIN YAZIM $EKLI C PRG YAZMA ETIGINE UYMUYOR CUNKU COPY-PASTE YAPTIM. KUSURA BAKMAYIN KIZLAR ;)
1- ornek1-tcp.c dosyasina bakiniz,inceleyiniz.Orada detayli aciklamalar mevcut.
2- ornek2-udp.c dosyasina bakiniz,inceleyiniz.Orada detayli aciklamalar mevcut. 3- portdancer.c : daha tamamlanmamis hali..fakat is goruyor. calismayan send message kismini gordun mu? ;)
***************************************CUT HERE-TOP OF 1ST MODEL PRG*****
/* tcp detector by intruder.-tH3 3Lus1v3 a member of www.trscene.org regardz to ALL babez.
bu prg, www.trscene.org ziyaretcilerine Linux socket programming
temellerini anlatabilmek icin ornek olarak yazilmistir.
degistirilir, baska formlara getirilebilir vs vs.
tamamiyla prototip,model,kaLIp olarak dusunebilirsiniz.
bunun ne yaptigini anlamak icin calistir...
sonra kendine telnet 127.0.0.1 portno yapabilirsin.
*/
#include
#include #include #include #include #include #include #include #include
#define kuyruk 10 /* kuyrukta kac guncel baglanti kalacak? 10 diyelim no prob. */
int main(int argc, char *argv[])
{ int sockfd, new_fd; /* socket degiskenlerimiz */ struct sockaddr_in my_addr; /* kendi adres bilgimiz */ struct sockaddr_in their_addr; /* client'in adres bilgisi */ /* biraz degisken tanimlayalim, lazim falan olur ;) */ int sin_size; char laf, *mesaj; int uzunluk,gidenbyte; struct hostent *h; /* gethostname icin */ char *hostname; /* I love pointers ;P */ int pid; /*konuyla pek ilgisi yok ama, server tarafindaki pid nosu.*/
char *mesaj2[30];
int i;
if (argc<2)
{ printf("\nUsage: %s portnumber\n",argv[0]); printf("\n"); return(-1); }
printf("\nNow,dancing with port %s is active.Waiting for a connection.\n",argv[1]);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket"); exit(1); } /* her zaman error check yapmaliyiz ! sence neden ? */
my_addr.sin_family = AF_INET; /* cinsimizi belirleyelim */
my_addr.sin_port = htons(atoi(argv[1])); /* portumuzu belirleyelim .htons(5555) gibi sabit de yapabiliriz. burada kullanicinin girdigi deger ataniyor. */
my_addr.sin_addr.s_addr = INADDR_ANY;
/* kendi IP'miz olsun bu tabii ki. eger IP'mizi biliyorsak ya da sabitse ornegin: my_addr.sin_addr.s_addr ="199.99.125.63" */
bzero(&(my_addr.sin_zero), 8);
/* struct'in kalan kismini 0'layalim.bunu kural olarak gor, $imdilik aynen kullan.ihmal de etme. */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
{ perror("bind"); exit(1); } /* porta baglama sirasinda hata olu$tu mu kontrol ettik.Eger hata ol$ursa program hemen kapaniyor.Eger hatalari kontrol etmezsek 'core dumped' gibi moral bozucu ve beklenmedik anda gocen programlarimiz olur.*/
if (listen(sockfd, kuyruk) == -1) {
perror("listen"); exit(1); } /* listeni kontrol ettirdik.aynen kullan */
while(1) { /* ana accept() loop'umuz */
sin_size = sizeof(struct sockaddr_in); if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \ &sin_size)) == -1) { perror("accept"); continue; } printf("\nwarning....: %s\n",inet_ntoa(their_addr.sin_addr));
/* bi takim paket belirleme numuneleri vs vs..alternative'leri de izle */
hostname=inet_ntoa(their_addr.sin_addr); /* compile sirasindaki pointer warning buradan kaynaklaniyor.. tur donu$umunu kontrolsuz yaptim ondan oluyor.ignore it ;P */
if ((h=gethostbyname(hostname))==NULL)
{ herror("gethostbyname"); exit(1); } printf("hostname-1= : %s\n",hostname); printf("hostname-2 : %s\n", h->h_name); printf("IP : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr))); pid=getpid(); printf("Server side PID: %d\n",pid); printf("Internet address is %s\n", inet_ntoa(their_addr.sin_addr.s_addr)); printf("Server side port number is %d\n", ntohs(my_addr.sin_port)); printf("Client side port number is %d\n", ntohs(their_addr.sin_port)); printf("Internet family ID is %d\n", their_addr.sin_family);
mesaj="yew are detected when performing some scan job.
\nI can see you babe.\n";
if (!fork()) { /* bu bizim child process */
if (send(new_fd, "oh yeah..cool ha?\n", 18, 0) == -1) perror("?\n"); /* oradaki 18 mesajin uzunlugu kadar.say istersen ;) aslinda, sizeof kullanmak daha mantikli degil mi? her seferinde byte mi sayacagiz.*/
/* send mesaj ornegi-mesaj */
uzunluk=strlen(mesaj); gidenbyte=send(new_fd,mesaj,uzunluk,0);
/* baska bi sekilde mesaj gonderme ornegi-mesaj2 : an array is wife of a pointer ;P*/
for (i=0;i<21;++i) { mesaj2[i]=".\n"; /* tum elemanlari . ile doldurduk garip karakterler gitmesin diye */ }
mesaj2[1]="\n";
mesaj2[2]="ok1\n"; mesaj2[3]="ok2\n"; /* dizinin kalan kismini yazmiyorum..ornekti bu..sen doldur istersen kalan kisim . olarak gidecek */
/* simdi olusturdugumuz mesaj2'yi gonderelim */
for (i=0;i<5;++i) { gidenbyte=send(new_fd,mesaj2[i],strlen(mesaj2[i]),0); } /*bu programi calistir..sonra kendine telnet yap sectigin porttan. neyin gittigini daha iyi gorursun. */
close(new_fd);
exit(0); } close(new_fd); /* buna artik ihtiyac yok */
while(waitpid(-1,NULL,WNOHANG) > 0); /* child process'i de temizle */
} } /* main function ended*/ ***************************************CUT HERE-BOTTOM OF 1ST MODEL PRG*****
***************************************CUT HERE-TOP OF 2nd MODEL PRG*****
/*
udp detector by intruder.-tH3 3Lus1v3 a member of www.trscene.org regardz to ALL babez.
bu prg, www.trscene.org ziyaretcilerine Linux socket programming
temellerini anlatabilmek icin ornek olarak yazilmistir.
degistirilir, baska formlara getirilebilir vs vs.
tamamiyla prototip,model,kaLIp olarak dusunebilirsiniz.
bunun ne yaptigini anlamak icin calistirirken portno olarak 31337 kullan.
sonra bounix gibi bo clientindan kendine baglanmaya cali$ ya da inetteki arkada$in windowstan denesin.
*/
#include
#include #include #include #include #include #include #include #include
#define kuyruk 10 /* kuyrukta kac guncel baglanti kalacak? 10 diyelim no prob. */
#define MAXBUFLEN 100
int main(int argc, char *argv[])
{ int sockfd, new_fd; /* socket degiskenlerimiz */ struct sockaddr_in my_addr; /* kendi adres bilgimiz */ struct sockaddr_in their_addr; /* client'in adres bilgisi */ /* biraz degisken tanimlayalim, lazim falan olur ;) */ int sin_size; int uzunluk,gidenbyte; struct hostent *h; /* gethostname icin */ char *hostname; /* I love pointers */ int pid;
int addr_len,numbytes;
char buf[MAXBUFLEN];
if (argc<2)
{ printf("\nUsage: %s portnumber\n",argv[0]); printf("\n"); return(-1); }
printf("\nNow,dancing with port %s is active.Waiting for an UDP connection.\n",argv[1]);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket"); exit(1); }
my_addr.sin_family = AF_INET; /* cinsimizi belirleyelim */
my_addr.sin_port = htons(atoi(argv[1]));/* portumuzu belirleyelim */ my_addr.sin_addr.s_addr = INADDR_ANY; /* kendi IP'miz olsun bu tabii ki */ bzero(&(my_addr.sin_zero), 8); /* struct'in kalan kismini 0'layalim */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) { perror("bind"); exit(1); }
while(1)
{ addr_len = sizeof(struct sockaddr); if ((numbytes=recvfrom(sockfd, buf, MAXBUFLEN, 0, \ (struct sockaddr *)&their_addr, &addr_len)) == -1) { perror("recvfrom"); exit(1); }
printf("got packet from %s\n",inet_ntoa(their_addr.sin_addr));
printf("packet is %d bytes long\n",numbytes); buf[numbytes] = '\0'; printf("packet contains \"%s\"\n",buf);
/* bi takim belirleme numuneleri vs vs..alternative'leri de izle */
hostname=inet_ntoa(their_addr.sin_addr); /* compile sirasindaki pointer warning buradan kaynaklaniyor..ignore it ;P */
if ((h=gethostbyname(hostname))==NULL)
{ herror("gethostbyname"); exit(1); } printf("hostname-1= : %s\n",hostname); printf("hostname-2 : %s\n", h->h_name); printf("IP : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr))); pid=getpid(); printf("Server side PID: %d\n",pid); printf("Internet address is %s\n", inet_ntoa(their_addr.sin_addr.s_addr)); printf("Server side port number is %d\n", ntohs(my_addr.sin_port)); printf("Client side port number is %d\n", ntohs(their_addr.sin_port)); printf("Internet family ID is %d\n", their_addr.sin_family); printf("----------------------\n\n");
} /* while ended */
close(sockfd);
} /*main fuction ended */
***************************************CUT HERE-BOTTOM OF 2nd MODEL PRG*****
***************************************CUT HERE-TOP OF 3rd MODEL PRG*****
/* portdancer.c by intruder.-tH3 3Lus1v3 regardz to ALL babez. anoher derivation of miplog for special purposes
*/
/* asagidaki include header'larinin sayisi gozunu korkutmasin..uzerinde oynadigim ve
burada bazi bolumleri cikarilmis yerler vardi..ayiklamaya ugrasmadim..aynen kullanabilirsin..zarari yok.*/
#include
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include
int main(int argc, char *argv[])
{ fd_set set; int TCPfd, ICMPfd, UDPfd; int int_of_send; int pid; char *msg;
struct ippkt_tcp
{ struct iphdr ip; struct tcphdr tcp; char buffer[10000]; }pkt_tcp;
struct ippkt_icmp
{ struct iphdr ip; struct icmphdr icmp; char buffer[10000]; }pkt_icmp;
struct ippkt_udp
{ struct iphdr ip; struct udphdr udp; char buffer[10000]; }pkt_udp;
struct servent *se;
struct in_addr i; struct hostent *he;
if (argc<2)
{ printf("\n\n",argv[0]); printf("\n"); /*return(-1);*/ }
printf("\nNow,dancing mode with ports is active.\nWaiting for a connection...\n",argv[1]);
printf("Server side pid : %d\n",getpid());
/* 1 defaya mahsus..affet..;P */
TCPfd=socket(AF_INET, SOCK_RAW, IPPROTO_TCP); /* tcp 6 */ ICMPfd=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); /* icmp 1 */ UDPfd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP); /* udp 17*/ while (1)
{
FD_ZERO(&set); FD_SET(TCPfd,&set); FD_SET(ICMPfd,&set); FD_SET(UDPfd,&set);
select(FD_SETSIZE, &set, NULL, NULL, NULL);
/* TCP CONNECTION DETECTED */
if (FD_ISSET(TCPfd,&set)) { read(TCPfd, (struct ippkt_tcp *)&pkt_tcp,9999);
se=getservbyport(pkt_tcp.tcp.dest, "tcp");
i.s_addr=pkt_tcp.ip.saddr;
he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET);
if(se == NULL) printf("TCP-1, port: %d--", ntohs(pkt_tcp.tcp.dest));
else printf("TCP-2,port:%s--",se->s_name); /* TCP-1: telnet gibi...TCP-2:rlogin gibi */
printf("from :%s--",he->h_name);
printf("IP:%s\n",inet_ntoa(i)); printf("address type:%d--",he->h_addrtype); printf("address length: %d\n",he->h_length);
/* SEND MESSAGE TO LEANOV */
/*msg="hi babe";
int_of_send=send(TCPfd,msg,7,0); int_of_send=write(TCPfd,"hi babex",9999); */ }
/* ICMP CONNECTION DETECTED */
if (FD_ISSET(ICMPfd,&set)) { printf("ICMP connection detected.\n");
read(ICMPfd, (struct ippkt_icmp *)&pkt_icmp, 9999);
i.s_addr=pkt_icmp.ip.saddr; he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET); printf("from :%s--",he->h_name); printf("IP:%s\n",inet_ntoa(i)); printf("address type:%d--",he->h_addrtype); printf("address length: %d\n",he->h_length);
switch(pkt_icmp.icmp.type) {
case ICMP_DEST_UNREACH : printf("Destination unreachable\n"); break; case ICMP_SOURCE_QUENCH : printf("source quench\n"); break; case ICMP_REDIRECT : printf("source route\n"); break; case ICMP_ECHO : printf("Ordinary ping\n"); break; case ICMP_INFO_REQUEST: printf("info request\n"); /* buradaki ICMP paket kontrol tiplerini cogaltabilirsin. bkz. senin include'daki *.h dosyalarindan birisinde bunun tam listesi var. */
break;
} /* switch ended */
}
/* UDP CONNECTION DETECTED */
if (FD_ISSET(UDPfd,&set)) { printf("UDP connection detected.\n"); read(UDPfd, (struct ippkt_udp *)&pkt_udp,9999); i.s_addr=pkt_udp.ip.saddr; he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET); se=getservbyport(pkt_udp.udp.dest, "udp"); printf("UDP, port: %d", ntohs(pkt_udp.udp.dest)); printf("from :%s--",he->h_name); printf("IP:%s\n",inet_ntoa(i)); printf("address type:%d--",he->h_addrtype); printf("address length: %d\n",he->h_length); }
FD_ZERO(&set);
FD_CLR(TCPfd,&set); TCPfd=socket(AF_INET, SOCK_RAW, IPPROTO_TCP); /* tcp 6 */ ICMPfd=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); /* icmp 1 */ UDPfd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP); /* udp 17*/
} /* while ended */
printf("flag.. final one");
} /*end of main(..) ;P */
***************************************CUT HERE-BOTTOM OF 3rd MODEL PRG*****
|
TCP/IP PROGRAMLARIÖRNEK CLIENT PROGRAMI
Bu program işgören (Server) bilgisayarda bulunan programla iletişim kurar ve mesaj gönderip, bu mesajın yanıtını bekler. Program işlemin bittiğini "son" değeri göndererek işgören programa bildirir. İki program arasındaki iletişim, "socket" kavramı ile kurulur. Client, "socket" açtıktan sonra "socket"i işgören programın adresine "connect" komutu ile bağlar. Daha sonra bu socket'e "write" komutu ile mesaj gönderir, "read" komutu ile gelen mesajı okur. İşlem bittiğinde işgören programa "son" mesajı gönderilir ve "socket" kapatılır.
Bu programda, hata kontrol adımları programın boyunu büyütmemek ve mantığını bozmamak için çıkarılmıştır. Programın boyu ne kadar kısa olursa o kadar kolay anlaşılır. İletişim protokolu olarak TCP/IP yerine AF_UNIX kullanılmıştır. Burada işgören program ve müşteri aynı bilgisayarda çalışır. TCP/IP kullanıldığında önce, "gethostbyname" komutu ile adres ve kullanılan protocol belirlenir. Daha sonra "getservbyname" komutu ile TCP/IP servisi için port numarası belirlenir "sockaddr_in" yapısı bu bilgilerle doldurulur. En son "connect" işlemi çalıştırılır.
#include #include #include main() { struct sockaddr_un to; int s; int tolen, len, n, maxlen; char msg[512], inbuf[512]; maxlen = 512; /********* socket acma islemi ***********/ s = socket(AF_UNIX,SOCK_STREAM,0); /********* isgoren programa baglanma *********/ to.sun_family = AF_UNIX; /* socket protocol ailesi */ strcpy(to.sun_path,"address"); /* socket adresi */ tolen = sizeof(to.sun_family) + sizeof(to.sun_path); connect(s,(struct sockaddr *) &to, tolen); memset(msg,'\0',maxlen); while(strncmp(msg,"son",3)) { /* gonderilen mesaj son degilse devam et */ printf("mesajı girin :"); gets(msg); len = strlen(msg); write(s,msg,len); /* mesaj gonderme */ n = read(s,inbuf,maxlen); /* cevap beklemede okunan n byte olur */ inbuf[n] = '\0'; puts(inbuf); /* gelen cevabi ekrana yazma */ } close(s); /* islem bitti socket kapatildi */ } ÖRNEK SERVER PROGRAMI
Server program, Client programlardan gelen bilgileri alır ekrana yazar sonra Client programa mesajın alındığını bildirir. Server, açılan bir "socket"i "bind" komutu ile adrese bağlar ve client bağlantıları için "listen" konumuna geçer. Client'tan gelen "connect" mesajlarını algılamak için "accept" komutu kullanılır. Server her zaman bir tane "accept" komutunda boş beklerken diğer kopya, bağlantı kurulmuş "socket" ten okuma yapar, okunan bilgiye cevap verir. Okunan mesaj "son" ise bu kopya işlemini bitirir.
#include #include #include #include jmp_buf jbuf; void bitti() { longjmp(jbuf,-1); } main() { struct sockaddr_un from; int s, s1; int fromlen, len, n, maxlen, maxqueue; char inbuf[512]; maxlen = 512; maxqueue = 10; signal(SIGTERM, bitti); if(setjmp(jbuf) != -1) { /********* socket acma islemi ***********/ s = socket(AF_UNIX,SOCK_STREAM,0); /********* sockete adres baglama **********/ from.sun_family = AF_UNIX; /* socket protocol ailesi */ strcpy(from.sun_path,"address"); /* socket adresi */ fromlen = sizeof(from.sun_family) + sizeof(from.sun_path); bind(s,(struct sockaddr *) &from , fromlen); /********* bekleme konumuna alma **********/ listen(s,maxqueue); /********* connect bekleme ****************/ /* client program connect bekleyen yoksa hata verir bu nedenle server connect bekler durumda olmalidir. */ do { s1 = accept(s,(struct sockaddr *) &from , fromlen); /**** connect geldi fork ile bir kopya baslat *****/ /* bir baska client connect gonderdiginde, server accept komutunda degisle, bu komuta gelinceye kadar beklemektedir. Bunun icin yeni bir server kopyasi calismali ve connect beklemelidir. */ if(fpid = fork()) { memset(inbuf,'\0',maxlen); while(strncmp(inbuf,"son",3)) { /*** okumayi eski kopya yapar, yeni kopya hala connect beklemektedir ****/ n = read(s1,inbuf,maxlen); inbuf[n] = '\0'; /* gelen bilgiyi isleme alma */ puts(inbuf); /* mesaj alindi bilgisini gonderme */ write(s1,"OK",2); } } } while(fpid == 0); } if(fpid == 0) { /*** connect beklerken kill -15 ile server durdurulursa ****/ close(s); unlink(from.sun_path); } else close(s1); }
Client programda olduğu gibi işgören program da AF_INET protokol ailesi ile kullanıldığında "gethostbyname" komutu ile yerel bilgisayarın adresi alınır. Daha sonra, "getservbyname" komutu ile INET servisinin port numarası alınır ve "sockaddr_in" yapısı bu bilgilerle doldurulur. Diğer komutlarda işlem akışı örnek programda anlatıldığı gibidir.
|
SDLC (Synchronous Data Link Communication)GİRİŞ
SDLC protokolune göre SNA ortamında iki tip bilgisayar vardır. Bunlardan merkezdekine birincil bilgisayar, uzaktan bağlanana ise ikincil bilgisayar denir. Birincil bilgisayar kurulan iletişim yöntemini denetleyen bilgisayardır. Fiziksel birimler birbirleri ile iletişimi kurduktan sonra, her iki bilgisayarda yer alan mantıksal birimler birbirleri ile oturum başlatır. Her mantıksal birim karşısındaki mantıksal birimle başka birimlerden bağımsız oturum kurabilir. Bir hat üzerinde birden çok ikincil bilgisayar olabilir. Bu bilgisayarlar fiziksel birimlerdir. Aynı hat üzerindeki birden çok fiziksel birim C1, C2 gibi adreslerle birbirlerinden ayrılır. Aynı hattı paylaşımlı kullanırlar. Bir fiziksel bilgisayarın karşı tarafa bağlantısı için gereken SDLC komutları şöyledir :
| ||||||||||||||||||||||
MAKE KOMUTU ve MAKEFILE
GENEL BİLGİLER
make komutu çalıştırıldığı directory'de makefile veya Makefile varsa burada belirtilen işlemleri yapar.make komutu makefile içindeki hedef tanımlara ulaşmak için tanımlanan bağımlılıkları da kullanarak belirtilendirectory'de bulunan tüm tarihi geçmiş kütüklerden liste oluşturur ve tanıma uygun işlemi yapar.
make programı tüm çevre (environment) tanımlarını okur. Boş olan tanımları dikkate almaz. "makefile" içindeki çevre değişkenlerine yapılan atamalar, bu değişkenlerin değerini değiştirir.
MAKEFLAGS isimli çevre değişkeni bu değişken "make" komutu için -f ve -p seçenekleri hariç, diğer komut seçeneklerini içerir. "make" programı bu değişkende tanımlanan seçeneklerle çalışır.
Seçenekler ne olursa olsun makefile içindeki $(MAKE), her koşulda çalıştırılır.
EKLEME KÜTÜKLERİ (INCLUDE FILES)
makefile içinde kullanılan include deyimi satırın başından başlar. Boşluk veya "tab" tuşundan sonrası kütük adı olarak kullanılır. "make" komutu include ile gösterilen kütüğü bulamaz ise "kütük bulunamadı" hatası verir.sinclude aynı amaç için kullanılır. Ancak kütük bulunamaz ise hata vermeden make işlemlere devam eder.
makefile "#!alternate_make" ile başlıyorsa, aynı çevre değişkenleri ile başka bir "make" kullanılır. #! satırında gerekiyorsa başka parametreler de tanımlanabilir. Bu satır makefile içinde tüm make komutlarından önce tanımlanmalıdır.
string1 = string2
gibi tanımlara macro tanımlar denir. macro adlarının ilk karakteri harf olmalıdır. Macro adlarında çoğu kez büyük harf kullanılır. macro adları içinde "._-+~" bulunabilir. macro tanımında string2 açıklama (comment) dışında satır sonu karakterine kadar olan herşeydir. $(string1) kullanılan her yerde string1 yerine string2değeri açılır.
$(string1[subst1=subst2])
biçimindeki tanımlarda seçenekli taşıma ve açma işlemi vardır. Macro içindeki subst1 bulunan her yeresubst2 değeri taşınır. Özel koşul olarak subst1 boş ise subst2 macronun sonuna eklenir.
MAKE İÇİNDEKİ (INTERNAL) MACRO TANIMLARI
Bu macroların sonuna D veya F eklenirse anlamları değişir. D eklenirse adlandıral macronun directory bölümü F eklenirse macronun kütük bölümü anlaşılır. Eğer $(@D) işleminde directory yoksa ./ açılan değer olur.
SON EKLER
Bazı adların bağımlı olduğu ön koşullar vardır. Örneğin .o her zaman .c ve .s gibi son eklere bağımlıdır. Eğer bu tür kütükleri günlemek için gerekli koşul makefile içinde yoksa veya kütük bulunamıyorsa, son ön koşuldan hedefi yaratmak için gereken derleme yapılır. Bu durumda make, son ekleri inceleyerek bağımlılık koşullarını belirler ve ilgili hedef kuralı bulur. Bu tür INTERNAL kuralları listelemek için
make -p -f/dev/null
komut satırı kullanılır. Bağımlılık kuralları makefile içinde yeniden tanımlanabilir veya -r komut seçeneği ile tümüyle atlanabilir.
Yukarıdaki anlatımda (bağımlılık kuralları) eğer '~' kullanılırsa, make programı gerekli kaynak programı SCCS (Source Code Control System) altından alır. Yani .c~.o kuralı SCCS altındaki C kaynak programını .o kütük haline dönüştürür.
makefile .c şeklinde bir kural x.c den nasıl x elde edileceğini gösterir. Bu işlem bir kaynaktan hedef elde etmek için önemlidir (örneğin shell script veya C programları). Null Suffix kuralı, birden çok bağımlılık durumunda make tarafından dikkate alınmaz.
Sistemde kullanılacak başka son ekler .SUFFIXES listesinde belirtilir. Bu listede yer alan son ekler ön koşul sıralamasına göre yerleştirilmelidir. Daha önceki belirtilen komut satırı ile bu tür son ek listesi ve bağımlılıklar kullanılan sistemdeki varsayılan değerleri görmek için alınabilir.
Kullanıcılar makefile içinde
prgm: a.o b.o cc a.o b.o -o prgm a.o b.o: incl.h
gibi kurallar tanımlayarak standard bağımlılıklara ekler yapabilirler.
kullanılabilecek macro tanımları :
CFLAGS cc için gereklidir LFLAGS lex için gereklidir YFLAGS yacc için gereklidir.
Bağımlılık ön koşulları makefile içinde kontrol edilebilir. .c son ekinden .o elde etmek için .c.o: kuralı tanımlanır. Burada bağımlılık belirtilmez. İçinde / olmayan ve . ile başlayan bir hedef her zaman bir kuralı belirtir, gerçek hedef değildir.
KITAPLIKLAR (LIBRARIES)
Eğer bir macro adı ve bağımlılık kuralında parantezler varsa buna arşiv kitaplığı denir. Yani lib(file.o) ve $(LIB)(file.o) içinde file.o olan arşiv kütüphanesini belirtir.
Arşiv kitaplığına ilişkin kurallar .XX.a tipindedir. Burada XX arsiv kitaplığı üyelerinin oluşturulduğu son ektir. XX arşiv üyeleri son ekinden farklı olmalıdır. Yani lib(file.o) açıkça file.o ya bağlı olamaz. Örnek
lib: lib(file1.o) lib(file2.o) lib(file3.o) @echo lib is non up-to-date .c.a: $(cc) -c $(CFLAGS) $< $(AR)$(ARFLAGS)$@$*.o rm -f $*.o
Bu kural make içinde zaten hazır olarak vardır. Daha ilginç bir örnek :
lib: lib(file1.o) lib(file2.o) lib(file3.o) $(CC) -c $(CFLAGS) $(?:.o=.c) $(AR) $(ARFLAGS) lib $? rm $? @echo lib is now up-to-date .c.a:;
Bu örnekte macro içinde yerine koyma kuralı kullanılır. $? lib içindeki kütüklerin listesidir. Yerine koyma kuralı tüm .c leri .o ya çevirir. Bu örnekteki .o.a:; makefile içinde kuralın kapatıldığını gösterir. Burada kullanılan noklaı virgül ile kuralın kapatılması sağlanır. Bu tür arşiv kitaplıklarında yaratma/günleme işlemi asm ve C dili karışımı kaynak programlar kullanıldığında çok yararlıdır ve işlemi hızlandırır.
PARALEL ÇALIŞTIRMA
make komutundaki -P seçeneği parelel çalıştırmayı başlatır. Bu işlem için make komutu önce tüm bağımlılıkları kaldırır ve sonuçta oluşan kümeleri aynı anda açar. Aynı anda yapılan işlem sayısı faktörü en çok iki olabilir. PARALLEL çevre değişkeni ile bu sayı değiştirilebilir.
Örnek Makefile kütükleri :
SHELL = /bin/sh
MAKE = make # Burada all ve install hedef tanımları include/printer.h kütüğüne # bağımlıdır. make programı bu bağımlılığa göre src directory'si # altındaki Makefile kütüğüne aynı parametrelerle bakar.
all install: include/printer.h
cd src; $(MAKE) $@
# bu tanımda printer.h kütüğünde yapılan bir değişiklik varsa
# configurasyon programı çalıştırılır. Bu program kullanılan # UNIX sistemi özelliklerine göre yeni Makefile yaratır.
include/printer.h:
configure
clean:
cd src; $(MAKE) $@
# src/Makefile
DESTOWN = admin DESTGRP = pamuk DESTBIN = ../bin
DEFINES = -I../include -DUNIX -DAIX
CC = cc CFLAGS = -g $(DEFINES) LIBS = -lcurses -ltli_r PROGRAMS = yazserv npbaslat sendmsg SRCS = sendmsg.c pbaslat.c yazserv.c HDRS = ../include/printer.h YAZSRV_OBJS = yazserv.o SNDMSG_OBJS = sendmsg.o BASLAT_OBJS = pbaslat.o
.c.o:
$(CC) -c $(CFLAGS) $<
all: $(PROGRAMS)
yazserv: $(YAZSRV_OBJS)
$(CC) $(YAZSRV_OBJS) $(LIBS) -o $@
npbaslat: $(BASLAT_OBJS)
$(CC) $(BASLAT_OBJS) $(LIBS) -o $@
sendmsg: $(SNDMSG_OBJS)
$(CC) $(SNDMSG_OBJS) $(LIBS) -o $@
install: $(PROGRAMS)
cp $(PROGRAMS) $(DESTBIN)
cd $(DESTBIN) && strip $(PROGRAMS) cd $(DESTBIN) && chmod 755 $(PROGRAMS) cd $(DESTBIN) && chown $(DESTOWN):$(DESTGRP) $(PROGRAMS)
clean:
cd $(DESTBIN) && rm -f $(PROGRAMS)
-rm -f $(PROGRAMS) $(YAZSRV_OBJS) $(BASLAT_OBJS) $(SNDMSG_OBJS)
yazserv.o: $(HDRS)
sendmsg.o: $(HDRS) pbaslat.o: $(HDRS)
EK
MAKE KOMUTU VERI TABANI
# GNU Make version 3.74,
# by Richard Stallman and Roland McGrath. # Copyright (C) 1988, 89, 90, 91, 92, 93, 94, 95 # Free Software Foundation, Inc. # This is free software; # see the source for copying conditions. # There is NO warranty; # not even for MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE.
# Variables
# default
F77 = $(FC) # default PREPROCESS.r = $(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F # automatic @F = $(notdir $@) # environment HOME = /u/ergun # default MAKE = $(MAKE_COMMAND) # environment LESSOPEN = |lesspipe.sh %s # default SUFFIXES := .out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S .mod .symi .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el # default COMPILE.r = $(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c # default LINK.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) # default LINK.s = $(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH) # environment MAIL = /var/spool/mail/ergun # environment PWD = /u/ergun/ben/docs # default LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH) # default TEXI2DVI = texi2dvi # automatic +F = $(notdir $+) # default COMPILE.f = $(FC) $(FFLAGS) $(TARGET_ARCH) -c # environment PS1 = %m:%~%# # automatic %F = $(notdir $%) # default LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) # default CO = co # automatic ?D = $(patsubst %/,%,$(dir $?)) # environment _ = /usr/bin/make # default PREPROCESS.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F # automatic # default M2C = m2c # default FC = f77 # default CC = cc # environment MINICOM = -c on # default LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH) # default CXX = g++ # default AR = ar # default CWEAVE = cweave # environment OPENWINHOME = /usr/openwin # default COMPILE.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c # environment USER = ergun # automatic *D = $(patsubst %/,%,$(dir $*)) # automatic ^D = $(patsubst %/,%,$(dir $^)) # default COMPILE.s = $(AS) $(ASFLAGS) $(TARGET_MACH) # makefile SHELL = /bin/sh # environment MANPATH = /usr/local/man:/usr/man/preformat:/usr/man: /usr/X11/man:/usr/openwin/man # default YACC = yacc # default COMPILE.def = $(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH) # default LINK.C = $(LINK.cc) # makefile MAKEFLAGS = p # default LINK.p = $(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) # default OUTPUT_OPTION = -o $@ # default MAKE_VERSION := 3.74 # default PREPROCESS.S = $(CC) -E $(CPPFLAGS) # environment MAKELEVEL := 0 # environment PS2 = > # default YACC.y = $(YACC) $(YFLAGS) # default COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c # default TANGLE = tangle # default CHECKOUT,v = $(patsubst $@-noexist,$(CO) $(COFLAGS) $< $@,
$(filter-out $@,$(firstword $(wildcard $@) $@-noexist)))
# default
LD = ld # environment MFLAGS = -p # default GET = get # environment ignoreeof = 10 # environment HOSTNAME = napoleon.yerel.yore.com.tr # default COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c # default PC = pc # default AS = as # automatic @D = $(patsubst %/,%,$(dir $@)) # environment HZ = 100 # default TEX = tex # environment TERM = linux # environment LOGNAME = ergun # environment SHLVL = 1 # environment LESS = -MM # default COMPILE.C = $(COMPILE.cc) # default LINT = lint # default F77FLAGS = $(FFLAGS) # default COMPILE.p = $(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c # default RM = rm -f # automatic +D = $(patsubst %/,%,$(dir $+)) # default WEAVE = weave # automatic ?F = $(notdir $?) # automatic %D = $(patsubst %/,%,$(dir $%)) # default CPP = $(CC) -E # automatic # default LEX = lex # default LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) # default LEX.l = $(LEX) $(LFLAGS) -t # default COMPILE.mod = $(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH) # default ARFLAGS = rv # automatic *F = $(notdir $*) # automatic ^F = $(notdir $^) # default LINT.c = $(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH) # default LINK.r = $(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH) # environment BULLDOZERLIB = /usr/local/lib/dozer-0.7.2b # default COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c # default MAKEFILES := # default CTANGLE = ctangle # default MAKE_COMMAND := make # environment PATH = /bin:/usr/bin:/usr/local/bin:/usr/X11/bin:/usr/andrew/bin: /usr/openwin/bin:/usr/games:.:/usr/local/bin/Thot/LINUX-ELF/bin: # default LINK.f = $(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH) # environment LS_COLORS = no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35: bd=40;33;01:cd=40;33;01:ex=01;32:*.cmd=01;32:*.exe=01;32: *.com=01;32:*.btm=01;32:*.bat=01;32:*.tar=01;31:*.tgz=01;31: *.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31: *.gz=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35: *.xpm=01;35:*.tif=01;35: # default MAKEINFO = makeinfo # 98 variables in 523 hash buckets. # average of 0.2 variables per bucket, max 3 in one bucket.
# Directories
# SCCS: could not be stat'd.
# /dev/RCS: could not be stat'd. # /dev (device 769, inode 4065): 1283 files, 42 impossibilities. # RCS: could not be stat'd. # /dev/SCCS: could not be stat'd.
# 1283 files, 42 impossibilities in 5 directories.
# Implicit Rules
%.out:
%.a:
%.ln:
%.o:
%: %.o
# commands to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.c:
%: %.c
# commands to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.ln: %.c
# commands to execute (built-in):
$(LINT.c) -C$* $<
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $< $(OUTPUT_OPTION)
%.cc:
%: %.cc
# commands to execute (built-in):
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.cc
# commands to execute (built-in):
$(COMPILE.cc) $< $(OUTPUT_OPTION)
%.C:
%: %.C
# commands to execute (built-in):
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.C
# commands to execute (built-in):
$(COMPILE.C) $< $(OUTPUT_OPTION)
%.p:
%: %.p
# commands to execute (built-in):
$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.p
# commands to execute (built-in):
$(COMPILE.p) $< $(OUTPUT_OPTION)
%.f:
%: %.f
# commands to execute (built-in):
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.f
# commands to execute (built-in):
$(COMPILE.f) $< $(OUTPUT_OPTION)
%.F:
%: %.F
# commands to execute (built-in):
$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.F
# commands to execute (built-in):
$(COMPILE.F) $< $(OUTPUT_OPTION)
%.f: %.F
# commands to execute (built-in):
$(PREPROCESS.F) $< $(OUTPUT_OPTION)
%.r:
%: %.r
# commands to execute (built-in):
$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.r
# commands to execute (built-in):
$(COMPILE.r) $< $(OUTPUT_OPTION)
%.f: %.r
# commands to execute (built-in):
$(PREPROCESS.r) $< $(OUTPUT_OPTION)
%.y:
%.ln: %.y
# commands to execute (built-in):
$(YACC.y) $<
$(LINT.c) -C$* y.tab.c $(RM) y.tab.c
%.c: %.y
# commands to execute (built-in):
$(YACC.y) $<
mv -f y.tab.c $@
%.l:
%.ln: %.l
# commands to execute (built-in):
@$(RM) $*.c
$(LEX.l) $< > $*.c $(LINT.c) -i $*.c -o $@ $(RM) $*.c
%.c: %.l
# commands to execute (built-in):
@$(RM) $@
$(LEX.l) $< > $@
%.r: %.l
# commands to execute (built-in):
$(LEX.l) $< > $@
mv -f lex.yy.r $@
%.s:
%: %.s
# commands to execute (built-in):
$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.s
# commands to execute (built-in):
$(COMPILE.s) -o $@ $<
%.S:
%: %.S
# commands to execute (built-in):
$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.S
# commands to execute (built-in):
$(COMPILE.S) -o $@ $<
%.s: %.S
# commands to execute (built-in):
$(PREPROCESS.S) $< > $@
%.mod:
%: %.mod
# commands to execute (built-in):
$(COMPILE.mod) -o $@ -e $@ $^
%.o: %.mod
# commands to execute (built-in):
$(COMPILE.mod) -o $@ $<
%.sym:
%.def:
%.sym: %.def
# commands to execute (built-in):
$(COMPILE.def) -o $@ $<
%.h:
%.info:
%.dvi:
%.tex:
%.dvi: %.tex
# commands to execute (built-in):
$(TEX) $<
%.texinfo:
%.info: %.texinfo
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.texinfo
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.texi:
%.info: %.texi
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.texi
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.txinfo:
%.info: %.txinfo
# commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.txinfo
# commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.w:
%.c: %.w
# commands to execute (built-in):
$(CTANGLE) $< - $@
%.tex: %.w
# commands to execute (built-in):
$(CWEAVE) $< - $@
%.ch:
%.web:
%.p: %.web
# commands to execute (built-in):
$(TANGLE) $<
%.tex: %.web
# commands to execute (built-in):
$(WEAVE) $<
%.sh:
%: %.sh
# commands to execute (built-in):
cat $< >$@
chmod a+x $@
%.elc:
%.el:
(%): %
# commands to execute (built-in):
$(AR) $(ARFLAGS) $@ $<
%.out: %
# commands to execute (built-in):
@rm -f $@
cp $< $@
%.c: %.w %.ch
# commands to execute (built-in):
$(CTANGLE) $^ $@
%.tex: %.w %.ch
# commands to execute (built-in):
$(CWEAVE) $^ $@
%:: %,v
# commands to execute (built-in):
+$(CHECKOUT,v)
%:: RCS/%,v
# commands to execute (built-in):
+$(CHECKOUT,v)
%:: s.%
# commands to execute (built-in):
$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<
%:: SCCS/s.%
# commands to execute (built-in):
$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<
# 82 implicit rules, 4 (4.9%) terminal.
# Files
# Not a target:
.c: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.texinfo.info: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.mod.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.mod) -o $@ $<
# Not a target:
.c.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.c) $< $(OUTPUT_OPTION)
# Not a target:
.s: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.txinfo.dvi: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
.DEFAULT: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.y.c: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(YACC.y) $<
mv -f y.tab.c $@
# Not a target:
.l: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.web.tex: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(WEAVE) $<
# Not a target:
.s.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.s) -o $@ $<
# Not a target:
.sym: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.texi: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.F.f: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(PREPROCESS.F) $< $(OUTPUT_OPTION)
# Not a target:
.dvi: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.web.p: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(TANGLE) $<
# Not a target:
.def: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.F: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.cc.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.cc) $< $(OUTPUT_OPTION)
# Not a target:
.S.s: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(PREPROCESS.S) $< > $@
# Not a target:
.ch: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.def.sym: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.def) -o $@ $<
# Not a target:
.F.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.F) $< $(OUTPUT_OPTION)
# Not a target:
.f: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.elc: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.y.ln: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(YACC.y) $<
$(LINT.c) -C$* y.tab.c $(RM) y.tab.c
# Not a target:
.texi.dvi: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
.el: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.texinfo.dvi: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
/dev/null: # Implicit rule search has been done. # Last modified Mon Jul 18 02:46:18 1994 (774488778) # File has been updated. # Successfully updated.
# Not a target:
.SUFFIXES: .out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.txinfo: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.p.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.p) $< $(OUTPUT_OPTION)
# Not a target:
.r.f: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(PREPROCESS.r) $< $(OUTPUT_OPTION)
# Not a target:
.w.tex: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(CWEAVE) $< - $@
# Not a target:
.txinfo.info: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.c.ln: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINT.c) -C$* $<
# Not a target:
.w: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.ln: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.l.r: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LEX.l) $< > $@
mv -f lex.yy.r $@
# Not a target:
.info: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.r.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.r) $< $(OUTPUT_OPTION)
# Not a target:
.h: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.C.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.C) $< $(OUTPUT_OPTION)
# Not a target:
.p: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.l.c: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
@$(RM) $@
$(LEX.l) $< > $@
# Not a target:
.sh: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
cat $< >$@
chmod a+x $@
# Not a target:
.web: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.out: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.cc: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.f.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.f) $< $(OUTPUT_OPTION)
# Not a target:
.texi.info: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.a: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.tex: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.l.ln: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
@$(RM) $*.c
$(LEX.l) $< > $*.c $(LINT.c) -i $*.c -o $@ $(RM) $*.c
# Not a target:
.y: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.S.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.S) -o $@ $<
# Not a target:
.tex.dvi: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(TEX) $<
# Not a target:
.r: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.mod: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(COMPILE.mod) -o $@ -e $@ $^
# Not a target:
.C: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.S: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.texinfo: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated.
# Not a target:
.w.c: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in):
$(CTANGLE) $< - $@
# 65 files in 1007 hash buckets.
# average 6.5 files per bucket, max 2 files in one bucket.
# VPATH Search Paths
# No `vpath' search paths
|
Yorum Gönder