Atmel Studio, projekt w wielu plikach i dyrektywa #include
Nov 24, 2013 11 Replies
A
Atlantis
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:
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.
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?
Didn't find your answer? Ask the community — no account required.
M
Marek
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
A
Atlantis
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?
G
Grzegorz Niemirowski
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ę.
G
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.
J
janusz_k
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
P
Piotr Gałka
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.
M
Marcin
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
P
Piotr Galka
Uzytkownik "Marcin" snipped-for-privacy@o2.pl napisal w wiadomosci news: snipped-for-privacy@googlegroups.com...
Otoczenie #include przez #ifdef zapobiega analizowaniu przez kompilator wlaczanego pliku. Kompilator nie jest jasnowidzem i po sekwencji: #ifndef __ByteTypes_H__ #define __ByteTypes_H__ nie wie, ze reszty moze nie czytac - musi wyszukac pasujacy #endif wiec musi przynajmniej analizowac kolejne #ifcostam (aby pominac odpowiednie #endif-y), co oznacza koniecznosc czytania calego pliku i co najmniej minimalnej analizy kazdej kolejnej linii kodu. Moje pliki .h sa wzglednie krótkie, ale biblioteczne pliki .h potrafia byc dlugasne. Kiedys dawno, gdy zaczynalem, komputery nie byly tak szybkie jak teraz (do tego pierwszy PC jaki kupilismy do firmy byl bez hdd). Przyjalem sobie wtedy taki zapis (i juz tak zostalo) bo przy kompilacji wiekszego programu oszczedzalo to otwierania i analizowania wielu plików, co dawalo wyrazne przyspieszenie kompilacji nawet na komputerze posiadajacym hdd, a co dopiero na moim. P.G.
M
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
M
Marek
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)?
M
Marcin
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
Join the Discussion
Have something to add? Share your thoughts — no account required.
Didn't find your answer?
Ask the community — no account required
Report Content
You are reporting this content to the moderators. They will look at it
ASAP.