Browse Source

--- Merging r22275 into '.':
U packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22275 into '.':
U .
--- Merging r22331 into '.':
G packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22331 into '.':
G .
--- Merging r22348 into '.':
G packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22348 into '.':
G .
--- Merging r22353 into '.':
G packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22353 into '.':
G .
--- Merging r22357 into '.':
G packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22357 into '.':
G .
--- Merging r22358 into '.':
G packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22358 into '.':
G .
--- Merging r22359 into '.':
G packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22359 into '.':
G .
--- Merging r22361 into '.':
G packages/fpmkunit/src/fpmkunit.pp
--- Recording mergeinfo for merge of r22361 into '.':
G .

git-svn-id: branches/fixes_2_6@25449 -

joost 12 years ago
parent
commit
2ae931e465
1 changed files with 399 additions and 29 deletions
  1. 399 29
      packages/fpmkunit/src/fpmkunit.pp

+ 399 - 29
packages/fpmkunit/src/fpmkunit.pp

@@ -203,6 +203,7 @@ Const
   AllMessages = [vlError,vlWarning,vlCommand,vlInfo];
 
 Type
+  TTargets = Class;
   { TNamedItem }
 
   TNamedItem = Class(TCollectionItem)
@@ -218,10 +219,14 @@ Type
   TNamedCollection = Class(TCollection)
   private
     FUniqueNames: Boolean;
+  private
+    function GetItem(Index: Integer): TNamedItem;
+    procedure SetItem(Index: Integer; AValue: TNamedItem);
   Public
     Function IndexOfName(const AName : String) : Integer;
     Function ItemByName(const AName : String) : TNamedItem;
     Property UniqueNames : Boolean Read FUniqueNames;
+    property Items[Index: Integer]: TNamedItem read GetItem write SetItem;
   end;
 
   { TNamedItemList }
@@ -392,8 +397,11 @@ Type
   { TPackageDictionary }
 
   TPackageDictionary = Class(TDictionary)
+  private
+    FMasterDictionary: TDictionary;
   Public
     Function GetValue(const AName,Args : String) : String; override;
+    property MasterDictionary: TDictionary read FMasterDictionary write FMasterDictionary;
   end;
 
 
@@ -419,6 +427,45 @@ Type
     Property RequireChecksum : Cardinal Read FRequireChecksum Write FRequireChecksum;
   end;
 
+  { TPackageVariant }
+
+  TPackageVariant = class(TNamedItem)
+  private
+    FOptions: TStrings;
+    FTargets: TTargets;
+  public
+    constructor Create(ACollection: TCollection); override;
+    destructor Destroy; override;
+    property Options: TStrings read FOptions;
+    property Targets: TTargets read FTargets;
+  end;
+
+  { TPackageVariants }
+
+  TPackageVariants = class(TNamedCollection)
+  private
+    FActivePackageVariantName: string;
+    FDefaultPackageVariantName: string;
+    FIsInheritable: boolean;
+    FName: string;
+    FOwner: TPersistent;
+    function GetActivePackageVariant: TPackageVariant;
+    function GetDefaultPackageVariant: TPackageVariant;
+    procedure SetActivePackageVariantName(AValue: string);
+    procedure SetDefaultPackageVariantName(AValue: string);
+  protected
+    function GetOwner: TPersistent; override;
+  public
+    function Add(AName: String): TPackageVariant; overload; virtual;
+    property Name: string read FName write FName;
+    property DefaultPackageVariant: TPackageVariant read GetDefaultPackageVariant;
+    property ActivePackageVariant: TPackageVariant read GetActivePackageVariant;
+    property DefaultPackageVariantName: string read FDefaultPackageVariantName write SetDefaultPackageVariantName;
+    property ActivePackageVariantName: string read FActivePackageVariantName write SetActivePackageVariantName;
+    property IsInheritable: boolean read FIsInheritable;
+  end;
+
+
   TDependencies = Class(TConditionalStrings)
     function GetDependency(Index : Integer): TDependency;
     procedure SetDependency(Index : Integer; const AValue: TDependency);
@@ -484,6 +531,7 @@ Type
   Public
     Constructor Create(ACollection : TCollection); override;
     Destructor Destroy; override;
+    procedure AssignTo(Dest: TPersistent); override;
     Function  GetOutputFileName (AOs : TOS) : String; Virtual;
     Function HaveOptions : Boolean;
     procedure SetName(const AValue: String);override;
@@ -654,6 +702,8 @@ Type
     FDescriptionFile : String;
     FDescription : String;
     FInstalledChecksum : Cardinal;
+    FUnitsOutputDir: String;
+    FPackageUnitInstallDir: String;
     // Cached directory of installed packages
     FUnitDir : String;
     // Used by buildunits
@@ -665,6 +715,7 @@ Type
     FDictionary : TDictionary;
     // Is set when all sourcefiles are found
     FAllFilesResolved: boolean;
