ESWE1P1 Opdracht 1: Inleiding QNX en make.

© Harry Broeders.

Inleiding QNX.

In dit practicum maken we gebruik van het real-time OS QNX Neutrino. Dit real-time OS is speciaal ontworpen om gebruikt te worden voor embedded systemen. Wij gebruiken het OS gewoon op PC's (lekker goedkoop) maar je moet je voorstellen dat de ontwikkelde software uiteindelijk als een embedded applicatie moet draaien. QNX Neutrino en de bijbehorende ontwikkelomgeving QNX Momentics zijn gratis te downloaden en ook thuis prima te gebruiken. Ik raad je sterk aan om zelf ook thuis met QNX aan de slag te gaan!

QNX is IEEE POSIX 1003.1 compatible. IEEE POSIX 1003.1 is een standaard voor UNIX systemen. QNX implementeert ook de real-time faciliteiten uit deze standaard, de meeste andere UNIX systemen (inclusief Linux) implementeren deze real-time faciliteiten niet. Er zijn wel enkele real-time versies van Linux beschikbaar maar ook deze zijn (tenminste degene die bij mij bekend zijn) niet POSIX compatible. Een ander bekend POSIX compatible RTOS is VxWorks.

In lokaal 428 (en ook in 213) is op elke PC QNX Neutrino beschikbaar. Je kunt inloggen als gebuiker root met paswoord root. Alle files die je daar opslaat blijven echter niet bewaard! Je kunt je files via scp (secure copy) opslaan op je H:\ drive. Dit wordt verderop uitgelegd.

Doordat QNX POSIX compatible is kun alle commando's die je bij het Linux practicum hebt geleerd toepassen. Een goede inleiding in het gebruik van UNIX (= Linux = QNX) kun je vinden op: http://wks.uts.ohio-state.edu/unix_course/intro-1.html. Je kunt onder QNX meerdere virtuele terminals openen. In een terminal window:

Opdracht 1a.

Log in op een QNX systeem in lokaal 428 of 213 als gebruiker root met paswoord root. Open een virtual terminal en probeer een paar van de bekende Linux commando's. Maak indien nodig gebruik van de helpfiles. Maak een directory eswe1 met daarin een file hallo.txt met de tekst Hallo:

mkdir eswe1
cd eswe1
echo "Hallo" >hallo.txt
ls
cat hallo.txt
cd ..
ls

Je kunt nu in een keer dit directory naar je H:\ drive kopiëren met het scp commando:

scp -r eswe1 EDU-jouwnaam@ssh-gw.hhs.nl:

Voor jouwnaam moet je uiteraard je eigen inlognaam invullen. De eerste keer dat je verbinding maakt wordt gevraagd:

The authenticity of host 'ssh-gw.hhs.nl (145.52.89.10)' can't be established.
RSA key fingerprint is 49:de:1a:c4:c0:42:d3:7e:6f:7b:85:1e:74:94:4f:87.
Are you sure you want to continue connecting (yes/no)?

Dit is een onderdeel van het SSH protocol en bedoeld om te controlleren of je echt met de juiste server praat. Meer info vind je hier: http://winscp.net/eng/docs/ssh#verifying_the_host_key. Beantwoord deze vraag met yes. Vervolgens wordt om je paswoord gevraagd.

Ook vanaf thuis kun je jouw H:\ drive benaderen!

Zoek je nog een VCP (Vrij Credit Point) opdracht? Ik zoek nog iemand die wil uitzoeken of er een grafische sftp client voor QNX beschikbaar is. Of die anders een eenvoudige grafische applicatie kan schrijven om, met 1 druk op de knop, je files van een QNX machine op te slaan op je H:\ drive (en weer te terug te zetten).

Verwijder nu het eswe1 directory en zet daarna de files die je op je H:\ drive hebt opgeslagen weer terug:

rm -r eswe1
ls
scp -r EDU-jouwnaam@ssh-gw.hhs.nl:eswe1 .
ls
cat eswe1/hallo.txt

Aan het eind van elk practicum moet je dus zelf je files opslaan en aan het begin van het volgende practicum kun je die files dan weer terugzetten.

