Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Delphi] Conditional Compiling *

Pagina: 1
Acties:
  • 151 views sinds 30-01-2008
  • Reageer

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 23:25
Ik wil van een programma van mij ook een console-versie maken. Het spreekt vanzelf dat de uitvoer hier bij anders moet. In de GUI doe ik de uitvoer (via messages uiteindelijk) naar een TMemo. Die is in de console-app niet beschikbaar (duh?).

Is er middels conditioneel compilen te ontdekken of je bezig bent vor een console-app of niet?

De windows-versie is bv:
Delphi:
1
2
3
4
5
6
7
Program Test1;

uses SysUtils, uitvoer;

begin
  Schrijf ('Hello world!');
end.


De console app is dan bv:
Delphi:
1
2
3
4
5
6
7
8
Program Test1con;
{$APPTYPE CONSOLE}
{$DEFINE CONSTEST}
uses SysUtils, uitvoer;

begin
  Schrijf ('Hello world!');
end.



Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Unit uitvoer;
uses SysUtils;

Procedure Schrijf(txt:string);

Procedure Schrijf(txt:string);
Begin
  {$IFDEF CONSTEST}
    WriteLn(txt);
  {$ELSE}
    Memo1.add(txt);
  {$ENDIF}
End;

end.


Ik hoopte via een eigen variabele (CONSTEST) te detecteren of er sprake is van een console-app, maar die moet in elke unit opnieuw worden gezet. Is er een andere manier om conditioneel te compileren?

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 23:25
Hieronder volgt een hoop onzin. {$IFDEF CONSOLE} werkt niet!

Volgens mij kan deze vraag alweer dicht.
Ik was via Google uitgekomen bij http://www.hu.freepascal....2000-December/000621.html

waar staat dat het niet kan, maar de briljante ingeving om {$IFDEF CONSOLE} te proberen kwam ik na het typen van dit topic pas op.

De unit wordt dan dus, bv:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Unit uitvoer;
uses SysUtils;

Procedure Schrijf(txt:string);

Procedure Schrijf(txt:string);
Begin
  {$IFDEF CONSOLE}
    WriteLn(txt);
  {$ELSE}
    Memo1.add(txt);
  {$ENDIF}
End;

end.

[ Voor 6% gewijzigd door jvdmeer op 17-12-2007 23:21 . Reden: {$IFDEF CONSOLE} werkt toch niet! ]


Verwijderd

Je kunt gewoon bij Project Options conditional defines zetten die voor het hele project gelden. Die $DEFINE zijn leuk en aardig, maar gelden enkel voor de betreffende unit of in units waar bestanden met conditional defines geinclude worden.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 28-11 08:35

curry684

left part of the evil twins

Wat jij zoekt is niet conditional compiling maar een fatsoenlijke scheiding van je functionaliteit in een class library en los daarvan 2 front-ends met verschillende subsystem Project Options voor console en GUI.

offtopic:
opgeloste topics worden hier overigens niet gesloten, alleen nutteloze topics. Een topic dat binnen 5 minuten door de topicstarter wordt opgelost heeft vaak nog steeds baat bij input van anderen en wordt bij zoekopdrachten geopend: topics worden gesloten als ze 'nutteloos' voor zowel search als discussie.

Professionele website nodig?


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 23:25
curry684 schreef op dinsdag 18 december 2007 @ 03:03:
Wat jij zoekt is niet conditional compiling maar een fatsoenlijke scheiding van je functionaliteit in een class library en los daarvan 2 front-ends met verschillende subsystem Project Options voor console en GUI.
Hoe bedoel je dat? Ik heb momenteel een project met daarin 2 exe's. (vergelijkbaar wscript.exe en cscript.exe). Deze roepen allerlei units aan.Hierbij wordt er gebruikt van logs. Deze logs worden via messages doorgegeven. Bij de gui-versie worden ze op verschillende getoond op verschillende tabbalden, en bij de console versie worden ze richting afzonderlijke logfiles geschreven (afhankelijk van thread).

Volgens mij, als ik zo in de code kijk (niet vergelijkbaar met de voorbeelden), dan heb ik juist de functionaliteit en de front-end erg goed gescheiden. Daarom kan ik nu juist makkelijk er een console-versie bij maken. Met de GUI-versie ben ik begonnen.

De grafische versie doet ongeveer:
Delphi:
1
2
3
4
begin
  Interpreter=TInterpreter.Create('test.script')
  Interpreter.Run
end;

en ontvangt de verschillende logs via messages.

de console-versie doet ongeveer
Delphi:
1
2
3
4
5
{$APPTYPE CONSOLE}
begin
  Interpreter=TInterpreter.Create('test.script')
  Interpreter.Run
end;

En hierbij worden de logs weggeschreven. Het enige verschil tussen de beide programma's bevindt zich in de log-unit. In het ene geval worden er messages gegenereerd, in het ander geval een writeln.

