소스 검색

Adding better support for platforms

Brian Fiete 5 년 전
부모
커밋
62346a53b0

+ 2 - 0
BeefBoot/BootApp.cpp

@@ -746,6 +746,8 @@ bool BootApp::Compile()
 		mDefines.Append("\n");
 	mDefines.Append("BF_64_BIT");
 	mDefines.Append("\nBF_LITTLE_ENDIAN");
+	mDefines.Append("\n");
+	mDefines.Append(BF_PLATFORM_NAME);
 
 	int ltoType = 0;
     BfProject_SetOptions(mProject, mTargetType, mStartupObject.c_str(), mDefines.c_str(), mOptLevel, ltoType, false, false, false, false);

+ 72 - 23
IDE/src/IDEApp.bf

@@ -1578,6 +1578,12 @@ namespace IDE
 			        sd.Add(recentFile);
 			}
 
+			using (sd.CreateArray("UserPlatforms"))
+			{
+			    for (var platformName in gApp.mWorkspace.mUserPlatforms)
+			        sd.Add(platformName);
+			}
+
 			using (sd.CreateArray("Breakpoints"))
 			{
 			    for (var breakpoint in mDebugger.mBreakpointList)
@@ -2691,17 +2697,20 @@ namespace IDE
 				 mConfigName.Set(configName);
 			}
 
-			String platformName = scope String();
-			data.GetString("LastPlatform", platformName);
-			if (!platformName.IsEmpty)
+			//
 			{
-			    Workspace.Config config;
-			    mWorkspace.mConfigs.TryGetValue(mConfigName, out config);
-			    if (config != null)
-			    {
-			        if (Utils.Contains(config.mPlatforms.Keys, platformName))
-			            mPlatformName.Set(platformName);
-			    }
+				String platformName = scope String();
+				data.GetString("LastPlatform", platformName);
+				if (!platformName.IsEmpty)
+				{
+				    Workspace.Config config;
+				    mWorkspace.mConfigs.TryGetValue(mConfigName, out config);
+				    if (config != null)
+				    {
+				        if (Utils.Contains(config.mPlatforms.Keys, platformName))
+				            mPlatformName.Set(platformName);
+				    }
+				}
 			}
 
 			using (data.Open("MainWindow"))
@@ -2721,6 +2730,18 @@ namespace IDE
 				IDEUtils.FixFilePath(fileStr);
 		        mRecentlyDisplayedFiles.Add(fileStr);
 			}
+
+			DeleteAndClearItems!(gApp.mWorkspace.mUserPlatforms);
+			for (data.Enumerate("UserPlatforms"))
+			{
+				String platformName = scope String();
+				data.GetCurString(platformName);
+				if (!gApp.mWorkspace.mUserPlatforms.Contains(platformName))
+				{
+					gApp.mWorkspace.mUserPlatforms.Add(new String(platformName));
+					gApp.mWorkspace.FixOptionsForPlatform(platformName);
+				}
+			}
     
 			for (var _breakpoint in data.Enumerate("Breakpoints"))
 		    {
@@ -6828,8 +6849,18 @@ namespace IDE
             return fileName.EndsWith(".h", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".hpp", StringComparison.OrdinalIgnoreCase);
         }
 
