Explorar o código

* support local and global install directories, default is to use a local
install dir for normal users and for root the global install dir
* updated unit check in fpmake build to look in local and global dirs
* auto bootstrap when fpmkunit is not found, no --bootstrap needed
* archive command line option to call fpmake archive

git-svn-id: trunk@9011 -

peter %!s(int64=18) %!d(string=hai) anos
pai
achega
100dab3c33

+ 7 - 2
utils/fppkg/fppkg.pp

@@ -138,11 +138,13 @@ begin
   Writeln('  -h --help          This help');
   Writeln('  -v --verbose       Set verbosity');
   Writeln('  -b --bootstrap     Special bootstrapping mode');
+  Writeln('  -g --global        Force installation to global (system-wide) directory');
   Writeln('Actions:');
   Writeln('  update             Update packages list');
   Writeln('  avail              List available packages');
   Writeln('  build              Build package');
   Writeln('  install            Install package');
+  Writeln('  archive            Create archive of package');
   Writeln('  download           Download package');
   Writeln('  convertmk          Convert Makefile.fpc to fpmake.pp');
   Writeln('  addconfig          Add a compiler configuration for the supplied compiler');
@@ -220,6 +222,8 @@ begin
         Include(Verbosity,StringToVerbosity(OptionArg(I)))
       else if CheckOption(I,'b','bootstrap') then
         Options.BootStrap:=true
+      else if CheckOption(I,'g','global') then
+        Options.InstallGlobal:=true
       else if CheckOption(I,'h','help') then
         begin
           ShowUsage;
@@ -277,6 +281,7 @@ var
   ActionPackage : TFPPackage;
   Args   : TActionArgs;
   OldCurrDir : String;
+  Res    : Boolean;
 begin
   OldCurrDir:=GetCurrentDir;
   LoadGlobalDefaults;
@@ -290,8 +295,8 @@ begin
     repeat
       if not ActionStack.Pop(ActionPackage,Action,Args) then
         break;
-      pkghandler.ExecuteAction(ActionPackage,Action,Args);
-    until false;
+      res:=pkghandler.ExecuteAction(ActionPackage,Action,Args);
+    until not res;
     Terminate;
 
   except

+ 6 - 1
utils/fppkg/pkgarchive.pp

@@ -18,6 +18,7 @@ type
   end;
 
 
+{$ifdef OLDCREATEARCHIVE}
   { TCreateArchive }
 
   TCreateArchive = Class(TPackagehandler)
@@ -26,6 +27,7 @@ type
   Public
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
+{$endif OLDCREATEARCHIVE}
 
 
 implementation
@@ -75,6 +77,7 @@ begin
 end;
 
 
+{$ifdef OLDCREATEARCHIVE}
 { TCreateArchive }
 
 procedure TCreateArchive.CreateArchive;
@@ -123,15 +126,17 @@ begin
   P.Free;
 end;
 
-
 function TCreateArchive.Execute(const Args: TActionArgs): boolean;
 begin
   CreateArchive;
   Result:=true;
 end;
+{$endif OLDCREATEARCHIVE}
 
 
 initialization
   RegisterPkgHandler('unziparchive',TUnzipArchive);
+{$ifdef OLDCREATEARCHIVE}
   RegisterPkgHandler('createarchive',TCreateArchive);
+{$endif OLDCREATEARCHIVE}
 end.

+ 15 - 1
utils/fppkg/pkgcommands.pp

@@ -66,7 +66,6 @@ type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
-
   { TCommandInstall }
 
   TCommandInstall = Class(TPackagehandler)
@@ -74,6 +73,13 @@ type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
+  { TCommandArchive }
+
+  TCommandArchive = Class(TPackagehandler)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
 
 function TCommandAddConfig.Execute(const Args:TActionArgs):boolean;
 begin
@@ -149,6 +155,13 @@ begin
 end;
 
 
+function TCommandArchive.Execute(const Args:TActionArgs):boolean;
+begin
+  ExecuteAction(CurrentPackage,'fpmakearchive',Args);
+  Result:=true;
+end;
+
+
 initialization
   RegisterPkgHandler('update',TCommandUpdate);
   RegisterPkgHandler('avail',TCommandAvail);
