gcc include

Fórumok

Sziasztok!

gcc-vel első lépéseim tenném meg, linux alatt.

Van egy main.c, amiben szerepel az alábbi pár sor a fájl elején:


#include "stdio.h"
#include "SAJAT_header.h"
#include "SAJAT_header2.h"

Van a main.c mellett egy könyvtár, aminek a neve sajINC, ebben van a fent említett két fájl.
A fordítást az alábbi paranccsal kívánom megtenni (egyelore az a.out bináris tökéletesen meg fog felelni):


gcc -I sajINC/ main.c

A problémám, hogy


root@beagleboard:/usr/local/src/SAJAT# gcc -I sajINC main.c
/tmp/ccuUV9Lv.o: In function `main':
main.c:(.text+0x4): undefined reference to `EGV'
main.c:(.text+0x8): undefined reference to `EGV'

holott a SAJAT_header.h tartalmazza az alábbi sort:


extern int EGV;

Úgy tűnik, mintha mégsem include-olná a headert. Mi a bánat miatt?

Hozzászólások

amikor a gcc paracsot kiadod, ket lepes tortenik:

- forditas
- linkeles.

A forditas hiba nelkul tortent, a linkeles hasalt el.

Tehat a program a C nyelv szerint jo, amde megse mukodokepes.

Az a baj, hogy az
'extern EGV'

azt jelenti, hogy: "valami masik modulban van egy EGV valtozo, ezt most a C nyelvnek elmondom, hogy a C fordito majd tudjon mit kezdeni vele, ha talalkozik az EGV valtozoval. Es kesobb a linker majd megtalalja az EGV valtozot."

viszont nem csinaltal masik modult, amiben ott is lenne ez az EGV valtozo. Igy a linker nem talalja meg.

2 lehetseges megoldas:
- amig nem tudod, hogy mi az a ket modul, addig nem hasznalod az extern kulcsszot
- csinalsz egy masik modult az alabbi egyetlen sorral:

int EGV;

es azt is leforditod, es a ket modult osszelinkeled.

"2 lehetseges megoldas:"

3. lehetoseg: -c-vel hivja meg, igy nem lesz linkeles. Irta, hogy egyelore a .o eleg.

Szerk: jah lehet, hogy rosszul ertelmeztem, nem .o kell neki...

----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
--> YouTube csatornám

Csak picit off:

> amikor a gcc paracsot kiadod, ket lepes tortenik:
>
> - forditas
> - linkeles.

Érdekes a megközelítésed, mivel feljebb aztán azt írod, hogy az include-olással lehet "szimulálni" a modulokat c-ben. Szerintem pont emiatt inkább három lépést szokás említeni: preprocessing, compiling, linking.

Tudom, hogy - szinte - bármeddig bonthatóak, részletezhetőek ezek a lépések, mégis az előfeldolgozás jól elkülöníthető része a fordítási folyamatnak.

Bizonyos nyelvekben a nyelvi modulhivatkozas kozvetlenul hozza van rendelve a linkelesi kornyezet osszerakasahoz.

A C nem ilyen. A C-ben egyaltalan nincsen nyelvi tamogatas a modul fogalmahoz, csak "olyan mintha" dolgok vannak.

Ha egy modul programjat (implementaciojat) berakod egy foo.c -be, es
ugyanennek a modulnak a definiciojat berakod egy foo.h -ba, akkor az

#include "foo.h"

es a forditas utan a foo.o -val valo osszelinkelessel egeszen jol lehet utanozni azt, amit mas nyelvek modulnak hivnak.
Viszint itt a C -nek, maganak a nyelvnek nem resze sem az #include, sem a linker. Es nincsen semmi-semmi segitseg, hogy a foo.h tenyleg a foo.c -ben implementalt kod definiciojat/prototipusat tartalmazza. Vagy valmi tok mast.

Azt hiszem, a jo C programozashoz szukseg van alapveto assembler es alapveto oprendszer felepules ismeretre. Azonban sok C programozoval talalkoztam, akinek egyaltalan, semmi ismerete nem volt ezekrol.

Azt gondolom, hogy (ha jól halbiologizálom ki) ez a feltétel teljesül (bár ezzel kapcsolatban a post-om hiányos), hiszen van egy sajat_header.c fájl is, ahol szerepel egy ilyen sor:

int EGV;

Akkor eszerint, ha jól értem, a fordításkori parancs nem jó, hanem valahogy úgy kellene fordítanom, hogy ebből a két fájlból (sajat_header.h és sajat_header.c) készüljön egy sajat_header.o, majd a main.c-t úgy kell fordítanom, hogy a linker használja fel a sajat_header.o fájlt?

Nem oly nehéz a google-n rákeresni, hogy gcc multiple source file tutorial, és még használható találatokat is kapsz.
Például: http://www.network-theory.co.uk/docs/gccintro/gccintro_11.html
http://crasseux.com/books/ctutorial/Compiling-multiple-files.html

Érdemes megérteni, hogy mi történik, mi az object, mi a header, mire jó az extern, mi a header guard stb.

Itt ezeken a linkeken azt olvastuk, hogy az alábbi szerkezet lefordításához
main.c:


#include	"nyenyere.h"


int main(void)
{
	EGV = 5;
	ASD();

	return 0;
}

és nyenyere.c:


#include	"nyenyere.h"

int EGV;

void ASD(void)
{
	int temp;

	temp += EGV;
}

és nyenyere.h:


#ifndef _NYENYERE_H_
#define	_NYENYERE_H_

	extern int EGV;

	void ASD(void);

#endif                

az alábbi parancsot kell alkalmaznom:


gcc main.c -o newhello

Ehhez képest nekem ezt mondja a linker (?):


root@beagleboard:/usr/local/src/nyenyere# gcc main.c -o newhello
/tmp/ccdS58n9.o: In function `main':
main.c:(.text+0x4): undefined reference to `EGV'
main.c:(.text+0x8): undefined reference to `EGV'
main.c:(.text+0x12): undefined reference to `ASD'
collect2: ld returned 1 exit status

Ennek a link szerint le kell fordulnia, mert a main.c include-olja a nyenyere.h-t, amihez viszont a nyenyere.c tartozik. A nyenyere.h-ban deklarált és a nyenyere.c-ben definiált részek formája, neve, típusa, stb. megegyezik, így ezek együtt egy modult alkotnak.

Nekem viszont nem fordul.
És akkor miért is?

1. lefordul. Ezt ugy hivjuk, hogy lefordul. A linkelesnel esik el: nem linkelodik.

2. ez hibas. A nyenyere.c -ben ilyen esetben ne include-oljad be a nyenyere.h -t. Mert akkor a fordito a kovetkezovel talalkozik:

extern int EGV;
int EGV;

3. Koncepcionalisan is hibas az extern hasznalata ugy alatalaban, hasonloan, mint a goto hasznalata. Tessek a kovetkezot hasznalni:

nyenyere.h:

#ifndef _NYENYERE_H_
#define _NYENYERE_H_
int get_EGV(void);
int inc_EGV(void);
#endif

nyenyere.c:

#include "nyenyere.h"
static int EGV=0;
int get_EGV()
{
return EGV;
}

void inc_EGV()
{
++EGV;
}

A források ismerete nélkül semmit nem lehet mondani arról, hogy mi "fagyasztotta".

Mindenesetre ha minden ami az adott alkalmazáshoz szükséges - és csak az - ugyanabban a könyvtárban van, akkor a

gcc *.c

pontosan a fentihez hasonló módon fog futni, de legalább áttekinthető. (Amúgy ha nem idézőjelet " - hanem aposztrófot ' használsz a grep paraméterénél, akkor megspórolod a backslash használatát.) Amógy nem tudom ezt akartad-e, de azt írtad, hogy a gcc fordítson le minden .c-re végződő fájlt, és az összesből csináljon egyetlen binárist (ami a.out néven jön létre az adott könyvtárban).

'más rendszeren'

vannak mindenféle helperek, amik néhány tipikus hibát megengedhetõvé tesznek. a gcc egy párat tud, más fordító másik párat.
A legtöbbször valami integrált editor-fordító-linker-debugger-projectkezelõvel találkozik az ember, ami nagyon kényelmessé teszi a munkát, azonban eltakarja a dolgok mûködését.

Pl a gcc az integrált linker és fordító. Neked most ez is baj.
Ahol a fenti példa lefordult, ott kellett lennie egy integrált projectkezelõnek is valahol a rendszerben.

OT: Szerintem amit kerdeztel arra mar kaptal valaszt, de azt hadd jegyezzem meg, hogy valoszinuleg az stdio-t nem a local include-ok kozott akartad megadni. Szoval azt nem idezojelek, hanem kacsacsorok kozott illik irni.