-        public void GetBeefPreprocessorMacros(List<String> macroList)
+        public void GetBeefPreprocessorMacros(DefinesSet macroList)
         {
+			let platform = Workspace.PlatformType.GetFromName(mPlatformName);
+			if (platform != .Unknown)
+			{
+				String def = scope .();
+				def.Append("BF_PLATFORM_");
+				platform.ToString(def);
+				def.ToUpper();
+				macroList.Add(def);
+			}
+
             var workspaceOptions = GetCurWorkspaceOptions();            
             if (workspaceOptions.mRuntimeChecks)
                 macroList.Add("BF_RUNTIME_CHECKS");
@@ -6891,9 +6922,9 @@ namespace IDE
 
                 if (options.mCOptions.mEnableBeefInterop)
                 {
-					var beefPreprocMacros = scope List<String>();
+					var beefPreprocMacros = scope DefinesSet();
                     GetBeefPreprocessorMacros(beefPreprocMacros);
-                    for (var beefPreprocMacro in beefPreprocMacros)
+                    for (var beefPreprocMacro in beefPreprocMacros.mDefines)
 					{
                         outResolveArgs.Add(new String("-D", beefPreprocMacro));
 					}
@@ -7784,17 +7815,11 @@ namespace IDE
 
             bfProject.SetDisabled(false);
 
-            var preprocessorMacros = scope List<String>();
+            var preprocessorMacros = scope DefinesSet();
 			void AddMacros(List<String> macros)
 			{
 				for (var macro in macros)
 				{
-					if (macro.StartsWith("!"))
-					{
-						let removeStr = scope String(macro, 1);
-						preprocessorMacros.Remove(removeStr);
-						continue;
-					}
 					preprocessorMacros.Add(macro);
 				}
 			}
@@ -7841,7 +7866,7 @@ namespace IDE
 
             bfProject.SetOptions(targetType,
                 project.mBeefGlobalOptions.mStartupObject,
-                preprocessorMacros,
+                preprocessorMacros.mDefines,
                 optimizationLevel, ltoType, options.mBeefOptions.mMergeFunctions, options.mBeefOptions.mCombineLoads,
                 options.mBeefOptions.mVectorizeLoops, options.mBeefOptions.mVectorizeSLP);
 
@@ -8507,9 +8532,9 @@ namespace IDE
 
             if (options.mCOptions.mEnableBeefInterop)
             {
-                var beefPreprocMacros = scope List<String>();
+                var beefPreprocMacros = scope DefinesSet();
                 GetBeefPreprocessorMacros(beefPreprocMacros);
-                for (var beefPreprocMacro in beefPreprocMacros)                
+                for (var beefPreprocMacro in beefPreprocMacros.mDefines)                
                     clangOptions.Append("-D", beefPreprocMacro, " ");
             }
 
@@ -9210,6 +9235,30 @@ namespace IDE
         {
 			Debug.Assert(mBuildContext == null);
 
+			let platform = Workspace.PlatformType.GetFromName(mPlatformName);
+			let hostPlatform = Workspace.PlatformType.GetHostPlatform();
+			if (platform == .Unknown)
+			{
+				OutputErrorLine("Failed to compiler for unknown platform '{}'", mPlatformName);
+				return false;
+			}
+
+			bool canCompile = false;
+			if (platform == hostPlatform)
+			{
+				canCompile = true;
+			}
+			else
+			{
+				canCompile = false;
+			}
+			
+			if (!canCompile)
+			{
+				OutputErrorLine("Cannot compile for platform '{}' from host platform '{}'", platform, hostPlatform);
+				return false;
+			}
+
 			if (mDbgCompileDump)
 			{
 				mDbgCompileIdx++;

+ 23 - 0
IDE/src/Workspace.bf

@@ -55,6 +55,20 @@ namespace IDE
 				default: return .Unknown;
 				}
 			}
+
+			public static PlatformType GetHostPlatform()
+			{
+#if BF_PLATFORM_WINDOWS
+				return .Windows;
+#endif
+
+#if BF_PLATFORM_LINUX
+				return .Linux;
+#endif
+
+#unwarn
+				return .Unknown;
+			}
 		}
 
 		public enum ToolsetType
@@ -338,6 +352,7 @@ namespace IDE
 		public bool mForceNextCompile;
         public List<CompileInstance> mCompileInstanceList = new List<CompileInstance>() ~ DeleteContainerAndItems!(_); // First item is primary compile, secondaries are hot reloads
 		public List<String> mPlatforms = new List<String>() ~ DeleteContainerAndItems!(_);
+		public List<String> mUserPlatforms = new List<String>() ~ DeleteContainerAndItems!(_);
 		public bool mIsDebugSession;
 
 		public int32 HotCompileIdx
@@ -866,6 +881,14 @@ namespace IDE
             }
         }
 