@@ -157,4 +170,5 @@ initialization
   RegisterPkgHandler('unzip',TCommandUnzip);
   RegisterPkgHandler('build',TCommandBuild);
   RegisterPkgHandler('install',TCommandInstall);
+  RegisterPkgHandler('archive',TCommandArchive);
 end.

+ 78 - 49
utils/fppkg/pkgfpmake.pp

@@ -10,6 +10,7 @@ uses
 implementation
 
 uses
+  fprepos,
   pkgoptions,
   pkgglobals,
   pkgmessages;
@@ -52,6 +53,13 @@ type
   { TFPMakeRunnerManifest }
 
   TFPMakeRunnerManifest = Class(TFPMakeRunner)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
+  { TFPMakeRunnerArchive }
+
+  TFPMakeRunnerArchive = Class(TFPMakeRunner)
   Public
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
@@ -98,6 +106,28 @@ end;
 { TFPMakeCompiler }
 
 Procedure TFPMakeCompiler.CompileFPMake;
+
+  function CheckUnitDir(const AUnitName:string;Out AUnitDir:string):boolean;
+  begin
+    Result:=false;
+    if Options.FPMakeLocalUnitDir<>'' then
+      begin
+        AUnitDir:=IncludeTrailingPathDelimiter(Options.FPMakeLocalUnitDir+AUnitName);
+        if DirectoryExists(AUnitDir) then
+          begin
+            Result:=true;
+            exit;
+          end;
+      end;
+    AUnitDir:=IncludeTrailingPathDelimiter(Options.FPMakeGlobalUnitDir+AUnitName);
+    if DirectoryExists(AUnitDir) then
+      begin
+        Result:=true;
+        exit;
+      end;
+    AUnitDir:='';
+  end;
+
 const
   TempBuildDir = 'build-fpmake';
 Var
@@ -130,88 +160,67 @@ begin
       // Special bootstrapping mode to compile fpmake?
       DoBootStrap:=False;
       NeedFPMKUnitSource:=False;
-      if Options.BootStrap then
-        begin
-{$ifdef check_bootstrap_names}
-          for i:=low(FPMKUnitDeps) to high(FPMKUnitDeps) do
-            if CurrentPackage.Name=FPMKUnitDeps[i] then
-              begin
-                DoBootStrap:=True;
-                break;
-              end;
-{$else check_bootstrap_names}
-          DoBootStrap:=True;
-{$endif check_bootstrap_names}
-        end;
-      // Compile options
-      //   -- bootstrapping compile with -g
-      //   -- default is to optimize, smartlink and strip to reduce
-      //      the executable size (there can be 100's of fpmake's on a system)
       OOptions:='-n';
-      if vInfo in Verbosity then
-        OOptions:=OOptions+' -vi';
-      if DoBootStrap then
-        OOptions:=OOptions+' -g'
-      else
-        OOptions:=OOptions+' -O2 -XXs';
-      // Check overall unit dir, this must exist at least for RTL
-      if not DirectoryExists(Options.FPMakeUnitDir) then
-        Error(SErrMissingDirectory,[Options.FPMakeUnitDir]);
       // Add FPMKUnit unit dir, if not found we use the internal fpmkunit source
-      DepDir:=IncludeTrailingPathDelimiter(Options.FPMakeUnitDir+'fpmkunit');
-      if DirectoryExists(DepDir) then
+      if CheckUnitDir('fpmkunit',DepDir) then
         OOptions:=OOptions+' -Fu'+DepDir
       else
         begin
-          if DoBootStrap then
-            begin
-              NeedFPMKUnitSource:=true;
-              OOptions:=OOptions+' -Fu'+TempBuildDir;
-            end
-          else
-            Error(SErrMissingDirectory,[DepDir]);
+          Log(vWarning,SWarnFPMKUnitNotFound);
+          DoBootStrap:=true;
+          NeedFPMKUnitSource:=true;
+          OOptions:=OOptions+' -Fu'+TempBuildDir;
         end;
       // Add PaszLib and Hash units dir
