Conditional compilation/fi

From Free Pascal wiki

Deutsch (de) English (en) suomi (fi) français (fr) русский (ru)

Mitä on ehdollinen kääntäminen?

Ehdollinen kääntäminen ottaa mukaan tai jättää pois lähdekoodin osia, jos ehto on olemassa tai ei ole.

Useimmissa käännetyissä kielissä tämän mahdollistavia ominaisuuksia kutsutaan käännösaikaiseksi direktiiveiksi. Käännösaikaiset direktiivit mahdollistavat koodin lohkon kääntämisen, joka perustuu ehtojen läsnäoloon tai puuttumiseen käännösaikana. Ne kuuluvat kääntäjän ohjeisiin.

Niitä voidaan käyttää moniin eri tarkoituksiin, kuten:

  • Alustakohtaisen koodin eristämiseen
  • Luonnollisen kielenvalintaan
  • Avoimen- ja suljetun lähdekoodin osien käyttöoikeudet
  • Eristämään kokeellista (experimental) ohjelmakoodia
  • Kääntäjän versioihin
  • Kirjastoversioihin
  • jne.

Free Pascal tukee erilaisia ehdollisen kääntämisen tyylejä:

  • Turbo Pascal ja varhaiset Delphi-tyyliset ohjeet
  • Mac Pascal -tyyliset ohjeet
  • Uudemmat Free Pascal ja Delphi -tyyliset ohjeet
  • Käännösaikaiset makrot

Huomaa, että tässä syntaksissa ei erotella isoja ja pieniä kirjaimia koska se vastaa Pascal syntaksia. Eli käytetään sekä pieniä että isoja kirjaimia.

Turbo Pascal tyyliset ohjeet

Turbo Pascal -tyyppisiä ohjeita ovat {$DEFINE}, {$IFDEF}, {$ENDIF}, {$IFNDEF}, {$IFOPT}, {$ELSE}, {$ELSEIF} ja {$UNDEF}. Tässä kuvaillaan ohjeita tyylin yhteydessä. Jotkut ohjeet määrittelevät toisella tyylillä laajennetun merkityksen.

Tämä tarkoittaa myöhemmin, että voidaan laajentaa tiettyjen direktiivien merkitystä, kuten esimerkiksi. {$DEFINE} makrojen yhteydessä.

$define

{$DEFINE}-ohje yksinkertaisesti ilmoittaa tunnisteen, jota voidaan myöhemmin käyttää ehdolliseen kääntämiseen:

{$DEFINE name} // Määrittää tunnisteen nimeltä "name"

Huomaa, että voit myös määrittää tunnisteen komentoriviltä tai IDEstä esimerkiksi

-dDEBUG komentorivillä on sama kuin

{$DEFINE DEBUG}

lähdekoodissa.


$undef

{$UNDEF}direktiivissä määritellään aiemmin määritelty symboli. Tässä on esimerkki, jota voidaan käyttää:

// Some older source code is polluted with {$IFDEF FPC} that are no 
// longer necessary depending on the Delphi version to which it it should be compatible.
// I always test this by trying this on top of the program or unit:
{$IFDEF FPC}
  {$MODE DELPHI}
  {$UNDEF FPC}
  {$DEFINE VER150} 
  // code will now compile as if it was Delphi 7, provided the original Delphi source code was indeed written for Delphi 7 and up.
{$ENDIF}

$ifdef ja $endif

Yksinkertaisin tapa määrittää ehdollisen koodin lohko on näin:

unit cross;
{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}

Yllä oleva esimerkki on varsin yleinen lähdekoodissa, joka on koottava sekä Delphissä että Free Pascalissa

Jos kääntäjä on Delphi, niin mitään ei tehdä, mutta jos kääntäjä on Free Pascal, se siirtää Free Pascalin kääntämään ja käyttämään Delphi-tilaa.

Ehdollinen tunniste "FPC" on määritelty järjestelmässä - on olemassa pitkä luettelo niistä. {$IFDEF} ja {$ENDIF} lohkon syntaksi on symmetrinen: jokaisella {$IFDEF}:llä on oma {$ENDIF}.

Vastaavia lohkoja voidaan auttaa tunnistamaan käyttämällä esim. sisennystä, mutta voidaan käyttää myös kommentteja:

{$IFDEF FPC this part is Free Pascal specific}
// some Free Pascal specific code
{$ENDIF Free Pascal specific code}
Warning-icon.png

Warning: Kommenttiominaisuutta ei usein ymmärretä. Sillä vain yksi ehto hyväksytään {$IFDEF} ehtoon. Kääntäjä olettaa lopun olevan kommenttia.
Alla oleva koodi suorittaa writeln lauseen, jos ja vain jos red on määritelty . Tässä esimerkissä {$ifdef blue} on vain kommenttia! Vaikka määrittely {$define blue} on voimassa.

// Täysin väärin ymmärretty ohjelma
{$define blue}  
begin
{$ifdef red or $ifdef blue}// kaikki red:n jälkeen on kommenttia
  writeln ('red or blue'); // tätä koodia ei koskaan suoriteta ellei red ole voimassa
{$endif red or blue}       // kaikki $endif:n jälkeen on kommenttia.
end.

