Atmel Studio, projekt w wielu plikach i dyrektywa #include

Do tej pory pisa³em swoje programy pod AVR-y w niezbyt elegancki sposób, umieszczaj±c wszystko w jednym pliku ¼ród³owym. W ramach nauki postanowi³em jednak zmieniæ ten nawyk, poza tym pojawi³a siê potrzeba wykorzystania cudzych bibliotek.

Stworzy³em wiêc nowy projekt w Atmel Studio, zaimportowa³em plik *.c i

*.h potrzebnej biblioteki, potworzy³em te¿ pliki dla swoich bibliotek. Maj±c jeszcze w wiêkszo¶ci puste pliki (tzn. zawieraj±ce jedynie niezbêdne szkielety programu) wykona³em "Build Solution"

Kompilator zwróci³ seriê b³êdów, wskazuj±c na plik nag³ówkowy zaimportowanej biblioteki. Wszystkie one dotyczy³y nieznanego typu zmiennej: "unknown type name 'uint16_t'" (tudzie¿ uint8_t), wystêpuj±cego w deklaracjach nazw funkcji, umieszczonych w owym pliku nag³ówkowym. Same definicje funkcji w pliku .c ju¿ o nic nie krzycza³y.

Doszed³em do tego, ¿e winny jest brak dyrektywy #include na pocz±tku feralnego pliku nag³ówkowego, który ze wzglêdu na nazwê jest sprawdzany przez kompilator jako pierwszy.

Mam teraz nastêpuj±ce wyj¶cia:

  1. Umie¶ciæ #include ju¿ na pocz±tku pliku nag³ówkowego, ale chyba nie jest to zbyt eleganckim wyj¶ciem. Na ró¿nych przyk³±dach widzê, ¿e te dyrektywy umieszcza siê raczej w plikach *.c.
  2. Zmieniæ nazwy plików tak, aby kompilowa³y siê pó¼niej.

A mo¿e istnieje jaki¶ sposób na poinformowanie kompilatora, ¿eby do³±czy³ okre¶lony plik ju¿ na samym pocz±tku? Albo ¿eby zmieni³ kolejno¶æ kompilacji poszczególnych plików?

Reply to
Atlantis
Loading thread data ...

Kolejno¶æ kompilacji nie powinna mieæ znaczenia. Skoro kluczowy plik nag³ówkowy jest potrzebny do kompilacji to dlaczego nie chcesz go za³±czyæ w plikach .c?

--
Marek
Reply to
Marek

W dniu 2013-11-24 10:47, Marek pisze:

W pliku .c jest za³±czony, brakuje go w pliku .h. Czyli jak mam rozumieæ najbardziej prawid³owym rozwi±zaniem bêdzie przeniesienie dyrektywy #include do pliku nag³ówkowego, jeszcze przed wyst±pieniem deklaracji funkcji?

Tylko dziwiê siê dlaczego w przyk³adach z ksi±¿ki, z której korzystam ("Mikrokontrolery AVR Jêzyk C - podstawy programowania") by³o to zrobione odwrotnie. Czy¿by akurat ECLIPSE taka sytuacja nie przeszkadza³a?

Reply to
Atlantis

Atlantis snipped-for-privacy@wp.pl napisał(a):

Jak to ze względu na nazwę? Kompilator leci po kolei po linijkach kodu.

Dlaczego nie? Skoro plik używa tych typów, to powinien zawierać includy definiujące te typy.

Tutaj jest w ogóle trochę specyficzna sytuacja. Mówimy bowiem o podstawowych typach dla AVR (i dla innych uC też), które są wykorzystywane praktycznie w każdym projekcie. Z tego względu praktycznie każdy plik .c będzie miał includa dla io.h i będzie importować te typy. Często będzie to pierwsza linijka w pliku .c. Z tego względu jeśli potem jest include biblioteki, to te typy są już znane i plik .h biblioteki nie musi ich kompilować. Dlatego autor biblioteki nie zaincludował io.h w pliku .h swojej biblioteki. Po prostu założył, że Ty to zrobisz w pliku .c i zrobisz to _przed_ includowaniem jego biblioteki.

Przyznam się, że nie wiem jakie wyjście jest tu uznawane za eleganckie. Moim jednak zdaniem biblioteka powinna zawierać wszystko co potrzeba i jak zaincludujemy jej plik .h to nie powinniśmy być zmuszaniu do includowania innych nagłówków definiujących typy wykorzystywane wewnętrznie przez tą bibliotekę. No chyba, że uznajemy io.h za wyjątek.