-      DepDir:=IncludeTrailingPathDelimiter(Options.FPMakeUnitDir+'hash');
-      if not DirectoryExists(DepDir) then
+      // we need to check for the zipper.ppu that is not
+      // delivered with fpc 2.0.4
+      if not CheckUnitDir('hash',DepDir) then
         begin
           if DoBootStrap then
             DepDir:=''
           else
-            Error(SErrMissingDirectory,[DepDir]);
+            Error(SErrMissingInstallPackage,['hash']);
         end;
-      DepDir2:=IncludeTrailingPathDelimiter(Options.FPMakeUnitDir+'paszlib');
-      if not FileExists(DepDir2+'zipper.ppu') then
+      if not CheckUnitDir('paszlib',DepDir2) or
+         not FileExists(DepDir2+'zipper.ppu') then
         begin
           if DoBootStrap then
             DepDir2:=''
           else
-            Error(SErrMissingDirectory,[DepDir2]);
+            Error(SErrMissingInstallPackage,['paszlib']);
         end;
       if (DepDir<>'') and (DepDir2<>'') then
         OOptions:=OOptions+' -Fu'+DepDir+' -Fu'+DepDir2
       else
         OOptions:=OOptions+' -dNO_UNIT_ZIPPER';
       // Add Process unit
-      DepDir:=IncludeTrailingPathDelimiter(Options.FPMakeUnitDir+'fcl-process');
-      if DirectoryExists(DepDir) then
+      if CheckUnitDir('fcl-process',DepDir) then
         OOptions:=OOptions+' -Fu'+DepDir
       else
         begin
           if DoBootStrap then
             OOptions:=OOptions+' -dNO_UNIT_PROCESS'
           else
-            Error(SErrMissingDirectory,[DepDir]);
+            Error(SErrMissingInstallPackage,['fcl-process']);
         end;
       // Add RTL unit dir
-      DepDir:=IncludeTrailingPathDelimiter(Options.FPMakeUnitDir+'rtl');
-      if not DirectoryExists(DepDir) then
-        Error(SErrMissingDirectory,[DepDir]);
+      if not CheckUnitDir('rtl',DepDir) then
+        Error(SErrMissingInstallPackage,['rtl']);
       OOptions:=OOptions+' -Fu'+DepDir;
       // Units in a directory for easy cleaning
       DeleteDir(TempBuildDir);
       ForceDirectories(TempBuildDir);
       OOptions:=OOptions+' -FU'+TempBuildDir;
+      // Compile options
+      //   -- bootstrapping compile with -g
+      //   -- default is to optimize, smartlink and strip to reduce
+      //      the executable size (there can be 100's of fpmake's on a system)
+      if vInfo in Verbosity then
+        OOptions:=OOptions+' -vi';
+      if DoBootStrap then
+        OOptions:=OOptions+' -g'
+      else
+        OOptions:=OOptions+' -O2 -XXs';
       // Create fpmkunit.pp if needed
       if NeedFPMKUnitSource then
         CreateFPMKUnitSource(TempBuildDir+PathDelim+'fpmkunit.pp');
@@ -238,14 +247,27 @@ end;
 
 Function TFPMakeRunner.RunFPMake(const Command:string) : Integer;
 Var
-  FPMakeBin : string;
+  FPMakeBin,
+  OOptions : string;
 begin
   { Maybe compile fpmake executable? }
   ExecuteAction(CurrentPackage,'compilefpmake');
+  { Create options }
+  OOptions:=' --nodefaults';
+  if vInfo in Verbosity then
+    OOptions:=OOptions+' --verbose';
+  OOptions:=OOptions+' --compiler='+Options.Compiler;
+  OOptions:=OOptions+' --CPU='+CPUToString(Options.CompilerCPU);
+  OOptions:=OOptions+' --OS='+OSToString(Options.CompilerOS);
+  if IsSuperUser or Options.InstallGlobal then
+    OOptions:=OOptions+' --baseinstalldir='+Options.GlobalInstallDir
+  else
+    OOptions:=OOptions+' --baseinstalldir='+Options.LocalInstallDir;
   { Run FPMake }
   FPMakeBin:='fpmake'+ExeExt;
   SetCurrentDir(PackageBuildPath);
