Parcourir la source

# 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 il y a 6 ans
Parent
commit
ae432bf0e6

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

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

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

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

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

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

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

@@ -163,6 +163,7 @@ Resourcestring
   SDbgPackageInstallRequired = 'Installation of package "%s" required for repository "%s"';
   SDbgPackageInstallRequired = 'Installation of package "%s" required for repository "%s"';
 
 
   SWarnBrokenAfterReinstall  = 'Package %s is still broken, even after re-installation. (%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';
   SProgrReinstallDependent   = 'Re-install packages which are dependent on just installed packages';
   SProgrInstallDependencies  = 'Install dependencies';
   SProgrInstallDependencies  = 'Install dependencies';

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

@@ -246,7 +246,7 @@ Type
     Destructor Destroy; override;
     Destructor Destroy; override;
     Procedure InitCompilerDefaults;
     Procedure InitCompilerDefaults;
     Procedure LoadCompilerFromFile(const AFileName : String);
     Procedure LoadCompilerFromFile(const AFileName : String);
-    Procedure SaveCompilerToFile(const AFileName : String);
+    function SaveCompilerToFile(const AFileName : String): Boolean;
     procedure LogValues(ALogLevel: TLogLevel; const ACfgName:string);
     procedure LogValues(ALogLevel: TLogLevel; const ACfgName:string);
     procedure UpdateLocalRepositoryOption(FppkgOptions: TFppkgOptions);
     procedure UpdateLocalRepositoryOption(FppkgOptions: TFppkgOptions);
     procedure CheckCompilerValues;
     procedure CheckCompilerValues;
@@ -984,6 +984,7 @@ begin
   FOptionParser := TTemplateParser.Create;
   FOptionParser := TTemplateParser.Create;
   FOptionParser.Values['AppConfigDir'] := GetFppkgConfigDir(false);
   FOptionParser.Values['AppConfigDir'] := GetFppkgConfigDir(false);
   FOptionParser.Values['UserDir'] := GetUserDir;
   FOptionParser.Values['UserDir'] := GetUserDir;
+  FSaveInifileChanges := True;
   {$ifdef unix}
   {$ifdef unix}
   FLocalInstallDir:='{LocalPrefix}'+'lib'+PathDelim+'fpc'+PathDelim+'{CompilerVersion}'+PathDelim;
   FLocalInstallDir:='{LocalPrefix}'+'lib'+PathDelim+'fpc'+PathDelim+'{CompilerVersion}'+PathDelim;
   FGlobalInstallDir:='{GlobalPrefix}'+'lib'+PathDelim+'fpc'+PathDelim+'{CompilerVersion}'+PathDelim;
   FGlobalInstallDir:='{GlobalPrefix}'+'lib'+PathDelim+'fpc'+PathDelim+'{CompilerVersion}'+PathDelim;
@@ -1076,6 +1077,10 @@ var
 begin
 begin
   if Compiler='' then
   if Compiler='' then
     Exit;
     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
   if (CompilerCPU=cpuNone) or
    (CompilerOS=osNone) or
    (CompilerOS=osNone) or
    (CompilerVersion='') then
    (CompilerVersion='') then
@@ -1175,6 +1180,10 @@ begin
             FSaveInifileChanges:=true;
             FSaveInifileChanges:=true;
             if (FConfigVersion>CurrentConfigVersion) then
             if (FConfigVersion>CurrentConfigVersion) then
               Error(SErrUnsupportedConfigVersion,[AFileName]);
               Error(SErrUnsupportedConfigVersion,[AFileName]);
+          end
+        else
+          begin
+            FSaveInifileChanges:=False;
           end;
           end;
         GlobalPrefix:=ReadString(SDefaults,KeyGlobalPrefix,FGlobalPrefix);
         GlobalPrefix:=ReadString(SDefaults,KeyGlobalPrefix,FGlobalPrefix);
         LocalPrefix:=ReadString(SDefaults,KeyLocalPrefix,FLocalPrefix);
         LocalPrefix:=ReadString(SDefaults,KeyLocalPrefix,FLocalPrefix);
@@ -1191,30 +1200,37 @@ begin
 end;
 end;
 
 
 
 
-procedure TCompilerOptions.SaveCompilerToFile(const AFileName: String);
+function TCompilerOptions.SaveCompilerToFile(const AFileName: String): Boolean;
 Var
 Var
   Ini : TIniFile;
   Ini : TIniFile;
 begin
 begin
-  if FileExists(AFileName) then
-    BackupFile(AFileName);
-  Ini:=TIniFile.Create(AFileName);
+  Result := False;
   try
   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;
 end;
 end;
 
 

+ 54 - 2
utils/fpcmkcfg/fpcmkcfg.pp

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

+ 11 - 0
utils/fpcmkcfg/fpmake.pp

@@ -11,6 +11,7 @@ Var
   P : TPackage;
   P : TPackage;
   T : TTarget;
   T : TTarget;
   Data2IncBin : string;
   Data2IncBin : string;
+  VS: string;
 
 
 begin
 begin
   With Installer do
   With Installer do
@@ -31,6 +32,16 @@ begin
     P.Directory:=ADirectory;
     P.Directory:=ADirectory;
     P.Version:='3.2.0-beta';
     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('fcl-base');
     P.Dependencies.Add('fpmkunit');
     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}/
 Path=%GlobalPath%/{CompilerVersion}/
 Prefix=%GlobalPrefix%
 Prefix=%GlobalPrefix%
 
 
+[IncludeFiles]
+FileMask=%CompilerConfigDir%conf.d/*.conf
+
 [Repository]
 [Repository]
 Name=user
 Name=user
 Description=User-installed packages
 Description=User-installed packages
-Path={LocalRepository}lib/fpc/{CompilerVersion}/
+Path={LocalRepository}%UserPathSuffix%
 Prefix={LocalRepository}
 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+
   'Path=%GlobalPath%/{CompilerVersio','n}/'#010+
   'Prefix=%GlobalPrefix%'#010+
   'Prefix=%GlobalPrefix%'#010+
   #010+
   #010+
+  '[IncludeFiles]'#010+
+  'FileMask=%CompilerConfigDir%conf.d/*.conf'#010+
+  #010+
   '[Repository]'#010+
   '[Repository]'#010+
   'Name=user'#010+
   'Name=user'#010+
   'Description=User-installed packages'#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
 Var
   P : TPackage;
   P : TPackage;
   T : TTarget;
   T : TTarget;
+  VS: string;
 
 
 begin
 begin
   With Installer do
   With Installer do
@@ -39,6 +40,16 @@ begin
 
 
     P.SupportBuildModes:=[bmOneByOne];
     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-base');
     P.Dependencies.Add('fcl-xml');
     P.Dependencies.Add('fcl-xml');
     P.Dependencies.Add('fcl-process');
     P.Dependencies.Add('fcl-process');

+ 43 - 1
utils/fppkg/fppkg.pp

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