浏览代码

# revisions: 40515,40687,40689,40690,40705,40711,40748,41197,41220,41226,41418,41742,41771,41848,41860,41946

git-svn-id: branches/fixes_3_2@42002 -
marco 6 年之前
父节点
当前提交
ae432bf0e6

+ 74 - 15
packages/fpmkunit/src/fpmkunit.pp

@@ -158,7 +158,7 @@ Type
   TLogEvent = Procedure (Level : TVerboseLevel; Const Msg : String) of Object;
   TNotifyProcEvent = procedure(Sender: TObject);
 
-  TRunMode = (rmCompile,rmBuild,rmInstall,rmArchive,rmClean,rmDistClean,rmManifest,rmZipInstall,rmPkgList,rmUnInstall,rmInfo);
+  TRunMode = (rmCompile,rmBuild,rmInstall,rmBuildInstall,rmArchive,rmClean,rmDistClean,rmManifest,rmZipInstall,rmPkgList,rmUnInstall,rmInfo);
 
   TBuildMode = (bmOneByOne, bmBuildUnit{, bmSkipImplicitUnits});
   TBuildModes = set of TBuildMode;
@@ -517,6 +517,8 @@ Type
     Property RequireChecksum : Cardinal Read FRequireChecksum Write FRequireChecksum;
   end;
 
+  TResourceFile = Class(TConditionalString);
+
   { TPackageVariant }
 
   TPackage = Class;
@@ -587,6 +589,13 @@ Type
     Property Dependencies[Index : Integer] : TDependency Read GetDependency Write SetDependency; default;
   end;
 
+  { TResourceFiles }
+
+  TResourceFiles = Class(TConditionalStrings)
+  public
+    Procedure GetInstallFiles(AList : TStrings; const APrefixU, APrefixB : String; ACPU:TCPU; AOS : TOS); virtual;
+  end;
+
   { TTarget }
 
   TTarget = Class(TNamedItem)
@@ -605,6 +614,7 @@ Type
     FUnitPath,
     FIncludePath : TConditionalStrings;
     FDependencies : TDependencies;
+    FResourceFiles : TResourceFiles;
     FCommands : TCommands;
     FDirectory: String;
     FExtension: String;
@@ -644,6 +654,7 @@ Type
     Procedure GetInstallFiles(List : TStrings; const APrefixU, APrefixB : String; ACPU:TCPU; AOS : TOS); virtual;
     Procedure GetArchiveFiles(List : TStrings; ACPU:TCPU; AOS : TOS); virtual;
     Property Dependencies : TDependencies Read FDependencies;
+    Property ResourceFiles: TResourceFiles read FResourceFiles;
     Property Commands : TCommands Read FCommands;
     Property State : TTargetState Read FTargetState;
     Property TargetType : TTargetType Read FTargetType Write FTargetType;
@@ -890,6 +901,7 @@ Type
     Property SupportBuildModes: TBuildModes read FSupportBuildModes write FSupportBuildModes;
     Property BuildMode: TBuildMode read FBuildMode;
     Property Flags: TStrings read FFlags;
+    Property PackageVersion: TFPVersion read FVersion;
     // Options which are passed to the compiler for packages which depend on
     // this package.
     Property TransmitOptions: TStrings Read GetTransmitOptions Write SetTransmitOptions;
@@ -1288,7 +1300,7 @@ Type
     Procedure Usage(const FMT : String; Args : Array of const);
     Procedure Compile(Force : Boolean); virtual;
     Procedure Clean(AllTargets: boolean); virtual;
-    Procedure Install; virtual;
+    Procedure Install(ForceBuild : Boolean); virtual;
     Procedure UnInstall; virtual;
     Procedure ZipInstall; virtual;
     Procedure Archive; virtual;
@@ -1762,6 +1774,7 @@ ResourceString
   SHelpCompile        = 'Compile all units in the package(s).';
   SHelpBuild          = 'Build all units in the package(s).';
   SHelpInstall        = 'Install all units in the package(s).';
+  SHelpBuildInstall   = 'Build and install all units in the package(s).';
   SHelpUnInstall      = 'Uninstall the package(s).';
   SHelpClean          = 'Clean (remove) all generated files in the package(s) for current CPU-OS target.';
   SHelpDistclean      = 'Clean (remove) all generated files in the package(s) for all targets.';
@@ -2813,6 +2826,21 @@ begin
   Result := GPluginManager;
 end;
 
