[Çözüldü] C'de kendi kütüphanelerimi nasıl kullanırım?

Başlatan edge35, 05 Ağustos 2017 - 00:58:31

« önceki - sonraki »

0 Üyeler ve 3 Ziyaretçi konuyu incelemekte.

edge35

C'de kendi kütüphanelerimi kullanmak istiyorum.

"deneme.h" adında bir kütüphane dosyası oluşturdum. İçerisine kullanacağım fonksiyonları yazdım.
C kaynak kodumun üstüne "#include "deneme.h"" yazdım.
Kaynak kod ile kütüphane dosyası aynı dizin içerisinde iken "gcc kaynakkod.c -o cikti.out" ile derleme işlemini yaptım. Sorunsuz bir şekilde çalıştı.

Fakat bu bağlantıda başka aşamalarda anlatılmış. Bağlantıda ne demek istediğini tam anlayamadım.

Benim yaptığım işlemin ne gibi sıkıntıları olabilir? Verdiğim linkteki şekilde yapılırsa ne farkı var? Yardımcı olabilirseniz sevinirim.
Linkteki ilgili kısmı alıntılıyorum.


Alıntı yapılan: https://www.cs.swarthmore.edu/~newhall/unixhelp/howto_C_libraries.html(2) IMPLEMENTATION: create a mylib.c file that #includes "mylib.h" and contains the implementation of every function in your library.

    #include "mylib.h"

    ...
    int total_foo;

    int foo(float y, float z) {
...
    }

