Multiplatform udvikling

Tags:    c++
Skrevet af Bruger #2695 @ 05.02.2004
Hej alle C/C++ kodere.
Denne artikel er tilgængt dem, som vil udvikle software, som kan compile under flere operativ systemer som f.eks. Windows og Linux. Jeg håber, det vil lykkes mig at få flere til at skrive arkitektur uafhængig kode :-)

Baggrund


C/C++ definerer en syntax som er standardiseret. Det betyder i teorien, at kode, som compiler under Linux, også burde compile under Windows. Det er bare ikke altid tilfældet og det kan der være flere årsager til:
* Man bruger et API, som er tilgængeligt på én platform men ikke på en anden.
* Compilere virker desværre ikke altid helt éns.

Det er alligevel muligt, at producere et stort program, som kan compile på flere platforme og som endda virker éns. Det er det jeg vil beskrive i denne artikel.

Betinget compilering


Inden C/C++ kode compiles, bliver den præprocesseret. Det betyder at visse strenge i koden bliver udskiftet med noget andet. F.eks. udskifter præprocessoren '#include <iostream>' med indholdet af iostream filen og hvis man har en '#define MAX(x,y) ((x) > (y) ? (x) : (y))' så vil præprocessoren efterfølgende udskifte alle referencer til MAX med '((x) > (y) ? (x) : (y))'.
Præprocessoren har også en feature, der gør det muligt at fjerne kode, som under visse omstændigheder ikke skal compiles, og det er denne feature, vi skal kigge nærmere på.
Ligesom man kan definere symboler '#define SOME_SYMBOL', så kan man også tjekke på, om et symbol er defineret. Det gøres med '#if defined(SOME_SYMBOL)'. Det kan illustreres med et lille eksempel:

Fold kodeboks ind/udKode 


Man kan også tjekke om et symbol ikke er defineret. Dette gøres med '#if !defined'. Eller man kan lave en '#else' eller '#elsif defined' som vist i dette eksempel:

Fold kodeboks ind/udKode 


Alle compilere kommer med nogle symboler, som altid er defineret. Under Linux er symbolet '__linux__' altid defineret og under Windows er '_WIN32' defineret. Det kan vi så tjekke på:

Fold kodeboks ind/udKode 


Fejl


Præprocessoren har også en feature der gør det muligt at standse compileringen, hvis vi mener, at der er noget galt. Denne feature hedder '#error' og bruges sådan her:

Fold kodeboks ind/udKode 


Et fuldt eksempel
Vi kan nu gå i gang med at lave et mere realistisk eksempel på et multiplatform program. Når man udvikler, laver man som oftest første version på én platform, og når den så virker, så porterer man koden til en anden, og den næste, osv. Jeg er Linux bruger, så jeg udvikler under Linux og porter til Windows.
Vores lille projekt bliver et program, som lister alle filer og directories i en given path.
Under Linux bruger man følgende funktioner til at iterere gennem filerne i et directory:
Fold kodeboks ind/udKode 


Vi prøver med Linux versionen:
Fold kodeboks ind/udKode 


Det det ser ud til at virke udmærket. Vi søger lidt på msdn.microsoft.com og finder ud af at de tilsvarende Windows kald hedder:
Fold kodeboks ind/udKode 


Så vi præprocesserer Linux koden ud og laver en Windows version:
Fold kodeboks ind/udKode 


Så nemt er det.

Arkitektur


Betinget compilering er en stærk feature men jo mindre man behøver at bruge den desto bedre, derfor bør man opbygge en arkitektur som abstraherer over forskelle i platformen.
Hvis vi skal bruge fil listninger flere steder i vores program ville det hurtigt blive grimt med en masse '#if defined' overalt. I stedet kunne vi definere en klasse, som indkapsler denne afhængighed og derefter glemme alt om den.
Man kan også slippe for at bekymre sig om arkitekturen ved at bruge platformuafhængige libraries. F.eks. kan man bruge ACE (http://www.cs.wustl.edu/~schmidt/ACE.html) til netværks og multi trådet programmering og Crypto++ (http://www.eskimo.com/~weidai/cryptlib.html) til kryptering.

Afslutning


Det var det !! Jeg håber ikke, at det var så svært, og jeg håber, at der kommer lidt mere platformuafhængig kode fra nu af.
Betinget compilering kan også bruges til andet end at skrive platform uafhængig kode.
Hvis man f.eks. er flere om at skrive på den samme kode og man gerne vil lave noget som måske ikke compiler eller virker længe, så kan man sørge for at det kun compiler hvis TEST_NEW_NET_PROTOCOL er defineret. Der er mange andre muligheder..flere end jeg vil nævne her.

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (5)

User
Bruger #4882 @ 29.02.04 17:30
God artikel, men du kunne nok godt forklare lidt bedre hvad der sker i det sidste eksempel
User
Bruger #3009 @ 15.05.04 15:40
Helt sikkert en god artikel, har længe manglet den!
User
Bruger #7954 @ 08.08.05 22:52
Fint at du nævner ACE osv, men hvad med Boost??

www.boost.org

Så undgår du alle de grimme defines, plus du får lækker kode. :D
User
Bruger #3353 @ 29.03.06 19:23
fin artikel men det går rigtig hurtig til sidst og ikke helt forklaret men 4 fordi at resten af artiklen var kanon"
User
Bruger #8985 @ 29.01.07 11:30
Super artikel. Du får fire. Det er bestemt noget jeg vil have i baghovedet, næste gang jeg skriver et program :).
Du skal være logget ind for at skrive en kommentar.
t