+{ TResourceFiles }
+
+procedure TResourceFiles.GetInstallFiles(AList: TStrings; const APrefixU, APrefixB: String; ACPU: TCPU; AOS: TOS);
+Var
+  I : Integer;
+  R : TResourceFile;
+begin
+  For I:=0 to Count-1 do
+    begin
+    R:=Tobject(Items[I]) as TResourceFile;
+    if (ACPU in R.CPUs) and (AOS in R.OSes) then
+      AList.Add(ConcatPaths([APrefixU, R.Value]));
+    end;
+end;
+
 { TfpmResolvePackagePathsPlugin }
 
 procedure TfpmResolvePackagePathsPlugin.ResolveUnitConfigFilenameForBasePath(
@@ -5194,6 +5222,8 @@ begin
       FRunMode:=rmBuild
     else if CheckCommand(I,'i','install') then
       FRunMode:=rmInstall
+    else if CheckCommand(I,'bi','buildinstall') then
+      FRunMode:=rmBuildInstall
     else if CheckCommand(I,'zi','zipinstall') then
       FRunMode:=rmZipInstall
     else if CheckCommand(I,'c','clean') then
@@ -5344,6 +5374,7 @@ begin
   LogCmd('compile',SHelpCompile);
   LogCmd('build',SHelpBuild);
   LogCmd('install',SHelpInstall);
+  LogCmd('buildinstall',SHelpBuildInstall);
   LogCmd('uninstall',SHelpUnInstall);
   LogCmd('clean',SHelpClean);
   LogCmd('distclean',SHelpDistclean);
@@ -5441,9 +5472,10 @@ begin
 end;
 
 
-procedure TCustomInstaller.Install;
+procedure TCustomInstaller.Install(ForceBuild : Boolean);
 begin
   NotifyEventCollection.CallEvents(neaBeforeInstall, self);
+  BuildEngine.ForceCompile := ForceBuild;
   BuildEngine.Install(Packages);
   NotifyEventCollection.CallEvents(neaAfterInstall, self);
 end;
@@ -5517,7 +5549,8 @@ begin
     Case RunMode of
       rmCompile : Compile(False);
       rmBuild   : Compile(True);
-      rmInstall : Install;
+      rmInstall : Install(False);
+      rmBuildInstall: Install(True);
       rmZipInstall : ZipInstall;
       rmArchive : Archive;
       rmClean    : Clean(False);
@@ -8007,19 +8040,21 @@ end;
 
 procedure TBuildEngine.Clean(APackage: TPackage; ACPU: TCPU; AOS: TOS);
 Var
-  List : TStringList;
+  List,List2 : TStringList;
   DirectoryList : TStringList;
   RemainingList : TStrings;
   i : longint;
 begin
-  List:=TStringList.Create;
+  List:=TUnsortedDuplicatesStringList.Create;
+  List.Duplicates:=DupIgnore;
   try
     List.Add(APackage.GetUnitConfigOutputFilename(ACPU,AOS));
     APackage.GetCleanFiles(List,ACPU,AOS);
     if (List.Count>0) then
       begin
       CmdDeleteFiles(List);
-      DirectoryList := TStringList.Create;
+      DirectoryList:=TUnsortedDuplicatesStringList.Create;
+      DirectoryList.Duplicates:=DupIgnore;
       try
         GetDirectoriesFromFilelist(List,DirectoryList);
         CmdRemoveDirs(DirectoryList);
@@ -8040,9 +8075,18 @@ begin
             Installer.Log(vlWarning,Format(SWarnRemovedNonEmptyDirectory,[APackage.Directory+APackage.GetBinOutputDir(ACPU,AOS)]));
             DirectoryList.Add(APackage.GetBinOutputDir(ACPU,AOS));
             RemainingList := TStringList.Create;
+            List2:=TStringList.Create;
             SearchFiles(AllFilesMask, APackage.GetBinOutputDir(ACPU,AOS), true, RemainingList);
             for i:=0 to RemainingList.Count-1 do
-              Installer.log(vlDebug,format('File %s still present',[RemainingList[i]]));
+              begin
+                if ExtractFileExt(Remaininglist[i])=PPUExt then
+                  Installer.log(vlDebug,format('File %s still present, add corresponding entry to fpmake',[RemainingList[i]]))
+                else
+                  Installer.log(vlDebug,format('File %s still present',[RemainingList[i]]));
+                List2.Add(IncludeTrailingPathDelimiter(APackage.GetUnitsOutputDir(ACPU,AOS))+Remaininglist[i]);
+              end;
+            CmdDeleteFiles(List2);
+            List2.Free;
             RemainingList.Free;
             CmdRemoveTrees(DirectoryList);
             DirectoryList.Clear;
@@ -8053,9 +8097,18 @@ begin
             Installer.Log(vlWarning,Format(SWarnRemovedNonEmptyDirectory,[APackage.Directory+APackage.GetUnitsOutputDir(ACPU,AOS)]));
             DirectoryList.Add(APackage.GetUnitsOutputDir(ACPU,AOS));
             RemainingList := TStringList.Create;
+            List2:=TStringList.Create;
             SearchFiles(AllFilesMask, APackage.GetUnitsOutputDir(ACPU,AOS), true, RemainingList);
             for i:=0 to RemainingList.Count-1 do
-              Installer.log(vlDebug,format('File %s still present',[RemainingList[i]]));
+              begin
+                if ExtractFileExt(Remaininglist[i])=PPUExt then
+                  Installer.log(vlDebug,format('File %s still present, add corresponding entry to fpmake',[RemainingList[i]]))
+                else
+                  Installer.log(vlDebug,format('File %s still present',[RemainingList[i]]));
+                List2.Add(IncludeTrailingPathDelimiter(APackage.GetUnitsOutputDir(ACPU,AOS))+RemainingList[i]);
+              end;
+            CmdDeleteFiles(List2);
+            List2.free;
             RemainingList.Free;
             CmdRemoveTrees(DirectoryList);
             DirectoryList.Clear;
@@ -8529,6 +8582,7 @@ begin
   FIncludePath:=TConditionalStrings.Create(TConditionalString);
   FObjectPath:=TConditionalStrings.Create(TConditionalString);
   FDependencies:=TDependencies.Create(TDependency);
+  FResourceFiles:=TResourceFiles.Create(TResourceFile);
   FCommands:=TCommands.Create(TCommand);
 end;
 
@@ -8539,6 +8593,7 @@ begin
   FreeAndNil(FObjectPath);
   FreeAndNil(FIncludePath);
   FreeAndNil(FDependencies);
+  FreeAndNil(FResourceFiles);
   FreeAndNil(FCommands);
   FreeAndNil(Foptions);
   inherited Destroy;
@@ -8565,6 +8620,7 @@ begin
     DestTarget.FileType := FileType;
     DestTarget.Directory := Directory;
     DestTarget.ResourceStrings := ResourceStrings;
+    DestTarget.ResourceFiles.Assign(ResourceFiles);
     DestTarget.Install := Install;
     DestTarget.FTargetSourceFileName := fTargetSourceFileName;
     DestTarget.ObjectPath.Assign(ObjectPath);
@@ -8737,15 +8793,17 @@ begin
     end
   else If (TargetType in [ttProgram,ttExampleProgram]) then
     begin
-    List.Add(APrefixB + GetProgramFileName(AOS));
-    if FileExists(APrefixB + GetProgramDebugFileName(AOS)) then
-      List.Add(APrefixB + GetProgramDebugFileName(AOS));
+      List.Add(APrefixB + GetProgramFileName(AOS));
+      if FileExists(APrefixB + GetProgramDebugFileName(AOS)) then
+        List.Add(APrefixB + GetProgramDebugFileName(AOS));
+      if (AOS in AllImportLibraryOSes) and FileExists(APrefixU + GetImportLibFilename(AOS)) then
+        List.Add(APrefixU + GetImportLibFilename(AOS));
     end
   else If (TargetType in [ttSharedLibrary]) then
     begin
-    List.Add(APrefixB + GetLibraryFileName(AOS));
-    if FileExists(APrefixB + GetLibraryDebugFileName(AOS)) then
-      List.Add(APrefixB + GetLibraryDebugFileName(AOS));
+      List.Add(APrefixB + GetLibraryFileName(AOS));
+      if FileExists(APrefixB + GetLibraryDebugFileName(AOS)) then
+        List.Add(APrefixB + GetLibraryDebugFileName(AOS));
     end;
   If ResourceStrings then
     begin
@@ -8813,6 +8871,7 @@ begin
           List.Add(APrefixU + RSTFileName);
         end;
      end;
+  FResourceFiles.GetInstallFiles(List, APrefixU, APrefixB, ACPU, AOS);
 end;
 
 

+ 58 - 1
packages/fppkg/src/fprepos.pp

@@ -98,6 +98,29 @@ type
     Property Dependencies[Index : Integer] : TFPDependency Read GetDependency Write SetDependency;default;
   end;
 
+
+  { TFPPackageVariant }
+
+  TFPPackageVariant = class(TCollectionItem)
+  private
+    FName: string;
+    FIsInheritable: boolean;
+    FOptions: TStringArray;
+  public
+    property Name: string read FName write FName;
+    property IsInheritable: boolean read FIsInheritable write FIsInheritable;
+    property Options: TStringArray read FOptions write FOptions;
+  end;
+
+  { TFPPackageVariants }
+
+  TFPPackageVariants = class(TCollection)
+  protected
+    function GetItem(Index: Integer): TFPPackageVariant;
+  public
+    property Items[Index: Integer]: TFPPackageVariant read GetItem;
+  end;
+
   { TFPPackage }
 
   TFPPackage = Class(TStreamCollectionItem)
@@ -126,6 +149,7 @@ type
     FChecksum : cardinal;
     FLocalFileName : String;
     FPackagesStructure: TFPCustomPackagesStructure;
+    FPackageVariants: TFPPackageVariants;
     function GetFileName: String;
     function GetRepository: TFPRepository;
     procedure SetName(const AValue: String);
@@ -169,6 +193,8 @@ type
     // Manual package from commandline not in official repository
     Property LocalFileName : String Read FLocalFileName Write FLocalFileName;
     Property PackagesStructure: TFPCustomPackagesStructure read FPackagesStructure write FPackagesStructure;
+    // Read from unit config file, not in official repository
+    Property PackageVariants: TFPPackageVariants read FPackageVariants;
   end;
 
   { TFPPackages }
@@ -325,6 +351,7 @@ const
   KeyFPMakeOptions = 'FPMakeOptions';
   KeyCPU      = 'CPU';
   KeyOS       = 'OS';
+  KeyPkgVar   = 'PackageVariant_';
 
 ResourceString
   SErrInvalidCPU           = 'Invalid CPU name : "%s"';
@@ -359,6 +386,13 @@ begin
   OS:=StringToOs(Copy(S,P+1,Length(S)-P));
 end;
 
+{ TFPPackageVariants }
+
+function TFPPackageVariants.GetItem(Index: Integer): TFPPackageVariant;
+begin
+  Result := inherited GetItem(Index) as TFPPackageVariant;
+end;
+
 { TFPCustomPackagesStructure }
 
 function TFPCustomPackagesStructure.GetUnitDirectory(APackage: TFPPackage): string;
@@ -482,6 +516,7 @@ begin
   FOSes:=AllOSes;
   FCPUs:=AllCPUs;
   FDependencies:=TFPDependencies.Create(TFPDependency);
+  FPackageVariants:=TFPPackageVariants.Create(TFPPackageVariant);
 end;
 
 
@@ -490,6 +525,7 @@ begin
   FreeAndNil(FDependencies);
   FreeAndNil(FVersion);
   FreeAndNil(FUnusedVersion);
+  FreeAndNil(FPackageVariants);
   inherited Destroy;
 end;
 
@@ -625,7 +661,9 @@ var
   VCPU : TCPU;
   i,k : Integer;
   DepChecksum : Cardinal;
-  DepName : String;
+  DepName: String;
+  PackageVariantStr, PackageVariantName: String;
+  PackageVariant: TFPPackageVariant;
   D : TFPDependency;
 begin
   With AStringList do
@@ -668,6 +706,25 @@ begin
       //NeedLibC:=Upcase(Values[KeyNeedLibC])='Y';
       IsFPMakeAddIn:=Upcase(Values[KeyAddIn])='Y';
       FPMakePluginUnits:=Values[KeyPluginUnits];
+
+      // Read packagevariants
+      i := 1;
+      repeat
+      PackageVariantStr := Values[KeyPkgVar+IntToStr(i)];
+      if PackageVariantStr<>'' then
+        begin
+        PackageVariant := FPackageVariants.Add as TFPPackageVariant;
+        PackageVariantName := Copy(PackageVariantStr, 1, pos(':', PackageVariantStr) -1);
+        if RightStr(PackageVariantName, 1) = '*' then
+          begin
+          PackageVariantName := Copy(PackageVariantName, 1, Length(PackageVariantName) -1);
+          PackageVariant.IsInheritable := True;
+          end;
+        PackageVariant.Name := PackageVariantName;
+        PackageVariant.Options := Copy(PackageVariantStr, pos(':', PackageVariantStr) +1).Split(',');
+        end;
+      inc(i);
+      until PackageVariantStr='';
     end;
 end;
 

+ 21 - 6
packages/fppkg/src/pkgfppkg.pp

@@ -30,6 +30,7 @@ type
     FCompilerOptions: TCompilerOptions;
     FFpmakeCompilerOptions: TCompilerOptions;
     FCurrentRemoteRepositoryURL: String;
+    FConfigurationFilename: string;
     function IncludeRepositoryTypeForPackageKind(ARepositoryType: TFPRepositoryType;
       APackageKind: TpkgPackageKind): Boolean;
     procedure ScanPackagesOnDisk(ACompilerOptions: TCompilerOptions; APackageKind: TpkgPackageKind; ARepositoryList: TComponentList);
@@ -42,6 +43,7 @@ type
     procedure LeaveFindBrokenpackages;
 
     procedure ClearRepositories(ARepositoryList: TComponentList);
+    function GetConfigurationFilename: string;
   public
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
@@ -78,6 +80,7 @@ type
     property FpmakeCompilerOptions: TCompilerOptions read FFpmakeCompilerOptions;
     property FPMakeRepositoryList: TComponentList read FFPMakeRepositoryList;
     property RepositoryList: TComponentList read FRepositoryList;
+    property ConfigurationFilename: string read GetConfigurationFilename;
   public
 
   end;
@@ -197,6 +200,7 @@ begin
     pkgglobals.Log(llDebug,SLogGeneratingGlobalConfig,[cfgfile])
   else
     pkgglobals.Log(llDebug,SLogLoadingGlobalConfig,[cfgfile]);
+  FConfigurationFilename := CfgFile;
   // Log configuration
   FOptions.LogValues(llDebug);
 end;
@@ -211,18 +215,22 @@ begin
   if FileExists(S) then
     begin
       pkgglobals.Log(llDebug,SLogLoadingCompilerConfig,[S]);
-      FCompilerOptions.LoadCompilerFromFile(S)
+      FCompilerOptions.LoadCompilerFromFile(S);
+      if FCompilerOptions.SaveInifileChanges then
+        // The file is in an old format, try to update the file but ignore
+        // any failures.
+        FCompilerOptions.SaveCompilerToFile(S);
     end
   else
     begin
-      // Generate a default configuration if it doesn't exists
-      if FOptions.GlobalSection.CompilerConfig='default' then
+      if FCompilerOptions.SaveInifileChanges then
+        // A new fppkg.cfg has been created, try to create a new compiler-configuration
+        // file too.
         begin
           pkgglobals.Log(llDebug,SLogGeneratingCompilerConfig,[S]);
           FCompilerOptions.InitCompilerDefaults;
-          FCompilerOptions.SaveCompilerToFile(S);
-          if FCompilerOptions.SaveInifileChanges then
-            FCompilerOptions.SaveCompilerToFile(S);
+          if not FCompilerOptions.SaveCompilerToFile(S) then
+            Error(SErrMissingCompilerConfig,[S]);
         end
       else
         Error(SErrMissingCompilerConfig,[S]);
@@ -237,6 +245,8 @@ begin
       pkgglobals.Log(llDebug,SLogLoadingFPMakeCompilerConfig,[S]);
       FFPMakeCompilerOptions.LoadCompilerFromFile(S);
       if FFPMakeCompilerOptions.SaveInifileChanges then
+        // The file is in an old format, try to update the file but ignore
+        // any failures.
         FFPMakeCompilerOptions.SaveCompilerToFile(S);
     end
   else
@@ -773,5 +783,10 @@ begin
     Result:=GetRemoteRepositoryURL(APackage.FileName);
 end;
 
+function TpkgFPpkg.GetConfigurationFilename: string;
+begin
+  Result := FConfigurationFilename;
+end;
+
 end.
 

+ 1 - 0
packages/fppkg/src/pkgmessages.pp

@@ -163,6 +163,7 @@ Resourcestring
   SDbgPackageInstallRequired = 'Installation of package "%s" required for repository "%s"';
 
   SWarnBrokenAfterReinstall  = 'Package %s is still broken, even after re-installation. (%s)';
+  SWarnFailedToWriteCompConf = 'Failed to write compiler-configuration file "%s": %s';
 
   SProgrReinstallDependent   = 'Re-install packages which are dependent on just installed packages';
   SProgrInstallDependencies  = 'Install dependencies';

+ 37 - 21
packages/fppkg/src/pkgoptions.pp

@@ -246,7 +246,7 @@ Type
     Destructor Destroy; override;
     Procedure InitCompilerDefaults;
     Procedure LoadCompilerFromFile(const AFileName : String);
-    Procedure SaveCompilerToFile(const AFileName : String);
+    function SaveCompilerToFile(const AFileName : String): Boolean;
     procedure LogValues(ALogLevel: TLogLevel; const ACfgName:string);
     procedure UpdateLocalRepositoryOption(FppkgOptions: TFppkgOptions);
     procedure CheckCompilerValues;
@@ -984,6 +984,7 @@ begin
   FOptionParser := TTemplateParser.Create;
   FOptionParser.Values['AppConfigDir'] := GetFppkgConfigDir(false);
   FOptionParser.Values['UserDir'] := GetUserDir;
+  FSaveInifileChanges := True;
   {$ifdef unix}
   FLocalInstallDir:='{LocalPrefix}'+'lib'+PathDelim+'fpc'+PathDelim+'{CompilerVersion}'+PathDelim;
   FGlobalInstallDir:='{GlobalPrefix}'+'lib'+PathDelim+'fpc'+PathDelim+'{CompilerVersion}'+PathDelim;
@@ -1076,6 +1077,10 @@ var
 begin
   if Compiler='' then
     Exit;
+  // This is not the place to complain when the compiler does
+  // not exist at all.
+  if not FileExists(Compiler) then
+    Exit;
   if (CompilerCPU=cpuNone) or
    (CompilerOS=osNone) or
    (CompilerVersion='') then
@@ -1175,6 +1180,10 @@ begin
             FSaveInifileChanges:=true;
             if (FConfigVersion>CurrentConfigVersion) then
               Error(SErrUnsupportedConfigVersion,[AFileName]);
+          end
+        else
+          begin
+            FSaveInifileChanges:=False;
           end;
         GlobalPrefix:=ReadString(SDefaults,KeyGlobalPrefix,FGlobalPrefix);
         LocalPrefix:=ReadString(SDefaults,KeyLocalPrefix,FLocalPrefix);
@@ -1191,30 +1200,37 @@ begin
 end;
 
 
-procedure TCompilerOptions.SaveCompilerToFile(const AFileName: String);
+function TCompilerOptions.SaveCompilerToFile(const AFileName: String): Boolean;
 Var
   Ini : TIniFile;
 begin
-  if FileExists(AFileName) then
-    BackupFile(AFileName);
-  Ini:=TIniFile.Create(AFileName);
+  Result := False;
   try
-    With Ini do
-      begin
-        WriteInteger(SDefaults,KeyConfigVersion,CurrentConfigVersion);
-        WriteString(SDefaults,KeyGlobalPrefix,FGlobalPrefix);
-        WriteString(SDefaults,KeyLocalPrefix,FLocalPrefix);
-        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);
-        FSaveInifileChanges:=False;
-      end;
-    Ini.UpdateFile;
-  finally
-    Ini.Free;
+    if FileExists(AFileName) then
+      BackupFile(AFileName);
+    Ini:=TIniFile.Create(AFileName);
+    try
+      With Ini do
+        begin
+          WriteInteger(SDefaults,KeyConfigVersion,CurrentConfigVersion);
+          WriteString(SDefaults,KeyGlobalPrefix,FGlobalPrefix);
+          WriteString(SDefaults,KeyLocalPrefix,FLocalPrefix);
+          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);
+          FSaveInifileChanges:=False;
+        end;
+      Ini.UpdateFile;
+    finally
+      Ini.Free;
+    end;
+    Result := True;
+  except
+    on E: Exception do
+      log(llWarning, SWarnFailedToWriteCompConf, [AFileName, E.Message]);
   end;
 end;
 

