123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- { Compile and run a pascal program.
- Copyright (C) 2011 Mattias Gaertner [email protected]
- This source is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 2 of the License, or (at your option)
- any later version.
- This code is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
- A copy of the GNU General Public License is available on the World Wide Web
- at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
- to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- MA 02110-1301, USA.
- }
- program instantfpc;
- {$mode objfpc}{$H+}
- uses
- Classes, SysUtils, InstantFPTools;
- const
- Version = '1.3';
- // 1.3 compile in a separate directory, so that parallel invocations do not overwrite link.res files
- Procedure Usage(Err : string);
- begin
- if (Err<>'') then
- Writeln('Error : ',Err);
- writeln('instantfpc '+Version);
- writeln;
- writeln('Run pascal source files as scripts.');
- writeln('Normal usage is to add to a program source file a first line');
- writeln('("shebang") "#!/usr/bin/instantfpc".');
- writeln('Then you can execute the source directly in the terminal/console.');
- writeln;
- writeln('instantfpc -h');
- writeln(' Print this help message and exit.');
- writeln;
- writeln('instantfpc -v');
- writeln(' Print version and exit.');
- writeln;
- writeln('instantfpc [compiler options] <source file> [program parameters]');
- writeln(' Compiles source and runs program.');
- writeln(' Source is compared with the cache. If cache is not valid then');
- writeln(' source is copied to cache with the shebang line commented and');
- writeln(' cached source is compiled.');
- writeln(' If compilation fails the fpc output is written to stdout and');
- writeln(' instantfpc exits with error code 1.');
- writeln(' If compilation was successful the program is executed.');
- writeln(' If the compiler options contains -B the program is always');
- writeln(' compiled.');
- writeln(' If the environment option INSTANTFPCOPTIONS is set it is');
- writeln(' passed to the compiler as first parameters.');
- writeln;
- writeln('instantfpc --get-cache');
- writeln(' Prints current cache directory and exit.');
- writeln;
- writeln('Options:');
- writeln;
- writeln(' --');
- Writeln(' Read program from standard input');
- writeln(' --set-cache=<path to cache>');
- writeln(' Set the cache to be used. Otherwise using environment variable');
- writeln(' INSTANTFPCCACHE.');
- writeln;
- writeln(' --compiler=<path to compiler>');
- writeln(' Normally fpc is searched in PATH and used as compiler.');
- writeln;
- writeln(' --skip-run');
- writeln(' Do not execute the program. Useful to test if script compiles.');
- writeln(' You probably want to combine it with -B.');
- writeln;
- writeln(' -B');
- writeln(' Always recompile.');
- Halt(Ord(Err<>''));
- end;
- Procedure DisplayCache;
- begin
- write(GetCacheDir);
- Halt(0);
- end ;
- var
- i,j: Integer;
- p: String;
- Filename: String;
- Src: TStringList;
- CacheDir: String;
- CacheFilename: String;
- OutputFilename: String;
- S,E : String;
- DeleteCache : Boolean = False;
- RunIt: boolean = true;
-
- // Return true if filename found.
-
- Function InterpretParam(p : String) : boolean;
- begin
- Result:=False;
- if (P='') then exit;
- if p='-v' then
- begin
- writeln('instantfpc '+Version);
- Halt(1);
- end
- else if p='-h' then
- usage('')
- else if p='--get-cache' then
- DisplayCache
- else if copy(p,1,11)='--compiler=' then
- begin
- delete(P,1,11);
- SetCompiler(p);
- end
- else if copy(p,1,12)='--set-cache=' then
- begin
- delete(P,1,12);
- SetCacheDir(p);
- end
- else if p='--skip-run' then
- begin
- RunIt:=false;
- end
- else if (P<>'') and (p[1]<>'-') then
- begin
- Filename:=p;
- Result:=True;
- end
- else if (p='--') then
- begin
- Filename:='--';
- Result:=True;
- end;
- end;
-
- begin
- Filename:='';
- { For example:
- /usr/bin/instantfpc -MObjFpc -Sh ./envvars.pas param1
- }
- for i:=1 to Paramcount do
- begin
- p:=ParamStr(i);
- if p='' then
- continue
- else
- begin
- if (I<>1) then
- begin
- if InterpretParam(p) then
- Break;
- end
- else
- begin
- // The linux kernel passes the whole shebang line as 1 argument.
- // We must parse and split it ourselves.
- Repeat
- J:=Pos(' ',P);
- if (J=0) then
- J:=Length(P)+1;
- if InterpretParam(Copy(P,1,J-1)) then
- Break;
- Delete(P,1,J);
- Until (P='');
- if (FileName<>'') then
- Break;
- end;
- end;
- end;
- if (Filename='') then
- Usage('Missing source file');
- CheckSourceName(Filename);
- Src:=TStringList.Create;
- try
- if FileName<>'--' then
- Src.LoadFromFile(Filename)
- else
- begin
- While not EOF do
- begin
- Readln(S);
- Src.Add(S);
- end;
- FileName:=ChangeFileExt(GetTempFileName,'.pp');
- DeleteCache:=true;
- end;
- CommentShebang(Src);
- CacheDir:=GetCacheDir;
- // check cache
- CacheFilename:=CacheDir+ExtractFileName(Filename);
- E:=LowerCase(ExtractFileExt(CacheFileName));
- if (E<>'.pp') and (E<>'.pas') and (E<>'.lpr') then
- CacheFileName:=CacheFileName+'.pas';
- OutputFilename:=CacheDir+ChangeFileExt(ExtractFileName(Filename),'');
- if not IsCacheValid(Src,CacheFilename,OutputFilename) then begin
- // save source in cache to find out next time if something changed
- Src.SaveToFile(CacheFilename);
- Compile(Filename,CacheFilename,OutputFilename);
- if deleteCache then
- DeleteFile(CacheFileName);
- end;
- // run
- if RunIt then
- Run(OutputFilename);
- if DeleteCache then
- DeleteFile(OutputFileName);
- finally
- // memory is freed by OS, but for debugging puposes you can do it manually
- {$IFDEF IFFreeMem}
- Proc.Free;
- Src.Free;
- {$ENDIF}
- end;
- end.
|