Tip: QNX kent net zoals Windows en Linux "command completion" (commado's en filenames worden automatisch afgemaakt) alleen gebruikt QNX hiervoor niet de TAB toets maar de ESC toets.

Ik heb nog niet geprobeerd om de files vanuit QNX op een USB stick op te slaan. Zie: http://www.qnx.com/developers/docs/6.3.2/neutrino/user_guide/hardware.html#USB

De ontwikkeltools van QNX (Momentics) zijn gebaseerd op de bekende GNU tools http://www.gnu.org. Bijna alles wat je leert over QNX kun je dus ook toepassen op Linux of elk ander UNIX systeem.

Opdracht 1a (vervolg).

Schrijf een klein C of C++ programma met behulp van ped (de standaard QNX editor) of met vi. Een ANSI C programma moet de extensie ".c" krijgen en een ANSI C++ programma de extensie ".cpp". Compileer het programma met gcc (voor C programma's) of g++ (voor C++ programma's) en run het gecompileerde programma a.out.

QNX heeft ook veel grafische programma's. Deze programma's kun je via de Launch button (waarschijnlijk heeft Microsoft de Start geregistreerd ;-) of via de rechter knoppenbalk opstarten. Enkele handige sneltoetsen:

QNX heeft ook een grafische File Manager:

De webbrowser van QNX heet Voyager. In plaats van Voyager kun je ook gebruik maken van de Mozilla browser.

Voor het ontwikkelen van software gebruiken wij het programma Workspace. Dit programma staat op de 3th party CD van QNX. Het bestaat uit een code editor, html browser en een koppeling met sh, make, gdb en ctags. De kleuren moet je even aan wennen (of aanpassen via Edit, Preferences menu).

Inleiding make.

Als een C programma gewijzigd wordt dan moet dit programma uiteraard opnieuw gecompileerd worden. Dit kan wel eens even duren als het C programma uit een groot aantal regels bestaat. Dit probleem kan opgelost worden door het C programma niet in 1 source file te plaatsen maar te verdelen over meerdere source files. Deze source files kunnen dan separaat gecompileerd worden m.b.v. het commando gcc -c source-filename. De op deze wijze verkregen z.g. object files zijn vanzelfsprekend niet "executable" omdat b.v. de adressen van gebruikte variabelen die in een andere source file gedefinieerd zijn (z.g. external variables) nog moeten worden ingevuld. Deze object files kunnen echter wel m.b.v. een z.g. linker (ld) samengevoegd worden tot 1 executable programma. Het commando gcc zal automatisch de linker ld aanroepen als de, als argumenten, meegegeven files object files zijn (herkenbaar aan de extensie ".o"). Als er nu wijziging aangebracht wordt in 1 van de source files van het programma dan is het dus niet meer nodig dat het gehele programma gecompileerd wordt. Er kan in dit geval volstaan worden met het separaat compileren van de gewijzigde source file en het opnieuw linken van alle object files. Deze manier van werken levert dus een aanzienlijke tijdsbesparing op bij de ontwikkeling en het testen van een "groot" C programma. De wet van behoud van ellende zorgt er echter voor dat deze manier van werken ook een aantal vragen of problemen oproept:

Het gebruik van z.g. "header files" lost het eerste probleem op en het gebruik van de UNIX utility make vormt een antwoord op de tweede vraag.

Header files.

M.b.v. de compiler directive #include "file_name.h" kunnen z.g. "header" files in een source programma opgenomen worden. De compiler (om precies te zijn de pre-processor) zal de regel waarop deze directive staat vervangen door de inhoud van de opgegeven header file. Het is gebruikelijk om header files de extensie ".h" te geven. Als er in verschillende source files b.v. gebruik gemaakt wordt van hetzelfde type, dan kan de betreffende type definitie in een header file worden opgenomen. Deze header file moet dan in alle source files die gebruik maken van dit type "included" worden. Als nu dit gemeenschappelijk gebruikte type gewijzigd moet worden dan kan volstaan worden met het wijzigen van de header file en het opnieuw compileren van de source files die gebruik maken van dit type.

Er bestaat bij veel "beginnende" C programmeurs verwarring over het gebruik van include files bij het gemeenschappelijk gebruik van variabelen en functies.

Het gemeenschappelijk gebruik van variabelen.

Stel dat een C programma verdeeld is over 3 source files en dat in al deze source files gebruik gemaakt wordt van de globale variabele globe van het type long. Het is nu niet goed om een header file aan te maken waarin de definitie:

	long globe;

is opgenomen en deze file in de 3 source files te "includen".

Dit werkt niet omdat bij het compileren van elke source file de variabele globe wordt gedefinieerd (in de object file wordt aangegeven dat er in het datasegment van het programma een variabele van het type long met als naam globe moet worden opgenomen die ook toegankelijk is voor andere object files). Als geprobeerd wordt om deze 3 object files te linken dan zal de linker een foutmelding geven omdat de variabele globe drie maal gedefinieerd is. (Om helemaal correct te zijn: Als geprobeerd wordt om deze 3 object files te linken dan zal de linker de fout herkennen en verbeteren. De linker zal de eerste definitie normaal verwerken en alle volgende identieke definities (die dus eigenlijk fout zijn) verwerken als declaraties. Dit gedrag heeft in het verleden voor veel problemen gezorgd bij het debuggen. Het lijkt namelijk alsof een bepaalde variabele in een bepaalde file gedefinieerd (en dus ook gealloceerd) wordt terwijl deze variabele in werkelijkheid ergens anders gedefinieerd is. De opvolger van C, de programmeertaal C++, genereert wel een foutmelding als een variabele meerdere malen globaal gedefinieerd wordt. De gcc compiler heeft een speciale linker optie -Wl,-warn-common. Als deze optie wordt opgegeven dan wordt een warning gegeven als een variabele meerdere keren gedefinieerd is.)

De juiste manier van werken is als volgt:

In 1 van de drie source files moet de variabele globe als volgt worden gedefinieerd:

	long globe;

Er moet een header file worden aangemaakt waarin de volgende declaratie is opgenomen:

	extern long globe;

D.w.z. dat de variabele globe in een andere file is gedefinieerd en dat het adres van deze variabele pas tijdens het linken kan worden ingevuld. Deze header file moet dan in de twee overige files "included" worden.

Het gemeenschappelijk gebruik van functies.

Voor het gemeenschappelijk gebruik van zelf geschreven functies geldt hetzelfde als voor het gemeenschappelijk gebruik van variabelen. Bij het gebruik van standaard functies heerst nogal eens verwarring over de functie van de header file:

Als gebruik gemaakt wordt van een standaard functie dan is het vaak nodig om een standaard header file te "includen". Als b.v. gebruik gemaakt wordt van de standaard functie sin() moet aan de compiler duidelijk gemaakt worden wat het return type van deze functie is. Dit kan op twee manieren:

De C code van de functie sin staat dus vanzelfsprekend niet in de header file math.h. De source code van de functie sin is vaak zelfs niet op het systeem aanwezig. De source code van de gebruikte GNU libraries (open-source) zijn wel beschikbaar. Misschien is de functie sin wel helemaal niet in C geschreven! De declaratie geeft alleen maar aan dat de functie vanuit C aan te roepen is. De object code van de functie sin bevindt zich in de math library (libm.a). Bij het linken moet er dus voor gezorgd worden dat deze object code wordt meegelinkt. M.b.v. de optie -lm kan opgegeven worden dat bij het linken de math library (libm.a) moet worden doorzocht en dat de gebruikte object modules moeten worden opgenomen in de uiteindelijke executable file. (Er is 1 library die bij het linken automatisch altijd wordt doorzocht. Dit is de z.g. "standard library" die o.a. de object code van alle functies die in stdio.h zijn gedeclareerd bevat.)

In nevenstaand figuur is een overzicht gegeven van de verschillende stappen die doorlopen moeten worden om een C programma dat verdeeld is over 2 source files te vertalen.

Mogelijke commando's:
van..c.naar..out gcc_p1.c_p2.c doorzoek alleen standard library
_ gcc_p1.c_p2.c_-lm doorzoek standard en math library
van..c.naar..o gcc_-c_p1.c maak p1.o
van..c.naar..s gcc_-S_p2.c maak p2.s
van..s.naar..out gcc_p1.s_p2.s alleen standard library
van..s.naar..o gcc_-c_p1.s maak p1.o
van..o.naar..out gcc_p1.o_p2.o alleen standard library
combinatie gcc_p1.c_p2.o_-lm Maak eerst p1.o m.b.v. de pre-processor, de compiler en de assembler. Doorzoek de standard library en de math library en link de benodigde object modules tezamen met p1.o en p2.o tot de executable file a.out.

Een overzicht van de verschillende opties waarmee je kunt bepalen welke acties de gcc compiler neemt kun je in de QNX help files vinden.

Make.

De UNIX utility make kan voorkomen dat, nadat er in verschillende source files wijzigingen aangebracht zijn, vergeten wordt om een gewijzigde source file te compileren. Een beschrijving van deze utility is hier beschikbaar. Lees in ieder geval dit hoofdstuk. (Het hele hoofdstuk!)

Opdracht 1b.

  • Kopieer de file sort.c naar je eigen directory.
  • Verdeel deze source code met behulp van de Workspace editor over minimaal 3 .c en 1 .h files. Je moet de door jou gekozen verdeling kunnen verdedigen.
  • Maak een bijbehorende makefile en compileer het programma m.b.v. deze makefile.
  • Verander 1 of meer van de sourcefiles en controleer of make correct werkt.

Bij de beoordeling wordt gevraagd om:

  • de door jou gekozen indeling van de verschillende modules te beargumenteren.
  • de code uit de door jou ontworpen makefile toe te lichten.
  • te laten zien dat make correct werkt.

Verder met opdracht 2...