+ 54 - 2
utils/fpcmkcfg/fpcmkcfg.pp

@@ -1,5 +1,6 @@
 {$mode objfpc}
 {$H+}
+{$macro on}
 {
     This file is part of Free Pascal Build tools
     Copyright (c) 2005 by Michael Van Canneyt
@@ -41,6 +42,19 @@ uses
 {$i fppkg.inc}
 {$i default.inc}
 
+{$ifndef package_version_major}
+  {$define package_version_major:=0}
+{$endif}
+{$ifndef package_version_minor}
+  {$define package_version_minor:=0}
+{$endif}
+{$ifndef package_version_micro}
+  {$define package_version_micro:=0}
+{$endif}
+{$ifndef package_version_build}
+  {$define package_version_build:=0}
+{$endif}
+
 Const
   BuildVersion={$I %FPCVERSION%};
   BuildTarget={$I %FPCTARGET%};
@@ -51,6 +65,10 @@ Const
   ExeExt = '.exe';
 {$endif unix}
 
+  version_major = package_version_major;
+  version_minor = package_version_minor;
+  version_micro = package_version_micro;
+  version_build = package_version_build;
 
 Resourcestring
   SUsage00  = 'Usage: %s [options]';
@@ -66,11 +84,15 @@ Resourcestring
   SUsage84  = '  -s            skip the creation of a backup-file.';
   SUsage87  = '  -p            force directory creation.';
   SUsage90  = '  -v            be verbose.';
+  SUsage95  = '  -V            show version.';
   Susage100 = '  -0            use built in fpc.cfg template (default)';
   Susage110 = '  -1            use built in fp.cfg template';
   Susage120 = '  -2            use built in fp.ini template';
   Susage130 = '  -3            use built in fppkg.cfg template';
   Susage140 = '  -4            use built in fppkg default compiler template';
+
+  SVersion  = 'Version: %s';
+
   SErrUnknownOption   = 'Error: Unknown option.';
   SErrArgExpected     = 'Error: Option "%s" requires an argument.';
   SErrIncompletePair  = 'Error: Incomplete name-value pair "%s".';
@@ -166,6 +188,14 @@ begin
     result := '#DEFINE NEEDCROSSBINUTILS';
 end;
 
+function GetDefaultUserPathSuffix: string;
+begin
+  if not (StringToOS(BuildOSTarget) in AllWindowsOSes) then
+    Result := 'lib/fpc/{CompilerVersion}'
+  else
+    Result := '';
+end;
+
 function GetDefaultGCCDir: string;
 
   var
@@ -276,6 +306,7 @@ begin
   TemplateParser.Values['COMPILERCONFIGDIR'] := GetDefaultCompilerConfigDir;
   TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
   TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
+  TemplateParser.Values['USERPATHSUFFIX'] := GetDefaultUserPathSuffix;
 
   Cfg:=TStringList.Create;
   Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
@@ -303,6 +334,7 @@ begin
   Writeln(SUsage84);
   Writeln(SUsage87);
   Writeln(SUsage90);
+  Writeln(SUsage95);
   Writeln(SUsage100);
   Writeln(SUsage110);
   Writeln(SUsage120);
@@ -311,6 +343,24 @@ begin
   Halt(1);
 end;
 
+Procedure Version;
+var
+  Version: string;
+begin
+  Version := '';
+  if version_major <> -1 then
+    Version := Version + IntToStr(version_major);
+  if version_minor <> -1 then
+    Version := Version + '.' + IntToStr(version_minor);
+  if version_micro <> -1 then
+    Version := Version + '.' + IntToStr(version_micro);
+  if version_build <> -1 then
+    Version := Version + '-'  + IntToStr(version_build);
+
+  Writeln(Format(SVersion,[Version]));
+  Halt(0);
+end;
+
 Procedure UnknownOption(Const S : String);
 
 begin
@@ -389,6 +439,7 @@ begin
     else
       case S[2] of
         'v' : Verbose:=True;
+        'V' : Version;
         'h' : Usage;
         'b' : ShowBuiltinCommand := true;
         'm' : begin
@@ -448,7 +499,7 @@ Procedure CreateFile;
 
 Var
   Fout : Text;
-  S,BFN : String;
+  S,BFN,ODir : String;
   I : Integer;
 
 begin
@@ -476,7 +527,8 @@ begin
     else
       Writeln(Format(SBackupCreated,[ExtractFileName(OutputFileName),ExtractFileName(BFN)]));
     end;
-  if (OutputFileName<>'') and not DirectoryExists(ExtractFilePath(OutputFileName)) then
+  ODir:=ExtractFilePath(OutputFileName);
+  if (OutputFileName<>'') and (ODir<>'') and not DirectoryExists(ODir) then
     begin
     if CreateDir then
       begin

+ 11 - 0
utils/fpcmkcfg/fpmake.pp

@@ -11,6 +11,7 @@ Var
   P : TPackage;
   T : TTarget;
   Data2IncBin : string;
+  VS: string;
 
 begin
   With Installer do
@@ -31,6 +32,16 @@ begin
     P.Directory:=ADirectory;
     P.Version:='3.2.0-beta';
 
+    P.Options.Add('-Sm');
+    Str(P.PackageVersion.Major, VS);
+    P.Options.Add('-dpackage_version_major:='+VS);
+    Str(P.PackageVersion.Minor, VS);
+    P.Options.Add('-dpackage_version_minor:='+VS);
+    Str(P.PackageVersion.Micro, VS);
+    P.Options.Add('-dpackage_version_micro:='+VS);
+    Str(P.PackageVersion.Build, VS);
+    P.Options.Add('-dpackage_version_build:='+VS);
+
     P.Dependencies.Add('fcl-base');
     P.Dependencies.Add('fpmkunit');
 

+ 4 - 5
utils/fpcmkcfg/fppkg.cfg

@@ -17,12 +17,11 @@ Description=Packages which are installed along with the Free Pascal Compiler
 Path=%GlobalPath%/{CompilerVersion}/
 Prefix=%GlobalPrefix%
 
+[IncludeFiles]
+FileMask=%CompilerConfigDir%conf.d/*.conf
+
 [Repository]
 Name=user
 Description=User-installed packages
-Path={LocalRepository}lib/fpc/{CompilerVersion}/
+Path={LocalRepository}%UserPathSuffix%
 Prefix={LocalRepository}
-
-[IncludeFiles]
-FileMask=%CompilerConfigDir%/conf.d/*.conf
-

+ 5 - 6
utils/fpcmkcfg/fppkg.inc

@@ -23,13 +23,12 @@ const fppkg : array[0..2,1..240] of char=(
   'Path=%GlobalPath%/{CompilerVersio','n}/'#010+
   'Prefix=%GlobalPrefix%'#010+
   #010+
+  '[IncludeFiles]'#010+
+  'FileMask=%CompilerConfigDir%conf.d/*.conf'#010+
+  #010+
   '[Repository]'#010+
   'Name=user'#010+
   'Description=User-installed packages'#010+
-  'Path={LocalRepository}lib/fpc/{CompilerVersion}/'#010+
-  'Prefix={LocalRepository}'#010+
-  #010+
-  '[IncludeFiles]'#010+
-  'FileMask=%CompilerConfigDir%/conf.d/*.conf'#010+
-  #010
+  'Path={LocalRepository}%UserPathSuffix%'#010+
+  'Prefix={LocalRepository}'#010
 );

+ 11 - 0
utils/fppkg/fpmake.pp

@@ -13,6 +13,7 @@ const
 Var
   P : TPackage;
   T : TTarget;
+  VS: string;
 
 begin
   With Installer do
@@ -39,6 +40,16 @@ begin
 
     P.SupportBuildModes:=[bmOneByOne];
 
+    P.Options.Add('-Sm');
+    Str(P.PackageVersion.Major, VS);
+    P.Options.Add('-dpackage_version_major:='+VS);
+    Str(P.PackageVersion.Minor, VS);
+    P.Options.Add('-dpackage_version_minor:='+VS);
+    Str(P.PackageVersion.Micro, VS);
+    P.Options.Add('-dpackage_version_micro:='+VS);
+    Str(P.PackageVersion.Build, VS);
+    P.Options.Add('-dpackage_version_build:='+VS);
+
     P.Dependencies.Add('fcl-base');
     P.Dependencies.Add('fcl-xml');
     P.Dependencies.Add('fcl-process');

+ 43 - 1
utils/fppkg/fppkg.pp

@@ -1,11 +1,24 @@
 program fppkg;
 
-{$mode objfpc}{$H+}
+{$mode objfpc}{$H+}{$macro on}
 
 {$if defined(VER2_2) and (FPC_PATCH<1)}
   {$fatal At least FPC 2.2.1 is required to compile fppkg}
 {$endif}
 
+{$ifndef package_version_major}
+  {$define package_version_major:=0}
+{$endif}
+{$ifndef package_version_minor}
+  {$define package_version_minor:=0}
+{$endif}
+{$ifndef package_version_micro}
+  {$define package_version_micro:=0}
+{$endif}
+{$ifndef package_version_build}
+  {$define package_version_build:=0}
+{$endif}
+
 uses
   // General
 {$ifdef unix}
@@ -28,6 +41,12 @@ uses
 {$endif}
   ;
 
+const
+  version_major = package_version_major;
+  version_minor = package_version_minor;
+  version_micro = package_version_micro;
+  version_build = package_version_build;
+
 Type
   { TMakeTool }
 
@@ -37,6 +56,7 @@ Type
     ParaPackages : TStringList;
     procedure MaybeCreateLocalDirs;
     procedure ShowUsage;
+    procedure ShowVersion;
   Public
     Constructor Create;
     Destructor Destroy;override;
@@ -94,6 +114,7 @@ begin
   Writeln('  -C --config-file   Specify the configuration file to use');
   Writeln('  -c --config        Set compiler configuration to use');
   Writeln('  -h --help          This help');
+  Writeln('  -V --version       Show version and exit');
   Writeln('  -v --verbose       Show more information');
   Writeln('  -d --debug         Show debugging information');
   Writeln('  -f --force         Force installation also if the package is already installed');
@@ -256,6 +277,11 @@ begin
           ShowUsage;
           halt(0);
         end
+      else if CheckOption(I,'V','version') then
+        begin
+          ShowVersion;
+          halt(0);
+        end
       else if (Length(Paramstr(i))>0) and (Paramstr(I)[1]='-') then
         begin
           if FirstPass then
@@ -426,6 +452,22 @@ begin
   SetCurrentDir(OldCurrDir);
 end;
 
+procedure TMakeTool.ShowVersion;
+var
+  Version: TFPVersion;
+begin
+  Version := TFPVersion.Create;
+  try
+    Version.Major := version_major;
+    Version.Minor := version_minor;
+    Version.Micro := version_micro;
+    Version.Build := version_build;
+    Writeln('Version: ', Version.AsString);
+  finally
+    Version.Free;
+  end;
+end;
+
 
 begin
   With TMakeTool.Create do