Kompilator analizując plik .c nie może widzieć żadnych nieznanych wyrażeń, musi mieć wszystko wcześniej zadeklarowane (niekoniecznie zdefiniowane, ale zadeklarowane tak). Stosujemy więc pliki nagłówkowe żeby udostępniać deklaracje typów i funkcji, definicje funkcji siedzą w plikach .c. Tutaj jest sytuacja taka, że plik .h odwołuje się do typów, których nie ma standardowo w języku C, dlatego w pliku .h może być odwołanie do innego pliku .h. Nie jest to nic dziwnego w bardziej złożonych projektach.

Po pierwsze kolejność kompilacji nie ma nic do rzeczy. Po drugie o kolejności decyduje plik Makefile albo inny skrypt budujący (zależnie od środowiska).

Poczytaj sobie jak działa kompilator. Kompiluje oddzielnie poszczególne pliki .c, zgodnie z tym, co ma wpisane w Makefile. I przestań mylić kompilację z dołączaniem plików .h. Kolejność kompilacji nie ma nic wspólnego z kolejnością dołączania. Pytasz o sposób informowania kompilatora o dołączanie na samym początku. Dołączanie jest przecież realizowane w kodzie źródłowym poprzez dyrektywy #include. W jakiej kolejności je napiszesz, w takiej wskazywane przez nie pliki będą dołączane. Poza tym mam wrażenie, że myślisz, że plik nagłówkowy się dołącza raz na cały projekt. Nie. On się dołącza w tym miejscu, w którym jest #include. I koniec końców dołączany jest to jakiegoś jednego, konkretnego pliku .c. Pliki .c są kompilowane oddzielnie i nie wiedzą o sobie. Dlatego includy często się powtarzają. Dopiero jak wszystkie pliki .c są skompilowane, to wkracza linker tworząc wynikowy plik wykonywalny i zapisując w nim skoki pod określone adresy. Dlatego w jednym pliku .c możesz odwoływać się do funkcji zdefiniowanej w drugim. Ale ten pierwszy musi znać deklarację.

Reply to
Grzegorz Niemirowski

Atlantis snipped-for-privacy@wp.pl napisał(a):

Tak, wtedy nie będziesz się musiał martwić o includowanie w pliku .c w odpowiedniej kolejności.

Eclipse nie ma nic do rzeczy bo to nie kompilator.

Reply to
Grzegorz Niemirowski

W dniu 24.11.2013 o 09:13 Atlantis snipped-for-privacy@wp.pl pisze:

A dołączyłeś w pliku .c ten nagłóówkowy .h ? chyba nie musisz dać coś w stylu #include "xxxx.h" w pliku .c

Reply to
janusz_k

Użytkownik "Atlantis" snipped-for-privacy@wp.pl napisał w wiadomości news:l6sceu$3r4$ snipped-for-privacy@portraits.wsisiz.edu.pl...

Ja robię tak: ============================ // Crc.h // Obliczanie sum kontrolnych CRC8, CRC16, CRC32 //------------------------------------------------------------------------------

#ifndef CrcH #define CrcH

#ifndef ByteTypesH #include "ByteTypes.h" // typy byte, word, dword, qword #endif

int crc8(byte* buf,int n,int crc=0xFF); int crc16(byte* buf,int n,int crc=0xFFFF); dword crc32(byte *buf,int n,dword crc=0xFFFFFFFF);

#endif ===========================

P.G.

Reply to
Piotr Gałka

W/g mnie ten drugi #ifdef ByteTypesH nie jest potrzebny. Pliki .h z toolachain'a zwykle maja juz wbudowane zabezpieczenie przed wielokrornym dolaczaniem ( sekwaencja: #ifndef __ByteTypes_H__ #define __ByteTypes_H__ //zawartosc pliku ByteTypes.h

#endif ) Ja uzyl bym po prostu #include "ByteTypes.h" ktory dolaczy sie o ile juz wczesniej nie zostal dolaczony przez inny plik .h

Marcin

Reply to
Marcin

Rozumiem, optymalizacja czasu kompilacji. Moze tez sie nad tym zastanowie, bo kompilacja projektu pod Keil'em ponad na 100 plikow .c zaczyna sie dluzyc w pracy. M

Reply to
Marcin

ponad na 100 plikow .c zaczyna sie dluzyc w pracy.

Za każdym razem musisz kompilować wszystkie 100 plików (czyt. zmiany są zawsze we wszystkich plikach)?

Reply to
Marek

Oczywiscie ze nie za kazdym razem - incremental build dziala. Jednak Czasami po updacie z SVNa czesciowy build nie dzialc - czy to wina IDE czy svn nie wnikalem doglebnie. Nawet winavr + eclipse + avrplugin +Ctrl-B zajmuje kilkanascie sek. Dodac flashowanie i czlowiek sie lapie, ze kazdej minimalnej zmiany na sztbko nie sprawdzac, czy "juz dziala"

Marcin

Reply to
Marcin

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.