-  Result:=ExecuteProcess(FPMakeBin,Command);
+  Result:=ExecuteProcess(FPMakeBin,Command+OOptions);
+
 end;
 
 
@@ -268,6 +290,12 @@ begin
 end;
 
 
+function TFPMakeRunnerArchive.Execute(const Args:TActionArgs):boolean;
+begin
+  result:=(RunFPMake('archive')=0);
+end;
+
+
 
 
 initialization
@@ -275,4 +303,5 @@ initialization
   RegisterPkgHandler('fpmakebuild',TFPMakeRunnerBuild);
   RegisterPkgHandler('fpmakeinstall',TFPMakeRunnerInstall);
   RegisterPkgHandler('fpmakemanifest',TFPMakeRunnerManifest);
+  RegisterPkgHandler('fpmakearchive',TFPMakeRunnerArchive);
 end.

+ 19 - 9
utils/fppkg/pkgglobals.pp

@@ -40,6 +40,7 @@ Function FixPath(const S : String) : string;
 Procedure DeleteDir(const ADir:string);
 Procedure SearchFiles(SL:TStringList;const APattern:string);
 Function GetCompilerInfo(const ACompiler,AOptions:string):string;
+function IsSuperUser:boolean;
 
 var
   Verbosity : TVerbosities;
@@ -49,20 +50,16 @@ Implementation
 
 // define use_shell to use sysutils.executeprocess
 //  as alternate to using 'process' in getcompilerinfo
-{$IFDEF GO32v2}
+{$IF defined(GO32v2) or defined(WATCOM) or defined(OS2)}
  {$DEFINE USE_SHELL}
-{$ENDIF GO32v2}
+{$ENDIF GO32v2 or WATCOM or OS2}
 
-{$IFDEF WATCOM}
- {$DEFINE USE_SHELL}
-{$ENDIF WATCOM}
-
-{$IFDEF OS2}
- {$DEFINE USE_SHELL}
-{$ENDIF OS2}
 
 uses
   typinfo,
+{$ifdef unix}
+  baseunix,
+{$endif}
 {$IFNDEF USE_SHELL}
   process,
 {$ENDIF USE_SHELL}
@@ -70,6 +67,7 @@ uses
   uriparser,
   pkgmessages;
 
+
 function StringToVerbosity(S: String): TVerbosity;
 Var
   I : integer;
@@ -81,6 +79,7 @@ begin
     Raise EPackagerError.CreateFmt(SErrInvalidVerbosity,[S]);
 end;
 
+
 Function VerbosityToString (V : TVerbosity): String;
 begin
   Result:=GetEnumName(TypeInfo(TVerbosity),Integer(V));
@@ -258,4 +257,15 @@ begin
   Move(Buf,Result[1],Count);
 end;
 
+
+function IsSuperUser:boolean;
+begin
+{$ifdef unix}
+  result:=(fpGetUID=0);
+{$else unix}
+  result:=true;
+{$endif unix}
+end;
+
+
 end.

+ 4 - 3
utils/fppkg/pkghandler.pp

@@ -64,7 +64,7 @@ type
 // Actions/PkgHandler
 procedure RegisterPkgHandler(const AAction:string;pkghandlerclass:TPackageHandlerClass);
 function GetPkgHandler(const AAction:string):TPackageHandlerClass;
-procedure ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil);
+function ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil):Boolean;
 
 
 Implementation
@@ -97,12 +97,13 @@ begin
 end;
 
 
-procedure ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil);
+function ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil):Boolean;
 var
   pkghandlerclass : TPackageHandlerClass;
   i : integer;
   logargs : string;
 begin
+  result:=false;
   pkghandlerclass:=GetPkgHandler(AAction);
   With pkghandlerclass.Create(nil,APackage) do
     try