+    FPackageVariants: TFPList;
     Function GetDescription : string;
     function GetDictionary: TDictionary;
     Function GetFileName : string;
@@ -683,6 +734,12 @@ Type
     destructor destroy; override;
     Function HaveOptions : Boolean;
     Function  GetUnitsOutputDir(ACPU:TCPU; AOS : TOS):String;
+    Function  GetUnitConfigOutputDir(ACPU:TCPU; AOS : TOS):String;
+    Procedure InheritPackageVariantsFromDependency(ADependencyPackage: TPackage);
+    Function  GetPackageVariantsByName(AName: string): TPackageVariants;
+    Procedure SetUnitsOutputDir(AValue: string);
+    Function  GetPackageUnitInstallDir(ACPU:TCPU; AOS : TOS):String;
+    Procedure SetPackageUnitInstallDir(AValue: string);
     Function  GetBinOutputDir(ACPU:TCPU; AOS : TOS) : String;
     Procedure GetCleanFiles(List : TStrings; ACPU:TCPU; AOS : TOS); virtual;
     procedure GetInstallFiles(List: TStrings;Types : TTargetTypes;ACPU:TCPU; AOS : TOS); virtual;
@@ -690,6 +747,9 @@ Type
     Procedure GetArchiveFiles(List : TStrings; ACPU:TCPU; AOS : TOS); virtual;
     Procedure GetArchiveSourceFiles(List : TStrings); virtual;
     Procedure GetManifest(Manifest : TStrings);
+    function  AddPackageVariant(AName: string; AIsInheritable: boolean): TPackageVariants;
+    procedure ApplyPackageVariantToCompilerOptions(ACompilerOptions: tstrings);
+    procedure SetDefaultPackageVariant;
     Property Version : String Read GetVersion Write SetVersion;
     Property FileName : String Read GetFileName Write FFileName;
     Property HomepageURL : String Read FHomepageURL Write FHomepageURL;
@@ -936,7 +996,7 @@ Type
     Procedure InstallUnitConfigFile(APAckage : TPackage; Const Dest : String);
     Function InstallPackageSourceFiles(APAckage : TPackage; stt : TSourceTypes; ttt : TTargetTypes; Const Dest : String):Boolean;
     Function FileNewer(const Src,Dest : String) : Boolean;
-    Procedure LogSearchPath(const ASearchPathName:string;Path:TConditionalStrings; ACPU:TCPU;AOS:TOS);
+    Procedure LogSearchPath(APackage: TPackage;const ASearchPathName:string;Path:TConditionalStrings; ACPU:TCPU;AOS:TOS);
     Function FindFileInPath(APackage: TPackage; Path:TConditionalStrings; AFileName:String; var FoundPath:String;ACPU:TCPU;AOS:TOS):Boolean;
 
     procedure GetDirectoriesFromFilelist(const AFileList, ADirectoryList: TStringList);
@@ -1036,6 +1096,7 @@ Type
     FListMode : Boolean;
     FLogLevels : TVerboseLevels;
     FFPMakeOptionsString: string;
+    FPackageVariantSettings: TStrings;
   Protected
     Procedure Log(Level : TVerboseLevel; Const Msg : String);
     Procedure CreatePackages; virtual;
@@ -1123,6 +1184,7 @@ Type
 
   TInstallerClass = Class of TCustomInstaller;
   TDictionaryClass = Class of TDictionary;
+  TPackageDictionaryClass = Class of TPackageDictionary;
 
 Type
   TArchiveEvent = Procedure (Const AFileName : String; List : TStrings) of Object;
@@ -1130,7 +1192,7 @@ Type
 
 Var
   DictionaryClass : TDictionaryClass = TDictionary;
-  PackageDictionaryClass : TDictionaryClass = TPackageDictionary;
+  PackageDictionaryClass : TPackageDictionaryClass = TPackageDictionary;
   OnArchiveFiles : TArchiveEvent = Nil;
   ArchiveFilesProc : TArchiveProc = Nil;
 
@@ -1220,6 +1282,7 @@ ResourceString
   SErrInvalidState      = 'Invalid state for target %s';
   SErrCouldNotCompile   = 'Could not compile target %s from package %s';
   SErrUnsupportedBuildmode = 'Package does not support this buildmode';
+  SErrBuildOptNotExist  = 'There are no build options with the name "%s"';
 
   SWarnCircularTargetDependency = 'Warning: Circular dependency detected when compiling target %s with target %s';
   SWarnCircularPackageDependency = 'Warning: Circular dependency detected when compiling package %s with package %s';
@@ -1361,6 +1424,7 @@ Const
   KeyAddIn    = 'FPMakeAddIn';
   KeySourcePath = 'SourcePath';
   KeyFPMakeOptions = 'FPMakeOptions';