+		public void FixOptionsForPlatform(String platformName)
+		{
+		    for (var configKV in mConfigs)
+		    {
+		        FixOptions(configKV.key, platformName);
+		    }
+		}
+
         public void FixOptions(String configName, String platformName)
         {
 			bool isTest = configName.Contains("Test");

+ 80 - 42
IDE/src/ui/ProjectProperties.bf

@@ -16,16 +16,17 @@ namespace IDE.ui
     public class ProjectProperties : BuildPropertiesDialog
     {   
 		ValueContainer<String> mVC;
-     
+
         enum CategoryType
         {
 			General, ///
             Project,
-			Platform,
+			/*Platform,
 			Platform_Windows,
-			Platform_Linux,
+			Platform_Linux,*/
             Dependencies,
 			Beef_Global,
+			Platform,
 
 			Targeted, ///
 			Beef_Targeted,
@@ -92,11 +93,9 @@ namespace IDE.ui
             var item = AddCategoryItem(globalItem, "Project");
 			if (!project.IsDebugSession)
             	item.Focused = true;
-			item = AddCategoryItem(globalItem, "Platform");
-			AddCategoryItem(item, "Windows");
-			AddCategoryItem(item, "Linux");
 			AddCategoryItem(globalItem, "Dependencies");
 			AddCategoryItem(globalItem, "Beef");
+			AddCategoryItem(globalItem, "Platform");
 			globalItem.Open(true, true);
 
 			var targetedItem = AddCategoryItem(root, "Targeted");
@@ -143,21 +142,19 @@ namespace IDE.ui
 			return false;
 		}
 
-        protected override bool IsCategoryTargeted(int32 categoryTypeInt)
+        protected override TargetedKind GetCategoryTargetedKind(int32 categoryTypeInt)
         {
         	switch ((CategoryType)categoryTypeInt)
 			{
 			case .General,
-				 .Targeted,
-				 .Platform,
 				 .Project,
 				 .Dependencies,
-				 .Platform_Linux,
-				 .Platform_Windows,
 				 .Beef_Global:
-				return false;
+				return .None;
+			case .Platform:
+				return .Platform;
 			default:
-				return true;
+				return .Config;
 			}
         }
 
@@ -427,14 +424,23 @@ namespace IDE.ui
 				mProject.SetupDefault(generalOptions);
 				targetDict[mCurPropertiesTargets[0]] = generalOptions;
 				UpdateFromTarget(targetDict);
-			case .Platform_Windows:
-				var windowsOptions = scope Project.WindowsOptions();
-				targetDict[mCurPropertiesTargets[0]] = windowsOptions;
-				UpdateFromTarget(targetDict);
-			case .Platform_Linux:
-				var linuxOptions = scope Project.LinuxOptions();
-				targetDict[mCurPropertiesTargets[0]] = linuxOptions;
-				UpdateFromTarget(targetDict);
+			case .Platform:
+				for (var platformName in mPlatformNames)
+				{
+					let platform = Workspace.PlatformType.GetFromName(platformName);
+					switch (platform)
+					{
+					case .Windows:
+						var windowsOptions = scope Project.WindowsOptions();
+						targetDict[mCurPropertiesTargets[0]] = windowsOptions;
+						UpdateFromTarget(targetDict);
+					case .Linux:
+						var linuxOptions = scope Project.LinuxOptions();
+						targetDict[mCurPropertiesTargets[0]] = linuxOptions;
+						UpdateFromTarget(targetDict);
+					default:
+					}
+				}
 			case .Build, .Debugging, .Beef_Targeted:
 				DeleteDistinctBuildOptions();
 				DistinctBuildOptions defaultTypeOptions = scope:: .();
@@ -488,7 +494,33 @@ namespace IDE.ui
 
 			DeleteAndNullify!(mCurProjectOptions);
 
-			if (IsCategoryTargeted(categoryTypeInt))
+			let targetKind = GetCategoryTargetedKind(categoryTypeInt);
+
+			bool areSamePlatforms = true;
+
+			if (targetKind == .Platform)
+			{
+				let platformKind = Workspace.PlatformType.GetFromName(platformName);
+
+				for (var checkPlatformName in mPlatformNames)
+				{
+					let checkPlatformKind = Workspace.PlatformType.GetFromName(checkPlatformName);
+					if (checkPlatformKind != platformKind)
+						areSamePlatforms = false;
+				}
+
+				if (areSamePlatforms)
+				{
+					mCurPropertiesTargets = new Object[1];
+					switch (platformKind)
+					{
+					case .Windows: mCurPropertiesTargets[0] = mProject.mWindowsOptions;
+					case .Linux: mCurPropertiesTargets[0] = mProject.mLinuxOptions;
+					default:
+					}
+				}
+			}
+			else if (targetKind == .Config)
 			{
 				mCurPropertiesTargets = new Object[mConfigNames.Count * mPlatformNames.Count];
 				mCurProjectOptions = new Project.Options[mConfigNames.Count * mPlatformNames.Count];
@@ -496,9 +528,6 @@ namespace IDE.ui
 				{
 					for (var checkPlatformName in mPlatformNames)
 					{
-						/*var projectConfig = mProject.mConfigs[checkConfigName];
-						mCurProjectOptions[propIdx] = projectConfig.mPlatforms[checkPlatformName];
-						mCurPropertiesTargets[propIdx] = mCurProjectOptions[propIdx];*/
 						let projectOptions = mProject.GetOptions(checkConfigName, checkPlatformName, true);
 						mCurProjectOptions[propIdx] = projectOptions;
 						mCurPropertiesTargets[propIdx] = projectOptions;
@@ -513,14 +542,10 @@ namespace IDE.ui
 					mCurPropertiesTargets[0] = mProject.mGeneralOptions;
 				else if (categoryType == .Beef_Global)
 					mCurPropertiesTargets[0] = mProject.mBeefGlobalOptions;
-				else if (categoryType == .Platform_Windows)
-					mCurPropertiesTargets[0] = mProject.mWindowsOptions;
-				else if (categoryType == .Platform_Linux)
-					mCurPropertiesTargets[0] = mProject.mLinuxOptions;
 			}
 
             ConfigDataGroup targetedConfigData;
-            if ((IsCategoryTargeted(categoryTypeInt)) &&
+            if ((GetCategoryTargetedKind(categoryTypeInt) == .Config) &&
 				((mConfigNames.Count == 1) && (mPlatformNames.Count == 1)))
             {
                 var key = Tuple<String, String>(configName, platformName);
@@ -531,25 +556,29 @@ namespace IDE.ui
 					key.Item2 = new String(key.Item2);
                     targetedConfigData = new ConfigDataGroup((int32)CategoryType.COUNT);
                     targetedConfigData.mTarget = key;
-                    mConfigDatas.Add(targetedConfigData);
                     mTargetedConfigDatas[key] = targetedConfigData;
                 }
             }
             else
             {
-                if (mUntargetedConfigData == null)
+                if (mMultiTargetConfigData == null)
                 {
-                    mUntargetedConfigData = new ConfigDataGroup((int32)CategoryType.COUNT);
-                    mConfigDatas.Add(mUntargetedConfigData);
+                    mMultiTargetConfigData = new ConfigDataGroup((int32)CategoryType.COUNT);
+					mMultiTargetConfigData.mIsMultiTargeted = true;
                 }
-                targetedConfigData = mUntargetedConfigData;
+                targetedConfigData = mMultiTargetConfigData;
 
-				if (IsCategoryTargeted(categoryTypeInt))
+				if (GetCategoryTargetedKind(categoryTypeInt) != .None)
 				{
 					DeleteAndNullify!(targetedConfigData.mPropPages[categoryTypeInt]);
 				}
             }
 
+			// Always add the current to the back so the most recently viewed one will apply changes last.
+			//  This matters when we have both project-specific and multiply-selected config data
+			mConfigDatas.Remove(targetedConfigData);
+			mConfigDatas.Add(targetedConfigData);
+
             if (targetedConfigData.mPropPages[(int32)categoryType] == null)
             {
                 CreatePropPage(categoryTypeInt, .AllowSearch | .AllowReset);
@@ -563,13 +592,22 @@ namespace IDE.ui
 
                 if (categoryType == CategoryType.Project)
                     PopulateGeneralOptions();
-				else if (categoryType == CategoryType.Platform_Windows)
-					PopulateWindowsOptions();
-				else if (categoryType == CategoryType.Platform_Linux)
-					PopulateLinuxOptions();
                 else if (categoryType == CategoryType.Dependencies)
                     PopulateDependencyOptions();
-				if (categoryType == CategoryType.Build)
+				else if (categoryType == .Platform)
+				{
+					if (areSamePlatforms)
+					{
+						let platformKind = Workspace.PlatformType.GetFromName(platformName);
+						switch (platformKind)
+						{
+						case .Windows: PopulateWindowsOptions();
+						case .Linux: PopulateLinuxOptions();
+						default:
+						}
+					}
+				}
+				else if (categoryType == CategoryType.Build)
 					PopulateBuildOptions();
 				else if (categoryType == CategoryType.Beef_Global				)
 					PopulateBeefSharedOptions();
@@ -976,7 +1014,7 @@ namespace IDE.ui
 											continue;
 										if (projectProperties.mProject != mProject)
 											continue;
-										if (IsCategoryTargeted(propPage.mCategoryType))
+										if (GetCategoryTargetedKind(propPage.mCategoryType) != .None)
 										{
 											if (mPropPage == propPage)
 											{

+ 40 - 8
IDE/src/ui/TargetedPropertiesDialog.bf

@@ -259,6 +259,13 @@ namespace IDE.ui
 
     public class TargetedPropertiesDialog : PropertiesDialog
     {
+		public enum TargetedKind
+		{
+			None,
+			Platform,
+			Config
+		}
+
         protected const String sConfigLabel = "Configuration:";
         protected const String sPlatformLabel = "Platform:";
 
@@ -273,6 +280,7 @@ namespace IDE.ui
 
 		protected class ConfigDataGroup
 		{
+			public bool mIsMultiTargeted;
 		    public Tuple<String, String> mTarget;
 		    public PropPage[] mPropPages ~ delete _;
 
@@ -289,7 +297,7 @@ namespace IDE.ui
 		}
 
 		protected Dictionary<Tuple<String, String>, ConfigDataGroup> mTargetedConfigDatas = new Dictionary<Tuple<String, String>, ConfigDataGroup>() ~ delete _;
-		protected ConfigDataGroup mUntargetedConfigData;
+		protected ConfigDataGroup mMultiTargetConfigData;
 		protected List<ConfigDataGroup> mConfigDatas = new List<ConfigDataGroup>() ~ DeleteContainerAndItems!(_);
 
         public this()
@@ -333,9 +341,9 @@ namespace IDE.ui
 			return (mConfigNames.Count != 1) || (mPlatformNames.Count != 1);
 		}
 
-        protected virtual bool IsCategoryTargeted(int32 categoryTypeInt)
+        protected virtual TargetedKind GetCategoryTargetedKind(int32 categoryTypeInt)
         {
-            return false;
+            return .None;
         }
 
 		public virtual void GetConfigList(List<String> configNames)
@@ -583,26 +591,50 @@ namespace IDE.ui
         {
             base.ShowPropPage(categoryTypeInt);
 
-            if (IsCategoryTargeted(categoryTypeInt))
+            if (GetCategoryTargetedKind(categoryTypeInt) == .Config)
             {
 				if (mConfigNames.Count == 1)
 				{
 	                String dispStr = ((mConfigNames.Count == 1) && (mActiveConfigName == mConfigNames[0])) ? StackStringFormat!("Active({0})", mConfigNames[0]) : mConfigNames[0];
 	                mConfigComboBox.Label = dispStr;
 				}
+				else
+				{
+					List<String> configNames = scope .();
+					GetConfigList(configNames);
+					if (mConfigNames.Count == configNames.Count)
+						mConfigComboBox.Label = "<All>";
+					else
+						mConfigComboBox.Label = "<Multiple>";
+				}
                 mConfigComboBox.mDisabled = false;
+			}
+			else
+			{
+				mConfigComboBox.Label = "N/A";
+				mConfigComboBox.mDisabled = true;
+			}
 
+			if (GetCategoryTargetedKind(categoryTypeInt) != .None)
+			{
 				if (mPlatformNames.Count == 1)
 				{
 	                String dispStr = ((mPlatformNames.Count == 1) && (mActivePlatformName == mPlatformNames[0])) ? StackStringFormat!("Active({0})", mPlatformNames[0]) : mPlatformNames[0];
 	                mPlatformComboBox.Label = dispStr;
 				}
+				else
+				{
+					List<String> platformNames = scope .();
+					GetPlatformList(platformNames);
+					if (mPlatformNames.Count == platformNames.Count)
+						mPlatformComboBox.Label = "<All>";
+					else
+						mPlatformComboBox.Label = "<Multiple>";
+				}
                 mPlatformComboBox.mDisabled = false;
             }
             else
             {
-                mConfigComboBox.Label = "N/A";
-                mConfigComboBox.mDisabled = true;
                 mPlatformComboBox.Label = "N/A";
                 mPlatformComboBox.mDisabled = true;
             }
@@ -618,7 +650,7 @@ namespace IDE.ui
 				{
 					if ((mConfigNames.Contains(configName)) && (mPlatformNames.Contains(platformName)))
 					{
-						if (mPropPage == mUntargetedConfigData.mPropPages[categoryType])
+						if (mPropPage == mMultiTargetConfigData.mPropPages[categoryType])
 						{
 							RemovePropPage();
 						}
@@ -637,7 +669,7 @@ namespace IDE.ui
 			}
 			else
 			{
-				if (!IsCategoryTargeted(categoryType))
+				if (GetCategoryTargetedKind(categoryType) == .None)
 					RemovePropPage();
 			}
 

+ 4 - 8
IDE/src/ui/WatchPanel.bf

@@ -831,13 +831,8 @@ namespace IDE.ui
 
 		public ~this()
 		{
-			//if (mOwnsWatchSeriesInfo)
-                //delete mWatchSeriesInfo;
 			if (mWatchSeriesInfo != null)
-			{					
-				// Why were we setting these to null here?  This caused the buttons to stay in the widget hierarchy when we scrolled a virtual listview around (since old items got deleted)
-				//mWatchSeriesInfo.mLessButton = null;				
-				//mWatchSeriesInfo.mMoreButton = null;
+			{
 				mWatchSeriesInfo.ReleaseRef();
 			}
 		}
@@ -1210,7 +1205,8 @@ namespace IDE.ui
                     lastValidListViewItem = watchListViewItem;
             }
 
-            if (mWatchSeriesInfo.mAddrs != null)
+			// This caused 'closing' opened items with Dictionay elements when stepping
+            /*if (mWatchSeriesInfo.mAddrs != null)
             {
                 int32 checkIdx = mWatchSeriesInfo.mStartMemberIdx + 1;
                 while (checkIdx < mParentItem.mChildItems.Count)
@@ -1220,7 +1216,7 @@ namespace IDE.ui
                         break;
                     mParentItem.RemoveChildItem(watchListViewItem);
                 }
-            }
+            }*/
         }
 
         public override void Update()

+ 34 - 26
IDE/src/ui/WorkspaceProperties.bf

@@ -118,16 +118,16 @@ namespace IDE.ui
 		}
 #endif
 
-        protected override bool IsCategoryTargeted(int32 categoryTypeInt)
+        protected override TargetedKind GetCategoryTargetedKind(int32 categoryTypeInt)
 		{
 			switch ((CategoryType)categoryTypeInt)
 			{
 			case .General,
-				 .Targeted,
+				 //.Targeted,
 				 .Beef_Global:
-				return false;
+				return .None;
 			default:
-				return true;
+				return .Config;
 			}
 		}
 
@@ -351,41 +351,49 @@ namespace IDE.ui
 
         protected override void CreateNewPlatform(String name)
         {
-            var workspace = IDEApp.sApp.mWorkspace;            
+            var workspace = gApp.mWorkspace;
             
             using (workspace.mMonitor.Enter())
             {
-                String useName = scope String(name);
-                useName.Trim();
-                if (!useName.IsEmpty)
+                String platformName = scope String(name);
+                platformName.Trim();
+                if (!platformName.IsEmpty)
                 {            
-                    for (var workspaceConfig in workspace.mConfigs.Values)
+                    /*for (var workspaceConfig in workspace.mConfigs)
                     {
-                        Workspace.Options workspaceOptions = new Workspace.Options();
-                        workspaceConfig.mPlatforms[new String(useName)] = workspaceOptions;
+						if (!workspaceConfig.value.mPlatforms.ContainsKey(useName))
+						{
+	                        Workspace.Options workspaceOptions = new Workspace.Options();
+							workspace.SetupDefault(workspaceOptions, workspaceConfig.key, useName);
+	                        workspaceConfig.value.mPlatforms[new String(useName)] = workspaceOptions;
+						}
                     }
 
 					for (var project in workspace.mProjects)
 					{
-					    for (var projectConfig in project.mConfigs.Values)
+					    for (var projectConfigKV in project.mConfigs)
 					    {
+							let projectConfig = projectConfigKV.value;
 							if (!projectConfig.mPlatforms.ContainsKey(useName))
 					        {
-								Project.Options projectOptions = new Project.Options();
-					            projectConfig.mPlatforms[new String(useName)] = projectOptions;
-								project.SetChanged();
+								project.CreateConfig(projectConfigKV.key, useName);
 							}
 					    }                            
-					}
+					}*/
+
+                    //IDEApp.sApp.mWorkspace.SetChanged();
+					gApp.mWorkspace.FixOptionsForPlatform(platformName);
+                    SelectPlatform(platformName);
 
-                    IDEApp.sApp.mWorkspace.SetChanged();
-                    SelectPlatform(useName);
+					gApp.mWorkspace.MarkPlatformNamesDirty();
+					if (!gApp.mWorkspace.mUserPlatforms.Contains(platformName))
+						gApp.mWorkspace.mUserPlatforms.Add(new String(platformName));
                 }
             }
         }
 
         protected override void ShowPropPage(int32 categoryTypeInt)
-        {          
+        {
             base.ShowPropPage(categoryTypeInt);
 
 			var configName = mConfigNames[0];
@@ -414,7 +422,7 @@ namespace IDE.ui
 			}
 
             ConfigDataGroup targetedConfigData;
-            if ((IsCategoryTargeted(categoryTypeInt)) &&
+            if ((GetCategoryTargetedKind(categoryTypeInt) != .None) &&
 				((mConfigNames.Count == 1) && (mPlatformNames.Count == 1)))
             {
                 var key = Tuple<String, String>(configName, platformName);
@@ -431,15 +439,15 @@ namespace IDE.ui
             }
             else
             {
-                if (mUntargetedConfigData == null)
+                if (mMultiTargetConfigData == null)
                 {
-                    mUntargetedConfigData = new ConfigDataGroup((int32)CategoryType.COUNT);
-                    mConfigDatas.Add(mUntargetedConfigData);
+                    mMultiTargetConfigData = new ConfigDataGroup((int32)CategoryType.COUNT);
+                    mConfigDatas.Add(mMultiTargetConfigData);
 					//Debug.WriteLine("Creating ConfigDataGroup {0} in {1}", mUntargetedConfigData, this);
                 }
-                targetedConfigData = mUntargetedConfigData;
+                targetedConfigData = mMultiTargetConfigData;
 
-				if (IsCategoryTargeted(categoryTypeInt))
+				if (GetCategoryTargetedKind(categoryTypeInt) != .None)
 				{
 					DeleteAndNullify!(targetedConfigData.mPropPages[categoryTypeInt]);
 				}
@@ -877,7 +885,7 @@ namespace IDE.ui
 									if (workspaceProperties == this)
 										continue;
 									
-									if (IsCategoryTargeted(propPage.mCategoryType))
+									if (GetCategoryTargetedKind(propPage.mCategoryType) != .None)
 									{
 										if (mPropPage == propPage)
 										{

+ 30 - 0
IDE/src/util/DefinesSet.bf

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+namespace IDE.util
+{
+	class DefinesSet
+	{
+		public List<String> mDefines = new List<String>() ~ DeleteContainerAndItems!(_);
+		public HashSet<String> mDefinesSet = new HashSet<String>() ~ delete _;
+
+		public void Add(StringView str)
+		{
+			if (str.StartsWith("!"))
+			{
+				String removeKey = scope .(str, 1);
+				if (mDefinesSet.Remove(removeKey))
+					mDefines.Remove(removeKey);
+				return;
+			}
+
+			if (!mDefinesSet.ContainsWith(str))
+			{
+				var strCopy = new String(str);
+				mDefines.Add(strCopy);
+				mDefinesSet.Add(strCopy);
+			}
+			
+		}
+	}
+}

+ 1 - 2
IDEHelper/Compiler/BfSystem.cpp

@@ -3603,8 +3603,7 @@ BF_EXPORT void BF_CALLTYPE BfProject_SetOptions(BfProject* bfProject, int target
 	bfProject->mCodeGenOptions = codeGenOptions;
 
 	bfProject->mPreprocessorMacros.Clear();
-	bfProject->mPreprocessorMacros.Add(BF_PLATFORM_NAME);
-
+	
 	int startIdx = 0;
 	int idx = 0;
 	while (true)