@@ -115,7 +116,7 @@ begin
             logargs:=logargs+','+Args[i];
         end;
       Log(vDebug,SLogRunAction,[AAction,logargs]);
-      Execute(Args);
+      result:=Execute(Args);
     finally
       Free;
     end;

+ 5 - 3
utils/fppkg/pkgmessages.pp

@@ -15,7 +15,8 @@ Resourcestring
   SErrMissingFPMake          = 'Missing configuration fpmake.pp';
   SErrMissingMakefilefpc     = 'Missing configuration Makefile.fpc';
   SErrMissingDirectory       = 'Missing directory "%s"';
-  SErrMissingCompilerConfig  = 'Could not found compiler configuration "%s"';
+  SErrMissingCompilerConfig  = 'Could not find compiler configuration "%s"';
+  SErrMissingInstallPackage  = 'Could not find package "%s"';
   SErrNoPackageSpecified     = 'No package specified';
   SErrOnlyLocalDir           = 'The speficied command "%s" works only on current dir, not on a (remote) package';
   SErrRunning                = 'The FPC make tool encountered the following error:';
@@ -38,7 +39,8 @@ Resourcestring
   SErrCWDFailed              = 'FTP CWD "%s" command failed.';
   SErrGETFailed              = 'FTP GET "%s" command failed.';
 
-  SWarnFPMKUnitNotFound      = 'Unit directory "%s" needed to compile fpmkunit is not found, compiling fpmake may file';
+  SWarnFPMKUnitDirNotFound   = 'Unit directory for package "%s" is not found, compiling fpmake may file';
+  SWarnFPMKUnitNotFound      = 'Package "fpmkunit" is not found, using internal bootstrap procedure';
 
   SLogGeneratingFPMake       = 'Generating fpmake.pp';
   SLogNotCompilingFPMake     = 'Skipping compiling of fpmake.pp, fpmake executable already exists';
@@ -53,7 +55,7 @@ Resourcestring
   SLogLoadingCompilerConfig  = 'Loading compiler configuration from "%s"';
   SLogGeneratingGlobalConfig = 'Generating default global configuration in "%s"';
   SLogDetectedCompiler       = 'Detected compiler "%s" (version %s for %s)';
-  SLogDetectedFPCDIR         = 'Detected FPCDIR "%s" will be used installation';
+  SLogDetectedFPCDIR         = 'Detected %s FPCDIR "%s"';
   SLogGeneratingCompilerConfig  = 'Generating default compiler configuration in "%s"';
   SLogLoadingPackagesFile    = 'Loading packages information from "%s"';
   SLogLoadingVersionsFile    = 'Loading local versions information from "%s"';

+ 71 - 51
utils/fppkg/pkgoptions.pp

@@ -44,12 +44,15 @@ Type
     FCompilerCPU: TCPU;
     FCompilerOS: TOS;
     FCompilerVersion : String;
-    FInstallDir : String;
+    FLocalInstallDir,
+    FGlobalInstallDir : String;
     // Compiler settings for compiling FPMake.pp
-    FFPMakeCompiler : String;
-    FFPMakeUnitDir : String;
+    FFPMakeCompiler,
+    FFPMakeLocalUnitDir,
+    FFPMakeGlobalUnitDir : String;
     // Parameter options
     FBootStrap : Boolean;
+    FInstallGlobal : Boolean;
     function GetOptString(Index: integer): String;
     procedure SetOptString(Index: integer; const AValue: String);
     procedure SetCompilerCPU(const AValue: TCPU);
@@ -80,16 +83,19 @@ Type
     Property CompilerTarget : String Index 7 Read GetOptString Write SetOptString;
     Property DefaultCompilerConfig : String Index 8 Read GetOptString Write SetOptString;
     Property CompilerVersion : String Index 9 Read GetOptString Write SetOptString;