+  KeyPackageVar = 'PackageVariant_';
 
 {****************************************************************************
                                 Helpers
@@ -1837,15 +1901,16 @@ begin
 end;
 
 
-function AddConditionalStrings(Dest : TStrings; Src : TConditionalStrings;ACPU:TCPU;AOS:TOS; Const APrefix : String='') : Integer ;
+function AddConditionalStrings(APackage: TPackage; Dest : TStrings; Src : TConditionalStrings;ACPU:TCPU;AOS:TOS; Const APrefix : String='') : Integer ;
 Var
   I : Integer;
   C : TConditionalString;
-  D : TDictionary;
+  D : TPackageDictionary;
   S : String;
 begin
   Result:=0;
   D := PackageDictionaryClass.Create(nil);
+  D.MasterDictionary := APackage.Dictionary;
   try
     D.AddVariable('CPU',CPUToString(ACPU));
     D.AddVariable('OS',OSToString(AOS));
@@ -2097,6 +2162,61 @@ begin
   Move(Buf,Result[1],Count);
 end;
 
+constructor TPackageVariant.Create(ACollection: TCollection);
+begin
+  inherited Create(ACollection);
+  FTargets := TTargets.Create(TTarget);
+  FOptions := TStringList.Create;
+end;
+
+destructor TPackageVariant.Destroy;
+begin
+  FOptions.Free;
+  FTargets.Free;
+  inherited Destroy;
+end;
+
+{ TPackageVariants }
+
+procedure TPackageVariants.SetDefaultPackageVariantName(AValue: string);
+begin
+  if FDefaultPackageVariantName=AValue then Exit;
+  if not assigned(ItemByName(avalue)) then
+    raise exception.CreateFmt(SErrBuildOptNotExist,[AValue]);
+  FDefaultPackageVariantName:=AValue;
+end;
+
+function TPackageVariants.GetOwner: TPersistent;
+begin
+  Result:=FOwner;
+end;
+
+function TPackageVariants.GetActivePackageVariant: TPackageVariant;
+begin
+  result := ItemByName(ActivePackageVariantName) as TPackageVariant;
+end;
+
+function TPackageVariants.GetDefaultPackageVariant: TPackageVariant;
+begin
+  result := ItemByName(DefaultPackageVariantName) as TPackageVariant;
+end;
+
+procedure TPackageVariants.SetActivePackageVariantName(AValue: string);
+begin
+  if FActivePackageVariantName=AValue then Exit;
+  if not assigned(ItemByName(avalue)) then
+    raise exception.CreateFmt(SErrBuildOptNotExist,[AValue]);
+  FActivePackageVariantName:=AValue;
+end;
+
+function TPackageVariants.Add(AName: String): TPackageVariant;
+begin
+  result := self.add as TPackageVariant;
+  result.Name := AName;
+  if FDefaultPackageVariantName='' then
+    FDefaultPackageVariantName:=AName;
+end;
+
 {$endif HAS_UNIT_PROCESS}
 
 { TConditionalDestStrings }
@@ -2152,7 +2272,10 @@ begin
   I:=Flist.IndexOf(AName);
   If (I=-1) then
     begin
-      result := GlobalDictionary.GetValue(AName,Args);
+      if assigned(MasterDictionary) then
+        result := MasterDictionary.GetValue(AName,Args)
+      else
+        result := GlobalDictionary.GetValue(AName,Args);
       Exit;
     end;
   O:=Flist.Objects[I];
@@ -2240,6 +2363,16 @@ end;
                                 TNamedCollection
 ****************************************************************************}
 
+function TNamedCollection.GetItem(Index: Integer): TNamedItem;
+begin
+  result := TNamedItem(inherited getItem(index));
+end;
+
+procedure TNamedCollection.SetItem(Index: Integer; AValue: TNamedItem);
+begin
+  inherited SetItem(Index, AValue);
+end;
+
 function TNamedCollection.IndexOfName(const AName: String): Integer;
 
 begin
@@ -2613,6 +2746,8 @@ begin
   FExamplePath:=TConditionalStrings.Create(TConditionalString);
   FTestPath:=TConditionalStrings.Create(TConditionalString);
   FCommands:=TCommands.Create(TCommand);
+  FUnitsOutputDir:='units'+PathDelim+'$(target)'+PathDelim;
+  FPackageVariants:=TFPList.Create;
   FCPUs:=AllCPUs;
   FOSes:=AllOSes;
   FInstalledChecksum:=$ffffffff;
@@ -2623,6 +2758,8 @@ end;
 
 
 destructor TPackage.destroy;
+var
+  i: integer;
 begin
   FreeAndNil(FDictionary);
   FreeAndNil(FDependencies);
@@ -2638,6 +2775,12 @@ begin
   FreeAndNil(FTargets);
   FreeAndNil(FVersion);
   FreeAndNil(FOptions);
+  for i := 0 to FPackageVariants.Count-1 do
+    begin
+    if TPackageVariants(FPackageVariants.Items[i]).Owner=Self then
+      TPackageVariants(FPackageVariants.Items[i]).Free;
+    end;
+  FreeAndNil(FPackageVariants);
   inherited destroy;
 end;
 
