1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00
Beef/IDE/src/Project.bf
2021-02-25 08:10:21 -08:00

2415 lines
72 KiB
Beef

using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Diagnostics;
using Beefy;
using Beefy.utils;
using Beefy.widgets;
using Beefy.gfx;
using Beefy.res;
using IDE.Compiler;
using IDE.ui;
using IDE.Util;
using System.Threading;
using System.Diagnostics;
using IDE.util;
namespace IDE
{
public class ProjectItem : ISerializable, RefCounted
{
public enum IncludeKind
{
Auto,
Manual,
Ignore
}
public enum CategoryKind
{
None,
SimpleSource,
}
public IncludeKind mIncludeKind;
public Project mProject;
public ProjectFolder mParentFolder;
public String mName = new String() ~ delete _;
public String mComment = new String() ~ delete _;
public virtual bool IncludeInMap
{
get
{
return true;
}
}
public ~this()
{
Debug.Assert(mRefCount == 0);
}
public virtual void Serialize(StructuredData data)
{
if (!String.IsNullOrEmpty(mName))
data.Add("Name", mName);
if (!String.IsNullOrEmpty(mComment))
data.Add("Comment", mComment);
}
public virtual void Deserialize(StructuredData data)
{
data.GetString("Name", mName);
data.GetString("Comment", mComment);
}
public static int NameSort(ProjectItem item1, ProjectItem item2)
{
return item1.mName.CompareTo(item2.mName);
}
public static int Compare(ProjectItem left, ProjectItem right)
{
int32 leftType = (left is ProjectFolder) ? 0 : 1;
int32 rightType = (right is ProjectFolder) ? 0 : 1;
if (leftType - rightType != 0)
return leftType - rightType;
return String.Compare(left.mName, right.mName, true);
}
public virtual void Dispose()
{
}
public virtual bool HasNonAuto()
{
return mIncludeKind != .Auto;
}
public bool IsIgnored()
{
if (mIncludeKind == .Ignore)
return true;
if (mParentFolder == null)
return false;
return mParentFolder.IsIgnored();
}
public virtual CategoryKind GetCategoryKind()
{
return .None;
}
public virtual void Detach()
{
ReleaseRef();
}
}
public class ProjectFileItem : ProjectItem
{
public String mPath ~ delete _;
public bool mIsWatching;
public override bool IncludeInMap
{
get
{
if ((mPath == null) || (mParentFolder.mPath == null))
return true;
String dirPath = scope .();
Path.GetDirectoryPath(mPath, dirPath);
return Path.Equals(dirPath, mParentFolder.mPath);
}
}
public this()
{
}
public ~this()
{
if ((mIsWatching) && (!IDEApp.sApp.mShuttingDown))
StopWatching();
}
public void GetFullImportPath(String outFullPath)
{
if (mProject.IsSingleFile)
{
if (gApp.mWorkspace.mCompositeFile.IsIncluded(mName))
{
outFullPath.Append(mName);
return;
}
}
if (mPath != null)
{
mProject.GetProjectFullPath(mPath, outFullPath);
IDEUtils.FixFilePath(outFullPath);
}
else if (mParentFolder != null)
{
mParentFolder.GetFullImportPath(outFullPath);
outFullPath.Append(Path.DirectorySeparatorChar);
outFullPath.Append(mName);
}
}
public override void Deserialize(StructuredData data)
{
base.Deserialize(data);
if (mPath == null)
{
mPath = new String();
data.GetString("Path", mPath);
if (mPath.IsEmpty) //TODO: Temporary
data.GetString("ImportPath", mPath);
IDEUtils.FixFilePath(mPath);
if ((mPath.IsEmpty) && (mParentFolder != null))
{
mPath.Append(mParentFolder.mPath);
mPath.Append(Path.DirectorySeparatorChar);
mPath.Append(mName);
}
if (mName.IsEmpty)
Path.GetFileName(mPath, mName);
}
//AddToResourceManager();
}
public override void Serialize(StructuredData data)
{
bool wantName = true;
if (mPath != null)
{
String predictedPath = scope String();
if (mParentFolder != null)
{
predictedPath.Append(mParentFolder.mPath);
predictedPath.Append(Path.DirectorySeparatorChar);
predictedPath.Append(mName);
}
if (mPath != predictedPath)
{
String writePath = scope .(mPath);
IDEUtils.CanonicalizeFilePath(writePath);
data.Add("Path", writePath);
String fileName = scope .();
Path.GetFileName(mPath, fileName);
wantName = fileName != mName;
}
}
if (wantName)
data.Add("Name", mName);
}
public virtual void StartWatching()
{
#if !CLI
Debug.Assert(!mIsWatching);
var fullPath = scope String();
GetFullImportPath(fullPath);
IDEApp.sApp.mFileWatcher.WatchFile(fullPath, this);
mIsWatching = true;
#endif
}
public virtual void StopWatching()
{
#if !CLI
Debug.Assert(mIsWatching);
var fullPath = scope String();
GetFullImportPath(fullPath);
IDEApp.sApp.mFileWatcher.RemoveWatch(fullPath, this);
mIsWatching = false;
#endif
}
public virtual void OnRename(String oldPath, String newPath)
{
}
public virtual void Rename(String newName, bool changePath = true)
{
bool wasWatching = mIsWatching;
if ((wasWatching) && (changePath))
StopWatching();
String dirName = scope String();
String fileName = scope String();
Path.GetDirectoryPath(mPath, dirName);
Path.GetFileName(mPath, fileName);
bool didNameMatch = mName == fileName;
if (IncludeInMap)
{
mParentFolder.mChildMap.Remove(mName);
mName.Set(newName);
bool added = mParentFolder.mChildMap.TryAdd(mName, this);
Debug.Assert(added);
}
if ((didNameMatch) && (changePath))
{
String newPath = scope String();
newPath..Append(dirName)
..Append(Path.DirectorySeparatorChar)
..Append(newName);
OnRename(mPath, newPath);
mPath.Set(newPath);
}
if ((wasWatching) && (changePath))
StartWatching();
}
public void RecalcPath()
{
mPath.Clear();
mPath.Append(mParentFolder.mPath);
mPath.Append(Path.DirectorySeparatorChar);
mPath.Append(mName);
}
}
public class ProjectSource : ProjectFileItem
{
// 'Unsaved content' is for when we compile from an unsaved file
//public string mUnsavedContent;
//public IdSpan mUnsavedCharIdData;
public FileEditData mEditData;
public bool mHasChangedSinceLastCompile = true;
public bool mWasBuiltWithOldHash;
public bool mHasChangedSinceLastSuccessfulCompile = true;
public bool mLoadFailed;
public bool HasChangedSinceLastCompile
{
get
{
return mHasChangedSinceLastCompile;
}
set
{
mHasChangedSinceLastCompile = value;
if (value)
mHasChangedSinceLastSuccessfulCompile = true;
}
}
public bool IsBeefFile
{
get
{
return IDEApp.IsBeefFile(mPath);
}
}
public this()
{
}
public ~this()
{
Dispose();
}
public override CategoryKind GetCategoryKind()
{
if (mIncludeKind != .Manual)
return .None;
if (mParentFolder.mPath == null)
return .SimpleSource;
var expectPath = scope String();
expectPath.Append(mParentFolder.mPath);
expectPath.Append(Path.DirectorySeparatorChar);
expectPath.Append(mName);
if (mPath != expectPath)
return .None;
return .SimpleSource;
}
public override void Dispose()
{
if (mEditData != null)
{
mEditData.mProjectSources.Remove(this);
mEditData.Deref();
mEditData = null;
}
}
public override void Detach()
{
Dispose();
base.Detach();
}
public override void Serialize(StructuredData data)
{
if ((mProject.IsSingleFile) && (mName == CompositeFile.sMainFileName))
return;
data.Add("Type", (mIncludeKind == .Ignore) ? "IgnoreSource" : "Source");
base.Serialize(data);
}
/*public void AddToResourceManager()
{
ResImageInfo resInfo = new ResImageInfo();
resInfo.mFilePath = mPath;
resInfo.mResId = mResId;
resInfo.mName = mName;
BFApp.sApp.mResourceManager.mIdToResInfoMap[mResId] = resInfo;
}*/
/*public override void Dispose()
{
if (mEditData != null)
{
//for (var entry in mEditData.mEditWidget.mEditWidgetContent.mUndoManager.)
//mEditData.mEditWidget.mEditWidgetContent.mUndoManager.Dispose();
mEditData.mEditWidget.mEditWidgetContent.mData.mUndoManager.WithActions(scope (undoAction) =>
{
if (undoAction is GlobalUndoAction)
{
var globalUndoAction = (GlobalUndoAction)undoAction;
globalUndoAction.Detach();
}
});
}
}*/
}
public class ProjectComposition : ProjectItem
{
public Composition mComposition;
public override void Serialize(StructuredData data)
{
base.Serialize(data);
using (data.CreateObject("Composition"))
{
}
}
public override void Deserialize(StructuredData data)
{
base.Deserialize(data);
using (data.Open("Composition"))
{
}
}
}
public class ProjectFolder : ProjectFileItem
{
public List<ProjectItem> mChildItems = new List<ProjectItem>() ~
{
for (var projectItem in mChildItems)
{
projectItem.Detach();
}
delete _;
};
public Dictionary<String, ProjectItem> mChildMap = new Dictionary<String, ProjectItem>() ~ delete _;
//public String mLastImportDir = new String() ~ delete _;
public bool mAutoInclude;
public bool mSortDirty;
public this()
{
}
public ~this()
{
if ((mIsWatching) && (!gApp.mShuttingDown))
StopWatching();
}
public override void Dispose()
{
for (var item in mChildItems)
{
item.Dispose();
}
}
public void GetFullDisplayName(String displayName)
{
if (mParentFolder == null)
return;
if (mParentFolder.mParentFolder != null)
{
mParentFolder.mParentFolder.GetFullDisplayName(displayName);
displayName.Append("/");
}
displayName.Append(mName);
}
public void GetRelDir(String path)
{
if (mPath != null)
{
path.Append(mPath);
return;
}
if ((mParentFolder != null) && (mParentFolder.mName.Length > 0))
{
var relDirStr = scope String();
mParentFolder.GetRelDir(relDirStr);
path..Append(relDirStr)
..Append(Path.DirectorySeparatorChar)
..Append(mName);
}
else
path.Append(mName);
}
public virtual void SortItems()
{
if (mSortDirty)
{
mChildItems.Sort(scope => ProjectItem.Compare);
mSortDirty = false;
}
for (var item in mChildItems)
{
var projectFolder = item as ProjectFolder;
if (projectFolder != null)
projectFolder.SortItems();
}
}
public void MarkAsUnsorted()
{
mSortDirty = true;
}
public bool IsAutoInclude()
{
//return (mAutoInclude != .Never) &&
//((mAutoInclude == .Always) || (mIncludeKind == .Auto));
return mAutoInclude;
}
public virtual void AddChildAtIndex(int index, ProjectItem item)
{
item.mParentFolder = this;
if ((mIsWatching) && (var projectFileItem = item as ProjectFileItem))
{
projectFileItem.StartWatching();
}
mChildItems.Insert(index, item);
if (item.IncludeInMap)
{
bool added = mChildMap.TryAdd(item.mName, item);
Debug.Assert(added);
}
}
public virtual void InsertChild(ProjectItem item, ProjectItem insertBefore)
{
int pos = (insertBefore != null) ? mChildItems.IndexOf(insertBefore) : mChildItems.Count;
AddChildAtIndex(pos, item);
}
public virtual void AddChild(ProjectItem item, ProjectItem addAfter = null)
{
int pos = (addAfter != null) ? (mChildItems.IndexOf(addAfter) + 1) : mChildItems.Count;
AddChildAtIndex(pos, item);
}
public virtual void RemoveChild(ProjectItem item)
{
var projectFileItem = item as ProjectFileItem;
if (projectFileItem != null)
{
if (projectFileItem.mIsWatching)
projectFileItem.StopWatching();
}
if (item.IncludeInMap)
mChildMap.Remove(item.mName);
mChildItems.Remove(item);
item.mParentFolder = null;
}
public override bool HasNonAuto()
{
if (mAutoInclude != (mIncludeKind == .Auto))
return true;
if (mIncludeKind != .Auto)
return true;
for (let child in mChildItems)
{
if (child.HasNonAuto())
return true;
}
return false;
}
public bool HasAlias()
{
if (mPath == null)
return false;
if (!mPath.EndsWith(mName))
return true;
if (mPath.Length > mName.Length)
{
// Make sure it's not just a partial match
char8 slashChar = mPath[mPath.Length - mName.Length];
return (slashChar == '\\') || (slashChar == '/');
}
return false;
}
public override void Serialize(StructuredData data)
{
if (!HasNonAuto())
return;
if (mParentFolder != null)
{
data.Add("Type", (mIncludeKind == .Ignore) ? "IgnoreFolder" : (mIncludeKind == .Auto) ? "AutoFolder" : "Folder");
base.Serialize(data);
if (mAutoInclude != (mIncludeKind == .Auto))
data.ConditionalAdd("AutoInclude", mAutoInclude, mIncludeKind == .Auto);
}
if (!mChildItems.IsEmpty)
{
for (CategoryKind categoryKind = .None; categoryKind <= .SimpleSource; categoryKind++)
{
IDisposable arrayCloseItem = null;
for (ProjectItem item in mChildItems)
{
if (!item.HasNonAuto())
continue;
if (item.GetCategoryKind() != categoryKind)
continue;
if (categoryKind == .SimpleSource)
{
if ((mProject.IsSingleFile) && (item.mName == CompositeFile.sMainFileName))
continue;
if (arrayCloseItem == null)
arrayCloseItem = data.CreateArray("Source", true);
data.Add(item.mName);
}
else
{
if (arrayCloseItem == null)
arrayCloseItem = data.CreateArray("Items");
using (data.CreateObject())
item.Serialize(data);
}
}
if (arrayCloseItem != null)
arrayCloseItem.Dispose();
}
}
}
public override void Deserialize(StructuredData data)
{
base.Deserialize(data);
//mLastImportDir.Clear();
//data.GetString("LastImportDir", mLastImportDir);
//var outer = data.Current;
bool doPopulate = false;
bool autoInclude = data.GetBool("AutoInclude", mIncludeKind == .Auto);
if ((autoInclude) && (!mAutoInclude))
doPopulate = true;
mAutoInclude = autoInclude;
for (data.Enumerate("Items"))
{
ProjectItem projectItem = null;
String type = scope String();
data.GetString("Type", type);
String name = scope String();
data.GetString("Name", name);
mChildMap.TryGetValue(name, out projectItem);
if (projectItem == null)
{
if (type == "Source")
{
projectItem = new ProjectSource();
projectItem.mIncludeKind = .Manual;
}
else if (type == "IgnoreSource")
{
projectItem = new ProjectSource();
projectItem.mIncludeKind = .Ignore;
}
else if (type == "Folder")
{
projectItem = new ProjectFolder();
projectItem.mIncludeKind = .Manual;
}
else if (type == "AutoFolder")
{
projectItem = new ProjectFolder();
projectItem.mIncludeKind = .Auto;
}
else if (type == "IgnoreFolder")
{
projectItem = new ProjectFolder();
projectItem.mIncludeKind = .Ignore;
}
else
continue;
projectItem.mProject = mProject;
projectItem.mParentFolder = this;
projectItem.Deserialize(data);
AddChild(projectItem);
}
else
{
if ((type == "IgnoreSource") ||
(type == "IgnoreFolder"))
projectItem.mIncludeKind = .Ignore;
projectItem.Deserialize(data);
}
}
for (data.Enumerate("Source"))
{
let projectItem = new ProjectSource();
data.GetCurString(projectItem.mName);
projectItem.mIncludeKind = .Manual;
projectItem.mProject = mProject;
projectItem.mParentFolder = this;
var path = new String()
..Append(mPath)
..Append(Path.DirectorySeparatorChar)
..Append(projectItem.mName);
projectItem.mPath = path;
AddChild(projectItem);
}
if (doPopulate)
Populate(mPath);
}
public void Populate(String relDir)
{
mAutoInclude = true;
var dirPath = scope String(mProject.mProjectDir);
dirPath.Append(Path.DirectorySeparatorChar);
dirPath.Append(relDir);
for (let fileEntry in Directory.EnumerateFiles(dirPath))
{
String fileName = scope String();
fileEntry.GetFileName(fileName);
if ((!gApp.IsFilteredOut(fileName)) && (!mChildMap.ContainsKey(fileName)))
{
let projectItem = new ProjectSource();
projectItem.mProject = mProject;
projectItem.mName.Set(fileName);
projectItem.mPath = new String(relDir);
projectItem.mPath.Append(Path.DirectorySeparatorChar);
projectItem.mPath.Append(fileName);
AddChild(projectItem);
}
}
for (let fileEntry in Directory.EnumerateDirectories(dirPath))
{
String dirName = scope String();
fileEntry.GetFileName(dirName);
// Why was this here?
/*if (dirName == "build")
continue;*/
if (mChildMap.ContainsKey(dirName))
continue;
let newRelDir = scope String(relDir);
if (!newRelDir.IsEmpty)
newRelDir.Append(Path.DirectorySeparatorChar);
newRelDir.Append(dirName);
let projectFolder = new ProjectFolder();
projectFolder.mProject = mProject;
projectFolder.mName.Set(dirName);
projectFolder.mPath = new String(relDir)
..Append(Path.DirectorySeparatorChar)
..Append(dirName);
AddChild(projectFolder);
projectFolder.Populate(newRelDir);
}
}
public override void StartWatching()
{
//base.StartWatching();
Debug.Assert(!mIsWatching);
mIsWatching = true;
// Add self as a watch
var fullPath = scope String();
GetFullImportPath(fullPath);
fullPath.Append(Path.DirectorySeparatorChar);
IDEApp.sApp.mFileWatcher.WatchFile(fullPath, this);
for (var child in mChildItems)
if (let childFileItem = child as ProjectFileItem)
if (!childFileItem.mIsWatching)
childFileItem.StartWatching();
}
public override void StopWatching()
{
base.StopWatching();
var fullPath = scope String();
GetFullImportPath(fullPath);
fullPath.Append(Path.DirectorySeparatorChar);
IDEApp.sApp.mFileWatcher.RemoveWatch(fullPath, this);
for (var child in mChildItems)
if (let childFileItem = child as ProjectFileItem)
if (childFileItem.mIsWatching)
childFileItem.StopWatching();
}
public override void OnRename(String oldPath, String newPath)
{
for (var child in mChildItems)
if (let childFileItem = child as ProjectFileItem)
{
if (childFileItem.mPath.StartsWith(oldPath, .OrdinalIgnoreCase))
{
var newChildPath = scope String();
newChildPath.Append(newPath);
newChildPath.Append(childFileItem.mPath, oldPath.Length);
childFileItem.OnRename(childFileItem.mPath, newChildPath);
childFileItem.mPath.Set(newChildPath);
}
}
}
}
[Reflect(.StaticFields | .NonStaticFields | .ApplyToInnerTypes)]
public class Project
{
class ConfigWriteData
{
public String mPlatform;
public String mOutputDir;
public StructuredData mData;
}
public enum BuildKind
{
case Normal;
case Test;
case StaticLib;
case DynamicLib;
case NotSupported;
public bool IsApplicationLib
{
get
{
return (this == .StaticLib) || (this == .DynamicLib);
}
}
}
public enum COptimizationLevel
{
O0,
O1,
O2,
O3,
Ofast,
Og,
FromWorkspace
}
public enum CCompilerType
{
Clang,
GCC
}
public enum CLibType
{
None,
Dynamic,
Static,
DynamicDebug,
StaticDebug,
SystemMSVCRT,
}
public enum BeefLibType
{
Dynamic,
DynamicDebug,
Static,
}
public enum TargetType
{
case BeefConsoleApplication,
BeefGUIApplication,
BeefLib,
BeefDynLib,
CustomBuild,
BeefTest,
C_ConsoleApplication,
C_GUIApplication,
BeefApplication_StaticLib,
BeefApplication_DynamicLib;
public bool IsBeef
{
get
{
switch (this)
{
case BeefConsoleApplication,
BeefGUIApplication,
BeefLib,
BeefDynLib,
BeefTest:
return true;
default:
return false;
}
}
}
public bool IsBeefApplication
{
get
{
switch (this)
{
case BeefConsoleApplication,
BeefGUIApplication:
return true;
default:
return false;
}
}
}
}
public class WindowsOptions
{
[Reflect]
public String mIconFile = new String() ~ delete _;
[Reflect]
public String mManifestFile = new String() ~ delete _;
[Reflect]
public String mDescription = new String() ~ delete _;
[Reflect]
public String mComments = new String() ~ delete _;
[Reflect]
public String mCompany = new String() ~ delete _;
[Reflect]
public String mProduct = new String() ~ delete _;
[Reflect]
public String mCopyright = new String() ~ delete _;
[Reflect]
public String mFileVersion = new String() ~ delete _;
[Reflect]
public String mProductVersion = new String() ~ delete _;
public bool HasVersionInfo()
{
return
!mDescription.IsWhiteSpace ||
!mComments.IsWhiteSpace ||
!mCompany.IsWhiteSpace ||
!mProduct.IsWhiteSpace ||
!mCopyright.IsWhiteSpace ||
!mFileVersion.IsWhiteSpace ||
!mProductVersion.IsWhiteSpace;
}
public void Deserialize(StructuredData data)
{
data.GetString("IconFile", mIconFile);
data.GetString("ManifestFile", mManifestFile);
data.GetString("Description", mDescription);
data.GetString("Comments", mComments);
data.GetString("Company", mCompany);
data.GetString("Product", mProduct);
data.GetString("Copyright", mCopyright);
data.GetString("FileVersion", mFileVersion);
data.GetString("ProductVersion", mProductVersion);
}
public void Serialize(StructuredData data)
{
data.ConditionalAdd("IconFile", mIconFile);
data.ConditionalAdd("ManifestFile", mManifestFile);
data.ConditionalAdd("Description", mDescription);
data.ConditionalAdd("Comments", mComments);
data.ConditionalAdd("Company", mCompany);
data.ConditionalAdd("Product", mProduct);
data.ConditionalAdd("Copyright", mCopyright);
data.ConditionalAdd("FileVersion", mFileVersion);
data.ConditionalAdd("ProductVersion", mProductVersion);
}
}
public class LinuxOptions
{
[Reflect]
public String mOptions = new String() ~ delete _;
public void Deserialize(StructuredData data)
{
data.GetString("Options", mOptions);
}
public void Serialize(StructuredData data)
{
data.ConditionalAdd("Options", mOptions);
}
}
public class GeneralOptions
{
[Reflect]
public TargetType mTargetType;
[Reflect]
public List<String> mAliases = new .() ~ DeleteContainerAndItems!(_);
}
public class BeefGlobalOptions
{
[Reflect]
public String mStartupObject = new String("") ~ delete _;
[Reflect]
public String mDefaultNamespace = new String() ~ delete _;
[Reflect]
public List<String> mPreprocessorMacros = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public List<DistinctBuildOptions> mDistinctBuildOptions = new List<DistinctBuildOptions>() ~ DeleteContainerAndItems!(_);
}
public enum BuildCommandTrigger
{
Never,
IfFilesChanged,
Always,
}
public class ProjectBuildOptions
{
[Reflect]
public BuildKind mBuildKind;
[Reflect]
public String mTargetDirectory = new String("$(BuildDir)") ~ delete _;
[Reflect]
public String mTargetName = new String("$(ProjectName)") ~ delete _;
[Reflect]
public String mOtherLinkFlags = new String("") ~ delete _;
[Reflect]
public CLibType mCLibType = .Static;
[Reflect]
public BeefLibType mBeefLibType = .Static;
[Reflect]
public int32 mStackSize;
[Reflect]
public BuildCommandTrigger mBuildCommandsOnCompile = .Always;
[Reflect]
public BuildCommandTrigger mBuildCommandsOnRun = .Always;
[Reflect]
public List<String> mLibPaths = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public List<String> mLinkDependencies = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public List<String> mPreBuildCmds = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public List<String> mPostBuildCmds = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public List<String> mCleanCmds = new List<String>() ~ DeleteContainerAndItems!(_);
}
public class DebugOptions
{
[Reflect]
public String mCommand = new String("$(TargetPath)") ~ delete _;
[Reflect]
public String mCommandArguments = new String("") ~ delete _;
[Reflect]
public String mWorkingDirectory = new String("$(ProjectDir)") ~ delete _;
[Reflect]
public List<String> mEnvironmentVars = new List<String>() ~ DeleteContainerAndItems!(_);
}
public class BeefOptions
{
[Reflect]
public List<String> mPreprocessorMacros = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public BuildOptions.RelocType mRelocType;
[Reflect]
public BuildOptions.PICLevel mPICLevel;
[Reflect]
public BuildOptions.BfOptimizationLevel? mOptimizationLevel;
[Reflect]
public BuildOptions.LTOType? mLTOType;
[Reflect]
public bool mMergeFunctions;
[Reflect]
public bool mCombineLoads;
[Reflect]
public bool mVectorizeLoops;
[Reflect]
public bool mVectorizeSLP;
[Reflect]
public List<DistinctBuildOptions> mDistinctBuildOptions = new List<DistinctBuildOptions>() ~ DeleteContainerAndItems!(_);
}
public class COptions
{
[Reflect]
public CCompilerType mCompilerType = CCompilerType.Clang;
[Reflect]
public String mOtherCFlags = new String("") ~ delete _;
[Reflect]
public String mOtherCPPFlags = new String("") ~ delete _;
[Reflect]
public List<String> mIncludePaths = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public bool mEnableBeefInterop;
[Reflect]
public List<String> mPreprocessorMacros = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public bool mDisableExceptions;
[Reflect]
public BuildOptions.SIMDSetting? mSIMD;
[Reflect]
public bool mGenerateLLVMAsm;
[Reflect]
public bool mNoOmitFramePointers;
[Reflect]
public bool mDisableInlining;
[Reflect]
public bool mStrictAliasing;
[Reflect]
public bool mFastMath;
[Reflect]
public bool mDisableRTTI;
[Reflect]
public COptimizationLevel mOptimizationLevel = .FromWorkspace;
[Reflect]
public bool mEmitDebugInfo;
[Reflect]
public String mAddressSanitizer = new String("") ~ delete _; // TODO: Add proper options
[Reflect]
public bool mAllWarnings;
[Reflect]
public bool mEffectiveCPPViolations;
[Reflect]
public bool mPedantic;
[Reflect]
public bool mWarningsAsErrors;
[Reflect]
public List<String> mSpecificWarningsAsErrors = new List<String>() ~ DeleteContainerAndItems!(_);
[Reflect]
public List<String> mDisableSpecificWarnings = new List<String>() ~ DeleteContainerAndItems!(_);
public ~this()
{
}
}
public class Options
{
[Reflect]
public ProjectBuildOptions mBuildOptions = new ProjectBuildOptions() ~ delete _;
[Reflect]
public BeefOptions mBeefOptions = new BeefOptions() ~ delete _;
[Reflect]
public COptions mCOptions = new COptions() ~ delete _;
[Reflect]
public DebugOptions mDebugOptions = new DebugOptions() ~ delete _;
public List<String> mClangObjectFiles ~ DeleteContainerAndItems!(_);
public Options Duplicate()
{
var newOptions = new Options();
Set!(newOptions.mBuildOptions.mTargetDirectory, mBuildOptions.mTargetDirectory);
Set!(newOptions.mBuildOptions.mTargetName, mBuildOptions.mTargetName);
Set!(newOptions.mBuildOptions.mOtherLinkFlags, mBuildOptions.mOtherLinkFlags);
Set!(newOptions.mBuildOptions.mCLibType, mBuildOptions.mCLibType);
Set!(newOptions.mBuildOptions.mLibPaths, mBuildOptions.mLibPaths);
Set!(newOptions.mBuildOptions.mLinkDependencies, mBuildOptions.mLinkDependencies);
Set!(newOptions.mBuildOptions.mPreBuildCmds, mBuildOptions.mPreBuildCmds);
Set!(newOptions.mBuildOptions.mPostBuildCmds, mBuildOptions.mPostBuildCmds);
Set!(newOptions.mBuildOptions.mCleanCmds, mBuildOptions.mCleanCmds);
Set!(newOptions.mBeefOptions.mPreprocessorMacros, mBeefOptions.mPreprocessorMacros);
Set!(newOptions.mBeefOptions.mOptimizationLevel, mBeefOptions.mOptimizationLevel);
Set!(newOptions.mBeefOptions.mLTOType, mBeefOptions.mLTOType);
Set!(newOptions.mBeefOptions.mRelocType, mBeefOptions.mRelocType);
Set!(newOptions.mBeefOptions.mPICLevel, mBeefOptions.mPICLevel);
Set!(newOptions.mBeefOptions.mMergeFunctions, mBeefOptions.mMergeFunctions);
Set!(newOptions.mBeefOptions.mCombineLoads, mBeefOptions.mCombineLoads);
Set!(newOptions.mBeefOptions.mVectorizeLoops, mBeefOptions.mVectorizeLoops);
Set!(newOptions.mBeefOptions.mVectorizeSLP, mBeefOptions.mVectorizeSLP);
for (var prev in mBeefOptions.mDistinctBuildOptions)
newOptions.mBeefOptions.mDistinctBuildOptions.Add(prev.Duplicate());
Set!(newOptions.mCOptions.mCompilerType, mCOptions.mCompilerType);
Set!(newOptions.mCOptions.mOtherCFlags, mCOptions.mOtherCFlags);
Set!(newOptions.mCOptions.mOtherCPPFlags, mCOptions.mOtherCPPFlags);
Set!(newOptions.mCOptions.mIncludePaths, mCOptions.mIncludePaths);
Set!(newOptions.mCOptions.mEnableBeefInterop, mCOptions.mEnableBeefInterop);
Set!(newOptions.mCOptions.mPreprocessorMacros, mCOptions.mPreprocessorMacros);
Set!(newOptions.mCOptions.mDisableExceptions, mCOptions.mDisableExceptions);
Set!(newOptions.mCOptions.mSIMD, mCOptions.mSIMD);
Set!(newOptions.mCOptions.mGenerateLLVMAsm, mCOptions.mGenerateLLVMAsm);
Set!(newOptions.mCOptions.mNoOmitFramePointers, mCOptions.mNoOmitFramePointers);
Set!(newOptions.mCOptions.mDisableInlining, mCOptions.mDisableInlining);
Set!(newOptions.mCOptions.mStrictAliasing, mCOptions.mStrictAliasing);
Set!(newOptions.mCOptions.mFastMath, mCOptions.mFastMath);
Set!(newOptions.mCOptions.mDisableRTTI, mCOptions.mDisableRTTI);
Set!(newOptions.mCOptions.mOptimizationLevel, mCOptions.mOptimizationLevel);
Set!(newOptions.mCOptions.mEmitDebugInfo, mCOptions.mEmitDebugInfo);
Set!(newOptions.mCOptions.mAddressSanitizer, mCOptions.mAddressSanitizer);
Set!(newOptions.mCOptions.mAllWarnings, mCOptions.mAllWarnings);
Set!(newOptions.mCOptions.mEffectiveCPPViolations, mCOptions.mEffectiveCPPViolations);
Set!(newOptions.mCOptions.mPedantic, mCOptions.mPedantic);
Set!(newOptions.mCOptions.mWarningsAsErrors, mCOptions.mWarningsAsErrors);
Set!(newOptions.mCOptions.mSpecificWarningsAsErrors, mCOptions.mSpecificWarningsAsErrors);
Set!(newOptions.mCOptions.mDisableSpecificWarnings, mCOptions.mDisableSpecificWarnings);
Set!(newOptions.mDebugOptions.mCommand, mDebugOptions.mCommand);
Set!(newOptions.mDebugOptions.mCommandArguments, mDebugOptions.mCommandArguments);
Set!(newOptions.mDebugOptions.mWorkingDirectory, mDebugOptions.mWorkingDirectory);
Set!(newOptions.mDebugOptions.mEnvironmentVars, mDebugOptions.mEnvironmentVars);
return newOptions;
}
}
public class Config
{
public Dictionary<String, Options> mPlatforms = new Dictionary<String, Options>() ~ DeleteDictionaryAndKeysAndValues!(_);
}
public class Dependency
{
public VerSpec mVerSpec ~ _.Dispose();
public String mProjectName ~ delete _;
}
public enum DeferState
{
None,
ReadyToLoad,
Pending,
Searching
}
public class VerReference
{
public String mSrcProjectName ~ delete _;
public VerSpec mVerSpec ~ _.Dispose();
}
public Monitor mMonitor = new Monitor() ~ delete _;
public String mNamespace = new String() ~ delete _;
public String mProjectDir = new String() ~ delete _;
public String mProjectName = new String() ~ delete _;
public String mProjectPath = new String() ~ delete _;
public DeferState mDeferState;
public List<VerReference> mVerReferences = new .() ~ DeleteContainerAndItems!(_);
//public String mLastImportDir = new String() ~ delete _;
public bool mHasChanged;
public bool mNeedsTargetRebuild;
public bool mForceCustomCommands;
public bool mEnabled = true;
public bool mLocked;
public bool mLockedDefault;
public bool mDeleted;
public int32 [] mColorDialogCustomColors;
public ProjectFolder mRootFolder ~ mRootFolder.ReleaseRef();
public int32 mCurResVer;
public int32 mLastGeneratedResVer;
public Dictionary<String, Config> mConfigs = new Dictionary<String, Config>() ~ DeleteDictionaryAndKeysAndValues!(_);
public GeneralOptions mGeneralOptions = new GeneralOptions() ~ delete _;
public BeefGlobalOptions mBeefGlobalOptions = new BeefGlobalOptions() ~ delete _;
// Platform-dependent options
public WindowsOptions mWindowsOptions = new WindowsOptions() ~ delete _;
public LinuxOptions mLinuxOptions = new LinuxOptions() ~ delete _;
public List<Dependency> mDependencies = new List<Dependency>() ~ DeleteContainerAndItems!(_);
public bool mLastDidBuild;
public bool mFailed;
public bool mNeedsCreate;
public List<String> mCurBfOutputFileNames ~ DeleteContainerAndItems!(_);
public String ProjectFileName
{
get
{
Debug.Assert(!mProjectPath.IsEmpty);
return mProjectPath;
}
}
public bool IsSingleFile
{
get
{
return (mProjectPath.IsEmpty) && (!mProjectDir.IsEmpty);
}
}
public bool IsDebugSession
{
get
{
return gApp.mWorkspace.IsDebugSession;
}
}
public bool IsEmpty
{
get
{
return mRootFolder.mChildItems.IsEmpty;
}
}
void SetupDefaultOptions(Options options)
{
options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)");
}
public static void GetSanitizedName(String projectName, String outName, bool allowDot = false)
{
for (let c in projectName.RawChars)
{
if ((c.IsLetterOrDigit) || (c == '_'))
outName.Append(c);
else if (c == '-')
outName.Append('_');
else if ((c == '.') && (allowDot))
outName.Append(c);
}
}
public this()
{
mRootFolder = new ProjectFolder();
mRootFolder.mProject = this;
if (gApp.mWorkspace.IsDebugSession)
mGeneralOptions.mTargetType = .CustomBuild;
SetupDefaultConfigs();
mBeefGlobalOptions.mStartupObject.Set("Program");
}
public void SetupDefaultConfigs()
{
List<String> platforms = scope List<String>();
if (IDEApp.sPlatform32Name != null)
platforms.Add(IDEApp.sPlatform32Name);
if (IDEApp.sPlatform64Name != null)
platforms.Add(IDEApp.sPlatform64Name);
List<String> configs = scope List<String>();
configs.Add("Debug");
configs.Add("Release");
configs.Add("Paranoid");
configs.Add("Test");
for (let platformName in platforms)
{
for (let configName in configs)
{
CreateConfig(configName, platformName);
}
}
}
public ~this()
{
}
public void GetProjectRelPath(String fullPath, String outRelPath)
{
Debug.Assert((Object)fullPath != outRelPath);
Path.GetRelativePath(fullPath, mProjectDir, outRelPath);
IDEUtils.FixFilePath(outRelPath);
}
public void GetProjectFullPath(String relPath, String outAbsPath)
{
Debug.Assert((Object)relPath != outAbsPath);
Path.GetAbsolutePath(relPath, mProjectDir, outAbsPath);
}
public void DeferLoad(StringView path)
{
if (!path.IsEmpty)
{
mProjectPath.Set(path);
mDeferState = .ReadyToLoad;
}
else
mDeferState = .Pending;
}
public bool Load(StringView path)
{
scope AutoBeefPerf("Project.Load");
mDeferState = .None;
mLastGeneratedResVer = 0;
mCurResVer = 0;
StructuredData structuredData = scope StructuredData();
if (!mProjectPath.IsEmpty)
{
mProjectDir.Clear();
mProjectPath.Clear();
if (!Environment.IsFileSystemCaseSensitive)
{
Path.GetActualPathName(path, mProjectPath);
}
if (mProjectPath.IsEmpty)
{
mProjectPath.Set(path);
IDEUtils.FixFilePath(mProjectPath);
}
Path.GetDirectoryPath(mProjectPath, mProjectDir);
if (structuredData.Load(ProjectFileName) case .Err)
return false;
}
else
{
if (gApp.StructuredLoad(structuredData, "Project") case .Err)
return false;
}
//Console.WriteLine(structuredData.ToJSON(true));
Deserialize(structuredData);
/*if (!mIsLegacyProject)
{
Save();
}*/
return true;
}
public void Serialize(StructuredData data)
{
mRootFolder.SortItems();
//data.Add("LastImportDir", mLastImportDir);
String deferredCreateObject = scope String();
bool isOpened = false;
void DeferCreateObject(String name)
{
deferredCreateObject.Set(name);
}
void FinishCreate()
{
if (!deferredCreateObject.IsEmpty)
{
data.CreateObject("General");
isOpened = true;
}
}
void TryClose()
{
if (isOpened)
{
isOpened = false;
}
}
void WriteStrings(String name, List<String> strs)
{
if (!strs.IsEmpty)
{
using (data.CreateArray(name))
{
for (var str in strs)
data.Add(str);
}
}
}
void WriteDistinctOptions(List<DistinctBuildOptions> distinctBuildOptions)
{
if (distinctBuildOptions.IsEmpty)
return;
using (data.CreateArray("DistinctOptions"))
{
for (let typeOptions in distinctBuildOptions)
{
// This '.Deleted' can only happen if we're editing the properties but haven't committed yet
if (typeOptions.mCreateState == .Deleted)
continue;
using (data.CreateObject())
typeOptions.Serialize(data);
}
data.RemoveIfEmpty();
}
}
if (!IsSingleFile)
data.Add("FileVersion", 1);
using (data.CreateObject("Project"))
{
if (!IsSingleFile)
data.Add("Name", mProjectName);
data.ConditionalAdd("TargetType", mGeneralOptions.mTargetType, GetDefaultTargetType());
data.ConditionalAdd("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
var defaultNamespace = scope String();
GetSanitizedName(mProjectName, defaultNamespace, true);
data.ConditionalAdd("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, defaultNamespace);
WriteStrings("Aliases", mGeneralOptions.mAliases);
WriteStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
WriteDistinctOptions(mBeefGlobalOptions.mDistinctBuildOptions);
data.RemoveIfEmpty();
}
bool isDefaultDependencies = false;
if (mDependencies.Count == 1)
{
var dep = mDependencies[0];
if ((dep.mProjectName == "corlib") &&
(dep.mVerSpec case .SemVer(let semVer)) &&
(semVer.mVersion == "*"))
{
isDefaultDependencies = true;
}
}
if (!isDefaultDependencies)
{
using (data.CreateObject("Dependencies", true))
{
for (var dependency in mDependencies)
{
//let verSpecStr = scope String();
//dependency.mVerSpec.Serialize(data);
//data.Add(dependency.mProjectName, verSpecStr);
dependency.mVerSpec.Serialize(dependency.mProjectName, data);
}
}
}
using (data.CreateObject("Platform"))
{
using (data.CreateObject("Windows"))
{
mWindowsOptions.Serialize(data);
data.RemoveIfEmpty();
}
using (data.CreateObject("Linux"))
{
mLinuxOptions.Serialize(data);
data.RemoveIfEmpty();
}
data.RemoveIfEmpty();
}
using (data.CreateObject("Configs"))
{
for (var configKeyValue in mConfigs)
{
var config = configKeyValue.value;
let configName = configKeyValue.key;
#unwarn
bool isRelease = configName.Contains("Release");
bool isParanoid = configName.Contains("Paranoid");
bool isDebug = isParanoid || configName.Contains("Debug");
bool isTest = configName.Contains("Test");
using (data.CreateObject(configName))
{
for (var platformKeyValue in config.mPlatforms)
{
//let platformName = platformKeyValue.Key;
var options = platformKeyValue.value;
using (data.CreateObject(platformKeyValue.key))
{
// Build
data.ConditionalAdd("BuildKind", options.mBuildOptions.mBuildKind, isTest ? .Test : .Normal);
data.ConditionalAdd("TargetDirectory", options.mBuildOptions.mTargetDirectory, "$(BuildDir)");
data.ConditionalAdd("TargetName", options.mBuildOptions.mTargetName, "$(ProjectName)");
data.ConditionalAdd("OtherLinkFlags", options.mBuildOptions.mOtherLinkFlags, "$(LinkFlags)");
data.ConditionalAdd("CLibType", options.mBuildOptions.mCLibType, isRelease ? .Static : .StaticDebug);
data.ConditionalAdd("BeefLibType", options.mBuildOptions.mBeefLibType, isRelease ? .Static : .Dynamic);
data.ConditionalAdd("StackSize", options.mBuildOptions.mStackSize, 0);
data.ConditionalAdd("BuildCommandsOnCompile", options.mBuildOptions.mBuildCommandsOnCompile, .Always);
data.ConditionalAdd("BuildCommandsOnRun", options.mBuildOptions.mBuildCommandsOnRun, .Always);
WriteStrings("LibPaths", options.mBuildOptions.mLibPaths);
WriteStrings("LinkDependencies", options.mBuildOptions.mLinkDependencies);
WriteStrings("PreBuildCmds", options.mBuildOptions.mPreBuildCmds);
WriteStrings("PostBuildCmds", options.mBuildOptions.mPostBuildCmds);
WriteStrings("CleanCmds", options.mBuildOptions.mCleanCmds);
// DebugOptions
data.ConditionalAdd("DebugCommand", options.mDebugOptions.mCommand, "$(TargetPath)");
data.ConditionalAdd("DebugCommandArguments", options.mDebugOptions.mCommandArguments);
data.ConditionalAdd("DebugWorkingDirectory", options.mDebugOptions.mWorkingDirectory, "$(ProjectDir)");
WriteStrings("EnvironmentVars", options.mDebugOptions.mEnvironmentVars);
// BeefOptions
bool hasDefaultPreprocs = false;
if (isRelease)
{
if ((options.mBeefOptions.mPreprocessorMacros.Count == 1) &&
(options.mBeefOptions.mPreprocessorMacros[0] == "RELEASE"))
hasDefaultPreprocs = true;
}
else if (isParanoid)
{
if ((options.mBeefOptions.mPreprocessorMacros.Count == 2) &&
(options.mBeefOptions.mPreprocessorMacros[0] == "DEBUG") &&
(options.mBeefOptions.mPreprocessorMacros[1] == "PARANOID"))
hasDefaultPreprocs = true;
}
else if (isDebug)
{
if ((options.mBeefOptions.mPreprocessorMacros.Count == 1) &&
(options.mBeefOptions.mPreprocessorMacros[0] == "DEBUG"))
hasDefaultPreprocs = true;
}
else if (isTest)
{
if ((options.mBeefOptions.mPreprocessorMacros.Count == 1) &&
(options.mBeefOptions.mPreprocessorMacros[0] == "TEST"))
hasDefaultPreprocs = true;
}
else
hasDefaultPreprocs = options.mBeefOptions.mPreprocessorMacros.Count == 0;
if (!hasDefaultPreprocs)
{
using (data.CreateArray("PreprocessorMacros"))
{
for (var macro in options.mBeefOptions.mPreprocessorMacros)
data.Add(macro);
}
}
data.ConditionalAdd("RelocType", options.mBeefOptions.mRelocType, .NotSet);
data.ConditionalAdd("PICLevel", options.mBeefOptions.mPICLevel, .NotSet);
data.ConditionalAdd("OptimizationLevel", options.mBeefOptions.mOptimizationLevel);
data.ConditionalAdd("LTOType", options.mBeefOptions.mLTOType);
data.ConditionalAdd("MergeFunctions", options.mBeefOptions.mMergeFunctions);
data.ConditionalAdd("CombineLoads", options.mBeefOptions.mCombineLoads);
data.ConditionalAdd("VectorizeLoops", options.mBeefOptions.mVectorizeLoops);
data.ConditionalAdd("VectorizeSLP", options.mBeefOptions.mVectorizeSLP);
WriteDistinctOptions(options.mBeefOptions.mDistinctBuildOptions);
#if IDE_C_SUPPORT
using (data.CreateObject("COptions"))
{
data.ConditionalAdd("CompilerType", options.mCOptions.mCompilerType);
data.ConditionalAdd("OtherCFlags", options.mCOptions.mOtherCFlags);
data.ConditionalAdd("OtherCPPFlags", options.mCOptions.mOtherCPPFlags);
if (options.mCOptions.mIncludePaths.Count > 0)
{
using (data.CreateArray("IncludePaths"))
{
for (var includePath in options.mCOptions.mIncludePaths)
data.Add(includePath);
}
}
data.ConditionalAdd("EnableBeefInterop", options.mCOptions.mEnableBeefInterop);
if (options.mCOptions.mPreprocessorMacros.Count > 0)
{
using (data.CreateArray("PreprocessorMacros"))
{
for (var macro in options.mCOptions.mPreprocessorMacros)
data.Add(macro);
}
}
data.ConditionalAdd("DisableExceptions", options.mCOptions.mDisableExceptions);
data.ConditionalAdd("SIMD", options.mCOptions.mSIMD, .FromWorkspace);
data.ConditionalAdd("GenerateLLVMAsm", options.mCOptions.mGenerateLLVMAsm);
data.ConditionalAdd("NoOmitFramePointers", options.mCOptions.mNoOmitFramePointers);
data.ConditionalAdd("DisableInlining", options.mCOptions.mDisableInlining);
data.ConditionalAdd("StrictAliasing", options.mCOptions.mStrictAliasing);
data.ConditionalAdd("FastMath", options.mCOptions.mFastMath);
data.ConditionalAdd("DisableRTTI", options.mCOptions.mDisableRTTI);
data.ConditionalAdd("OptimizationLevel", options.mCOptions.mOptimizationLevel, .FromWorkspace);
data.ConditionalAdd("EmitDebugInfo", options.mCOptions.mEmitDebugInfo);
//if (options.mCOptions.mAddressSanitizer)
//data.Add("AddressSanitizer", options.mCOptions.mAddressSanitizer);
data.ConditionalAdd("AllWarnings", options.mCOptions.mAllWarnings);
data.ConditionalAdd("EffectiveCPPViolations", options.mCOptions.mEffectiveCPPViolations);
data.ConditionalAdd("Pedantic", options.mCOptions.mPedantic);
data.ConditionalAdd("WarningsAsErrors", options.mCOptions.mWarningsAsErrors);
if (options.mCOptions.mSpecificWarningsAsErrors.Count > 0)
{
using (data.CreateArray("SpecificWarningsAsErrors"))
{
for (var warning in options.mCOptions.mSpecificWarningsAsErrors)
data.Add(warning);
}
}
if (options.mCOptions.mDisableSpecificWarnings.Count > 0)
{
using (data.CreateArray("DisableSpecificWarnings"))
{
for (var warning in options.mCOptions.mDisableSpecificWarnings)
data.Add(warning);
}
}
}
#endif
data.RemoveIfEmpty();
}
}
data.RemoveIfEmpty();
}
}
data.RemoveIfEmpty();
}
/*data.Add("LinkFlags", mLinkFlags);
if (mCompileFlags != null)
{
using (data.CreateArray("CompileFlags"))
{
foreach (var str in mCompileFlags)
data.Add(str);
}
}*/
bool isDefaultProjectFolder = true;
if (!IsSingleFile)
{
if (mRootFolder.mPath != "src")
isDefaultProjectFolder = false;
if (!mRootFolder.mAutoInclude)
isDefaultProjectFolder = false;
}
bool IsDefaultFolder(ProjectFolder folder)
{
if (folder.mParentFolder != null)
{
if (!folder.mAutoInclude)
return false;
if (folder.mIncludeKind != .Auto)
return false;
}
for (var childItem in folder.mChildItems)
{
if (var childFolder = childItem as ProjectFolder)
{
if (!IsDefaultFolder(childFolder))
return false;
}
if (var childSource = childItem as ProjectSource)
{
if ((IsSingleFile) && (childSource.mName == CompositeFile.sMainFileName))
{
// Ignore
}
else
{
if (childSource.mIncludeKind != .Auto)
return false;
if (!childSource.mComment.IsEmpty)
return false;
}
}
}
return true;
}
if (!IsDefaultFolder(mRootFolder))
isDefaultProjectFolder = false;
if (!isDefaultProjectFolder)
{
using (data.CreateObject("ProjectFolder"))
{
mRootFolder.Serialize(data);
data.RemoveIfEmpty();
}
}
}
TargetType GetDefaultTargetType()
{
if (mBeefGlobalOptions.mStartupObject.IsEmpty)
return TargetType.BeefLib;
return TargetType.BeefConsoleApplication;
}
public void Deserialize(StructuredData data)
{
//mLastImportDir.Clear();
//data.GetString("LastImportDir", mLastImportDir);
/*mLinkFlags = data.GetString("LinkFlags");
using (data.Open("CompileFlags"))
{
if (data.IsArray)
{
mCompileFlags = new List<string>();
for (int i = 0; i < data.Count; i++)
mCompileFlags.Add(data.GetString(i));
}
}*/
void ReadStrings(String name, List<String> strs)
{
for (data.Enumerate(name))
{
String cmd = new String();
data.GetCurString(cmd);
strs.Add(cmd);
}
}
using (data.Open("Project"))
{
if (!IsSingleFile)
data.GetString("Name", mProjectName);
ReadStrings("Aliases", mGeneralOptions.mAliases);
data.GetString("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
var defaultNamespace = scope String();
GetSanitizedName(mProjectName, defaultNamespace, true);
data.GetString("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, defaultNamespace);
ReadStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
for (data.Enumerate("DistinctOptions"))
{
var typeOptions = new DistinctBuildOptions();
typeOptions.Deserialize(data);
mBeefGlobalOptions.mDistinctBuildOptions.Add(typeOptions);
}
var targetTypeName = scope String();
data.GetString("TargetType", targetTypeName);
switch (targetTypeName)
{ // Handle Legacy names first
case "BeefWindowsApplication":
mGeneralOptions.mTargetType = .BeefGUIApplication;
case "C_WindowsApplication":
mGeneralOptions.mTargetType = .C_GUIApplication;
default:
mGeneralOptions.mTargetType = data.GetEnum<TargetType>("TargetType", GetDefaultTargetType());
}
}
using (data.Open("Platform"))
{
using (data.Open("Windows"))
mWindowsOptions.Deserialize(data);
using (data.Open("Linux"))
mLinuxOptions.Deserialize(data);
}
if (!data.Contains("Dependencies"))
{
var dep = new Project.Dependency();
dep.mProjectName = new .("corlib");
dep.mVerSpec = .SemVer(new .("*"));
mDependencies.Add(dep);
}
else
{
for (let depName in data.Enumerate("Dependencies"))
{
var dep = new Dependency();
defer { delete dep; }
if (dep.mVerSpec.Parse(data) case .Err)
{
var err = scope String();
err.AppendF("Unable to parse version specifier for {0} in {1}", depName, mProjectPath);
gApp.Fail(err);
continue;
}
dep.mProjectName = new String(depName);
mDependencies.Add(dep);
dep = null;
}
}
for (var dep in mDependencies)
{
switch (gApp.AddProject(dep.mProjectName, dep.mVerSpec))
{
case .Ok(let project):
case .Err(let err):
gApp.OutputLineSmart("ERROR: Unable to load project '{0}' specified in project '{1}'", dep.mProjectName, mProjectName);
}
}
DeleteDictionaryAndKeysAndValues!(mConfigs);
mConfigs = new Dictionary<String, Config>();
for (var configNameSV in data.Enumerate("Configs"))
{
let configName = scope String(configNameSV);
Config config = new Config();
#unwarn
bool isRelease = configName.Contains("Release");
bool isParanoid = configName.Contains("Paranoid");
bool isDebug = isParanoid || configName.Contains("Debug");
bool isTest = configName.Contains("Test");
mConfigs[new String(configName)] = config;
for (var platformName in data.Enumerate())
{
Options options = new Options();
config.mPlatforms[new String(platformName)] = options;
// Build
options.mBuildOptions.mBuildKind = data.GetEnum<BuildKind>("BuildKind", isTest ? .Test : .Normal);
data.GetString("TargetDirectory", options.mBuildOptions.mTargetDirectory, "$(BuildDir)");
data.GetString("TargetName", options.mBuildOptions.mTargetName, "$(ProjectName)");
data.GetString("OtherLinkFlags", options.mBuildOptions.mOtherLinkFlags, "$(LinkFlags)");
options.mBuildOptions.mCLibType = data.GetEnum<CLibType>("CLibType", isRelease ? .Static : .StaticDebug);
options.mBuildOptions.mBeefLibType = data.GetEnum<BeefLibType>("BeefLibType", isRelease ? .Static : .Dynamic);
options.mBuildOptions.mStackSize = data.GetInt("StackSize");
options.mBuildOptions.mBuildCommandsOnCompile = data.GetEnum<BuildCommandTrigger>("BuildCommandsOnCompile", .Always);
options.mBuildOptions.mBuildCommandsOnRun = data.GetEnum<BuildCommandTrigger>("BuildCommandsOnRun", .Always);
ReadStrings("LibPaths", options.mBuildOptions.mLibPaths);
ReadStrings("LinkDependencies", options.mBuildOptions.mLinkDependencies);
ReadStrings("PreBuildCmds", options.mBuildOptions.mPreBuildCmds);
ReadStrings("PostBuildCmds", options.mBuildOptions.mPostBuildCmds);
ReadStrings("CleanCmds", options.mBuildOptions.mCleanCmds);
// DebugOptions
data.GetString("DebugCommand", options.mDebugOptions.mCommand, "$(TargetPath)");
data.GetString("DebugCommandArguments", options.mDebugOptions.mCommandArguments);
data.GetString("DebugWorkingDirectory", options.mDebugOptions.mWorkingDirectory, "$(ProjectDir)");
ReadStrings("EnvironmentVars", options.mDebugOptions.mEnvironmentVars);
// BeefOptions
ClearAndDeleteItems(options.mBeefOptions.mPreprocessorMacros);
if (data.Contains("PreprocessorMacros"))
{
for (var _preproc in data.Enumerate("PreprocessorMacros"))
{
var str = new String();
data.GetCurString(str);
options.mBeefOptions.mPreprocessorMacros.Add(str);
}
}
else
{
if (isRelease)
options.mBeefOptions.mPreprocessorMacros.Add(new String("RELEASE"));
if (isDebug)
options.mBeefOptions.mPreprocessorMacros.Add(new String("DEBUG"));
if (isParanoid)
options.mBeefOptions.mPreprocessorMacros.Add(new String("PARANOID"));
if (isTest)
options.mBeefOptions.mPreprocessorMacros.Add(new String("TEST"));
}
options.mBeefOptions.mRelocType = data.GetEnum<BuildOptions.RelocType>("RelocType");
options.mBeefOptions.mPICLevel = data.GetEnum<BuildOptions.PICLevel>("PICLevel");
if (data.Contains("OptimizationLevel"))
options.mBeefOptions.mOptimizationLevel = data.GetEnum<BuildOptions.BfOptimizationLevel>("OptimizationLevel");
if (data.Contains("LTOType"))
options.mBeefOptions.mLTOType = data.GetEnum<BuildOptions.LTOType>("LTOType");
options.mBeefOptions.mMergeFunctions = data.GetBool("MergeFunctions");
options.mBeefOptions.mCombineLoads = data.GetBool("CombineLoads");
options.mBeefOptions.mVectorizeLoops = data.GetBool("VectorizeLoops");
options.mBeefOptions.mVectorizeSLP = data.GetBool("VectorizeSLP");
for (data.Enumerate("DistinctOptions"))
{
var typeOptions = new DistinctBuildOptions();
typeOptions.Deserialize(data);
options.mBeefOptions.mDistinctBuildOptions.Add(typeOptions);
}
#if IDE_C_SUPPORT
using (data.Open("COptions"))
{
options.mCOptions.mCompilerType = data.GetEnum<CCompilerType>("CompilerType", .Clang);
data.GetString("OtherCFlags", options.mCOptions.mOtherCFlags);
data.GetString("OtherCPPFlags", options.mCOptions.mOtherCPPFlags);
DeleteAndClearItems!(options.mCOptions.mIncludePaths);
using (data.Open("IncludePaths"))
{
for (int32 i = 0; i < data.Count; i++)
{
var str = new String();
data.GetString(i, str);
options.mCOptions.mIncludePaths.Add(str);
}
}
options.mCOptions.mEnableBeefInterop = data.GetBool("EnableBeefInterop");
DeleteAndClearItems!(options.mCOptions.mPreprocessorMacros);
using (data.Open("PreprocessorMacros"))
{
for (int32 i = 0; i < data.Count; i++)
{
var str = new String();
data.GetString(i, str);
options.mCOptions.mPreprocessorMacros.Add(str);
}
}
data.GetBool("DisableExceptions", options.mCOptions.mDisableExceptions);
options.mCOptions.mSIMD = data.GetEnum<SIMDSetting>("SIMD", SIMDSetting.FromWorkspace);
options.mCOptions.mGenerateLLVMAsm = data.GetBool("GenerateLLVMAsm");
options.mCOptions.mNoOmitFramePointers = data.GetBool("NoOmitFramePointers");
options.mCOptions.mDisableInlining = data.GetBool("DisableInlining");
options.mCOptions.mStrictAliasing = data.GetBool("StrictAliasing");
options.mCOptions.mFastMath = data.GetBool("FastMath");
options.mCOptions.mDisableRTTI = data.GetBool("DisableRTTI");
options.mCOptions.mOptimizationLevel = data.GetEnum<COptimizationLevel>("OptimizationLevel", .FromWorkspace);
options.mCOptions.mEmitDebugInfo = data.GetBool("EmitDebugInfo", isRelease ? false : true);
data.GetString("AddressSanitizer", options.mCOptions.mAddressSanitizer);
options.mCOptions.mAllWarnings = data.GetBool("AllWarnings");
options.mCOptions.mEffectiveCPPViolations = data.GetBool("EffectiveCPPViolations");
options.mCOptions.mPedantic = data.GetBool("Pedantic");
options.mCOptions.mWarningsAsErrors = data.GetBool("WarningsAsErrors");
using (data.Open("SpecificWarningsAsErrors"))
{
for (int32 i = 0; i < data.Count; i++)
{
var str = new String();
data.GetString(i, str);
options.mCOptions.mSpecificWarningsAsErrors.Add(str);
}
}
using (data.Open("DisableSpecificWarnings"))
{
for (int32 i = 0; i < data.Count; i++)
{
var str = new String();
data.GetString(i, str);
options.mCOptions.mDisableSpecificWarnings.Add(str);
}
}
}
#endif
}
}
SetupDefaultConfigs();
if (!IsSingleFile)
{
mRootFolder.mPath = new String("src");
using (data.Open("ProjectFolder"))
mRootFolder.Deserialize(data);
/*if (Directory.Exists(scope String(mProjectDir, "/src")))
{
mRootFolder.Populate("src");
}*/
}
else
{
mRootFolder.mPath = new String();
Path.GetDirectoryPath(gApp.mWorkspace.mCompositeFile.FilePath, mRootFolder.mPath);
mRootFolder.mIncludeKind = .Manual;
let srcFile = new ProjectSource();
srcFile.mIncludeKind = .Manual;
srcFile.mProject = this;
srcFile.mParentFolder = mRootFolder;
srcFile.mPath = new String(CompositeFile.sMainFileName);
srcFile.mName.Set(CompositeFile.sMainFileName);
mRootFolder.AddChild(srcFile);
using (data.Open("ProjectFolder"))
mRootFolder.Deserialize(data);
}
mRootFolder.StartWatching();
}
public void FinishCreate(bool allowCreateDir = true)
{
if (!mRootFolder.mIsWatching)
{
String fullPath = scope String();
mRootFolder.GetFullImportPath(fullPath);
if (Directory.Exists(fullPath))
{
mRootFolder.Populate("src");
}
else if (!allowCreateDir)
{
return;
}
else
Directory.CreateDirectory(fullPath).IgnoreError();
mRootFolder.StartWatching();
}
mNeedsCreate = false;
}
public void SetupDefault()
{
mRootFolder.mPath = new String("src");
mRootFolder.mAutoInclude = true;
if (Directory.Exists(scope String(mProjectDir, "/src")))
{
mRootFolder.Populate("src");
mRootFolder.StartWatching();
}
SetupDefault(mBeefGlobalOptions);
}
public void Save()
{
if (mNeedsCreate)
FinishCreate();
StructuredData aData = scope StructuredData();
aData.CreateNew();
Serialize(aData);
String tomlString = scope String();
aData.ToTOML(tomlString);
if (!mProjectPath.IsEmpty)
{
if (!gApp.SafeWriteTextFile(ProjectFileName, tomlString))
return;
}
else
{
// If it's just the FileVersion then don't save anything...
/*if (tomlString.Count('\n') < 2)
tomlString.Clear();*/
gApp.StructuredSave("Project", tomlString);
}
mHasChanged = false;
}
public Options GetOptions(String configName, String platformName)
{
Config config;
mConfigs.TryGetValue(configName, out config);
if (config == null)
return null;
Options options;
config.mPlatforms.TryGetValue(platformName, out options);
return options;
}
public Options GetOptions(String configName, String platformName, bool createOnDemand)
{
var options = GetOptions(configName, platformName);
if ((options == null) && (createOnDemand))
options = CreateConfig(configName, platformName);
return options;
}
public void SetChanged()
{
gApp.MarkDirty();
mHasChanged = true;
}
delegate String ProjectItemStringDelegate<T>(T projectItem);
void SourceIterate<T>(String sourceText, ProjectItem projectItem, ProjectItemStringDelegate<T> theDelegate) where T : ProjectItem
{
if (projectItem is T)
sourceText.Append(theDelegate((T) projectItem), Environment.NewLine);
if (projectItem is ProjectFolder)
{
var projectFolder = (ProjectFolder)projectItem;
for (var childItem in projectFolder.mChildItems)
SourceIterate<T>(sourceText, childItem, theDelegate);
}
}
delegate void ProjectItemStructuredDataDelegate<T>(ConfigWriteData data, T projectItem);
void ConfigIterate<T>(ConfigWriteData data, ProjectItem projectItem, ProjectItemStructuredDataDelegate<T> theDelegate) where T : ProjectItem
{
if (projectItem is T)
theDelegate(data, (T)projectItem);
data.mData = null;
data.mOutputDir = null;
data.mPlatform = null;
if (projectItem is ProjectFolder)
{
var projectFolder = (ProjectFolder)projectItem;
for (var childItem in projectFolder.mChildItems)
ConfigIterate<T>(data, childItem, theDelegate);
}
}
void WriteItemConfigData(ConfigWriteData data, ProjectItem item)
{
StructuredData aData = data.mData;
if (!(item is ProjectFolder))
{
ProjectSource aProjectImage = item as ProjectSource;
if (aProjectImage != null)
{
using (aData.CreateObject())
{
aData.Add("Type", "Image");
aData.Add("Name", aProjectImage.mName);
String imageFullPath = scope String();
GetProjectFullPath(aProjectImage.mPath, imageFullPath);
String imageRelPath = scope String();
Path.GetRelativePath(imageFullPath, data.mOutputDir, imageRelPath);
IDEUtils.CanonicalizeFilePath(imageRelPath);
aData.Add("Path", imageRelPath);
}
}
}
}
public void UpdateResConfigData()
{
}
public void Update()
{
}
public void WithProjectItems(delegate void(ProjectItem) func)
{
List<int32> idxStack = scope List<int32>();
List<ProjectFolder> folderStack = scope List<ProjectFolder>();
folderStack.Add(mRootFolder);
idxStack.Add(0);
while (folderStack.Count > 0)
{
int32 curIdx = idxStack[idxStack.Count - 1]++;
ProjectFolder curFolder = folderStack[folderStack.Count - 1];
if (curIdx >= curFolder.mChildItems.Count)
{
folderStack.RemoveAt(folderStack.Count - 1);
idxStack.RemoveAt(idxStack.Count - 1);
continue;
}
var projectItem = curFolder.mChildItems[curIdx];
if (projectItem is ProjectFolder)
{
folderStack.Add((ProjectFolder)projectItem);
idxStack.Add(0);
continue;
}
func(projectItem);
}
}
public bool HasDependency(String projectName, bool checkRecursively = true)
{
HashSet<Project> checkedProject = scope .();
bool CheckDependency(Project project)
{
if (!checkedProject.Add(project))
return false;
for (var dependency in project.mDependencies)
{
if (dependency.mProjectName == projectName)
return true;
let depProject = gApp.mWorkspace.FindProject(dependency.mProjectName);
if ((depProject != null) && (checkRecursively) && (CheckDependency(depProject)))
return true;
}
return false;
}
return CheckDependency(this);
}
public void SetupDefault(Options options, String configName, String platformName)
{
bool isRelease = configName.Contains("Release");
bool isParanoid = configName.Contains("Paranoid");
bool isDebug = isParanoid || configName.Contains("Debug");
bool isTest = configName.Contains("Test");
let platformType = Workspace.PlatformType.GetFromName(platformName);
if (isRelease)
options.mBeefOptions.mPreprocessorMacros.Add(new String("RELEASE"));
if (isDebug)
options.mBeefOptions.mPreprocessorMacros.Add(new String("DEBUG"));
if (isParanoid)
options.mBeefOptions.mPreprocessorMacros.Add(new String("PARANOID"));
if (isTest)
options.mBeefOptions.mPreprocessorMacros.Add(new String("TEST"));
options.mBuildOptions.mCLibType = isRelease ? .Static : .StaticDebug;
options.mBuildOptions.mBeefLibType = isRelease ? .Static : .Dynamic;
options.mBuildOptions.mStackSize = 0;
switch (platformType)
{
case .Linux,
.Windows,
.macOS:
options.mBuildOptions.mBuildKind = isTest ? .Test : .Normal;
default:
options.mBuildOptions.mBuildKind = .StaticLib;
}
if (platformType == .Android)
{
options.mBeefOptions.mRelocType = .PIC;
}
options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)");
if (gApp.mWorkspace.IsDebugSession)
{
options.mBuildOptions.mTargetName.Clear();
options.mDebugOptions.mWorkingDirectory.Clear();
options.mBuildOptions.mBuildCommandsOnCompile = .Always;
options.mBuildOptions.mBuildCommandsOnRun = .Never;
}
}
public void SetupDefault(GeneralOptions generalOptions)
{
}
public void SetupDefault(BeefGlobalOptions generalOptions)
{
generalOptions.mDefaultNamespace.Clear();
GetSanitizedName(mProjectName, generalOptions.mDefaultNamespace, true);
generalOptions.mStartupObject.Set(scope String()..AppendF("{}.Program", generalOptions.mDefaultNamespace));
}
public Options CreateConfig(String configName, String platformName)
{
String* configKeyPtr = null;
Config* configPtr = null;
Config config = null;
if (mConfigs.TryAdd(configName, out configKeyPtr, out configPtr))
{
config = new Config();
*configPtr = config;
*configKeyPtr = new String(configName);
}
else
config = *configPtr;
String* platformKeyPtr = null;
Options* optionsPtr = null;
Options options = null;
if (config.mPlatforms.TryAdd(platformName, out platformKeyPtr, out optionsPtr))
{
options = new Options();
*optionsPtr = options;
*platformKeyPtr = new String(platformName);
SetupDefault(options, configName, platformName);
}
return *optionsPtr;
}
}
}