-    Property InstallDir : String Index 10 Read GetOptString Write SetOptString;
-    Property DefaultVerbosity : String Index 11 Read GetOptString Write SetOptString;
-    Property PackagesDir : String Index 12 Read GetOptString Write SetOptString;
-    Property CompilerConfigDir : String Index 13 Read GetOptString Write SetOptString;
-    Property FPMakeCompiler : String Index 14 Read GetOptString Write SetOptString;
-    Property FPMakeUnitDir : String Index 15 Read GetOptString Write SetOptString;
-    Property CurrentCompilerConfig : String Index 16 Read GetOptString Write SetOptString;
+    Property GlobalInstallDir : String Index 10 Read GetOptString Write SetOptString;
+    Property LocalInstallDir : String Index 11 Read GetOptString Write SetOptString;
+    Property DefaultVerbosity : String Index 12 Read GetOptString Write SetOptString;
+    Property PackagesDir : String Index 13 Read GetOptString Write SetOptString;
+    Property CompilerConfigDir : String Index 14 Read GetOptString Write SetOptString;
+    Property FPMakeCompiler : String Index 15 Read GetOptString Write SetOptString;
+    Property FPMakeGlobalUnitDir : String Index 16 Read GetOptString Write SetOptString;
+    Property FPMakeLocalUnitDir : String Index 17 Read GetOptString Write SetOptString;
+    Property CurrentCompilerConfig : String Index 18 Read GetOptString Write SetOptString;
     Property CompilerOS : TOS Read FCompilerOS Write SetCompilerOS;
     Property CompilerCPU : TCPU Read FCompilerCPU Write SetCompilerCPU;
     Property BootStrap : Boolean Read FBootStrap Write FBootStrap;
+    Property InstallGlobal : Boolean Read FInstallGlobal Write FInstallGlobal;
   end;
 
 var
@@ -98,9 +104,6 @@ var
 Implementation
 
 uses
-{$ifdef unix}
-  baseunix,
-{$endif}
   pkgglobals,
   pkgmessages;
 
@@ -130,13 +133,15 @@ Const
   KeyCompilerConfig        = 'CompilerConfig';
   KeyVerbosity             = 'Verbosity';
   // Compiler dependent config
-  KeyInstallDir            = 'InstallDir';
+  KeyGlobalInstallDir      = 'GlobalInstallDir';
+  KeyLocalInstallDir       = 'LocalInstallDir';
   KeyCompiler              = 'Compiler' ;
   KeyCompilerOS            = 'OS';
   KeyCompilerCPU           = 'CPU';
   KeyCompilerVersion       = 'Version';
   KeyFPMakeCompiler        = 'FPMakeCompiler';
-  KeyFPMakeUnitDir         = 'FPMakeUnitDir';
+  KeyFPMakeGlobalUnitDir   = 'FPMakeGlobalUnitDir';
+  KeyFPMakeLocalUnitDir    = 'FPMakeLocalUnitDir';
 
 
 { TPackagerOptions }
@@ -159,13 +164,15 @@ begin
     7 : Result:=MakeTargetString(CompilerCPU,CompilerOS);
     8 : Result:=FDefaultCompilerConfig;
     9 : Result:=FCompilerVersion;
-   10 : Result:=FInstallDir;
-   11 : Result:=FDefaultVerbosity;
-   12 : Result:=FPackagesDir;
-   13 : Result:=FCompilerConfigDir;
-   14 : Result:=FFPMakeCompiler;
-   15 : Result:=FFPMakeUnitDir;
-   16 : Result:=FCurrentCompilerConfig;
+   10 : Result:=FGlobalInstallDir;
+   11 : Result:=FLocalInstallDir;
+   12 : Result:=FDefaultVerbosity;
+   13 : Result:=FPackagesDir;
+   14 : Result:=FCompilerConfigDir;
+   15 : Result:=FFPMakeCompiler;
+   16 : Result:=FFPMakeGlobalUnitDir;
+   17 : Result:=FFPMakeLocalUnitDir;
+   18 : Result:=FCurrentCompilerConfig;
   end;
 end;
 
@@ -183,13 +190,15 @@ begin
     7 : StringToCPUOS(AValue,FCompilerCPU,FCompilerOS);
     8 : FDefaultCompilerConfig:=AValue;
     9 : FCompilerVersion:=AValue;