@@ -2658,7 +2801,64 @@ end;
 
 Function TPackage.GetUnitsOutputDir(ACPU:TCPU; AOS : TOS):String;
 begin
-  Result:='units'+PathDelim+MakeTargetString(ACPU,AOS);
+  result:=FixPath(Dictionary.Substitute(FUnitsOutputDir,['CPU',CPUToString(ACPU),'OS',OSToString(AOS),'target',MakeTargetString(ACPU,AOS)]));
+end;
+
+function TPackage.GetUnitConfigOutputDir(ACPU: TCPU; AOS: TOS): String;
+begin
+  result:=FixPath(Dictionary.Substitute('units'+PathDelim+'$(target)'+PathDelim,['CPU',CPUToString(ACPU),'OS',OSToString(AOS),'target',MakeTargetString(ACPU,AOS)]));
+end;
+
+procedure TPackage.InheritPackageVariantsFromDependency(ADependencyPackage: TPackage);
+var
+  i: integer;
+  APackageVariants: TPackageVariants;
+begin
+  for i := 0 to ADependencyPackage.FPackageVariants.Count-1 do
+    begin
+      APackageVariants := TPackageVariants(ADependencyPackage.FPackageVariants[i]);
+      if APackageVariants.IsInheritable then
+        begin
+        if not assigned(GetPackageVariantsByName(APackageVariants.Name)) then
+          begin
+          FPackageVariants.Add(APackageVariants);
+          end;
+        end;
+    end;
+end;
+
+function TPackage.GetPackageVariantsByName(AName: string): TPackageVariants;
+var
+  i: Integer;
+begin
+  result := nil;
+  for i := 0 to FPackageVariants.Count-1 do
+    if SameText(TPackageVariants(FPackageVariants.Items[i]).Name, AName) then
+      begin
+      result := TPackageVariants(FPackageVariants.Items[i]);
+      break;
+      end;
+end;
+
+procedure TPackage.SetUnitsOutputDir(AValue: string);
+begin
+  if AValue<>'' then
+    FUnitsOutputDir:=IncludeTrailingPathDelimiter(AValue)
+  else
+    FUnitsOutputDir:='';
+end;
+
+function TPackage.GetPackageUnitInstallDir(ACPU: TCPU; AOS: TOS): String;
+begin
+  result:=FixPath(Dictionary.Substitute(FPackageUnitInstallDir,['CPU',CPUToString(ACPU),'OS',OSToString(AOS),'target',MakeTargetString(ACPU,AOS)]));
+end;
+
+procedure TPackage.SetPackageUnitInstallDir(AValue: string);
+begin
+  if AValue<>'' then
+    FPackageUnitInstallDir:=IncludeTrailingPathDelimiter(AValue)
+  else
+    FPackageUnitInstallDir:='';
 end;
 
 
@@ -2675,7 +2875,7 @@ Var
 begin
   OB:=IncludeTrailingPathDelimiter(GetBinOutputDir(ACPU,AOS));
   OU:=IncludeTrailingPathDelimiter(GetUnitsOutputDir(ACPU,AOS));
-  AddConditionalStrings(List,CleanFiles,ACPU,AOS);
+  AddConditionalStrings(Self, List,CleanFiles,ACPU,AOS);
   For I:=0 to FTargets.Count-1 do
     FTargets.TargetItems[I].GetCleanFiles(List, OU, OB, ACPU, AOS);
 end;
@@ -2688,7 +2888,7 @@ Var
   T : TTarget;
 begin
   if Types=[] then
-    AddConditionalStrings(List,InstallFiles,ACPU,AOS)
+    AddConditionalStrings(Self, List,InstallFiles,ACPU,AOS)
   else
     begin
       OB:=IncludeTrailingPathDelimiter(GetBinOutputDir(Defaults.CPU,Defaults.OS));
@@ -2900,6 +3100,49 @@ begin
     end;
 end;
 
+function TPackage.AddPackageVariant(AName: string; AIsInheritable: boolean): TPackageVariants;
+begin
+  result := TPackageVariants.Create(TPackageVariant);
+  result.Name:=AName;
+  result.FIsInheritable:=AIsInheritable;
+  FPackageVariants.Add(result);
+  result.FOwner := Self;
+end;
+
+procedure TPackage.ApplyPackageVariantToCompilerOptions(ACompilerOptions: tstrings);
+var
+  i: integer;
+  PackageVariants: TPackageVariants;
+begin
+  for i := 0 to FPackageVariants.Count-1 do
+    begin
+    PackageVariants := TPackageVariants(FPackageVariants.Items[i]);
+    ACompilerOptions.AddStrings(PackageVariants.ActivePackageVariant.Options);
+    end;
+end;
+
+procedure TPackage.SetDefaultPackageVariant;
+var
+  i,j: integer;
+  PackageVariants: TPackageVariants;
+begin
+  for i := 0 to FPackageVariants.Count-1 do
+    begin
+    PackageVariants := TPackageVariants(FPackageVariants.Items[i]);
+    if Installer.FPackageVariantSettings.Values[PackageVariants.Name]<>'' then
+      PackageVariants.ActivePackageVariantName:= Installer.FPackageVariantSettings.Values[PackageVariants.Name]
+    else
+      PackageVariants.ActivePackageVariantName:= PackageVariants.DefaultPackageVariantName;
+    Dictionary.AddVariable(PackageVariants.Name,PackageVariants.ActivePackageVariantName);
+    SetUnitsOutputDir(FUnitsOutputDir+'$('+PackageVariants.name+')');
+    SetPackageUnitInstallDir(FPackageUnitInstallDir+'$('+PackageVariants.Name+')');
+    // Do not add targets f the package is inerited
+    if PackageVariants.GetOwner=Self then
+      for j := 0 to PackageVariants.ActivePackageVariant.Targets.count -1 do
+        targets.add.assign(PackageVariants.ActivePackageVariant.Targets.items[j]);
+    end;
+end;
+
 
 procedure TPackage.LoadUnitConfigFromFile(Const AFileName: String);
 var
