instantfpc is now part of fpc 2.5.1

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1741 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
mgaertner
2011-07-09 08:51:55 +00:00
parent 6e94c155b9
commit 8d9d597057
3 changed files with 0 additions and 430 deletions

View File

@ -1,77 +0,0 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
</Flags>
<SessionStorage Value="InIDEConfig"/>
<MainUnit Value="0"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<VersionInfo>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<Units Count="2">
<Unit0>
<Filename Value="instantfpc.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="instantfpc"/>
</Unit0>
<Unit1>
<Filename Value="instantfptools.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="InstantFPTools"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="10"/>
<Target>
<Filename Value="instantfpc"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Other>
<CompilerMessages>
<UseMsgFile Value="True"/>
</CompilerMessages>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -1,125 +0,0 @@
{ Compile and run a pascal program.
Copyright (C) 2011 Mattias Gaertner mattias@freepascal.org
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., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
program instantfpc;
{$mode objfpc}{$H+}
uses
Classes, SysUtils, InstantFPTools;
const
Version = '1.0';
var
i: Integer;
p: String;
Filename: String;
Src: TStringList;
CacheDir: String;
CacheFilename: String;
OutputFilename: String;
ExeExt: String;
begin
Filename:='';
{ For example:
/usr/bin/instantfpc -MObjFpc -Sh ./envvars.pas param1
}
for i:=1 to Paramcount do begin
p:=ParamStr(i);
//writeln('Param: ',i,' ',p);
if p='' then
continue
else if p='-v' then begin
writeln('instantfpc '+Version);
Halt(1);
end
else if p='-h' then begin
writeln('instantfpc '+Version);
writeln;
writeln('instantfpc -h');
writeln(' This help message.');
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;
writeln('instantfpc --get-cache');
writeln(' Prints cache directory to stdout.');
writeln;
writeln('instantfpc --compiler=<path to compiler>');
writeln(' Normally fpc is searched in PATH and used as compiler.');
writeln;
writeln('Normal usage is to add as first line ("shebang") "#!/usr/bin/instantfpc"');
writeln('to a program source file. Then you can execute the source like a script.');
Halt(0);
end else if p='--get-cache' then begin
CacheDir:=GetCacheDir;
write(CacheDir);
Halt(0);
end else if (p[1]<>'-') then begin
// the first non flag parameter is the file name of the script
// followed by the parameters for the script
Filename:=p;
break;
end;
end;
if Filename='' then begin
writeln('missing source file');
Halt(1);
end;
CheckSourceName(Filename);
Src:=TStringList.Create;
try
Src.LoadFromFile(Filename);
CommentShebang(Src);
CacheDir:=GetCacheDir;
// check cache
CacheFilename:=CacheDir+ExtractFileName(Filename);
ExeExt:='';
OutputFilename:=CacheDir+ChangeFileExt(ExtractFileName(Filename),ExeExt);
if not IsCacheValid(Src,CacheFilename,OutputFilename) then begin
// save source in cache to find out next time if something changed
Src.SaveToFile(CacheFilename);
Compile(CacheFilename,OutputFilename);
end;
// run
Run(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.

View File

@ -1,228 +0,0 @@
unit InstantFPTools;
{$mode objfpc}{$H+}
interface
uses
{$IFNDEF MSWINDOWS}
Unix,
{$ENDIF}
Classes, SysUtils, Process;
procedure CheckSourceName(const Filename: string);
procedure CommentShebang(Src: TStringList);
function GetCacheDir: string;
function IsCacheValid(Src: TStringList;
const CachedSrcFile, CachedExeFile: string): boolean;
procedure Compile(const CacheFilename, OutputFilename: string);
function GetCompiler: string;
function GetCompilerParameters(const SrcFilename, OutputFilename: string): string;
procedure Run(const Filename: string);
implementation
procedure AddParam(p: string; var Line: string);
begin
if p='' then exit;
if Line<>'' then Line:=Line+' ';
if (p[1]<>'"') and (System.Pos(' ',p)>0) then
p:='"'+p+'"';
Line:=Line+p;
end;
procedure CheckSourceName(const Filename: string);
var
Ext: String;
begin
// avoid name clashes
Ext:=lowercase(ExtractFileExt(Filename));
if (Ext<>'') and (Ext<>'.pas') and (Ext<>'.pp') and (Ext<>'.p')
and (Ext<>'.lpr') and (Ext<>'.txt') and (Ext<>'.sh')
then begin
writeln('invalid source extension ',Ext);
Halt(1);
end;
end;
procedure CommentShebang(Src: TStringList);
var
Line: string;
i: Integer;
begin
// comment shebang #!
if (Src.Count=0) then exit;
Line:=Src[0];
i:=1;
if copy(Line,1,3)=#$EF#$BB#$BF then
inc(i,3);// UTF8 BOM
if (i>length(Line)) or (Line[i]<>'#') then exit;
Src[0]:=copy(Line,1,i-1)+'//'+copy(Line,i,length(Line));
end;
function GetCacheDir: string;
begin
Result:=GetEnvironmentVariable('INSTANTFPCCACHE');
if Result='' then begin
Result:=GetEnvironmentVariable('HOME');
if Result<>'' then
Result:=IncludeTrailingPathDelimiter(Result)+'.cache'+PathDelim+'instantfpc';
end;
if Result='' then begin
writeln('missing environment variable: HOME or INSTANTFPCCACHE');
Halt(1);
end;
Result:=IncludeTrailingPathDelimiter(ExpandFileName(Result));
if not ForceDirectories(Result) then begin
writeln('unable to create cache directory "'+Result+'"');
Halt(1);
end;
end;
function IsCacheValid(Src: TStringList; const CachedSrcFile,
CachedExeFile: string): boolean;
var
OldSrc: TStringList;
i: Integer;
p: String;
begin
Result:=false;
for i:=1 to Paramcount do begin
p:=ParamStr(i);
if (p='') or (p[1]<>'-') then break;
if p='-B' then exit; // always compile
end;
if not FileExists(CachedSrcFile) then exit;
if not FileExists(CachedExeFile) then exit;
OldSrc:=TStringList.Create;
OldSrc.LoadFromFile(CachedSrcFile);
Result:=Src.Equals(OldSrc);
{$IFDEF IFFreeMem}
OldSrc.Free;
{$ENDIF}
end;
function GetCompiler: string;
const
CompilerParam = '--compiler=';
var
Path: String;
p: Integer;
StartPos: LongInt;
Dir: String;
CompFile: String;
i: Integer;
Param: String;
begin
for i:=1 to Paramcount do begin
Param:=ParamStr(i);
if (Param='') or (Param[1]<>'-') then break;
if copy(Param,1,length(CompilerParam))=CompilerParam then begin
CompFile:=copy(Param,length(CompilerParam)+1,length(Param));
Result:=ExpandFileName(CompFile);
if not FileExists(Result) then begin
writeln('Error: '+CompFile+' not found, check the ',CompilerParam,' parameter.');
Halt(1);
end;
exit;
end;
end;
{$IFDEF Windows}
CompFile:='fpc.exe';
{$ELSE}
CompFile:='fpc';
{$ENDIF}
Path:=GetEnvironmentVariable('PATH');
if PATH<>'' then begin
p:=1;
while p<=length(Path) do begin
StartPos:=p;
while (p<=length(Path)) and (Path[p]<>':') do inc(p);
if StartPos<p then begin
Dir:=copy(Path,StartPos,p-StartPos);
Result:=ExpandFileName(IncludeTrailingPathDelimiter(Dir))+CompFile;
if FileExists(Result) then exit;
end;
inc(p);
end;
end;
writeln('Error: '+CompFile+' not found in PATH');
Halt(1);
end;
procedure Compile(const CacheFilename, OutputFilename: string);
var
Compiler: String;
CompParams: String;
Proc: TProcess;
Count: Int64;
ss: TStringStream;
buf : Array[1..4096] of byte;
begin
Compiler:=GetCompiler;
CompParams:=GetCompilerParameters(CacheFilename,OutputFilename);
//writeln('Compiler=',Compiler,' Params=',CompParams);
if FileExists(OutputFilename) and not DeleteFile(OutputFilename) then begin
writeln('unable to delete ',OutputFilename);
Halt(1);
end;
Proc:=TProcess.Create(nil);
Proc.CommandLine:=Compiler+' '+CompParams;
Proc.Options:= [poUsePipes, poStdErrToOutput];
Proc.ShowWindow := swoHide;
Proc.Execute;
ss:=TStringStream.Create('');
repeat
Count:=Proc.Output.Read(Buf,4096);
if Count>0 then
ss.write(buf,count);
until Count=0;
if (not Proc.WaitOnExit) or (Proc.ExitStatus<>0) then begin
write(ss.DataString);
Halt(1);
end;
ss.Free;
Proc.Free;
end;
function GetCompilerParameters(const SrcFilename, OutputFilename: string): string;
{ For example:
/usr/bin/instantfpc -MObjFpc -Sh ./envvars.pas param1
The shebang compile parameters: -MObjFpc -Sh
}
var
p: String;
begin
Result:='';
if (Paramcount>0) then begin
p:=ParamStr(1);
if (p<>'') and (p[1]='-') then
Result:=p; // copy compile params from the script
end;
AddParam('-o'+OutputFilename {$IFDEF MSWINDOWS} + '.exe' {$ENDIF},Result);
AddParam(SrcFilename,Result);
end;
procedure Run(const Filename: string);
var
p: PPChar;
begin
p:=argv;
inc(p);
while (p<>nil) do begin
if (p^<>nil) and (p^^<>'-') then begin
break;
end;
inc(p);
end;
{$IFDEF MSWINDOWS}
Inc(p); //lose the first command-line argument with the the script filename
Halt(ExecuteProcess(Filename,[p^]));
{$ELSE}
Halt(FpExecV(Filename,p));
{$ENDIF}
end;
end.