ISCC.dpr 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. program ISCC;
  2. {$APPTYPE CONSOLE}
  3. {
  4. Inno Setup
  5. Copyright (C) 1997-2025 Jordan Russell
  6. Portions by Martijn Laan
  7. For conditions of distribution and use, see LICENSE.TXT.
  8. Command-line compiler
  9. }
  10. {x$DEFINE STATICCOMPILER}
  11. { For debugging purposes, remove the 'x' to have it link the compiler code
  12. into this program and not depend on ISCmplr.dll. You will also need to add the
  13. ..\Components and Src folders to the Delphi Compiler Search path in the project
  14. options. Also see IDE.MainForm's STATICCOMPILER and Compiler.Compile's STATICPREPROC. }
  15. uses
  16. SafeDLLPath in '..\Components\SafeDLLPath.pas',
  17. Windows,
  18. SysUtils,
  19. Classes,
  20. {$IFDEF STATICCOMPILER} Compiler.Compile, {$ENDIF}
  21. PathFunc in '..\Components\PathFunc.pas',
  22. Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
  23. Shared.CompilerInt in 'Src\Shared.CompilerInt.pas',
  24. Shared.FileClass in 'Src\Shared.FileClass.pas',
  25. Shared.ConfigIniFile in 'Src\Shared.ConfigIniFile.pas',
  26. Shared.SignToolsFunc in 'Src\Shared.SignToolsFunc.pas',
  27. Shared.Int64Em in 'Src\Shared.Int64Em.pas';
  28. {$SETPEOSVERSION 6.1}
  29. {$SETPESUBSYSVERSION 6.1}
  30. {$WEAKLINKRTTI ON}
  31. {$R Res\ISCC.manifest.res}
  32. {$R Res\ISCC.versionandicon.res}
  33. type
  34. PScriptLine = ^TScriptLine;
  35. TScriptLine = record
  36. LineText: String;
  37. Next: PScriptLine;
  38. end;
  39. TOptionID = 0..25;
  40. TOptions = packed set of TOptionID;
  41. TIsppOptions = packed record
  42. ParserOptions: TOptions;
  43. Options: TOptions;
  44. VerboseLevel: Byte;
  45. InlineStart: string[7];
  46. InlineEnd: string[7];
  47. SpanSymbol: AnsiChar;
  48. end;
  49. var
  50. StdOutHandle, StdErrHandle: THandle;
  51. StdOutHandleIsConsole, StdErrHandleIsConsole: Boolean;
  52. ScriptFilename: String;
  53. Definitions, IncludePath, IncludeFiles, Output, OutputPath, OutputFilename: String;
  54. SignTools: TStringList;
  55. ScriptLines, NextScriptLine: PScriptLine;
  56. CurLine: String;
  57. StartTime, EndTime: DWORD;
  58. Quiet, ShowProgress, WantAbort: Boolean;
  59. ProgressPoint: TPoint;
  60. LastProgress: String;
  61. IsppOptions: TIsppOptions;
  62. IsppMode: Boolean;
  63. procedure WriteToStdHandle(const Handle: THandle; const HandleIsConsole: Boolean; S: String);
  64. begin
  65. if Copy(S, 1, 1) <> #13 then
  66. S := S + #13#10;
  67. if HandleIsConsole then begin
  68. var CharsWritten: DWORD;
  69. WriteConsole(Handle, @S[1], Length(S), CharsWritten, nil);
  70. end else begin
  71. var Utf8S := Utf8Encode(S);
  72. var BytesWritten: DWORD;
  73. WriteFile(Handle, Utf8S[1], Length(Utf8S), BytesWritten, nil);
  74. end;
  75. end;
  76. procedure WriteStdOut(const S: String; const Warning: Boolean = False);
  77. var
  78. CSBI: TConsoleScreenBufferInfo;
  79. DidSetColor: Boolean;
  80. begin
  81. DidSetColor := Warning and StdOutHandleIsConsole and GetConsoleScreenBufferInfo(StdOutHandle, CSBI) and
  82. SetConsoleTextAttribute(StdOutHandle, FOREGROUND_INTENSITY or FOREGROUND_RED or FOREGROUND_GREEN);
  83. try
  84. WriteToStdHandle(StdOutHandle, StdOutHandleIsConsole, S);
  85. finally
  86. if DidSetColor then
  87. SetConsoleTextAttribute(StdOutHandle, CSBI.wAttributes);
  88. end;
  89. end;
  90. procedure WriteStdErr(const S: String; const Error: Boolean = False);
  91. var
  92. CSBI: TConsoleScreenBufferInfo;
  93. DidSetColor: Boolean;
  94. begin
  95. DidSetColor := Error and StdErrHandleIsConsole and GetConsoleScreenBufferInfo(StdErrHandle, CSBI) and
  96. SetConsoleTextAttribute(StdErrHandle, FOREGROUND_INTENSITY or FOREGROUND_RED);
  97. try
  98. WriteToStdHandle(StdErrHandle, StdErrHandleIsConsole, S);
  99. finally
  100. if DidSetColor then
  101. SetConsoleTextAttribute(StdErrHandle, CSBI.wAttributes);
  102. end;
  103. end;
  104. function GetCursorPos: TPoint;
  105. var
  106. CSBI: TConsoleScreenBufferInfo;
  107. begin
  108. if not StdOutHandleIsConsole or not GetConsoleScreenBufferInfo(StdOutHandle, CSBI) then
  109. Exit;
  110. Result.X := CSBI.dwCursorPosition.X;
  111. Result.Y := CSBI.dwCursorPosition.Y;
  112. end;
  113. procedure SetCursorPos(const P: TPoint);
  114. var
  115. Coords: TCoord;
  116. CSBI: TConsoleScreenBufferInfo;
  117. begin
  118. if not StdOutHandleIsConsole or not GetConsoleScreenBufferInfo(StdOutHandle, CSBI) then
  119. Exit;
  120. if P.X < 0 then Exit;
  121. if P.Y < 0 then Exit;
  122. if P.X > CSBI.dwSize.X then Exit;
  123. if P.Y > CSBI.dwSize.Y then Exit;
  124. Coords.X := P.X;
  125. Coords.Y := P.Y;
  126. SetConsoleCursorPosition(StdOutHandle, Coords);
  127. end;
  128. procedure WriteProgress(const S: String);
  129. var
  130. CSBI: TConsoleScreenBufferInfo;
  131. Str: String;
  132. begin
  133. if StdOutHandleIsConsole and GetConsoleScreenBufferInfo(StdOutHandle, CSBI) then begin
  134. if Length(S) > CSBI.dwSize.X then
  135. Str := Copy(S, 1, CSBI.dwSize.X)
  136. else
  137. Str := Format('%-' + IntToStr(CSBI.dwSize.X) + 's', [S]);
  138. end else
  139. Str := S;
  140. WriteToStdHandle(StdOutHandle, StdOutHandleIsConsole, Str);
  141. end;
  142. function ConsoleCtrlHandler(dwCtrlType: DWORD): BOOL; stdcall;
  143. begin
  144. { Abort gracefully when Ctrl+C/Break is pressed }
  145. WantAbort := True;
  146. Result := True;
  147. end;
  148. procedure ReadScriptLines(const F: TTextFileReader);
  149. var
  150. LineNumber: Integer;
  151. PrevLine, L: PScriptLine;
  152. begin
  153. LineNumber := 1;
  154. PrevLine := nil;
  155. while not F.Eof do begin
  156. New(L);
  157. try
  158. L.LineText := F.ReadLine;
  159. if Pos(#0, L.LineText) <> 0 then
  160. raise Exception.CreateFmt('Illegal null character on line %d', [LineNumber]);
  161. L.Next := nil;
  162. except
  163. Dispose(L);
  164. raise;
  165. end;
  166. if Assigned(PrevLine) then
  167. PrevLine.Next := L
  168. else begin
  169. ScriptLines := L;
  170. NextScriptLine := L;
  171. end;
  172. PrevLine := L;
  173. Inc(LineNumber);
  174. end;
  175. end;
  176. procedure FreeScriptLines;
  177. var
  178. L, NextLine: PScriptLine;
  179. begin
  180. L := ScriptLines;
  181. ScriptLines := nil;
  182. NextScriptLine := nil;
  183. while Assigned(L) do begin
  184. NextLine := L.Next;
  185. Dispose(L);
  186. L := NextLine;
  187. end;
  188. end;
  189. function CompilerCallbackProc(Code: Integer; var Data: TCompilerCallbackData;
  190. AppData: Longint): Integer; stdcall;
  191. procedure PrintProgress(Progress: String);
  192. var
  193. Pt: TPoint;
  194. begin
  195. if (Progress = '') or (LastProgress = Progress) then
  196. Exit;
  197. Pt := GetCursorPos;
  198. if Pt.Y <= ProgressPoint.Y then
  199. Exit
  200. else if ProgressPoint.X < 0 then begin
  201. ProgressPoint := Pt;
  202. WriteStdOut('');
  203. Pt := GetCursorPos;
  204. end;
  205. SetCursorPos(ProgressPoint);
  206. WriteProgress(#13 + Progress);
  207. LastProgress := Progress;
  208. SetCursorPos(Pt);
  209. end;
  210. var
  211. S, BytesCompressedPerSecond, SecondsRemaining: String;
  212. begin
  213. if WantAbort then begin
  214. Result := iscrRequestAbort;
  215. Exit;
  216. end;
  217. Result := iscrSuccess;
  218. case Code of
  219. iscbReadScript: begin
  220. { Note: In Inno Setup 3.0.1 and later we can ignore Data.Reset since
  221. it is only True once (when reading the first line). }
  222. if Assigned(NextScriptLine) then begin
  223. CurLine := NextScriptLine.LineText;
  224. NextScriptLine := NextScriptLine.Next;
  225. Data.LineRead := PChar(CurLine);
  226. end;
  227. end;
  228. iscbNotifyStatus:
  229. if not Quiet then
  230. WriteStdOut(Data.StatusMsg, Data.Warning)
  231. else if ShowProgress then
  232. PrintProgress(Trim(Data.StatusMsg));
  233. iscbNotifySuccess: begin
  234. EndTime := GetTickCount;
  235. if not Quiet then begin
  236. WriteStdOut('');
  237. if Data.OutputExeFilename <> '' then begin
  238. WriteStdOut(Format('Successful compile (%.3f sec). ' +
  239. 'Resulting Setup program filename is:',
  240. [(EndTime - StartTime) / 1000]));
  241. WriteStdOut(Data.OutputExeFilename);
  242. end else
  243. WriteStdOut(Format('Successful compile (%.3f sec). ' +
  244. 'Output was disabled.',
  245. [(EndTime - StartTime) / 1000]));
  246. end;
  247. end;
  248. iscbNotifyError:
  249. if Assigned(Data.ErrorMsg) then begin
  250. S := 'Error';
  251. if Data.ErrorLine <> 0 then
  252. S := S + Format(' on line %d', [Data.ErrorLine]);
  253. if Assigned(Data.ErrorFilename) then
  254. S := S + ' in ' + Data.ErrorFilename
  255. else if ScriptFilename <> '' then
  256. S := S + ' in ' + ScriptFilename;
  257. S := S + ': ' + Data.ErrorMsg;
  258. WriteStdErr(S, True);
  259. end;
  260. iscbNotifyIdle:
  261. if ShowProgress and (Data.CompressProgress <> 0) then begin
  262. if Data.BytesCompressedPerSecond <> 0 then
  263. BytesCompressedPerSecond := Format(' at %.2f kb/s', [Data.BytesCompressedPerSecond / 1024])
  264. else
  265. BytesCompressedPerSecond := '';
  266. if Data.SecondsRemaining <> -1 then
  267. SecondsRemaining := Format(', %d seconds remaining', [Data.SecondsRemaining])
  268. else
  269. SecondsRemaining := '';
  270. PrintProgress(Format('Compressing: %.2f%% done%s%s', [Data.CompressProgress / Data.CompressProgressMax * 100, BytesCompressedPerSecond, SecondsRemaining]));
  271. end;
  272. end;
  273. end;
  274. procedure ProcessCommandLine;
  275. procedure SetOption(var Options: TOptions; Option: Char; Value: Boolean);
  276. begin
  277. if Value then
  278. Include(Options, Ord(UpCase(Option)) - Ord('A'))
  279. else
  280. Exclude(Options, Ord(UpCase(Option)) - Ord('A'))
  281. end;
  282. procedure InitIsppOptions(var Opt: TIsppOptions; var Definitions, IncludePath, IncludeFiles: String);
  283. begin
  284. with Opt do begin
  285. SetOption(Options, 'C', True);
  286. SetOption(ParserOptions, 'B', True);
  287. SetOption(ParserOptions, 'P', True);
  288. VerboseLevel := 0;
  289. InlineStart := '{#';
  290. InlineEnd := '}';
  291. end;
  292. Definitions := 'ISPPCC_INVOKED'#1;
  293. IncludePath := ExtractFileDir(NewParamStr(0));
  294. IncludeFiles := '';
  295. end;
  296. procedure ReadOptionsParam(var Options: TOptions; Symbol: Char);
  297. var
  298. I: Integer;
  299. S: String;
  300. begin
  301. for I := 1 to NewParamCount do
  302. begin
  303. S := NewParamStr(I);
  304. if Length(S) = 4 then
  305. if ((S[1] = '/') or (S[1] = '-')) and (UpCase(S[2]) = Symbol) then
  306. case S[4] of
  307. '-': SetOption(Options, S[3], False);
  308. '+': SetOption(Options, S[3], True)
  309. else
  310. raise Exception.CreateFmt('Invalid command line option: %s', [S]);
  311. end;
  312. end;
  313. end;
  314. function IsParam(const S: String): Boolean;
  315. begin
  316. Result := (Length(S) >= 2) and ((S[1] = '/') or (S[1] = '-'));
  317. end;
  318. function GetParam(var S: String; Symbols: String): Boolean;
  319. begin
  320. Result := IsParam(S) and
  321. (CompareText(Copy(S, 2, Length(Symbols)), Symbols) = 0);
  322. if Result then
  323. S := Copy(S, 2 + Length(Symbols), MaxInt);
  324. end;
  325. function FindParam(var Index: Integer; Symbols: String): String;
  326. var
  327. I: Integer;
  328. S: String;
  329. begin
  330. for I := Index to NewParamCount do
  331. begin
  332. S := NewParamStr(I);
  333. if IsParam(S) and (CompareText(Copy(S, 2, Length(Symbols)), Symbols) = 0) then
  334. begin
  335. Result := Copy(S, 2 + Length(Symbols), MaxInt);
  336. Index := I + 1;
  337. Exit;
  338. end;
  339. end;
  340. Index := MaxInt;
  341. Result := '';
  342. end;
  343. procedure ShowBanner;
  344. begin
  345. WriteStdOut('Inno Setup 6 Command-Line Compiler');
  346. WriteStdOut('Copyright (C) 1997-2025 Jordan Russell. All rights reserved.');
  347. WriteStdOut('Portions Copyright (C) 2000-2025 Martijn Laan. All rights reserved.');
  348. if IsppMode then
  349. WriteStdOut('Portions Copyright (C) 2001-2004 Alex Yackimoff. All rights reserved.');
  350. WriteStdOut('https://www.innosetup.com');
  351. WriteStdOut('');
  352. end;
  353. procedure ShowUsage;
  354. begin
  355. WriteStdErr('Usage: iscc [options] scriptfile.iss');
  356. WriteStdErr('or to read from standard input: iscc [options] -');
  357. WriteStdErr('Options:');
  358. WriteStdErr(' /O(+|-) Enable or disable output (overrides Output)');
  359. WriteStdErr(' /O<path> Output files to specified path (overrides OutputDir)');
  360. WriteStdErr(' /F<filename> Specifies an output filename (overrides OutputBaseFilename)');
  361. WriteStdErr(' /S<name>=<command> Sets a SignTool with the specified name and command');
  362. WriteStdErr(' (Any Sign Tools configured using the Compiler IDE will be specified automatically)');
  363. WriteStdErr(' /Q Quiet compile (print error messages only)');
  364. WriteStdErr(' /Qp Enable quiet compile while still displaying progress');
  365. if IsppMode then begin
  366. WriteStdErr(' /D<name>[=<value>] Emulate #define public <name> <value>');
  367. WriteStdErr(' /$<letter>(+|-) Emulate #pragma option -<letter>(+|-)');
  368. WriteStdErr(' /P<letter>(+|-) Emulate #pragma parseroption -<letter>(+|-)');
  369. WriteStdErr(' /I<paths> Emulate #pragma include <paths>');
  370. WriteStdErr(' /J<filename> Emulate #include <filename>');
  371. WriteStdErr(' /{#<string> Emulate #pragma inlinestart <string>');
  372. WriteStdErr(' /}<string> Emulate #pragma inlineend <string>');
  373. WriteStdErr(' /V<number> Emulate #pragma verboselevel <number>');
  374. end;
  375. WriteStdErr(' /? Show this help screen');
  376. WriteStdErr('');
  377. WriteStdErr('Examples: iscc "c:\isetup\samples\my script.iss"');
  378. WriteStdErr(' iscc /Qp /O"My Output" /F"MyProgram-1.0" /Sbyparam=$p "c:\isetup\samples\my script.iss"');
  379. if IsppMode then begin
  380. WriteStdErr(' iscc /$c- /Pu+ "/DLic=Trial Lic.txt" /IC:\INC;D:\INC scriptfile.iss');
  381. WriteStdErr('');
  382. end;
  383. end;
  384. var
  385. I: Integer;
  386. S: String;
  387. begin
  388. if IsppMode then begin
  389. InitIsppOptions(IsppOptions, Definitions, IncludePath, IncludeFiles);
  390. { Also see below }
  391. ReadOptionsParam(IsppOptions.Options, '$');
  392. ReadOptionsParam(IsppOptions.ParserOptions, 'P');
  393. end;
  394. for I := 1 to NewParamCount do begin
  395. S := NewParamStr(I);
  396. if (S = '') or IsParam(S) then begin
  397. if GetParam(S, 'Q') then begin
  398. Quiet := True;
  399. ShowProgress := CompareText(S, 'P') = 0;
  400. end
  401. else if GetParam(S, 'O') then begin
  402. if S = '-' then Output := 'no'
  403. else if S = '+' then Output := 'yes'
  404. else OutputPath := S;
  405. end
  406. else if GetParam(S, 'F') then
  407. OutputFilename := S
  408. else if GetParam(S, 'S') then begin
  409. if Pos('=', S) = 0 then begin
  410. ShowBanner;
  411. WriteStdErr('Invalid option: ' + S, True);
  412. Halt(1);
  413. end;
  414. SignTools.Add(S);
  415. end else if IsppMode and GetParam(S, 'D') then begin
  416. Definitions := Definitions + S + #1;
  417. end
  418. else if IsppMode and GetParam(S, 'I') then begin
  419. IncludePath := IncludePath + ';' + S;
  420. end
  421. else if IsppMode and GetParam(S, 'J') then begin
  422. IncludeFiles := IncludeFiles + S + #1;
  423. end
  424. else if IsppMode and GetParam(S, '{#') then begin
  425. if S <> '' then IsppOptions.InlineStart := AnsiString(S);
  426. end
  427. else if IsppMode and GetParam(S, '}') then begin
  428. if S <> '' then IsppOptions.InlineEnd := AnsiString(S);
  429. end
  430. else if IsppMode and GetParam(S, 'V') then begin
  431. if S <> '' then IsppOptions.VerboseLevel := StrToIntDef(S, 0);
  432. end
  433. else if IsppMode and (GetParam(S, '$') or GetParam(S, 'P')) then begin
  434. { Already handled above }
  435. end
  436. else if S = '/?' then begin
  437. ShowBanner;
  438. ShowUsage;
  439. Halt(1);
  440. end
  441. else begin
  442. ShowBanner;
  443. WriteStdErr('Unknown option: ' + S, True);
  444. Halt(1);
  445. end;
  446. end
  447. else begin
  448. { Not a switch; must be the script filename }
  449. if ScriptFilename <> '' then begin
  450. ShowBanner;
  451. WriteStdErr('You may not specify more than one script filename.', True);
  452. Halt(1);
  453. end;
  454. ScriptFilename := S;
  455. end;
  456. end;
  457. if ScriptFilename = '' then begin
  458. ShowBanner;
  459. ShowUsage;
  460. Halt(1);
  461. end;
  462. if not Quiet then
  463. ShowBanner;
  464. end;
  465. procedure Go;
  466. procedure AppendOption(var Opts: String; const OptName, OptValue: String);
  467. begin
  468. Opts := Opts + OptName + '=' + OptValue + #0;
  469. end;
  470. function ConvertOptionsToString(const Options: TOptions): String;
  471. var
  472. I: TOptionID;
  473. begin
  474. Result := '';
  475. for I := 0 to 25 do
  476. if I in Options then
  477. Result := Result + Chr(Ord('a') + I);
  478. end;
  479. procedure IsppOptionsToString(var S: String; Opt: TIsppOptions; Definitions, IncludePath, IncludeFiles: String);
  480. begin
  481. with Opt do begin
  482. AppendOption(S, 'ISPP:ParserOptions', ConvertOptionsToString(ParserOptions));
  483. AppendOption(S, 'ISPP:Options', ConvertOptionsToString(Options));
  484. AppendOption(S, 'ISPP:VerboseLevel', IntToStr(VerboseLevel));
  485. AppendOption(S, 'ISPP:InlineStart', String(InlineStart));
  486. AppendOption(S, 'ISPP:InlineEnd', String(InlineEnd));
  487. end;
  488. AppendOption(S, 'ISPP:Definitions', Definitions);
  489. AppendOption(S, 'ISPP:IncludePath', IncludePath);
  490. AppendOption(S, 'ISPP:IncludeFiles', IncludeFiles);
  491. end;
  492. var
  493. ScriptPath: String;
  494. ExitCode: Integer;
  495. Ver: PCompilerVersionInfo;
  496. F: TTextFileReader;
  497. Params: TCompileScriptParamsEx;
  498. Options: String;
  499. Res: Integer;
  500. I: Integer;
  501. IDESignTools: TStringList;
  502. begin
  503. if ScriptFilename <> '-' then begin
  504. ScriptFilename := PathExpand(ScriptFilename);
  505. ScriptPath := PathExtractPath(ScriptFilename);
  506. end
  507. else begin
  508. { Read from standard input }
  509. ScriptFilename := '<stdin>';
  510. ScriptPath := GetCurrentDir;
  511. end;
  512. {$IFNDEF STATICCOMPILER}
  513. Ver := ISDllGetVersion;
  514. {$ELSE}
  515. Ver := ISGetVersion;
  516. {$ENDIF}
  517. if Ver.BinVersion < $05000500 then begin
  518. { 5.0.5 or later is required since we use TCompileScriptParamsEx }
  519. WriteStdErr('Incompatible compiler engine version.', True);
  520. Halt(1);
  521. end;
  522. ProgressPoint.X := -1;
  523. ExitCode := 0;
  524. try
  525. if ScriptFilename <> '<stdin>' then
  526. F := TTextFileReader.Create(ScriptFilename, fdOpenExisting, faRead, fsRead)
  527. else
  528. F := TTextFileReader.CreateWithExistingHandle(GetStdHandle(STD_INPUT_HANDLE));
  529. try
  530. ReadScriptLines(F);
  531. finally
  532. F.Free;
  533. end;
  534. if not Quiet then begin
  535. WriteStdOut('Compiler engine version: ' + String(Ver.Title) + ' ' + String(Ver.Version));
  536. WriteStdOut('');
  537. end;
  538. FillChar(Params, SizeOf(Params), 0);
  539. Params.Size := SizeOf(Params);
  540. Params.SourcePath := PChar(ScriptPath);
  541. Params.CallbackProc := CompilerCallbackProc;
  542. Options := '';
  543. if Output <> '' then
  544. AppendOption(Options, 'Output', Output);
  545. if OutputPath <> '' then
  546. AppendOption(Options, 'OutputDir', OutputPath);
  547. if OutputFilename <> '' then
  548. AppendOption(Options, 'OutputBaseFilename', OutputFilename);
  549. for I := 0 to SignTools.Count-1 do
  550. Options := Options + AddSignToolParam(SignTools[I]);
  551. IDESignTools := TStringList.Create;
  552. try
  553. { Also automatically read and add SignTools defined using the IDE. Adding
  554. these after the command line SignTools so that the latter are always
  555. found first by the compiler. }
  556. ReadSignTools(IDESignTools);
  557. for I := 0 to IDESignTools.Count-1 do
  558. Options := Options + AddSignToolParam(IDESignTools[I]);
  559. finally
  560. IDESignTools.Free;
  561. end;
  562. if IsppMode then
  563. IsppOptionsToString(Options, IsppOptions, Definitions, IncludePath, IncludeFiles);
  564. Params.Options := PChar(Options);
  565. StartTime := GetTickCount;
  566. {$IFNDEF STATICCOMPILER}
  567. Res := ISDllCompileScript(Params);
  568. {$ELSE}
  569. Res := ISCompileScript(Params, False);
  570. {$ENDIF}
  571. case Res of
  572. isceNoError: ;
  573. isceCompileFailure: begin
  574. ExitCode := 2;
  575. WriteStdErr('Compile aborted.', True);
  576. end;
  577. else
  578. ExitCode := 1;
  579. WriteStdErr(Format('Internal error: ISDllCompileScript returned ' +
  580. 'unexpected result (%d).', [Res]), True);
  581. end;
  582. finally
  583. FreeScriptLines;
  584. end;
  585. if ExitCode <> 0 then
  586. Halt(ExitCode);
  587. end;
  588. begin
  589. SignTools := TStringList.Create;
  590. try
  591. StdOutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
  592. StdErrHandle := GetStdHandle(STD_ERROR_HANDLE);
  593. var Mode: DWORD;
  594. StdOutHandleIsConsole := GetConsoleMode(StdOutHandle, Mode);
  595. StdErrHandleIsConsole := GetConsoleMode(StdErrHandle, Mode);
  596. SetConsoleCtrlHandler(@ConsoleCtrlHandler, True);
  597. try
  598. IsppMode := FileExists(ExtractFilePath(NewParamStr(0)) + 'ispp.dll');
  599. ProcessCommandLine;
  600. Go;
  601. except
  602. { Show a friendlier exception message. (By default, Delphi prints out
  603. the exception class and address.) }
  604. WriteStdErr(GetExceptMessage, True);
  605. Halt(2);
  606. end;
  607. finally
  608. SignTools.Free;
  609. end;
  610. end.