static define app = ((GuiApplication)__thisModule);
#endif
+#define OPTION(x) ((uint)(&((ProjectOptions)0).x))
+
bool eString_PathInsideOfMore(char * path, char * of, char * pathRest)
{
if(!path[0] || !of[0])
}
}
-class BuildExclusionInfo : struct
-{
- SetBool excluded;
- Map<Platform, bool> platformSpecific { };
-}
-
class ProjectNode : ListItem
{
public:
};
LinkList<ProjectNode> files;
- ProjectOptions options;
- Array<PlatformOptions> platforms;
- List<ProjectConfig> configurations;
-
- property ProjectConfig config
+ property ProjectOptions options
{
- get
+ get { return project ? project.options : options; }
+ set { if(project) { delete project.options; project.options = value; } else { delete options; options = value; } }
+ isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
+ }
+ property Array<PlatformOptions> platforms
+ {
+ get { return project ? project.platforms : platforms; }
+ set
{
- Project prj;
- ProjectConfig result = null;
- /*if(configurations)
- printf("test\n");
- if(prj)
- printf("test\n");*/
- if(configurations && (prj = property::project) && prj.config)
+ if(project) { project.platforms = value; }
+ else
{
- const char * projectConfigName = prj.config.name;
- for(config : configurations)
+ if(platforms) { platforms.Free(); delete platforms; }
+ if(value)
{
- if(!strcmpi(config.name, projectConfigName))
- {
- result = config;
- break;
- }
+ List<PlatformOptions> empty { };
+ Iterator<PlatformOptions> it { value };
+ platforms = value;
+ for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
+ for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
+ delete empty;
}
}
- return result;
}
- }
-
- ProjectConfig GetMatchingNodeConfig(ProjectConfig config)
- {
- ProjectConfig nodeConfig = null;
- if(configurations)
+ isset
{
- const char * configName = config.name;
- for(cfg : configurations)
+ Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
+ if(platforms)
{
- if(!strcmpi(cfg.name, configName))
+ for(p : platforms)
{
- nodeConfig = cfg;
- break;
+ if(p.options && !p.options.isEmpty)
+ return true;
}
}
- }
- return nodeConfig;
- }
-
- property bool ecflags
- {
- get
- {
- ProjectConfig config = this.config;
- ProjectOptions options = this.options;
- SetBool memoryGuard = localMemoryGuard;
- String defaultNameSpace = localDefaultNameSpace;
- SetBool strictNameSpaces = localStrictNameSpaces;
- SetBool noLineNumbers = localNoLineNumbers;
-
- if(memoryGuard || defaultNameSpace || strictNameSpaces || noLineNumbers)
- return true;
- else if(parent.parent)
- return parent.ecflags;
- else
- return false;
+ return false;
}
}
- property bool memoryGuard
+ property List<ProjectConfig> configurations
{
- get
+ get { return project ? project.configurations : configurations; }
+ set
{
- ProjectConfig config = this.config;
- ProjectOptions options = this.options;
- SetBool memoryGuard = localMemoryGuard;
- if(!memoryGuard)
+ if(project)
{
- if(parent)
- return parent.memoryGuard;
+ if(project.configurations)
+ {
+ project.configurations.Free();
+ delete project.configurations;
+ }
+ project.configurations = value;
}
- return memoryGuard == true;
- }
- }
- property String defaultNameSpace
- {
- get
- {
- ProjectConfig config = this.config;
- ProjectOptions options = this.options;
- String defaultNameSpace = localDefaultNameSpace;
- if(!defaultNameSpace)
+ else
{
- if(parent)
- return parent.defaultNameSpace;
+ if(configurations) { configurations.Free(); delete configurations; }
+ if(value)
+ {
+ List<ProjectConfig> empty { };
+ Iterator<ProjectConfig> it { value };
+ configurations = value;
+ for(c : configurations)
+ {
+ bool somethingSet = c.options && !c.options.isEmpty;
+ // TODO: Implement isset keyword
+ if(!somethingSet && c.platforms && c.platforms.count)
+ {
+ for(p : c.platforms)
+ {
+ if(p.options && !p.options.isEmpty)
+ {
+ somethingSet = true;
+ break;
+ }
+ }
+ }
+ if(!somethingSet)
+ empty.Add(c);
+ }
+ for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
+ delete empty;
+ }
}
- return defaultNameSpace;
}
- }
- property bool strictNameSpaces
- {
- get
+ isset
{
- ProjectConfig config = this.config;
- ProjectOptions options = this.options;
- SetBool strictNameSpaces = localStrictNameSpaces;
- if(!strictNameSpaces)
+ if(!parent) return true;
+ if(configurations)
{
- if(parent)
- return parent.strictNameSpaces;
+ for(c : configurations)
+ {
+ bool somethingSet = c.options && !c.options.isEmpty;
+ if(!somethingSet && c.platforms && c.platforms.count)
+ {
+ for(p : c.platforms)
+ {
+ if(p.options && !p.options.isEmpty)
+ {
+ somethingSet = true;
+ break;
+ }
+ }
+ }
+ return somethingSet;
+ }
}
- return strictNameSpaces == true;
+ return false;
}
}
- property bool noLineNumbers
+
+private:
+ ProjectOptions options;
+ Array<PlatformOptions> platforms;
+ List<ProjectConfig> configurations;
+ ProjectNodeType nodeType;
+ ProjectNode parent;
+ char * name;
+ char * info;
+
+ // This holds the absolute path of the .epj for the project topnode (without the filename)
+ // It holds a relative path to the topNode (project) for other nodes (folders and files)
+ // For folders, it includes the folder it refers to. If there is a name difference between the
+ // file system folder and the grouping folder of the project view, it maps to that folder.
+ char * path;
+
+ NodeTypes type;
+ NodeIcons icon;
+ int indent;
+ DataRow row;
+
+ bool modified;
+
+ // This is only set for Top Nodes
+ Project project;
+
+ ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
{
- get
+ ProjectConfig nodeConfig = null;
+ if(property::configurations && prjConfig)
{
- ProjectConfig config = this.config;
- ProjectOptions options = this.options;
- SetBool noLineNumbers = localNoLineNumbers;
- if(!noLineNumbers)
+ const char * configName = prjConfig.name;
+ for(cfg : property::configurations)
{
- if(parent)
- return parent.noLineNumbers;
+ if(!strcmpi(cfg.name, configName))
+ {
+ nodeConfig = cfg;
+ break;
+ }
}
- return noLineNumbers == true;
}
+ return nodeConfig;
}
property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
return buffer;
}
- void CollectPerFileAndDirOptions(ProjectConfig projectConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
+ void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
{
ProjectNode node = null;
- ProjectConfig config = GetMatchingNodeConfig(projectConfig);
+ ProjectConfig config = GetMatchingNodeConfig(prjConfig);
List<ProjectNode> nodeStack { };
-
+
for(node = this; node && node.parent; node = node.parent)
nodeStack.Add(node);
- // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
+ // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
// TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
while((node = nodeStack.lastIterator.data))
{
- if(node.options && node.options.preprocessorDefinitions)
+ ProjectConfig config = GetMatchingNodeConfig(prjConfig);
+ ProjectOptions nodeOptions = node.property::options;
+ if(nodeOptions && nodeOptions.preprocessorDefinitions)
{
- for(def : node.options.preprocessorDefinitions)
+ for(def : nodeOptions.preprocessorDefinitions)
perFilePreprocessorDefs.Add(CopyString(def));
}
if(config && config.options && config.options.preprocessorDefinitions)
for(def : config.options.preprocessorDefinitions)
perFilePreprocessorDefs.Add(CopyString(def));
}
- if(node.options && node.options.includeDirs)
+ if(nodeOptions && nodeOptions.includeDirs)
{
- for(dir : node.options.includeDirs)
+ for(dir : nodeOptions.includeDirs)
perFileIncludeDirs.Add(CopySystemPath(dir));
}
if(config && config.options && config.options.includeDirs)
delete nodeStack;
}
-private:
- ProjectNodeType nodeType;
- ProjectNode parent;
- char * name;
- char * info;
-
- // This holds the absolute path of the .epj for the project topnode (without the filename)
- // It holds a relative path to the topNode (project) for other nodes (folders and files)
- // For folders, it includes the folder it refers to. If there is a name difference between the
- // file system folder and the grouping folder of the project view, it maps to that folder.
- char * path;
-
- NodeTypes type;
- NodeIcons icon;
- int indent;
- DataRow row;
-
- bool modified;
-
- // This is only set for Top Nodes
- Project project;
property Project project
{
{
for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
}
- if(configurations)
+ if(property::configurations)
{
- for(c : configurations; !strcmp(c.name, oldName))
+ for(c : property::configurations; !strcmp(c.name, oldName))
{
delete c.name;
c.name = CopyString(newName);
{
for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
}
- if(configurations)
+ if(property::configurations)
{
- Iterator<ProjectConfig> c { configurations };
+ Iterator<ProjectConfig> c { property::configurations };
while(c.Next())
{
ProjectConfig config = c.data;
break;
}
}
- if(!configurations.count)
- {
- delete configurations;
- }
+ if(!property::configurations.count)
+ property::configurations = null;
}
}
backupNode.files = { };
for(f : files) backupNode.files.Add(f.Backup());
}
- if(options)
- backupNode.options = options.Copy();
+ if(property::options)
+ backupNode.options = property::options.Copy();
- if(platforms)
+ if(property::platforms)
{
backupNode.platforms = { };
- for(p : platforms)
+ for(p : property::platforms)
backupNode.platforms.Add(p.Copy());
}
- if(configurations)
+ if(property::configurations)
{
backupNode.configurations = { };
- for(c : configurations)
+ for(c : property::configurations)
backupNode.configurations.Add(c.Copy());
}
return backupNode;
}
}
- delete options;
- if(platforms)
- {
- platforms.Free();
- delete platforms;
- }
- if(configurations)
- {
- configurations.Free();
- delete configurations;
- }
-
- options = backupNode.options ? backupNode.options.Copy() : null;
+ property::options = backupNode.options ? backupNode.options.Copy() : null;
if(backupNode.platforms)
{
- platforms = { };
+ Array<PlatformOptions> platforms { };
+ property::platforms = platforms;
+
for(p : backupNode.platforms)
platforms.Add(p.Copy());
}
if(backupNode.configurations)
{
- configurations = { };
+ List<ProjectConfig> configurations { };
+ property::configurations = configurations;
for(c : backupNode.configurations)
configurations.Add(c.Copy());
}
if(!needClass)
{
// TOCHECK: Called from JSON writer
- if(nodeType == file && !options && !configurations && !platforms && name)
+ if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
{
strcpy(tempString, "\"");
strcat(tempString, property::fileName);
files.Free();
delete files;
}
- delete options;
+ if(!project)
+ delete options;
- if(platforms)
+ if(!project && platforms)
{
platforms.Free();
delete platforms;
};
- if(configurations)
+ if(!project && configurations)
{
configurations.Free();
delete configurations;
}
}
- property TwoStrings platformSpecificFu
+ TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
{
- get
+ TwoStrings result { a = CopyString(""), b = CopyString("") };
+ // note: unknown platform is for common
+ Map<Platform, SetBool> exclusionInfo { };
+ MapNode<Platform, SetBool> mn;
+ char * exp, * var;
+ int len;
+ SetBool common;
+
+ CollectExclusionInfo(exclusionInfo, prjConfig);
+ common = exclusionInfo[unknown];
{
- TwoStrings result { a = CopyString(""), b = CopyString("") };
- BuildExclusionInfo exclusion = exclusionInfo;
- char * exp, * var;
- int len;
- Platform platform;
- if(exclusion.platformSpecific.count > 1)
+ Map<Platform, SetBool> cleaned { };
+ SetBool opposite = common == true ? false : true;
+ for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
{
- MapNode<Platform, bool> mn;
+ if(mn.key == unknown || mn.value == opposite)
+ cleaned[mn.key] = mn.value;
+ }
+ delete exclusionInfo;
+ exclusionInfo = cleaned;
+ }
+ if(exclusionInfo.count > 1)
+ {
+ if(exclusionInfo.count > 2)
+ {
exp = result.a;
len = strlen(exp) + strlen("$(if $(or ");
exp = renew exp char[len+1];
strcat(exp, "$(if $(or ");
result.a = exp;
- for(mn = exclusion.platformSpecific.root.minimum; mn; mn = mn.next)
+ for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
{
- if(mn.value)
+ if(mn.key != unknown)
{
char * comma = mn.next ? "," : "";
- platform = mn.key;
- var = PlatformToMakefileVariable(platform);
+ var = PlatformToMakefileTargetVariable(mn.key);
exp = result.a;
len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
exp = result.a;
len = strlen(exp) + strlen("),");
exp = renew exp char[len+1];
- strcat(exp, "),");
- result.a = exp;
-
- exp = exclusion.excluded == true ? result.b : result.a;
- len = strlen(exp) + strlen(",");
- exp = renew exp char[len+1];
- strcat(exp, ",");
- if(exclusion.excluded == true) result.b = exp; else result.a = exp;
-
- exp = result.b;
- len = strlen(exp) + strlen(")");
- exp = renew exp char[len+1];
- strcat(exp, ")");
- result.b = exp;
}
- else if(exclusion.platformSpecific.count)
+ else
{
- platform = exclusion.platformSpecific.root.minimum.key;
- var = PlatformToMakefileVariable(platform);
+ if(exclusionInfo.root.minimum.key != unknown)
+ var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
+ else
+ var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
exp = result.a;
len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
exp = renew exp char[len+1];
strcat(exp, "$(if $(");
strcat(exp, var);
- strcat(exp, "),");
- result.a = exp;
+ }
- exp = exclusion.excluded == true ? result.b : result.a;
- len = strlen(exp) + strlen(",");
- exp = renew exp char[len+1];
- strcat(exp, ",");
- if(exclusion.excluded == true) result.b = exp; else result.a = exp;
+ strcat(exp, "),");
+ result.a = exp;
- exp = result.b;
- len = strlen(exp) + strlen(")");
- exp = renew exp char[len+1];
- strcat(exp, ")");
- result.b = exp;
- }
- return result;
+ exp = common == true ? result.b : result.a;
+ len = strlen(exp) + strlen(",");
+ exp = renew exp char[len+1];
+ strcat(exp, ",");
+ if(common == true) result.b = exp; else result.a = exp;
+
+ exp = result.b;
+ len = strlen(exp) + strlen(")");
+ exp = renew exp char[len+1];
+ strcat(exp, ")");
+ result.b = exp;
}
+ delete exclusionInfo;
+
+ return result;
}
- property bool isExcluded
+ bool GetIsExcluded(ProjectConfig prjConfig)
{
- get
+ bool result;
+ // note: unknown platform is for common
+ Map<Platform, SetBool> exclusionInfo { };
+ CollectExclusionInfo(exclusionInfo, prjConfig);
+ if(exclusionInfo.count == 0)
+ result = false;
+ else if(exclusionInfo.count == 1)
+ result = exclusionInfo.root.minimum.value == true;
+ else
{
- return exclusionInfo.excluded == true && exclusionInfo.platformSpecific.count == 0;
+ SetBool check = exclusionInfo.root.minimum.value;
+ MapNode<Platform, SetBool> mn;
+ for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
+ {
+ if(check != mn.value)
+ break;
+ }
+ if(!mn) // all are same
+ result = check == true;
+ else
+ result = false;
}
+ delete exclusionInfo;
+ return result;
}
- property BuildExclusionInfo exclusionInfo
+ void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
{
- get
+ // note: unknown platform is for common
+ Platform platform;
+ ProjectConfig config = GetMatchingNodeConfig(prjConfig);
+ ProjectOptions options = property::options;
+ Array<PlatformOptions> platforms = property::platforms;
+ List<ProjectConfig> configurations = property::configurations;
+
+ if(parent)
+ parent.CollectExclusionInfo(output, prjConfig);
+ else
+ output[unknown] = unset;
+
+ if(options && options.excludeFromBuild)
+ output[unknown] = options.excludeFromBuild;
+
+ if(config && config.options && config.options.excludeFromBuild)
+ output[unknown] = config.options.excludeFromBuild;
+
+ if(platforms)
{
- BuildExclusionInfo result { };
- ProjectConfig config = property::config;
- if(config && config.options && config.options.excludeFromBuild)
- result.excluded = config.options.excludeFromBuild;
- else if(options && options.excludeFromBuild)
- result.excluded = options.excludeFromBuild;
- else if(parent)
+ for(p : platforms)
{
- BuildExclusionInfo parentExclusion = parent.exclusionInfo;
- if(parentExclusion.excluded)
- {
- result.excluded = parentExclusion.excluded;
- if(parentExclusion.platformSpecific.count)
- {
- MapNode<Platform, bool> mn;
- for(mn = parentExclusion.platformSpecific.root.minimum; mn; mn = mn.next)
- {
- if(mn.value)
- {
- result.platformSpecific[mn.key] = true;
- }
- }
- }
- }
- if(result.excluded)
- {
- SetBool opposite = result.excluded == true ? false : true;
- Platform platform;
- if(platforms)
- {
- for(p : platforms)
- {
- if(p.options.excludeFromBuild == opposite && (platform = p.name))
- result.platformSpecific[platform] = true;
- }
- }
- if(config && config.platforms)
- {
- for(p : config.platforms)
- {
- if(p.options.excludeFromBuild == opposite && (platform = p.name))
- result.platformSpecific[platform] = true;
- }
- }
- }
+ if(p.options.excludeFromBuild && (platform = p.name))
+ output[platform] = p.options.excludeFromBuild;
+ }
+ }
+ if(config && config.platforms)
+ {
+ for(p : config.platforms)
+ {
+ if(p.options.excludeFromBuild && (platform = p.name))
+ output[platform] = p.options.excludeFromBuild;
}
- return result;
}
}
return result;
}
+ ProjectNode FindByFullPath(char * path, bool includeResources)
+ {
+ ProjectNode result = null;
+ if(files)
+ {
+ for(child : files)
+ {
+ if(includeResources || child.type != resources)
+ {
+ if(child.type != folder && child.name)
+ {
+ char p[MAX_LOCATION];
+ child.GetFullFilePath(p);
+ if(!strcmpi(p, path))
+ {
+ result = child;
+ break;
+ }
+ }
+ result = child.FindByFullPath(path, includeResources);
+ if(result)
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
{
ProjectNode result = null;
return result;
}
- ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
+ ProjectNode FindSameNameConflict(char * name, bool includeResources,
+ Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
{
- ProjectNode node = null;
- char temp[MAX_LOCATION];
-
- GetLastDirectory(filePath, temp);
- if(!checkIfExists || !project.topNode.Find(temp, false))
+ ProjectNode result = null;
+ Map<Platform, SetBool> compareExclusion { };
+ SetBool common, commonComp;
+ SetBool actual, actualComp;
+ if(files)
{
- // Do the check for folder in the same parent or resource files only here
- if(type == folder || !checkIfExists)
- {
- for(node : files)
- {
- if(node.name && !strcmpi(node.name, temp))
- return null;
- }
- }
-
- node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
- if(type != file)
- {
- node.files = { };
- node.nodeType = folder;
- }
- if(type != folder)
+ for(child : files)
{
- if(filePath)
+ if(includeResources || child.type != resources)
{
- StripLastDirectory(filePath, temp);
+ if(child.type != folder && child.name && !strcmpi(child.name, name))
+ {
+ child.CollectExclusionInfo(compareExclusion, prjConfig);
+ common = exclusionInfo[unknown];
+ commonComp = compareExclusion[unknown];
+ if(exclusionInfo.count == 1 && compareExclusion.count == 1)
+ {
+ if(!(common == true || commonComp == true))
+ {
+ result = child;
+ break;
+ }
+ }
+ else
+ {
+ Platform platform;
+ for(platform = (Platform)1; platform < Platform::enumSize; platform++)
+ {
+ actual = common;
+ actualComp = commonComp;
+ if(exclusionInfo[platform] != unset)
+ actual = exclusionInfo[platform];
+ if(compareExclusion[platform] != unset)
+ actualComp = compareExclusion[platform];
+ if(!(actual == true || actualComp == true))
+ {
+ result = child;
+ break;
+ }
+ }
+ if(result) break;
+ }
+ compareExclusion.Free();
+ break;
+ }
+ result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
+ if(result) break;
+ }
+ }
+ compareExclusion.Free();
+ }
+ delete compareExclusion;
+ return result;
+ }
+
+ ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
+ {
+ ProjectNode node = null;
+ char temp[MAX_LOCATION];
+ Map<Platform, SetBool> exclusionInfo { };
+
+ GetLastDirectory(filePath, temp);
+ //if(!checkIfExists || !project.topNode.Find(temp, false))
+
+ // TOCHECK: Shouldn't this apply either for all configs or none?
+ CollectExclusionInfo(exclusionInfo, project.config);
+ if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
+ {
+ // Do the check for folder in the same parent or resource files only here
+ if(type == folder || !checkIfExists)
+ {
+ for(node : files)
+ {
+ if(node.name && !strcmpi(node.name, temp))
+ return null;
+ }
+ }
+
+ node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
+ if(type != file)
+ {
+ node.files = { };
+ node.nodeType = folder;
+ }
+ if(type != folder)
+ {
+ if(filePath)
+ {
+ StripLastDirectory(filePath, temp);
MakePathRelative(temp, project.topNode.path, temp);
node.path = CopyUnixPath(temp);
}
}
files.Insert(after, node);
}
+ delete exclusionInfo;
return node;
}
return result;
}
- void GenFileFlags(File f, Project project)
+ bool ContainsFilesWithExtension(char * extension)
{
- ProjectNode node = null;
- List<ProjectNode> nodeStack { };
-
- for(node = this; node && node.parent; node = node.parent)
- nodeStack.Add(node);
-
- // Should we reverse this stack to give priority to the per-file includes?
-
- while((node = nodeStack.lastIterator.data))
+ if(type == file)
{
- ProjectConfig config = node.config;
- if(node.options && node.options.preprocessorDefinitions)
- OutputListOption(f, "D", node.options.preprocessorDefinitions, inPlace, false);
- if(config && config.options && config.options.preprocessorDefinitions)
- OutputListOption(f, "D", config.options.preprocessorDefinitions, inPlace, false);
- if(node.options && node.options.includeDirs)
- OutputListOption(f, "I", node.options.includeDirs, inPlace, true);
- if(config && config.options && config.options.includeDirs)
- OutputListOption(f, "I", config.options.includeDirs, inPlace, true);
-
- nodeStack.lastIterator.Remove();
+ char ext[MAX_EXTENSION];
+ GetExtension(name, ext);
+ if(!fstrcmp(ext, extension))
+ return true;
}
- delete nodeStack;
+ else if(files)
+ {
+ bool needed = false;
+ for(child : files)
+ if(child.ContainsFilesWithExtension(extension))
+ return true;
+ }
+ return false;
}
- void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo)
+ void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
{
if(type == file)
{
{
for(child : files)
{
- if(child.type != resources && (child.type == folder || !child.isExcluded))
- child.GenMakefileGetNameCollisionInfo(namesInfo);
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
}
}
}
- int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType, Map<String, NameCollisionInfo> namesInfo, Array<String> items)
+ int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
+ Map<String, NameCollisionInfo> namesInfo, Array<String> items,
+ ProjectConfig prjConfig, bool * containsCXX)
{
int count = 0;
if(type == file)
{
char s[2048];
- TwoStrings ts = platformSpecificFu;
+ TwoStrings ts = GetPlatformSpecificFu(prjConfig);
char moduleName[MAX_FILENAME];
char extension[MAX_EXTENSION];
GetExtension(name, extension);
{
if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
- !strcmpi(extension, "ec") || !strcmpi(extension, "m"))
+ !strcmpi(extension, "m"))
{
char modulePath[MAX_LOCATION];
items.Add(CopyString(s));
}
}
+ else if(printType == eCsources)
+ {
+ if(!strcmpi(extension, "ec"))
+ {
+ char modulePath[MAX_LOCATION];
+
+ ReplaceUnwantedMakeChars(modulePath, path);
+ ReplaceUnwantedMakeChars(moduleName, name);
+ sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
+ items.Add(CopyString(s));
+ count++;
+ }
+ }
else if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
!strcmpi(extension, "m"))
{
bool collision;
NameCollisionInfo info;
+ count++;
ReplaceSpaces(moduleName, name);
StripExtension(moduleName);
info = namesInfo[moduleName];
collision = info ? info.IsExtensionColliding(extension) : false;
sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
items.Add(CopyString(s));
+ if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
+ *containsCXX = true;
}
}
- else if(!strcmpi(extension, "ec"))
- {
- ReplaceSpaces(moduleName, name);
- StripExtension(moduleName);
- if(printType == objects)
- count++;
- s[0] = '\0';
- if(printType == objects)
- sprintf(s, "%s$(OBJ)%s.o%s", ts.a, moduleName, ts.b);
- else if(printType == cObjects)
- sprintf(s, "%s$(OBJ)%s.c%s", ts.a, moduleName, ts.b);
- else if(printType == symbols)
- sprintf(s, "%s$(OBJ)%s.sym%s", ts.a, moduleName, ts.b);
- else if(printType == imports)
- sprintf(s, "%s$(OBJ)%s.imp%s", ts.a, moduleName, ts.b);
- if(s[0])
- items.Add(CopyString(s));
- }
delete ts;
}
else if(files)
{
for(child : files)
{
- if(child.type != resources && (child.type == folder || !child.isExcluded))
- count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items);
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
}
}
return count;
}
- void GenMakefilePrintSymbolRules(File f, Project project)
+ void GenMakefilePrintSymbolRules(File f, Project project,
+ ProjectConfig prjConfig, Map<Platform, bool> parentExcludedPlatforms,
+ Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
{
+ int ifCount = 0;
+ Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
//ProjectNode child;
//char objDir[MAX_LOCATION];
- CompilerConfig compiler = GetCompilerConfig();
- //ReplaceSpaces(objDir, project.config.objDir.dir);
+ //ReplaceSpaces(objDir, config.objDir.dir);
//eSystem_Log("Printing Symbol Rules\n");
if(type == file)
char extension[MAX_EXTENSION];
char modulePath[MAX_LOCATION];
char moduleName[MAX_FILENAME];
-
+
GetExtension(name, extension);
if(!strcmpi(extension, "ec"))
{
if(!result)
{
#endif
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
moduleName, modulePath, moduleName, extension);
#if 0
modulePath, moduleName, extension, moduleName);
*/
- f.Printf("\t$(ECP) $(CECFLAGS)");
- if(ecflags)
+ f.Puts("\t$(ECP)");
+
+ f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
+
+ GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
+ GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
+
+ f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n\n",
+ modulePath, moduleName, extension, moduleName);
+ CloseRulesPlatformExclusionIfs(f, ifCount);
+ }
+ }
+ if(files)
+ {
+ bool needed = false;
+ if(ContainsFilesWithExtension("ec"))
+ {
+ for(child : files)
{
- if(memoryGuard)
- f.Printf(" -memguard");
- if(strictNameSpaces)
- f.Printf(" -strictns");
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
{
- char * s = defaultNameSpace;
- if(s && s[0])
- f.Printf(" -defaultns %s", s);
+ needed = true;
+ break;
}
}
- else
- f.Printf(" $(ECFLAGS)");
- f.Printf(" $(CFLAGS)");
- GenFileFlags(f, project);
- f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n\n",
+ }
+ if(needed)
+ {
+ Map<Platform, bool> excludedPlatforms { };
+ for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
+ for(platform : platforms)
+ {
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
+ for(child : files)
+ {
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ child.GenMakefilePrintSymbolRules(f, project, prjConfig, excludedPlatforms,
+ nodeCFlagsMapping, nodeECFlagsMapping);
+ }
+ }
+ CloseRulesPlatformExclusionIfs(f, ifCount);
+ delete excludedPlatforms;
+ }
+ }
+ delete platforms;
+ }
+
+ void GenMakefilePrintPrepecsRules(File f, Project project,
+ ProjectConfig prjConfig, Map<Platform, bool> parentExcludedPlatforms,
+ Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
+ {
+ int ifCount = 0;
+ ProjectConfig config = GetMatchingNodeConfig(prjConfig);
+ Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
+ //ProjectNode child;
+ //char objDir[MAX_LOCATION];
+ //ReplaceSpaces(objDir, config.objDir.dir);
+
+ //eSystem_Log("Printing Symbol Rules\n");
+ if(type == file)
+ {
+ char extension[MAX_EXTENSION];
+ char modulePath[MAX_LOCATION];
+ char moduleName[MAX_FILENAME];
+
+ GetExtension(name, extension);
+ if(!strcmpi(extension, "ec"))
+ {
+ DualPipe dep;
+ char command[2048];
+
+ ReplaceSpaces(moduleName, name);
+ StripExtension(moduleName);
+
+ ReplaceSpaces(modulePath, path);
+ if(modulePath[0]) strcat(modulePath, SEPS);
+
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
+ f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
+ moduleName, modulePath, moduleName, extension);
+ //$(CPP) -x c -E ../extras/gui/controls/DirectoriesBox.ec -o $(OBJ)DirectoriesBox$(EC)
+ /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
+ modulePath, moduleName, extension, moduleName);*/
+
+ f.Puts("\t$(CPP)");
+
+ //f.Puts(" $(CECFLAGS)");
+ //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
+ GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
+
+ f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n\n",
modulePath, moduleName, extension, moduleName);
+ CloseRulesPlatformExclusionIfs(f, ifCount);
}
}
if(files)
{
- for(child : files)
+ bool needed = false;
+ if(ContainsFilesWithExtension("ec"))
{
- // TODO: Platform specific options
- if(child.type != resources && (child.type == folder || !child.isExcluded))
- child.GenMakefilePrintSymbolRules(f, project);
+ for(child : files)
+ {
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ {
+ needed = true;
+ break;
+ }
+ }
+ }
+ if(needed)
+ {
+ Map<Platform, bool> excludedPlatforms { };
+ for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
+ for(platform : platforms)
+ {
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
+ for(child : files)
+ {
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ child.GenMakefilePrintPrepecsRules(f, project, prjConfig, excludedPlatforms,
+ nodeCFlagsMapping, nodeECFlagsMapping);
+ }
+ }
+ CloseRulesPlatformExclusionIfs(f, ifCount);
+ delete excludedPlatforms;
}
}
- delete compiler;
+ delete platforms;
}
- void GenMakefilePrintCObjectRules(File f, Project project)
+ void GenMakefilePrintCObjectRules(File f, Project project,
+ ProjectConfig prjConfig, Map<Platform, bool> parentExcludedPlatforms,
+ Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
{
+ int ifCount = 0;
+ ProjectConfig config = GetMatchingNodeConfig(prjConfig);
+ Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
//ProjectNode child;
//char objDir[MAX_LOCATION];
- CompilerConfig compiler = GetCompilerConfig();
- //ReplaceSpaces(objDir, project.config.objDir.dir);
+ //ReplaceSpaces(objDir, config.objDir.dir);
//eSystem_Log("Printing C Object Rules\n");
if(type == file)
{
char extension[MAX_EXTENSION];
char modulePath[MAX_LOCATION];
char moduleName[MAX_FILENAME];
-
+
GetExtension(name, extension);
if(!strcmpi(extension, "ec"))
{
strcat(command, item);
}
- for(item : project.config.includeDirs)
+ for(item : config.includeDirs)
{
strcat(command, " -I");
if(strchr(item, ' '))
else
strcat(command, item);
}
- for(item : project.config.preprocessorDefs)
+ for(item : config.preprocessorDefs)
{
strcat(command, " -D");
strcat(command, item);
moduleName, modulePath, moduleName, extension);
*/
#endif
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
moduleName, modulePath, moduleName, extension, moduleName);
#if 0
modulePath, moduleName, extension, moduleName);
*/
- f.Printf("\t$(ECC)");
- if(ecflags)
- {
- f.Printf("%s $(CECFLAGS)", noLineNumbers ? " -nolinenumbers" : "");
- if(memoryGuard)
- f.Printf(" -memguard");
- if(strictNameSpaces)
- f.Printf(" -strictns");
- {
- char * s = defaultNameSpace;
- if(s && s[0])
- f.Printf(" -defaultns %s", s);
- }
- }
- else
- f.Printf(" $(CECFLAGS) $(ECFLAGS)");
- f.Printf(" $(CFLAGS) $(FVISIBILITY)");
- GenFileFlags(f, project);
+ f.Puts("\t$(ECC)");
+
+ f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
+ GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
+ GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
+ f.Puts(" $(FVISIBILITY)");
+
f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n\n",
modulePath, moduleName, extension, moduleName);
+ CloseRulesPlatformExclusionIfs(f, ifCount);
}
}
if(files)
{
- for(child : files)
+ bool needed = false;
+ if(ContainsFilesWithExtension("ec"))
{
- // TODO: Platform specific options
- if(child.type != resources && (child.type == folder || !child.isExcluded))
- child.GenMakefilePrintCObjectRules(f, project);
+ for(child : files)
+ {
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ {
+ needed = true;
+ break;
+ }
+ }
+ }
+ if(needed)
+ {
+ Map<Platform, bool> excludedPlatforms { };
+ for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
+ for(platform : platforms)
+ {
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
+ for(child : files)
+ {
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ child.GenMakefilePrintCObjectRules(f, project, prjConfig, excludedPlatforms,
+ nodeCFlagsMapping, nodeECFlagsMapping);
+ }
+ }
+ CloseRulesPlatformExclusionIfs(f, ifCount);
+ delete excludedPlatforms;
}
}
- delete compiler;
+ delete platforms;
}
- void GenMakefilePrintObjectRules(File f, Project project, Map<String, NameCollisionInfo> namesInfo)
+ void GenMakefilePrintObjectRules(File f, Project project,
+ Map<String, NameCollisionInfo> namesInfo,
+ ProjectConfig prjConfig,
+ Map<Platform, bool> parentExcludedPlatforms,
+ Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
{
+ int ifCount = 0;
+ ProjectConfig config = GetMatchingNodeConfig(prjConfig);
+ Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
//ProjectNode child;
//char objDir[MAX_LOCATION];
- CompilerConfig compiler = GetCompilerConfig();
- //ReplaceSpaces(objDir, project.config.objDir.dir);
+ //ReplaceSpaces(objDir, config.objDir.dir);
//eSystem_Log("Printing Object Rules\n");
if(type == file)
{
char extension[MAX_EXTENSION];
char modulePath[MAX_LOCATION];
char moduleName[MAX_FILENAME];
-
+
GetExtension(name, extension);
/*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
!strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
!strcmpi(extension, "cxx"))*/
- if((!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
- !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")) ||
- !strcmpi(extension, "ec"))
+ if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
+ !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
+ !strcmpi(extension, "m") || !strcmpi(extension, "ec"))
{
DualPipe dep;
char command[2048];
// *** Dependency command ***
if(!strcmpi(extension, "ec"))
- sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", compiler.ccCommand, moduleName, moduleName);
+ sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
else
- sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", compiler.ccCommand, moduleName, modulePath, moduleName, extension);
+ sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
+ moduleName, modulePath, moduleName, extension);
if(!strcmpi(extension, "ec"))
f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
strcat(command, item);
}
- for(item : project.config.includeDirs)
+ for(item : config.includeDirs)
{
strcat(command, " -I");
if(strchr(item, ' '))
else
strcat(command, item);
}
- for(item : project.config.preprocessorDefs)
+ for(item : config.preprocessorDefs)
{
strcat(command, " -D");
strcat(command, item);
if(!result)
{
#endif
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
+
/*if(!strcmpi(extension, "ec"))
f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
else*/
}
#endif
}
- f.Printf("\t$(CC) $(CFLAGS)");
- GenFileFlags(f, project);
+ f.Printf("\t$(%s)", (!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx")) ? "CXX" : "CC");
+
+ GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
+
if(!strcmpi(extension, "ec"))
f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n\n", moduleName, moduleName);
else
f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n\n",
modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
collision ? "." : "", collision ? extension : "");
+ CloseRulesPlatformExclusionIfs(f, ifCount);
}
}
if(files)
{
+ bool needed = false;
for(child : files)
{
- // TODO: Platform specific options
- if(child.type != resources && (child.type == folder || !child.isExcluded))
- child.GenMakefilePrintObjectRules(f, project, namesInfo);
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ {
+ needed = true;
+ break;
+ }
+ }
+ if(needed)
+ {
+ Map<Platform, bool> excludedPlatforms { };
+ for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
+ for(platform : platforms)
+ {
+ OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
+ for(child : files)
+ {
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, excludedPlatforms,
+ nodeCFlagsMapping, nodeECFlagsMapping);
+ }
+ }
+ CloseRulesPlatformExclusionIfs(f, ifCount);
+ delete excludedPlatforms;
}
}
- delete compiler;
+ delete platforms;
}
- void GenMakefileAddResources(File f, String resourcesPath)
+ void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
{
int count = 0;
if(files)
for(c = 0; c < files.count; c++)
{
ProjectNode child = files[c];
- TwoStrings ts = child.platformSpecificFu;
+ TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
if(count > 0 && ts)
prev = true;
- if(child.type == file && !child.isExcluded && !(count > 0 && ts))
+ if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
{
bool useRes;
char tempPath[MAX_LOCATION];
// $(EAR) aw%s --- /*quiet ? "q" : */""
if(count == 0)
- f.Printf("\t%s$(EAR) aw $(TARGET)", ts.a);
+ f.Printf("\t%s$(EAR) $(EARFLAGS) $(TARGET)", ts.a);
tempPath[0] = '\0';
if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
quotes = "\"";
else
quotes = "";
- f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", resPath, quotes);
+ f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", tempPath, quotes);
count++;
}
if(count == 10 || (count > 0 && (ts || !child.next)))
for(child : files)
{
if(child.type == folder)
- child.GenMakefileAddResources(f, resourcesPath);
+ child.GenMakefileAddResources(f, resourcesPath, prjConfig);
}
}
}
+
+ void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
+ Map<String, int> cflagsVariations, Map<int, int> nodeCFlagsMapping,
+ Map<String, int> ecflagsVariations, Map<int, int> nodeECFlagsMapping,
+ Map<Platform, ProjectOptions> parentByPlatformOptions)
+ {
+ Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
+ if(type == file || type == folder || type == project)
+ {
+ bool hasPerNodeOptions = type == project;
+ if(!hasPerNodeOptions)
+ {
+ if(options && !options.isEmpty)
+ hasPerNodeOptions = true;
+ else if(configurations)
+ {
+ for(c : configurations)
+ {
+ if(c.options && !c.options.isEmpty)
+ {
+ hasPerNodeOptions = true;
+ break;
+ }
+ if(c.platforms)
+ {
+ for(p : c.platforms)
+ {
+ if(p.options && !p.options.isEmpty)
+ {
+ hasPerNodeOptions = true;
+ break;
+ }
+ }
+ if(hasPerNodeOptions)
+ break;
+ }
+ }
+ }
+ if(!hasPerNodeOptions && platforms)
+ {
+ for(p : platforms)
+ {
+ if(p.options && !p.options.isEmpty)
+ {
+ hasPerNodeOptions = true;
+ break;
+ }
+ }
+ }
+
+ }
+ if(hasPerNodeOptions)
+ {
+ bool isEqual = false, isGreater = false;
+ ComplexComparison complexCmp;
+ DynamicString s;
+ Map<Platform, ProjectOptions> additionsByPlatformOptions { };
+ ProjectOptions platformsCommonOptions;
+ ProjectOptions byFileConfigPlatformProjectOptions;
+
+ DynamicString cflags { };
+ DynamicString ecflags { };
+
+ Platform platform;
+
+ byPlatformOptions = { };
+
+ for(platform = (Platform)1; platform < Platform::enumSize; platform++)
+ {
+ byFileConfigPlatformProjectOptions =
+ BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
+ byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
+ }
+
+ CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
+
+ byPlatformOptions[unknown] = platformsCommonOptions;
+
+ if(parentByPlatformOptions)
+ {
+ complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
+ parentByPlatformOptions, additionsByPlatformOptions);
+ isGreater = complexCmp == greater;
+ isEqual = complexCmp == equal;
+ }
+
+ if(!isEqual)
+ {
+ if(!isGreater)
+ {
+ // absolutely common stuff outside of platform only, stuff that can't be changed by platform
+ // This would normally go in crossplatform.mk (or compiler.cf if compiler-specific)
+ // cflags.concatf(" \\\n\t $(if $(DEBIAN_PACKAGE),$(CPPFLAGS),) $(if $(DEBUG), -D_DEBUG,)");
+ }
+
+ for(platform = (Platform)1; platform < Platform::enumSize; platform++)
+ {
+ byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
+ s = { };
+ GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
+ if(s.count > 1)
+ cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
+ delete s;
+ s = { };
+ GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
+ if(s.count > 1)
+ ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
+ delete s;
+ }
+
+ platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
+ s = { };
+ GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
+ if(s.count > 1)
+ cflags.concatf(isGreater ? "%s" : " \\\n\t%s", (String)s);
+ delete s;
+ s = { };
+ GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
+ if(s.count > 1)
+ ecflags.concatf(" \\\n\t%s", (String)s);
+ delete s;
+
+ if(isGreater)
+ {
+ cflags.concatf(" \\\n\t");
+ DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "CFLAGS", cflags);
+ }
+ }
+
+ additionsByPlatformOptions.Free();
+ delete additionsByPlatformOptions;
+
+ // output
+ {
+ if(isEqual)
+ {
+ nodeCFlagsMapping[(int)this] = nodeCFlagsMapping[(int)parent];
+ nodeECFlagsMapping[(int)this] = nodeECFlagsMapping[(int)parent];
+ }
+ else
+ {
+ String s;
+ int variationNum;
+
+ variationNum = 1;
+ if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
+ cflagsVariations[s] = variationNum = cflagsVariations.count;
+ nodeCFlagsMapping[(int)this] = variationNum;
+
+ variationNum = 1;
+ if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
+ ecflagsVariations[s] = variationNum = ecflagsVariations.count;
+ nodeECFlagsMapping[(int)this] = variationNum;
+ }
+ }
+
+ delete cflags;
+ delete ecflags;
+ }
+ else
+ {
+ // output
+ {
+ nodeCFlagsMapping[(int)this] = nodeCFlagsMapping[(int)parent];
+ nodeECFlagsMapping[(int)this] = nodeECFlagsMapping[(int)parent];
+ }
+ }
+
+ }
+ if(files)
+ {
+ for(child : files)
+ {
+ if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
+ child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
+ cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
+ byPlatformOptions);
+ }
+ }
+
+ if(byPlatformOptions != parentByPlatformOptions)
+ {
+ byPlatformOptions.Free();
+ delete byPlatformOptions;
+ }
+ }
+
+ Array<Platform> GetPlatformsArrayFromExcluisionInfo(ProjectConfig prjConfig)
+ {
+ Array<Platform> platforms { };
+ Map<Platform, SetBool> exclusionInfo { };
+ CollectExclusionInfo(exclusionInfo, prjConfig);
+ if(exclusionInfo[unknown] == true && exclusionInfo.count > 1)
+ for(mn : exclusionInfo; mn == false)
+ platforms.Add(&mn);
+ else
+ platforms.Add(unknown);
+ delete exclusionInfo;
+ return platforms;
+ }
+}
+
+// the code in this function is closely matched to OptionsBox::Load
+// and accompanying derivations of OptionBox and their use of OptionSet,
+// OptionCheck, LoadOption and FinalizeLoading methods.
+// output changing modification should be mirrored in both implementations
+static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
+{
+ ProjectOptions output { };
+
+ // legend: e Element
+ // o Option (of a ProjectOptions)
+ // n Node (ProjectNode)
+ // p Platform
+ // u Utility (GenericOptionTools)
+
+ int e;
+ int o;
+ int priority = 0;
+ int includeDirsOption = OPTION(includeDirs);
+ ProjectNode n;
+ char * platformName = platform ? platform.OnGetString(0,0,0) : null;
+
+ Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
+ Array<bool> optionDone { size = OPTION(postbuildCommands) };
+ Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
+
+ GenericOptionTools<SetBool> utilSetBool {
+ bool OptionCheck(ProjectOptions options, int option) {
+ return *(SetBool*)((byte *)options + option) == true;
+ }
+ void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
+ if(options && (*(SetBool*)((byte *)options + option) == true))
+ *(SetBool*)((byte *)output + option) = true;
+ }
+ };
+ GenericOptionTools<String> utilString {
+ void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
+ String * string = (String*)((byte *)output + option);
+ if(*string) delete *string;
+ if(options)
+ *string = CopyString(*(String*)((byte *)options + option));
+ }
+ };
+ StringArrayOptionTools utilStringArrays {
+ mergeValues = true;
+ caseSensitive = true;
+ bool OptionCheck(ProjectOptions options, int option) {
+ String string = *(String*)((byte *)options + option);
+ return string && string[0];
+ }
+ bool OptionSet(ProjectOptions options, int option) {
+ Array<String> strings = *(Array<String>*)((byte *)options + option);
+ if(mergeValues && !configReplaces)
+ return strings && strings.count;
+ else
+ return strings != null;
+ }
+ void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
+ if(mergeValues)
+ {
+ Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
+ if(strings)
+ {
+ int order = 0;
+ Array<String> tempStrings = optionTempStrings[option];
+ if(!tempStrings)
+ optionTempStrings[option] = tempStrings = { };
+ for(s : strings)
+ {
+ bool found = false;
+ char priorityMark[10];
+ order++;
+ if(priority)
+ sprintf(priorityMark, "%04d\n", priority * 100 + order);
+ for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
+ if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
+ }
+ }
+ }
+ else
+ {
+ Array<String> * newStrings = (Array<String>*)((byte *)options + option);
+ Array<String> * strings = (Array<String>*)((byte *)output + option);
+ if(*strings) { strings->Free(); delete *strings; }
+ if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
+ }
+ }
+ void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
+ if(mergeValues)
+ {
+ Array<String> tempStrings = optionTempStrings[option];
+ Array<String> * strings = (Array<String>*)((byte *)output + option);
+ if(*strings) { strings->Free(); delete *strings; }
+ if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
+ delete tempStrings;
+ }
+ }
+ };
+ GenericOptionTools<WarningsOption> utilWarningsOption {
+ bool OptionCheck(ProjectOptions options, int option) {
+ WarningsOption value = *(WarningsOption*)((byte *)options + option);
+ return value && value != none;
+ }
+ void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
+ WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
+ *(WarningsOption*)((byte *)output + option) = value;
+ }
+ };
+ GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
+ bool OptionCheck(ProjectOptions options, int option) {
+ OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
+ return value && value != none;
+ }
+ void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
+ OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
+ *(OptimizationStrategy*)((byte *)output + option) = value;
+ }
+ };
+ GenericOptionTools<BuildBitDepth> utilBuildBitDepth {
+ bool OptionCheck(ProjectOptions options, int option) {
+ BuildBitDepth value = *(BuildBitDepth*)((byte *)options + option);
+ return value && value != all;
+ }
+ void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
+ BuildBitDepth value = options ? *(BuildBitDepth*)((byte *)options + option) : (BuildBitDepth)0;
+ *(BuildBitDepth*)((byte *)output + option) = value;
+ }
+ };
+
+ Map<int, GenericOptionTools> ot { };
+
+ // The following are compiler options
+
+ ot[OPTION(debug)] = utilSetBool;
+ ot[OPTION(memoryGuard)] = utilSetBool;
+ ot[OPTION(profile)] = utilSetBool;
+ ot[OPTION(noLineNumbers)] = utilSetBool;
+ ot[OPTION(strictNameSpaces)] = utilSetBool;
+ ot[OPTION(fastMath)] = utilSetBool;
+
+ ot[OPTION(defaultNameSpace)] = utilString;
+
+ ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
+ ot[OPTION(includeDirs)] = utilStringArrays;
+
+ ot[OPTION(warnings)] = utilWarningsOption;
+
+ ot[OPTION(optimization)] = utilOptimizationStrategy;
+
+ ot[OPTION(buildBitDepth)] = utilBuildBitDepth;
+
+ for(n = node; n; n = n.parent)
+ {
+ ProjectConfig nodeConfig = null;
+ if(n.parent)
+ priority++;
+ else
+ priority = 99;
+ if(projectConfig && n.configurations)
+ {
+ for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
+ {
+ if(platform && c.platforms)
+ {
+ for(p : c.platforms; !strcmpi(p.name, platformName))
+ {
+ for(uu : ot)
+ {
+ GenericOptionTools u = uu;
+ o = &uu;
+ if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
+ {
+ u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
+ if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
+ optionConfigXplatformSet[o] = true;
+ }
+ }
+ break;
+ }
+ }
+ nodeConfig = c;
+ break;
+ }
+ }
+ for(uu : ot)
+ {
+ GenericOptionTools u = uu;
+ o = &uu;
+ if(!optionDone[o])
+ {
+ if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
+ {
+ for(p : n.platforms; !strcmpi(p.name, platformName))
+ {
+ if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
+ {
+ u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
+ if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
+ }
+ break;
+ }
+ }
+ if(!optionDone[o] && nodeConfig && nodeConfig.options &&
+ ((u.mergeValues && !u.configReplaces) ?
+ u.OptionCheck(nodeConfig.options, o) :
+ u.OptionSet(nodeConfig.options, o)))
+ {
+ u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
+ if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
+ }
+ if(!optionDone[o])
+ {
+ if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
+ {
+ u.LoadOption(n.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
+ if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
+ }
+ else if(!n.parent)
+ {
+ u.LoadOption(null, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
+ if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
+ }
+ }
+ }
+ }
+ }
+ for(uu : ot)
+ {
+ GenericOptionTools u = uu;
+ o = &uu;
+ if(!optionDone[o])
+ u.FinalizeLoading(o, optionTempStrings, output);
+ }
+
+ delete optionConfigXplatformSet;
+ delete optionDone;
+ delete optionTempStrings;
+
+ delete utilSetBool;
+ delete utilString;
+ delete utilStringArrays;
+ delete utilWarningsOption;
+ delete utilOptimizationStrategy;
+ delete utilBuildBitDepth;
+
+ delete ot;
+
+ return output;
+}
+
+static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
+{
+ char * s;
+ int i;
+ ProjectOptions first;
+ ProjectOptions commonOptions;
+
+ Map<String, int> countIncludeDirs { };
+ Map<String, int> countPreprocessorDefinitions { };
+ Map<String, bool> commonIncludeDirs { };
+ Map<String, bool> commonPreprocessorDefinitions { };
+
+ for(options : byPlatformOptions) { first = options; break; }
+
+ *platformsCommonOptions = commonOptions = first.Copy();
+
+ if(commonOptions.includeDirs)
+ commonOptions.includeDirs.Free();
+ if(commonOptions.preprocessorDefinitions)
+ commonOptions.preprocessorDefinitions.Free();
+
+ for(options : byPlatformOptions)
+ {
+ if(options != first)
+ {
+ if(commonOptions.debug && options.debug != commonOptions.debug)
+ commonOptions.debug = unset;
+ if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
+ commonOptions.memoryGuard = unset;
+ if(commonOptions.profile && options.profile != commonOptions.profile)
+ commonOptions.profile = unset;
+ if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
+ commonOptions.noLineNumbers = unset;
+ if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
+ commonOptions.strictNameSpaces = unset;
+ if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
+ commonOptions.fastMath = unset;
+
+ if(commonOptions.warnings && options.warnings != commonOptions.warnings)
+ commonOptions.warnings = unset;
+ if(commonOptions.optimization && options.optimization != commonOptions.optimization)
+ commonOptions.optimization = unset;
+ if(commonOptions.buildBitDepth && options.buildBitDepth != commonOptions.buildBitDepth)
+ commonOptions.buildBitDepth = all;
+
+ if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
+ delete commonOptions.defaultNameSpace;
+ }
+
+ CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
+ CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
+ }
+
+ GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
+ commonIncludeDirs, commonOptions.includeDirs);
+ GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
+ commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
+
+ for(options : byPlatformOptions)
+ {
+ if(options.debug && options.debug == commonOptions.debug)
+ options.debug = unset;
+ if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
+ options.memoryGuard = unset;
+ if(options.profile && options.profile == commonOptions.profile)
+ options.profile = unset;
+ if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
+ options.noLineNumbers = unset;
+ if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
+ options.strictNameSpaces = unset;
+ if(options.fastMath && options.fastMath == commonOptions.fastMath)
+ options.fastMath = unset;
+
+ if(options.warnings && options.warnings == commonOptions.warnings)
+ options.warnings = unset;
+ if(options.optimization && options.optimization == commonOptions.optimization)
+ options.optimization = unset;
+ if(options.buildBitDepth && options.buildBitDepth == commonOptions.buildBitDepth)
+ options.buildBitDepth = all;
+
+ if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
+ delete options.defaultNameSpace;
+
+ RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
+ RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
+ }
+
+ delete countIncludeDirs;
+ delete countPreprocessorDefinitions;
+ delete commonIncludeDirs;
+ delete commonPreprocessorDefinitions;
+}
+
+static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
+ Map<Platform, ProjectOptions> parentByPlatformOptions,
+ Map<Platform, ProjectOptions> additionsByPlatformOptions)
+{
+ ComplexComparison result = equal;
+ ComplexComparison compare;
+ Platform platform;
+ for(platform = (Platform)0; platform < Platform::enumSize; platform++)
+ {
+ ProjectOptions additionalOptions;
+ additionsByPlatformOptions[platform] = { };
+ additionalOptions = additionsByPlatformOptions[platform];
+ compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
+ if(compare == greater && result == equal)
+ result = greater;
+ else if(compare == different)
+ {
+ result = different;
+ break;
+ }
+ }
+ return result;
+}
+
+static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
+{
+ ComplexComparison result = equal;
+ if(options.debug != parentOptions.debug ||
+ options.memoryGuard != parentOptions.memoryGuard ||
+ options.profile != parentOptions.profile ||
+ options.noLineNumbers != parentOptions.noLineNumbers ||
+ options.strictNameSpaces != parentOptions.strictNameSpaces ||
+ options.fastMath != parentOptions.fastMath ||
+ options.warnings != parentOptions.warnings ||
+ options.optimization != parentOptions.optimization ||
+ (options.defaultNameSpace != parentOptions.defaultNameSpace &&
+ strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
+ result = different;
+ else
+ {
+ if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
+ !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
+ result = different;
+ if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
+ (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
+ result = greater;
+ }
+ return result;
+}
+
+enum ComplexComparison { different/*, smaller*/, equal, greater };
+
+static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
+{
+ bool result = true;
+ if((!strings || !strings.count) && originals && originals.count)
+ result = false;
+ else if(strings && strings.count && (!originals || !originals.count))
+ {
+ if(!*additions)
+ *additions = { };
+ for(s : strings)
+ additions->Add(CopyString(s));
+ }
+ else if(strings && strings.count && originals && originals.count)
+ {
+ Map<String, String> map { };
+ MapIterator<String, bool> mit { map = map };
+ for(it : strings)
+ {
+ char * s = strstr(it, "\n");
+ s = s ? s+1 : it;
+ map[s] = it;
+ }
+ for(it : originals)
+ {
+ char * s = strstr(it, "\n");
+ s = s ? s+1 : it;
+ if(!mit.Index(s, false))
+ {
+ result = false;
+ break;
+ }
+ else
+ map[s] = null;
+ }
+ if(result)
+ {
+ if(!*additions)
+ *additions = { };
+ for(it : map)
+ {
+ if(it)
+ additions->Add(CopyString(it));
+ }
+ }
+ delete map;
+ }
+ return result;
+}
+
+static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
+{
+ if(strings)
+ {
+ for(it : strings)
+ {
+ char * s = it;
+ if(s && s[0])
+ counts[s]++;
+ }
+ }
+}
+
+static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
+{
+ for(it : counts)
+ {
+ int i = it;
+ if(i == goodCount)
+ {
+ char * s = ⁢
+ strings.Add(CopyString(s));
+ common[s] = true;
+ }
+ }
+}
+
+static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
+{
+ if(strings)
+ {
+ Array<String> tmp { };
+ MapIterator<String, bool> mit { map = common };
+ for(it : strings)
+ {
+ char * s = it;
+ if(!mit.Index(s, false))
+ tmp.Add(CopyString(s));
+ }
+ strings.Free();
+ if(tmp.count)
+ {
+ for(s : tmp)
+ strings.Add(CopyString(s));
+ tmp.Free();
+ }
+ delete tmp;
+ }
+}
+
+static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<int, int> nodeFlagsMapping, String variableName, File f)
+{
+ int customFlags;
+ customFlags = nodeFlagsMapping[(int)node];
+ if(customFlags > 1)
+ f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
+ else
+ f.Printf(" $(%s)", variableName);
+}
+
+static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<int, int> nodeFlagsMapping, String variableName, DynamicString s)
+{
+ int customFlags;
+ customFlags = nodeFlagsMapping[(int)node];
+ if(customFlags > 1)
+ s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
+ else
+ s.concatf(" $(%s)", variableName);
+}
+
+static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
+{
+ if(!isGreater)
+ {
+ //if(gccCompiler)
+ {
+ if(options.optimization == speed || options.optimization == size ||
+ options.fastMath == true || options.debug == true)
+ {
+ if(options.debug != true)
+ {
+ s.concatf(" $(if $(DEBUG),");
+ s.concatf(" -g");
+ s.concatf(",");
+ }
+ switch(options.optimization)
+ {
+ case speed: s.concatf(" -O2"); break;
+ case size: s.concatf(" -Os"); break;
+ }
+ if(options.fastMath == true)
+ s.concatf(" -ffast-math");
+ if(options.debug == true)
+ s.concatf(" -g");
+ if(options.debug != true)
+ s.concatf(")");
+ }
+ else if(commonOptions)
+ s.concatf(" $(if $(DEBUG),-g)");
+ if(options.buildBitDepth || (commonOptions && prjWithEcFiles))
+ s.concatf(" %s", (!options || !options.buildBitDepth || options.buildBitDepth == bits32) ? "$(FORCE_32_BIT)" : "$(FORCE_64_BIT)");
+ if(commonOptions)
+ s.concatf(" $(FPIC)");
+ }
+ switch(options.warnings)
+ {
+ case all: s.concatf(" -Wall"); break;
+ case none: s.concatf(" -w"); break;
+ }
+ if(options.profile)
+ s.concatf(" -pg");
+ }
+
+ if(options && options.preprocessorDefinitions)
+ ListOptionToDynamicString("D", options.preprocessorDefinitions, false, lineEach, "\t\t\t", false, s);
+ if(options && options.includeDirs)
+ ListOptionToDynamicString("I", options.includeDirs, true, lineEach, "\t\t\t", true, s);
+}
+
+static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
+{
+ if(options.memoryGuard == true)
+ s.concat(" -memguard");
+ if(options.noLineNumbers == true)
+ s.concat(" -nolinenumbers");
+ if(options.strictNameSpaces == true)
+ s.concat(" -strictns");
+ if(options.defaultNameSpace && options.defaultNameSpace[0])
+ s.concatf(" -defaultns %s", options.defaultNameSpace);
+}
+
+static void ListOptionToDynamicString(char * option, Array<String> list, bool prioritize,
+ ListOutputMethod method, String newLineStart, bool noSpace, DynamicString s)
+{
+ if(list.count)
+ {
+ if(method == newLine)
+ s.concatf(" \\\n%s", newLineStart);
+ if(prioritize)
+ {
+ Map<String, int> sortedList { };
+ MapNode<String, int> mn;
+ for(item : list)
+ sortedList[item] = 1;
+ for(mn = sortedList.root.minimum; mn; mn = mn.next)
+ {
+ char * start = strstr(mn.key, "\n");
+ if(method == lineEach)
+ s.concatf(" \\\n%s", newLineStart);
+ s.concatf(" -%s", option);
+ if(noSpace)
+ StringNoSpaceToDynamicString(s, start ? start+1 : mn.key);
+ else
+ s.concat(start ? start+1 : mn.key);
+ }
+ delete sortedList;
+ }
+ else
+ {
+ for(item : list)
+ {
+ if(method == lineEach)
+ s.concatf(" \\\n%s", newLineStart);
+ s.concatf(" -%s", option);
+ if(noSpace)
+ StringNoSpaceToDynamicString(s, item);
+ else
+ s.concat(item);
+ }
+ }
+ }
+}
+
+class GenericOptionTools<class X>
+{
+ bool mergeValues, configReplaces;
+
+ virtual bool OptionSet(ProjectOptions options, int option) {
+ if(*(X*)((byte *)options + option))
+ return true;
+ return false;
+ }
+
+ // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
+
+ virtual bool OptionCheck(ProjectOptions options, int option) {
+ return OptionSet(options, option);
+ }
+
+ virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
+ virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
+}
+
+class StringArrayOptionTools : GenericOptionTools<Array<String>>
+{
+ bool caseSensitive;
}
class NameCollisionInfo
return colliding;
}
}
+
+static inline void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Platform platform,
+ Map<Platform, bool> parentExcludedPlatforms, Map<Platform, bool> excludedPlatforms)
+{
+ if(platform != unknown && !parentExcludedPlatforms[platform])
+ {
+ if(*ifCount) // we really need a if defined(a) || defined(b) here
+ f.Puts("else\n"); // instead of repeating the rules for each platform
+ (*ifCount)++; // hmm... what?
+ f.Printf("ifdef %s\n\n", PlatformToMakefileTargetVariable(platform));
+ if(excludedPlatforms)
+ excludedPlatforms[platform] = true;
+ }
+}
+
+static inline void CloseRulesPlatformExclusionIfs(File f, int ifCount)
+{
+ if(ifCount)
+ {
+ int c;
+ for(c = 0; c < ifCount; c++)
+ f.Puts("endif\n");
+ f.Puts("\n");
+ }
+}