[ Voor 0% gewijzigd door jvdmeer op 18-12-2007 10:06 . Reden: typo ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 28-11 20:02

Tomatoman

Fulltime prutser

(jarig!)
Heb je al overwogen om een scheiding te maken door middel van classes? Je maakt twee verschillende classes die allebei descendants zijn van een abstracte base class. De ene class schrijft tekst naar een console, de andere naar een memo. Even uit de losse pols:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
type
  TAbstractLog = class
  public
    procedure Schrijven(const Txt: string); virtual; abstract;
  end;

  TConsoleLog = class(TAbstractLog)
  public
    procedure Schrijven(const Txt: string); override;
  end;

  TMemoLog = class(TAbstractLog)
  private
    FMemo: TMemo;
  public
    constructor Create(AMemo: TMemo);
    procedure Schrijven(const Txt: string); override;
  end;

implementation

procedure TConsoleLog.Schrijven(const Txt: string); 
begin
  WriteLn(Txt);
end;

constructor TMemoLog.Create(AMemo: TMemo);
begin
  FMemo := AMemo;
end;

procedure TMemoLog.Schrijven(const Txt: string); 
begin
  FMemo.Add(Txt);
end;

En in de unit waarin je code code aanroept:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var
  Log: TAbstractLog;

procedure CreateLog;
begin 
  {$IFDEF CONSOLE} 
    Log := TConsoleLog.Create;
  {$ELSE} 
    Log := TMemoLog.Create(Memo1);
  {$ENDIF} 
end;

procedure AddLogText(const S: string);
begin
  Log.Schrijven(S);
end;

Nu heb je maar op één plaats een conditional define gebruikt, namelijk daar waar je het log-object creërt, en heb je voor de rest alleen generieke code geschreven. Dat maakt je code een stuk leesbaarder en ook een stuk beter te onderhouden.

Een goede grap mag vrienden kosten.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 28-11 08:35

curry684

left part of the evil twins

Als je die scheiding al goed hebt zitten heb je alleen maar geluk :) Wat ik bedoel is dat je de 'generieke functionaliteit', dus het feitelijke testen zelf, in een losse classlib doet. Deze staat vervolgens toe een logger van buitenaf te registreren, die correct logt afhankelijk van z'n omgeving. Bijv. in C#-pseudo (m'n Delphi is echt 6 jaar geleden):
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface iLogTarget
{
  void Log(string logMessage);
}

class ConsoleLogTarget implements iLogTarget
{
  void Log(string logMessage) { Console.WriteLine(logMessage);
}

// GUI-versie:
static void main()
{
  MyTester woot = new MyTester();
  woot.RegisterLogTarget(new ConsoleLogTarget());
  InstantiateGUI(woot);
}

Snappie? :)

edit:
damn the tomatoman :P

Professionele website nodig?


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 23:25
tomatoman schreef op dinsdag 18 december 2007 @ 10:34:
[... Lang, leesbaar en logisch verhaal]
Deze oplossing leek mij ook wel wat, maar ik ben zelf niet zo een voorstander ervan dat er allerlei code voor TMemo e.d. terecht komt in de console-versie en v.v. Dat vind ik zelf een slechte gedachte. En middels Conditional Compiling, wordt de code helemaal weggelaten.

De log-code (gui danwel console) zal hoe dan ook zowel in de debug als in de definitieve code terechtkomen.

Maar misschien doe ik hier overdreven in, en kan ik daarin gewoon op de optimizer vertrouwen.
curry684 schreef op dinsdag 18 december 2007 @ 10:36:
[...]
Deze staat vervolgens toe een logger van buitenaf te registreren, die correct logt afhankelijk van z'n omgeving.
[...]

edit:
damn the tomatoman :P
Dit stukkie van je reactie begrijp ik niet. Wat bedoel je met 'van buitenaf'. Het is niet mijn bedoeling dat ik andere software moet gaan gebruiken om de logs te bekijken. In de gui-versie zit momenteel ook een debugger, die (indien gewenst) na elke regel de inhoud van alle variabelen/objecten toont. In de console versie zal dat er dus niet inzitten.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 28-11 08:35

curry684

left part of the evil twins

Wat je wil is de feitelijke functionaliteit in een generieke classlibrary stoppen, die opdrachten 'van buitenaf' aanneemt en output 'naar buitenaf' terugstuurt. De 'buitenkant' is dan dus een shell die enkel interfacet met de binnenkant.

Ter vergelijking werken webbrowsers hetzelfde. In Internet Explorer zit de feitelijke renderer in %SYSTEM32%/shdocvw.dll, en is iexplorer.exe enkel een GUI shell die er wat leuke knopjes en een adresbalk omheen zet. Je scheidt zo dus je presentatie en business logic correct, waardoor je meerdere versies kunt maken die in de diepte exact hetzelfde doen.

Professionele website nodig?

Pagina: 1