-   10 : FInstallDir:=FixPath(AValue);
-   11 : FDefaultVerbosity:=AValue;
-   12 : FPackagesDir:=FixPath(AValue);
-   13 : FCompilerConfigDir:=FixPath(AValue);
-   14 : FFPMakeCompiler:=AValue;
-   15 : FFPMakeUnitDir:=FixPath(AValue);
-   16 : FCurrentCompilerConfig:=AValue;
+   10 : FGlobalInstallDir:=FixPath(AValue);
+   11 : FLocalInstallDir:=FixPath(AValue);
+   12 : FDefaultVerbosity:=AValue;
+   13 : FPackagesDir:=FixPath(AValue);
+   14 : FCompilerConfigDir:=FixPath(AValue);
+   15 : FFPMakeCompiler:=AValue;
+   16 : FFPMakeGlobalUnitDir:=FixPath(AValue);
+   17 : FFPMakeLocalUnitDir:=FixPath(AValue);
+   18 : FCurrentCompilerConfig:=AValue;
   end;
   FDirty:=True;
 end;
@@ -236,7 +245,7 @@ var
 begin
   // Retrieve Local fppkg directory
 {$ifdef unix}
-  if (fpGetUID=0) then
+  if IsSuperUser then
     begin
       if DirectoryExists('/usr/local/lib/fpc') then
         LocalDir:='/usr/local/lib/fpc/fppkg/'
@@ -263,13 +272,13 @@ begin
   FCurrentCompilerConfig:=FDefaultCompilerConfig;
   FDefaultVerbosity:='error,warning,info,debug,commands';
   FBootStrap:=False;
+  FInstallGlobal:=False;
 end;
 
 
 Procedure TPackagerOptions.InitCompilerDefaults;
 var
   infoSL : TStringList;
-  DepDir : String;
   i : Integer;
 begin
   FCompiler:=FileSearch('fpc'+ExeExt,GetEnvironmentVariable('PATH'));
@@ -287,33 +296,40 @@ begin
   Log(vDebug,SLogDetectedCompiler,[FCompiler,FCompilerVersion,MakeTargetString(FCompilerCPU,FCompilerOS)]);
   // Use the same algorithm as the compiler, see options.pas
 {$ifdef Unix}
-  FInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
-  if FInstallDir='' then
+  FGlobalInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
+  if FGlobalInstallDir='' then
     begin
-      FInstallDir:='/usr/local/lib/fpc/'+FCompilerVersion+'/';
-      if not DirectoryExists(FInstallDir) and
+      FGlobalInstallDir:='/usr/local/lib/fpc/'+FCompilerVersion+'/';
+      if not DirectoryExists(FGlobalInstallDir) and
          DirectoryExists('/usr/lib/fpc/'+FCompilerVersion) then
-        FInstallDir:='/usr/lib/fpc/'+FCompilerVersion+'/';
+        FGlobalInstallDir:='/usr/lib/fpc/'+FCompilerVersion+'/';
     end;
 {$else unix}
-  FInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
-  if FInstallDir='' then
+  FGlobalInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
+  if FGlobalInstallDir='' then
     begin
-      FInstallDir:=ExtractFilePath(FCompiler)+'../';
-      if not(DirectoryExists(FInstallDir+'/units')) and
-         not(DirectoryExists(FInstallDir+'/rtl')) then
-        FInstallDir:=FInstallDir+'../';
+      FGlobalInstallDir:=ExtractFilePath(FCompiler)+'../';
+      if not(DirectoryExists(FGlobalInstallDir+'/units')) and
+         not(DirectoryExists(FGlobalInstallDir+'/rtl')) then
+        FGlobalInstallDir:=FGlobalInstallDir+'../';
     end;
 {$endif unix}
