Ko program preraste eno samo datoteko, potrebuje red. Datoteke se razmnožijo, prevajanje postane zapleteno, končni rezultat pa ni jasno ločen od izvorne kode. Tu nastopi pravi programski produkt – projekt z jasno strukturo, Makefile sistemom in vlogo za vsak imenik.
V tem poglavju spoznamo, kako so organizirani resni programi za sistem Partner. Za vzor nam bo demonstracijski program iz repozitorija idp-app, ki je prosto dostopen na GitHubu:
https://github.com/iskra-delta/idp-app
Program sam po sebi ni zapleten – po zaslonu odskakuje štirinajst majhnih žog. Toda za tistega, ki ga je treba spraviti v tek, je to velik korak: grafika v ločljivosti 1024×256 točk, dvojno preklapljanje strani, zbirniška pisava za naslov in popoln Makefile, ki za vas prevede vse skupaj znotraj Docker vsebnika.
Na vrhu zaslona je naslov. Pod njim je omejeno polje, po katerem se premikajo žoge – vsaka s svojo hitrostjo in smerjo. Ko žoga zadene rob, se odbije. Animacija teče gladko, ker program nikoli ne riše neposredno na prikazano stran zaslona.
Namesto tega uporablja dvojno preklapljanje strani (double buffering): medtem ko se ena stran prikazuje, program tiho riše na drugo. Ko je nova slika pripravljena, strani zamenja z enim samim klicem. Gledalec nikoli ne vidi vmesnega stanja – le gladko gibanje. To je klasičen trik, ki so ga programerji izpilili v zgodnjih osemdesetih, ko so igre morale teči hitro na skromni strojni opremi.
Program prenesete na PC računalnik z Linuxom z orodjem Git. Ukaz git clone ustvari nov imenik z vso izvorno kodo, datotekami Makefile in dokumentacijo:
git clone https://github.com/iskra-delta/idp-app
Po prenosu vstopite v imenik projekta:
cd idp-app
Zdaj ste pripravljeni na gradnjo.
Po prenosu boste v imeniku videli naslednjo strukturo:
idp-app/
├── Makefile
├── README.md
└── src/
├── Makefile
├── idp8x16_font.s
└── main.c
Vsak del ima svojo vlogo:
Makefile v korenu projekta je vstopna točka za gradnjo. Skrbi za zagon Docker vsebnika in prenese gradnjo nanj.src/Makefile vsebuje dejansko logiko prevajanja: pravila za datoteke C in zbirnik, povezovanje ter ustvarjanje diskovne slike.src/main.c je glavna izvorna datoteka z vso logiko animacije in grafike.src/idp8x16_font.s je zbirniška datoteka s pisavo, s katero program izrisuje naslov na zaslonu.Po uspešni gradnji sistem samodejno ustvari še dva imenika:
build/ – vmesna objektna koda in rezultati prevajanja,bin/ – končni rezultati: demo.com in demo.img.Projekt ima dve datoteki Makefile, vsako na svoji ravni. Skupaj tvorita elegantno ločitev med tem, kako se program prevaja, in tem, kje se prevaja.
Korenski Makefile je vstopna točka, ki jo kličete iz PC računalnika. Njegova naloga je preprosta: zagnati Docker vsebnik in v njem poklicati src/Makefile. Sam ne ve ničesar o prevajalniku – le pripravi okolje:
DOCKER_IMAGE ?= wischner/sdcc-z80-idp:latest
WORKDIR := $(CURDIR)
PROJECTS_DIR := $(abspath ..)
PROJECT_NAME := $(notdir $(WORKDIR))
UID := $(shell id -u)
GID := $(shell id -g)
DOCKER_RUN = docker run --rm \
--user $(UID):$(GID) \
-v "$(PROJECTS_DIR):/workspace" \
-w "/workspace/$(PROJECT_NAME)" \
$(DOCKER_IMAGE)
all:
@$(DOCKER_RUN) make -C src all
Posebej zanimiva je vrstica z -v: v vsebnik se priklopi nadrejeni imenik projekta, ne projekt sam. S tem Docker vsebnik dobi dostop do imenikov build/ in bin/, ki se nahajata v korenu projekta in kamor se shranjujejo rezultati. Spremenljivki UID in GID zagotovita, da ustvarjene datoteke ostanejo vaše in ne v lasti korenskega uporabnika.
Korenski Makefile pozna tri cilje:
all – prevede projekt,clean – izbriše imenika build/ in bin/,docker-pull – prenese Docker sliko, preden začnete z delom.src/Makefile vsebuje dejansko logiko prevajanja. Deluje znotraj Docker vsebnika in pozna vse podrobnosti orodne verige:
.c prevede z sdcc v objektno datoteko .rel in jo shrani v build/..s prevede z sdasz80 – to je zbirnik za Z80.ugpx.lib v datoteko .ihx.sdobjcopy pretvori .ihx v izvršljivo datoteko demo.com.cpmdisk ustvari diskovno sliko demo.img in nanjo doda demo.com.Celotna veriga od izvorne kode do diskovne slike se sproži samodejno z enim samim ukazom.
Gradnjo zaženete z ukazom:
make
Ob prvem zagonu Docker samodejno prenese sliko wischner/sdcc-z80-idp, če je še nimate lokalno. Nadaljnji zagoni so hitrejši, ker slika že obstaja. Po kratkem času boste v imeniku bin/ dobili:
bin/demo.com ← izvršljiva datoteka CP/M
bin/demo.img ← diskovna slika za emulator
Za brisanje vseh rezultatov gradnje:
make clean
Zaženite emulator PartEm in priključite bin/demo.img kot disk B:. Ko se prikaže ukazni poziv sistema Partner, zaženite program:
B:DEMO
Na zaslonu se prikaže naslov in po njem štirinajst žog, ki se odbijajo po polju. Program se po 200 sličicah zaključi sam od sebe in se vrne v ukazni poziv.
Demonstracijski program idp-app je namerno preprost – ima le imenik src/ in rezultate v bin/. Ko projekt raste, je koristno vedeti, kakšna je ustaljena struktura večjih C projektov. Spoznajmo jo:
projekt/
├── src/ izvorna koda programa
├── include/ javne glave (.h), ki jih vidijo drugi moduli
├── lib/ knjižnice, ki jih projekt vključuje ali gradi
├── build/ objektna koda in vmesni rezultati prevajanja
├── bin/ končni izvršljivi programi in diskovne slike
├── tests/ avtomatski testi
└── docs/ dokumentacija
Vsak imenik ima jasno dogovorjeno vlogo:
include/.Dobra struktura projekta ni le estetska odločitev. Je tista, ki vam bo po šestih mesecih dala vedeti, kam sodi nova datoteka.