@@ -2910,6 +3153,10 @@ var
   DepChecksum : Cardinal;
   DepName : String;
   D : TDependency;
+  PackageVariantsStr: string;
+  PackageVarName: string;
+  pv: TPackageVariants;
+  AnIsInheritable: boolean;
 begin
   L:=TStringList.Create;
   Try
@@ -2941,6 +3188,40 @@ begin
         FreeAndNil(L2);
         NeedLibC:=Upcase(Values[KeyNeedLibC])='Y';
         IsFPMakeAddIn:=Upcase(Values[KeyAddIn])='Y';
+
+        i := 1;
+        repeat
+        PackageVariantsStr:=Values[KeyPackageVar+inttostr(i)];
+        if PackageVariantsStr<>'' then
+          begin
+            k := pos(':',PackageVariantsStr);
+            if k > 0 then
+              begin
+                PackageVarName:=copy(PackageVariantsStr,1,k-1);
+                if PackageVarName[Length(PackageVarName)]='*' then
+                  begin
+                  SetLength(PackageVarName,Length(PackageVarName)-1);
+                  AnIsInheritable:=true;
+                  end
+                else
+                  AnIsInheritable:=false;
+                PackageVariantsStr:=copy(PackageVariantsStr,k+1,length(PackageVariantsStr)-k);
+                pv := AddPackageVariant(PackageVarName, AnIsInheritable);
+
+                k := pos(',',PackageVariantsStr);
+                while k>0 do
+                  begin
+                    PackageVarName:=copy(PackageVariantsStr,1,k-1);
+                    PackageVariantsStr:=copy(PackageVariantsStr,k+1,length(PackageVariantsStr)-k);
+                    pv.Add(PackageVarName);
+                    k := pos(',',PackageVariantsStr);
+                  end;
+                pv.Add(PackageVariantsStr);
+              end;
+          end;
+        inc(i);
+        until PackageVariantsStr='';
+
       end;
   Finally
     L.Free;
@@ -2950,9 +3231,11 @@ end;
 procedure TPackage.SaveUnitConfigToStringList(const AStringList: TStrings; ACPU: TCPU; AOS: TOS);
 Var
   Deps : String;
-  i : integer;
+  i,j : integer;
   D : TDependency;
   p : TPackage;
+  PackageVariants : TPackageVariants;
+  PackageVariantsStr: string;
 begin
   with AStringList do
     begin
@@ -2988,6 +3271,18 @@ begin
         Values[KeyAddIn]:='Y'
       else
         Values[KeyAddIn]:='N';
+      for i := 0 to FPackageVariants.Count-1 do
+        begin
+          PackageVariants := TPackageVariants(FPackageVariants.Items[i]);
+          PackageVariantsStr:=PackageVariants.Name;
+          if PackageVariants.IsInheritable then
+            PackageVariantsStr:=PackageVariantsStr+'*';
+          PackageVariantsStr := PackageVariantsStr +':'+PackageVariants.DefaultPackageVariantName;
+          for j := 0 to PackageVariants.Count-1 do
+            if not sametext(PackageVariants.Items[j].Name, PackageVariants.DefaultPackageVariantName) then
+              PackageVariantsStr:=PackageVariantsStr+','+PackageVariants.Items[j].Name;
+          values[KeyPackageVar+inttostr(i+1)] := PackageVariantsStr;
+        end;
     end;
 end;
 
@@ -3522,6 +3817,7 @@ end;
 
 constructor TCustomInstaller.Create(AOwner: TComponent);
 begin
+  FPackageVariantSettings := TStringList.Create;
   GlobalDictionary:=DictionaryClass.Create(Nil);
   AnalyzeOptions;
   GlobalDictionary.AddVariable('BaseInstallDir',Defaults.BaseInstallDir);
@@ -3537,6 +3833,7 @@ begin
   FreePackages;
   FreeAndNil(Defaults);
   FreeAndNil(GlobalDictionary);