$ifndef

Tämä on päinvastainen kuin {$IFDEF} eli koodi sisältyy tiettyyn ehtoon, jota ei ole määritelty. Yksinkertainen esimerkki on:

{$IFNDEF FPC Tämä osa ei kuulu Free Pascal kääntäjälle}
// jotain erityistä koodia mitä Free Pascal ei käännä
{$ENDIF koodin osa päättyi joka oli vain muille kääntäjille kuin  Free Pascal}

$else ja $elseif

{$ELSE} käytetään kääntämään koodia, joka ei kuulu koodilohkoon, jonka määrittelee vastaava {$IFDEF}. Se on toimii myös {$IFOPT}, {$IF} tai {$IFC} kanssa.

{$IFDEF red}  
   writeln('Red is defined');  
{$ELSE  no red}  
  {$IFDEF blue}  
   writeln('Blue is defined, but red is not defined');  
  {$ELSE no blue}  
  writeln('Neither red nor blue is defined'); 
  {$ENDIF blue}  
{$ENDIF red}

Tällainen sisäkkäinen ehdolliseen kääntämiseen kirjoitettu koodi käyttäen edellä mainittua syntaksia voi olla hyvin sotkuista ja lukematonta. Onneksi sitä voidaan yksinkertaistaa käyttämällä {$ELSEIF}. Alla on vastaava koodi:

{$IF Defined(red)}  
  writeln('Red is defined');  
{$ELSEIF Defined(blue)}  
  writeln('Blue is defined');  
{$ELSEIF Defined(green)}  
  writeln('Green is defined');   
{$ELSE}
  writeln('Neither red, blue or green. Must be black...or something else...');
{$ENDIF}

Tämä on paljon luettavampi.

$ifopt

{$IFOPT} -toiminnolla voidaan tarkistaa, onko tietty kääntämisvaihtoehto määritetty.

Programmers manual:

 The {$IFOPT switch} will compile the text that follows it if the switch switch is currently in the specified state. If it isn’t in      
 the specified state, then compilation continues after the corresponding {$ELSE} or {$ENDIF} directive.

Esimerkiksi:

 {$IFOPT M+}  
   Writeln(Compiled with type information);  
 {$ENDIF}

Kääntää Writeln-lauseen vain, jos tyyppitietojen generointi on käytössä. Huomautus: {$IFOPT}-ohje hyväksyyn vain lyhyitä vaihtoehtoja, eli {$IFOPT TYPEINFO} ei hyväksytä.

Yleisesti tätä käytetään kun testataan onko DEBUG tila käytössä:

{$IFOPT D+}{$NOTE debug-tila on käytössä}{$ENDIF}

Tällaiset määritykset voivat myös sijaita fpc.cfg: n kaltaisissa määritystiedostoissa, jotka sisältävät myös täydellisen selityksen siitä, miten sitä käytetään:

# ----------------------
# Defines (preprocessor)
# ----------------------
#
# nested #IFNDEF, #IFDEF, #ENDIF, #ELSE, #DEFINE, #UNDEF are allowed
#
# -d is the same as #DEFINE
# -u is the same as #UNDEF
#
#
# Some examples (for switches see below, and the -? help pages)
#
# Try compiling with the -dRELEASE or -dDEBUG on the command line
#
# For a release compile with optimizes and strip debug info
#IFDEF RELEASE
  -O2
  -Xs
  #WRITE Compiling Release Version
#ENDIF

Mitä ei saa tehdä

Mitä vikaa tässä koodissa? Voitko havaita sen?

var
  MyFilesize:
  {$ifdef Win32} 
    Cardinal 
  {$else}
    int64
  {$endif}

Vastaus on:

Tässä ohjelmoija joutui ansaan, joka on yleinen: jos käyttää määritelmää niin pitää varmistaa että sen logiikka on vankka. Muuten tällainen koodi voi helposti aiheuttaa ognelmia. Kääntäjä ei havaitse logiikkavirheitä!

On aina hyvä ymmärtää tällaisia ​​asioita erityisesti ja että tällaiset asiat voidaan helposti korjata.

var
  MyFilesize:
  {$if defined(Win32)} 
    Cardinal 
  {$elseif defined(Win64)}
    Qword;
  {$else}
     {$error this code is written for win32 or win64}
  {$endif}

Tähän on ratkaisu, joka ei käytä ehtoja lainkaan:

var
  MyFilesize:NativeUint;

Mitä vikaa tässä koodissa?

  
{$IFDEF BLUE AND $IFDEF RED} Form1.Color := clYellow; {$ENDIF}
{$IFNDEF RED AND $IFNDEF BLUE} Form1.Color := clAqua; {$ENDIF}

Vastaus on:

  • Katso kohtaa missä kerrottiin kommenteista ja varoitettiin niistä
  • Kääntäjän ohjeet siis ohjaavat käännöstä.
Directives, definitions and conditionals definitions
global compiler directives • local compiler directives

Conditional Compiler Options • Conditional compilation • Macros and Conditionals • Platform defines
$IF