(3) create a LIBRARY OBJECT FILE that can be linked into other programs that use your library (use the -c option to gcc to tell it just to create an object file (a .o file) rather than an executable:

    gcc -o mylib.o -c mylib.c

you can then use the mylib.o file as the "library file" and statically link it into other programs that use it, or...

(3a) alternately, you can create a SHARED OBJECT FILE from one or more .o files that can be linked into other programs that use your library A shared object file is the Unix name for a dynamically linked library whose code is loaded into the a.out file at runtime. To create a .so file use the -shared flag to gcc. Here is what an example build might look like:

       gcc -shared -o libmylib.so  mylib.o blah.o grr.o  -lm

(3b) you could also build an ARCHIVE FILE (a statically linked library, libmylib.a) from one or more .o files. If you link with a static library, its code is copied into the a.out file at runtime.

See gcc documentation for more information on how to build .a and .so files.

(4) USE the library in other programs:

    step 1: Add an include line (#include "mylib.h") in all program source files that use library definitions (e.g., test.c).

    step 2: Link the program's .c file with the library object file
            (i.e. specify the mylib.o file as a command line argument to gcc):

            gcc  test.c mylib.o

        OR to link in libmylib.so (or libmylib.a):

             gcc  test.c -lmylib

        OR to link with a library not in the standard path:

             gcc  test.c -L/home/newhall/lib -lmylib

        The resulting a.out out will contain machine code for all the functions
        defined in test.c plus any mylib library functions that are called by
        the test.c code.


Not: Her ne kadar alıntılasam da bağlatının içeriğine bakmanızda fayda var.


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

edge35



Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

Amenofis

-c parametresini verdiğin zaman sadece derleme yapar, yani çalışabilir dosya oluşmaz. Derlenmiş obje dosyalarını (.o uzantılı) bir yerde saklayarak daha sonra kullanabilirsin. Mesela "gcc main.c derlenmis.o" yazdığın zaman main.c derlenir, sonra da main.o ve derlenmis.o bağlanır. Bu en basit formu.

Birbiriyle ilişkili obje dosyalarını arşivleyip tek dosya haline getirebilirsin. Buna static library denir. Arşivlemek için "ar" uygulaması var gcc paketinde.

gcc -c a.c b.c c.c d.c
ar rcs libabcd.a a.o b.o c.o d.o

Daha sonra bu kütüphaneyi kullanmak istediğinde, mesela kütüphane ev dizininde diyelim.
gcc main.c -L$HOME -labcd
-L ile kütüphanenin bulunduğu yolu veriyorsun, -l ile de ismini. İsmi verirken "lib" takısını yazmıyorsun.

edge35

Yani benim yaptığım gibi yapılmasında bir sıkıntı ve ya eksiklik yok o zaman. Doğru anladım mı?


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

Amenofis

Nasıl yaptığını bilmiyorum. Bütün kodu başlık dosyasına yazdıysan her seferinde tekrar derlenir. Benim dediğim gibi yaparsan sadece bir kere derlenir.

edge35

[mention=629665]@Amenofis[/mention] bu şekilde yapmıştım
Alıntı yapılan: edge35 - 05 Ağustos 2017 - 00:58:31
"deneme.h" adında bir kütüphane dosyası oluşturdum. İçerisine kullanacağım fonksiyonları yazdım.
C kaynak kodumun üstüne "#include "deneme.h"" yazdım.
Kaynak kod ile kütüphane dosyası aynı dizin içerisinde iken "gcc kaynakkod.c -o cikti.out" ile derleme işlemini yaptım. Sorunsuz bir şekilde çalıştı.

Sizin anlattığınız yöntemi tam olmasa da anladım galiba. Fakat o şekilde yapmakl benim yaptığım arasında ne gibi bir fark var? Sizin anlattığınız şekilde kullanmanın ne gibi faydaları olur?


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

Amenofis

Amaç nedir, önce buna cevap vermen lazım. Kendi kütüphanemi oluşturayım diyorsan sebebi aynı kodları tekrar tekrar derlemek istemediğin içindir. Aksi halde kodları kopyala yapıştır da yapabilirsin ama bu hamallık olur.

Diğer bir sebep kaynak kodunu gizlemek olabilir. Başlık dosyasına yazdıkların derleme esnasında hazır olmak zorunda. Yani hepsi apaçık görünür. .c dosyasına yazıp derlediklerin ise ikili koda dönüşür. Yani kütüphaneni dağıtmak isteyip te kaynak kodunu vermek istemezsen bu opsiyonu seçmek zorundasın. Gerçi kodu gizlemek linux dünyasında pek kabul görmez ama yine de örnekleri var.

Tabi mutlaka text halde olması gereken kodlar da var. Mesela macrolar, inline olmasını istediğin fonksiyonlar, derlenmiş fonksiyonların prototipleri, struct tanımlamaları, global değişkenlerin extern bildirimleri... Bunları başlık dosyası içine koyacaksın ve kütüphaneyi kullanırken include edeceksin.

edge35

Amacım fonksiyonları kullanacağım zamanlarda direk fonksiyon ismini yazarak kullanabilmek. Diğer dosyayı aç, ilgili fonksiyonu bul, kopyala yapıştır, uğraşmak istemiyorum. Bir de ana kaynak kodda fazla şey olsun istemiyorum, daha az ve sadece o programı ilgilendiren şeyler olsun istiyorum. Şimdiki kullanım amacım bu.

Ama ileride gerçekten program diyebileceğim şeyler yazarsam, zaten kütüphane bile kullansam o programı ilgilendirmeyen fonksiyonları tutmam. O program için bir kütüphane dosyası oluşturur, sadece lazım olanları atarım içerisine. Yani şimdiki biraz daha kendimi geliştirmek için yazdığım kodlarla ilgili.

Alıntı YapKendi kütüphanemi oluşturayım diyorsan sebebi aynı kodları tekrar tekrar derlemek istemediğin içindir.
Tekrar tekrar derlemek sıkıntılı bir işlem mi ki? Sonuçta derleme işlemini bilgisayar yapıyor, ben sadece komutu veriyorum, kütüphane olsa da olmasada derleme komutunu vereceğim.

Bu arada sürekli sorular sormaktaki amacım öğrenmek, hala acemi olduğum için bilmediğim çok fazla şey var.


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

Amenofis

Evet derleme sıkıntılı bir işlem. Sıkıntılı olduğu için IDE veya makefile ile derlerken sadece modifiye edilen kaynak kod dosyasının derlendiğini görürsün. Diğerlerini tekrar derlemezler.

Şimdiye kadar hep kısa kodları derlediğin için bunun sıkıntısını görmemişsin. Kurduğun kütüphanelerin neden derlenmiş halde dağıtıldığını bir düşün derim. 

edge35

#9
Anladım, teşekkür ederim. Daha gideceğim çok yol var anlaşılan.

Bir de kütüphane dosyaları oluşturma hakkında tavsiye verebilir misiniz? Kaynak da önerebilirsiniz. Ben direk fonksiyonu alıp ".h" uzaktılı dosyaya yapıştırıyorum.

Bir de kütüphane içerisindeki fonksiyonların ihtiyaç duyduğu asıl fonksiyonları (stdlip.h, mayh.h gibi) kütüphane dosyasında ekliyorum. Bunun bir yanlışlığı var mı?


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

Amenofis

Daha önce dediğim gibi o yaptığın pek doğru sayılmaz. Yani teknik olarak sakıncası olmasa da ona kütüphane denmez.

Kendin kaynak koymuşsun işte, orada yazılanları uygulayabilirsin. Standart prosedür aynı isimli bir .h (başlık) bir de .c (kaynak kod) dosyası oluşturmak. Başlık dosyasına sadece zorunlu olan şeyleri yaz, geri kalan herşeyi .c dosyasına at. Çünkü kaynak kod bir kere, başlık dosyası ise sürekli derlenir. Amaç derleme süresini mümkün olduğunca kısa tutmak. Başlık dosyası ne kadar kabarık olursa dosyada değişiklik yapma ihtimalin o kadar artar. Eğer değişiklik yaparsan o başlık dosyasını include eden (doğrudan ya da dolaylı) bütün kaynak kod dosyaları tekrar derlenmek zorunda kalır. Gerçi bunun sadece kütüphane ile alakası yok, herhangi bir proje üstünde çalışırken de dikkat edilmesi gereken şeyler.

edge35

Anladığım kadarıyla bu .c (kaynak kod) dosyası programın değil de .h dosyasının kaynak dosyası oluyor galiba. Eğer öyleyse bu başlık ve kaynak kod dosyalarına yazacaklarımı nasıl ayırt edeceğim. Sadece zorunlu olanları başlık dosyasına yaz demişsiniz. Yani program için gerekmeyen fonksiyonları mı yazmayayım. Yoksa fonksiyonları falan kaynak kod dosyasına yazıp başlık dosyasına değişken gibi şeyleri mi yazmam gerekiyor.


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

Reverser

merhaba, yazdığın kodu görebilir miyim ? @Amenofis kütüphane için -L bayrağından bahsetmiş fakat senin bahsettiğin konu header sanırım ?

XFCE ROCKS !
Powered by Thunar & XFWM4



edge35

[mention=629814]@Reverser[/mention] tabi ki, buyrun.
#ifndef _MYILMAZ_H_
#define _MYILMAZ_H_

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>

char *f_simdi_zaman (char istek)
{
char *return_value;

time_t simdi = time(0);
struct tm zaman;
zaman = *localtime(&simdi);

if(istek == 's') //ss.dd
{
return_value = (char*) malloc(sizeof(char)*6);
strftime(return_value ,sizeof(char)*6 ,"%H.%M" ,&zaman);
}
else if(istek == 't') //gg.aa.yyyy
{
return_value = (char*) malloc(sizeof(char)*12);
strftime(return_value ,sizeof(char)*12 ,"%d.%m.%Y" ,&zaman);
}
else if(istek == 'z') //ss.dd gg.aa.yyyy
{
return_value = (char*) malloc(sizeof(char)*18);
strftime (return_value ,sizeof(char)*18 ,"%H.%M %d.%m.%Y" ,&zaman);
}
else if (istek == 'y') //yyyy.aa.gg
{
return_value = (char*) malloc (sizeof(char)*12);
strftime (return_value ,sizeof(char)*12 ,"%Y.%m.%d" ,&zaman);
}

return return_value;
}

void f_buyuk_harf (char string[]) //"string[]" dizgisini büyük harflere çevirerek üzerinde kaydeder, harf dışındaki elemanlara bir şey yapmaz.
{
for (int i = 0; string[i] != '\0'; ++i)
{
if (string[i] >= 'a' && string[i] <= 'z')
{
string[i] = string[i] - 32;
}
/*string[i] = toupper(string[i]);*/
}
}

void f_kucuk_harf (char string[]) //"string[]" dizgisini küçük harflere çevirerek üzerinde kaydeder, harf dışındaki elemanlara bir şey yapmaz.
{
for (int i = 0; string[i] != '\0'; ++i)
{
if (string[i] >= 'A' && string[i] <= 'Z')
{
string[i] = string[i] + 32;
}
}
}

char *f_buyuk_harf_string (char string[]) //"string[]" dizgisini büyük harflere çevirerek döndürür, dizginin aslına bir şey yapmaz, harf dışındaki elemanlara bir şey yapmaz.
{
char *temp = (char*) malloc(sizeof(char)*1);

int i;
for (i = 0; string[i] != '\0'; ++i)
{
temp = (char*) realloc(temp ,sizeof(char)*(2+i));
if(string[i] >= 'a' && string[i] <= 'z')
{
temp[i] = string[i] - 32;
}
else if (string[i] >= 'A' && string[i] <= 'Z')
{
temp[i] = string[i];
}
else
{
temp[i] = string[i];
}
}
temp[i] = '\0';

return temp;
}

char *f_kucuk_harf_string (char string[]) //"string[]" dizgisini küçük harflere çevirerek döndürür, dizginin aslına bir şey yapmaz, harf dışındaki elemanlara bir şey yapmaz.
{
char *temp = (char*) malloc(sizeof(char)*1);

int i;
for (i = 0; string[i] != '\0'; ++i)
{
temp = (char*) realloc(temp ,sizeof(char)*(2+i));
if(string[i] >= 'a' && string[i] <= 'z')
{
temp[i] = string[i];
}
else if (string[i] >= 'A' && string[i] <= 'Z')
{
temp[i] = string[i] + 32;
}
else
{
temp[i] = string[i];
}
}
temp[i] = '\0';

return temp;
}

void fgets_stdin(char *yazi ,int size ,int yeni_satir) //1) Klavyeden girilen yazının başında '\n' varsa (yeni_satir = 1) siler, yoksa (yeni_satir = 2) bir şey yapmaz.
//2) Sonundaki '\n' karakterini siler.
{
if(yeni_satir == 1)
{
getchar();
fgets(yazi, size ,stdin);
for (int i = 0; yazi[i] != '\0'; ++i) //fgets en son yeni satır "\n" alır, bunu silip string sonu "\0" ile değiştiriliyor.
{
if (yazi[i] == '\n')
{
yazi[i] = '\0';
break;
}
}
}

else if (yeni_satir == 0)
{
fgets(yazi, size ,stdin);
for (int i = 0; yazi[i] != '\0'; ++i) //fgets en son yeni satır "\n" alır, bunu silip string sonu "\0" ile değiştiriliyor.
{
if (yazi[i] == '\n')
{
yazi[i] = '\0';
break;
}
}
}
}

void fgets_dosya(char *yazi ,int size ,FILE *dosya)
{
fgets(yazi, 2 ,dosya);
fgets(yazi, size ,dosya);

for (int i = 0; yazi[i] != '\0'; ++i) //fgets en son yeni satır "\n" alır, bunu silip string sonu "\0" ile değiştiriliyor.
{
if (yazi[i] == '\n')
{
yazi[i] = '\0';
break;
}
}
}

char *buay_turkce (void)
{
char *buay = (char*) malloc(sizeof(char)*12);

time_t simdi = time(0);
struct tm zaman;
zaman = *localtime(&simdi);

strftime(buay ,sizeof(char)*12 ,"%B" ,&zaman);

if (strcmp (buay, "January") == 0) memcpy(buay ,"Ocak" ,sizeof(char)*12);
else if (strcmp (buay, "February") == 0) memcpy(buay ,"Şubat" ,sizeof(char)*12);
else if (strcmp (buay, "March") == 0) memcpy(buay ,"Mart" ,sizeof(char)*12);
else if (strcmp (buay, "April") == 0) memcpy(buay ,"Nisan" ,sizeof(char)*12);
else if (strcmp (buay, "May") == 0) memcpy(buay ,"Mayıs" ,sizeof(char)*12);
else if (strcmp (buay, "June") == 0) memcpy(buay ,"Haziran" ,sizeof(char)*12);
else if (strcmp (buay, "July") == 0) memcpy(buay ,"Temmuz" ,sizeof(char)*12);
else if (strcmp (buay, "August") == 0) memcpy(buay ,"Ağustos" ,sizeof(char)*12);
else if (strcmp (buay, "September") == 0) memcpy(buay ,"Eylül" ,sizeof(char)*12);
else if (strcmp (buay, "October") == 0) memcpy(buay ,"Ekim" ,sizeof(char)*12);
else if (strcmp (buay, "November") == 0) memcpy(buay ,"Kasım" ,sizeof(char)*12);
else if (strcmp (buay, "December") == 0) memcpy(buay ,"Aralık" ,sizeof(char)*12);

return buay;
}

void f_devam_bas(int enter)
{
for (int i = 0; i < enter; ++i)
{
puts("");
}
puts("Devam etmek için bir \"Enter\"a basınız...");
getchar();
}

void free_myilmaz (void)
{
//free(*return_value);
//free(temp);
}

int f_dosya_kopyala (char dosya_ismi[] ,char hedef_dosya_ismi[]) //dosya_ismi isimli txt dosyasını hedef_dosya_ismi isimli txt dosyasına kopyalar.
{
FILE *dg_kaynak, *dg_hedef;

dg_kaynak = fopen(dosya_ismi ,"r");
if (dg_kaynak == NULL)
{
printf("\"%s\" dosyası okunamadı.\n",dosya_ismi );
return 1;
}

dg_hedef = fopen(hedef_dosya_ismi ,"w");
if (dg_hedef == NULL)
{
printf("\"%s\" dosyası oluşturulamadı.\n",hedef_dosya_ismi );
return 2;
}

char ch;
while (1)
{
ch = fgetc(dg_kaynak);

if (ch == EOF) break;
else putc(ch, dg_hedef);
}


fclose (dg_kaynak);
fclose (dg_hedef);


return 0;
}

#endif

Sanırsam dediğiniz gibi başlık oluyor benim dediğim.


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)

Reverser

kendi oluşturduğun header ile ana kaynak dosyan aynı dizindeyse şayet dizin yapısı şu şekilde olmalı;

helloworld
|_>main.c
|_>headerim.h

kod içeriği ise şu şekilde;

#include "headerim"

int main(int argc, char *argv[])
{
   ...
}

XFCE ROCKS !
Powered by Thunar & XFWM4



edge35

[mention=629819]@Reverser[/mention] Yani hearder benim yazdığım şekilde, main.c içeriği de sizin verdiğiniz şekilde olacak, değil mi?

Peki header ile kütüphane dosyasının farkı nedir?


Sorunlarımı çözerken her şeyiyle öğrenmeye çalışıyorum. Bana balık verenden Allah razı olsun, ama bana balık tutmayı öğretenden Allah daha çok razı olsun :)