+  FreeAndNil(FPackageVariantSettings);
   inherited destroy;
 end;
 
@@ -3605,6 +3902,28 @@ procedure TCustomInstaller.AnalyzeOptions;
     if AddToOptionString and Result then FFPMakeOptionsString := FFPMakeOptionsString+' '+O;
   end;
 
+  Function CheckBuildOptionSetValue(Index: Integer): boolean;
+  var
+    O : String;
+    BuildModeName: string;
+    P: integer;
+  begin
+    O:=Paramstr(Index);
+    result := O[1]='+';
+    if result then
+      begin
+      P:=Pos('=',Paramstr(Index));
+      If (P=0) then
+        Error(SErrNeedArgument,[Index,O])
+      else
+        begin
+        BuildModeName:=copy(o,2,P-2);
+        Delete(O,1,P);
+        FPackageVariantSettings.Values[BuildModeName] := O;
+        end;
+      end;
+  end;
+
   Function CheckCustomOption(Index : Integer; out CustOptName: string): Boolean;
   var
     O : String;
@@ -3760,7 +4079,7 @@ begin
         CustomFpMakeCommandlineValues := TStringList.Create;
       CustomFpMakeCommandlineValues.Values[CustOptName]:=OptionArg(I)
       end
-    else if not Defaults.IgnoreInvalidOptions then
+    else if (not CheckBuildOptionSetValue(I)) and (not Defaults.IgnoreInvalidOptions) then
       begin
       Usage(SErrInValidArgument,[I,ParamStr(I)]);
       end;
@@ -4434,7 +4753,7 @@ begin
 end;
 
 
-Procedure TBuildEngine.LogSearchPath(const ASearchPathName:string;Path:TConditionalStrings; ACPU:TCPU;AOS:TOS);
+procedure TBuildEngine.LogSearchPath(APackage: TPackage; const ASearchPathName: string; Path: TConditionalStrings; ACPU: TCPU; AOS: TOS);
 var
   S : String;
   I : Integer;
@@ -4448,7 +4767,7 @@ begin
         begin
           if S<>'' then
             S:=S+PathSeparator;
-          S:=S+GlobalDictionary.ReplaceStrings(C.Value)
+          S:=S+APackage.Dictionary.ReplaceStrings(C.Value)
         end;
     end;
   if S<>'' then