-  Log(vDebug,SLogDetectedFPCDIR,[FInstallDir]);
+  Log(vDebug,SLogDetectedFPCDIR,['global',FGlobalInstallDir]);
+  // User writable install directory
+  if not IsSuperUser then
+    begin
+      FLocalInstallDir:=FLocalRepository+'lib'+PathDelim+FCompilerVersion+PathDelim;
+      Log(vDebug,SLogDetectedFPCDIR,['local',FLocalInstallDir]);
+    end;
   // Detect directory where fpmake units are located
   FFPMakeCompiler:=FCompiler;
-  FFPMakeUnitDir:=FInstallDir+'units'+PathDelim+CompilerTarget+PathDelim;
+  FFPMakeGlobalUnitDir:=FGlobalInstallDir+'units'+PathDelim+CompilerTarget+PathDelim;
+  FFPMakeLocalUnitDir:=FLocalInstallDir+'units'+PathDelim+CompilerTarget+PathDelim;
   for i:=low(FPMKUnitDeps) to high(FPMKUnitDeps) do
     begin
-      DepDir:=FFPMakeUnitDir+FPMKUnitDeps[i]+PathDelim;
-      if not DirectoryExists(DepDir) then
-        Log(vWarning,SWarnFPMKUnitNotFound,[DepDir]);
+      if not DirectoryExists(FFPMakeGlobalUnitDir+FPMKUnitDeps[i]+PathDelim) and
+         not DirectoryExists(FFPMakeLocalUnitDir+FPMKUnitDeps[i]+PathDelim) then
+        Log(vWarning,SWarnFPMKUnitNotFound,[FPMKUnitDeps[i]]);
     end;
 end;
 
@@ -383,13 +399,15 @@ procedure TPackagerOptions.LoadCompilerFromIni(Ini: TCustomIniFile);
 begin
  With Ini do
    begin
-     FInstallDir:=FixPath(ReadString(SDefaults,KeyInstallDir,FInstallDir));
+     FGlobalInstallDir:=FixPath(ReadString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir));
+     FLocalInstallDir:=FixPath(ReadString(SDefaults,KeyLocalInstallDir,FLocalInstallDir));
      FCompiler:=ReadString(SDefaults,KeyCompiler,FCompiler);
      FCompilerOS:=StringToOS(ReadString(SDefaults,KeyCompilerOS,OSToString(CompilerOS)));
      FCompilerCPU:=StringToCPU(ReadString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU)));
      FCompilerVersion:=ReadString(SDefaults,KeyCompilerVersion,FCompilerVersion);
      FFPMakeCompiler:=ReadString(SDefaults,KeyFPMakeCompiler,FFPMakeCompiler);
-     FFPMakeUnitDir:=FixPath(ReadString(SDefaults,KeyFPMakeUnitDir,FFPMakeUnitDir));
+     FFPMakeGlobalUnitDir:=FixPath(ReadString(SDefaults,KeyFPMakeGlobalUnitDir,FFPMakeGlobalUnitDir));
+     FFPMakeLocalUnitDir:=FixPath(ReadString(SDefaults,KeyFPMakeLocalUnitDir,FFPMakeLocalUnitDir));
    end;
 end;
 
@@ -398,13 +416,15 @@ procedure TPackagerOptions.SaveCompilerToIni(Ini: TCustomIniFile);
 begin
  With Ini do
    begin
-     WriteString(SDefaults,KeyInstallDir,FInstallDir);
+     WriteString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir);
+     WriteString(SDefaults,KeyLocalInstallDir,FLocalInstallDir);
      WriteString(SDefaults,KeyCompiler,FCompiler);
      WriteString(SDefaults,KeyCompilerOS,OSToString(CompilerOS));
      WriteString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU));
      WriteString(SDefaults,KeyCompilerVersion,FCompilerVersion);
      WriteString(SDefaults,KeyFPMakeCompiler,FFPMakeCompiler);
-     WriteString(SDefaults,KeyFPMakeUnitDir,FFPMakeUnitDir);
+     WriteString(SDefaults,KeyFPMakeGlobalUnitDir,FFPMakeGlobalUnitDir);
+     WriteString(SDefaults,KeyFPMakeLocalUnitDir,FFPMakeLocalUnitDir);
    end;
 end;