@@ -4495,7 +4814,7 @@ Procedure TBuildEngine.ResolveFileNames(APackage : TPackage; ACPU:TCPU;AOS:TOS;D
   var
     SD,SF  : String;
   begin
-    LogSearchPath('package source',APackage.SourcePath,ACPU,AOS);
+    LogSearchPath(APackage,'package source',APackage.SourcePath,ACPU,AOS);
     SD:=APackage.Dictionary.ReplaceStrings(T.Directory);
     SF:=APackage.Dictionary.ReplaceStrings(T.SourceFileName);
     if SD='' then
@@ -4520,8 +4839,8 @@ Procedure TBuildEngine.ResolveFileNames(APackage : TPackage; ACPU:TCPU;AOS:TOS;D
     D : TDependency;
     j : integer;
   begin
-    LogSearchPath('target include',T.IncludePath,ACPU,AOS);
-    LogSearchPath('package include',APackage.IncludePath,ACPU,AOS);
+    LogSearchPath(APackage,'target include',T.IncludePath,ACPU,AOS);
+    LogSearchPath(APackage,'package include',APackage.IncludePath,ACPU,AOS);
     for j:=0 to T.Dependencies.Count-1 do
       begin
         D:=T.Dependencies[j];
@@ -4565,7 +4884,7 @@ Procedure TBuildEngine.ResolveFileNames(APackage : TPackage; ACPU:TCPU;AOS:TOS;D
   var
     SD,SF  : String;
   begin
-    LogSearchPath('package example',APackage.ExamplePath,ACPU,AOS);
+    LogSearchPath(APackage,'package example',APackage.ExamplePath,ACPU,AOS);
     SD:=APackage.Dictionary.ReplaceStrings(T.Directory);
     SF:=APackage.Dictionary.ReplaceStrings(T.SourceFileName);
     if SD='' then
@@ -4655,13 +4974,13 @@ begin
       if (APackage.UnitDir='') and
          (Defaults.LocalUnitDir<>'') then
         begin
-          APackage.UnitDir:=IncludeTrailingPathDelimiter(Defaults.LocalUnitDir)+APackage.Name;
+          APackage.UnitDir:=IncludeTrailingPathDelimiter(Defaults.LocalUnitDir)+APackage.Name+PathDelim+APackage.GetPackageUnitInstallDir(defaults.CPU, Defaults.OS);
           if not SysDirectoryExists(APackage.UnitDir) then
             APackage.UnitDir:='';
         end;
       if APackage.UnitDir='' then
         begin
-          APackage.UnitDir:=IncludeTrailingPathDelimiter(Defaults.GlobalUnitDir)+APackage.Name;
+          APackage.UnitDir:=IncludeTrailingPathDelimiter(Defaults.GlobalUnitDir)+APackage.Name+PathDelim+APackage.GetPackageUnitInstallDir(defaults.CPU, Defaults.OS);
           if not SysDirectoryExists(APackage.UnitDir) then
             APackage.UnitDir:=DirNotFound;
         end;
@@ -4796,8 +5115,8 @@ begin
   // Object Path
   L:=TUnsortedDuplicatesStringList.Create;
   L.Duplicates:=dupIgnore;
-  AddConditionalStrings(L,APackage.ObjectPath,Defaults.CPU,Defaults.OS);
-  AddConditionalStrings(L,ATarget.ObjectPath,Defaults.CPU,Defaults.OS);
+  AddConditionalStrings(APackage, L,APackage.ObjectPath,Defaults.CPU,Defaults.OS);
+  AddConditionalStrings(APackage, L,ATarget.ObjectPath,Defaults.CPU,Defaults.OS);
   for i:=0 to L.Count-1 do
     Args.Add('-Fo'+AddPathPrefix(APackage,L[i]));
   FreeAndNil(L);
@@ -4806,8 +5125,8 @@ begin
   L.Duplicates:=dupIgnore;
   AddDependencyUnitPaths(L,APackage);
   AddDependencyPaths(L,depUnit,ATarget);
-  AddConditionalStrings(L,APackage.UnitPath,Defaults.CPU,Defaults.OS);
-  AddConditionalStrings(L,ATarget.UnitPath,Defaults.CPU,Defaults.OS);
+  AddConditionalStrings(APackage, L,APackage.UnitPath,Defaults.CPU,Defaults.OS);
+  AddConditionalStrings(APackage, L,ATarget.UnitPath,Defaults.CPU,Defaults.OS);
   for i:=0 to L.Count-1 do
     Args.Add('-Fu'+AddPathPrefix(APackage,L[i]));
   FreeAndNil(L);
@@ -4815,14 +5134,17 @@ begin
   L:=TUnsortedDuplicatesStringList.Create;
   L.Duplicates:=dupIgnore;
   AddDependencyPaths(L,depInclude,ATarget);
-  AddConditionalStrings(L,APackage.IncludePath,Defaults.CPU,Defaults.OS);
-  AddConditionalStrings(L,ATarget.IncludePath,Defaults.CPU,Defaults.OS);
+  AddConditionalStrings(APackage, L,APackage.IncludePath,Defaults.CPU,Defaults.OS);
+  AddConditionalStrings(APackage, L,ATarget.IncludePath,Defaults.CPU,Defaults.OS);
   for i:=0 to L.Count-1 do
     Args.Add('-Fi'+AddPathPrefix(APackage,L[i]));
   FreeAndNil(L);
   // Custom Options
   If (Defaults.HaveOptions) then
     Args.AddStrings(Defaults.Options);
+
+  APackage.ApplyPackageVariantToCompilerOptions(Args);
+
   If (APackage.HaveOptions) then
     Args.AddStrings(APackage.Options);
   If (ATarget.HaveOptions) then
@@ -4964,8 +5286,12 @@ begin
   if ATarget.TargetType in [ttExampleUnit, ttExampleProgram] then
     Exit;
 
+  // Files which should not be compiled on this target can not trigger a compile.
+  if not TargetOK(ATarget) then
+    Exit;
+
   // Check output file
-  if not result and TargetOK(ATarget) then
+  if not result then
     begin
       if ATarget.TargetType in ProgramTargets then
         OD:=APackage.GetBinOutputDir(Defaults.CPU,Defaults.OS)
@@ -5044,7 +5370,7 @@ begin
   If Assigned(ATarget.BeforeCompile) then
     ATarget.BeforeCompile(ATarget);
 
-  if APackage.BuildMode=bmBuildUnit then
+  if (APackage.BuildMode=bmBuildUnit) and not (ATarget.TargetType in [ttProgram,ttExampleProgram]) then
     begin
       APackage.FBUTarget.Dependencies.AddUnit(ATarget.Name).FTargetFileName:=ATarget.TargetSourceFileName;
     end
@@ -5218,6 +5544,8 @@ begin
         begin
           Log(vlDebug, Format(SDbgLoading, [F]));
           Result.LoadUnitConfigFromFile(F);
+          result.SetDefaultPackageVariant;
+          result.UnitDir:=result.UnitDir+Result.GetPackageUnitInstallDir(Defaults.CPU, Defaults.OS);
         end;
       // Check recursive implicit dependencies
       CompileDependencies(Result);
@@ -5263,6 +5591,7 @@ begin
              (P.InstalledChecksum<>$ffffffff) and
              (P.InstalledChecksum<>D.RequireChecksum) then
             Log(vlDebug,SDbgPackageChecksumChanged,[P.Name]);
+          APackage.InheritPackageVariantsFromDependency(P);
         end;
     end;
 end;
@@ -5304,6 +5633,7 @@ begin
              (P.InstalledChecksum<>$ffffffff) and
              (P.InstalledChecksum<>D.RequireChecksum) then
             Log(vlDebug,SDbgPackageChecksumChanged,[P.Name]);
+          APackage.InheritPackageVariantsFromDependency(P);
         end;
     end;
 end;
@@ -5494,7 +5824,7 @@ begin
 
     if RegenerateUnitconfigFile then
       begin
-        UC:=IncludeTrailingPathDelimiter(AddPathPrefix(APackage,APackage.GetUnitsOutputDir(Defaults.CPU,Defaults.OS)))+UnitConfigFile;
+        UC:=IncludeTrailingPathDelimiter(AddPathPrefix(APackage,APackage.GetUnitConfigOutputDir(Defaults.CPU,Defaults.OS)))+UnitConfigFile;
         Log(vlInfo, Format(SDbgGenerating, [UC]));
         APackage.SaveUnitConfigToFile(UC,Defaults.CPU,Defaults.OS);
       end;
@@ -5573,6 +5903,8 @@ begin
       result := False;
       Exit;
     end;
+  APackage.SetDefaultPackageVariant;
+
   ResolveFileNames(APackage,Defaults.CPU,Defaults.OS,True,False);
   If NeedsCompile(APackage) then
     result := True
@@ -5609,7 +5941,7 @@ Var
 begin
   List:=TStringList.Create;
   Try
-    List.add(IncludeTrailingPathDelimiter(APackage.GetUnitsOutputDir(Defaults.CPU,Defaults.OS))+UnitConfigFile);
+    List.add(IncludeTrailingPathDelimiter(APackage.GetUnitConfigOutputDir(Defaults.CPU,Defaults.OS))+UnitConfigFile);
     CmdCopyFiles(List,Dest);
   Finally
     List.Free;
@@ -5671,19 +6003,21 @@ begin
     B:=false;
     GlobalDictionary.AddVariable('PackageName',APackage.Name);
     GlobalDictionary.AddVariable('unitinstalldir',Defaults.UnitInstallDir);
+    GlobalDictionary.AddVariable('packageunitinstalldir',APackage.GetPackageUnitInstallDir(Defaults.CPU,Defaults.OS));
 
     D:=IncludeTrailingPathDelimiter(Defaults.BaseInstallDir);
     // This is to install the TPackage.Installfiles, which are not related to any
     // target
     if InstallPackageFiles(APackage,[],D) then
       B:=true;
-    D:=IncludeTrailingPathDelimiter(Defaults.UnitInstallDir);
+    D:=IncludeTrailingPathDelimiter(Defaults.UnitInstallDir)+APackage.GetPackageUnitInstallDir(Defaults.CPU,Defaults.OS);
     if InstallPackageFiles(APackage,[ttUnit, ttImplicitUnit],D) then
       B:=true;
     // By default do not install the examples. Maybe add an option for this later
     //if InstallPackageFiles(APAckage,ttExampleUnit,D) then
     //  B:=true;
     // Unit (dependency) configuration if there were units installed
+    D:=IncludeTrailingPathDelimiter(Defaults.UnitInstallDir);
     if B then
       InstallUnitConfigFile(APackage,D);
     // Programs
@@ -6268,6 +6602,42 @@ begin
   inherited Destroy;
 end;
 
+procedure TTarget.AssignTo(Dest: TPersistent);
+var
+  DestTarget: TTarget;
+begin
+  if Dest is TTarget then
+    begin
+    DestTarget := TTarget(Dest);
+    DestTarget.Dependencies.Assign(Dependencies);
+    DestTarget.Commands.Assign(Commands);
+    DestTarget.FTargetState := FTargetState;
+    DestTarget.TargetType := TargetType;
+    DestTarget.CPUs := CPUs;
+    DestTarget.OSes := OSes;
+    DestTarget.Mode := Mode;
+    DestTarget.Options := Options;
+    DestTarget.Name :=  Name;
+    DestTarget.Extension:= Extension;
+    DestTarget.FPCTarget := FPCTarget;
+    DestTarget.FileType := FileType;
+    DestTarget.Directory := Directory;
+    DestTarget.ResourceStrings := ResourceStrings;
+    DestTarget.Install := Install;
+    DestTarget.FTargetSourceFileName := fTargetSourceFileName;
+    DestTarget.ObjectPath.Assign(ObjectPath);
+    DestTarget.UnitPath.Assign(UnitPath);
+    DestTarget.IncludePath.Assign(IncludePath);
+    DestTarget.FXML := FXML;
+    DestTarget.AfterCompile := AfterCompile;
+    DestTarget.BeforeCompile := BeforeCompile;
+    DestTarget.BeforeClean := BeforeCompile;
+    DestTarget.AfterClean := AfterClean;
+    end
+  else
+    inherited AssignTo(Dest);
+end;
+
 function TTarget.GetOptions: TStrings;
 begin
   If Foptions=Nil then