1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(&((ProjectOptions)0).x))
17 bool eString_PathInsideOfMore(char * path, char * of, char * pathRest)
19 if(!path[0] || !of[0])
20 return false; // What to do here? Ever used?
23 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
24 char pathPart[MAX_FILENAME]; //, pathRest[MAX_LOCATION];
26 strcpy(pathRest, path);
27 for(; ofRest[0] && pathRest[0];)
29 SplitDirectory(ofRest, ofPart, ofRest);
30 SplitDirectory(pathRest, pathPart, pathRest);
31 if(fstrcmp(pathPart, ofPart))
34 if(!ofRest[0] && !pathRest[0])
36 else if(!pathRest[0]) // not inside of, it's the other way around
42 enum NodeTypes { project, file, folder, resources, folderOpen };
45 genFile, ewsFile, epjFile, folder, openFolder, ecFile, ehFile,
46 cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile,
47 archiveFile, packageFile, opticalMediaImageFile, mFile;
49 NodeIcons ::SelectFileIcon(char * filePath)
52 if(filePath && filePath[0])
54 char extension[MAX_EXTENSION];
55 GetExtension(filePath, extension);
58 if(!strcmpi(extension, WorkspaceExtension))
60 else if(!strcmpi(extension, ProjectExtension))
62 else if(!strcmpi(extension, "ec"))
64 else if(!strcmpi(extension, "eh"))
66 else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
67 !strcmpi(extension, "cxx"))
69 else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
70 !strcmpi(extension, "hxx"))
72 else if(!strcmpi(extension, "c"))
74 else if(!strcmpi(extension, "h"))
76 else if(!strcmpi(extension, "m"))
78 else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
79 !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
81 else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
82 !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
83 !strcmpi(extension, "js"))
85 else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
86 !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
87 !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
88 !strcmpi(extension, "ico"))
90 else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
91 !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
93 else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
94 !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
95 !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
96 !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
97 !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
98 !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
100 else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
101 !strcmpi(extension, "rpm"))
103 else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
104 !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
105 !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
106 !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
107 icon = opticalMediaImageFile;
115 icon = genFile; // tocheck: error icon?
119 NodeIcons ::SelectNodeIcon(NodeTypes type)
138 #define SELECTION_COLOR Color { 10, 36, 106 }
144 // this is so not working, why!
146 // return result was not even executed (did not step on while debugging)
147 class TwoStrings : struct
167 class ProjectNode : ListItem
172 set { return { fileName = value }; }
173 // TOCHECK: Is this isset necessary at all?
174 isset { return nodeType == file && !options && !configurations && !platforms && !files; }
176 property String folder
181 if(strchr(value, '/'))
183 char p[MAX_LOCATION];
184 char n[MAX_FILENAME];
185 GetLastDirectory(value, n);
186 StripLastDirectory(value, p);
187 name = CopyString(n);
188 path = CopyString(p);
191 name = CopyString(value);
195 // TOCHECK: Non Reentrant
196 static char insidePath[MAX_LOCATION];
198 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
199 PathCatSlash(insidePath, name);
201 if(!fstrcmp(path, insidePath))
205 strcpy(insidePath, path);
206 if(!insidePath[0]) strcpy(insidePath, ".");
207 PathCatSlash(insidePath, name);
211 isset { return nodeType == folder; }
213 property String fileName
218 if(strchr(value, '/'))
220 char p[MAX_LOCATION];
221 char n[MAX_FILENAME];
222 GetLastDirectory(value, n);
223 StripLastDirectory(value, p);
224 name = CopyValidateMakefilePath(n);
225 path = CopyValidateMakefilePath(p);
228 name = CopyValidateMakefilePath(value);
232 // TOCHECK: Non Reentrant
233 static char insidePath[MAX_LOCATION];
235 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
236 if(!fstrcmp(path, insidePath))
240 strcpy(insidePath, path);
241 if(!insidePath[0]) strcpy(insidePath, ".");
242 PathCatSlash(insidePath, name);
246 isset { return nodeType == file && (options || configurations || platforms); }
249 LinkList<ProjectNode> files;
250 property ProjectOptions options
252 get { return project ? project.options : options; }
253 set { if(project) { delete project.options; project.options = value; } else { delete options; options = value; } }
254 isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
256 property Array<PlatformOptions> platforms
258 get { return project ? project.platforms : platforms; }
261 if(project) { project.platforms = value; }
264 if(platforms) { platforms.Free(); delete platforms; }
267 List<PlatformOptions> empty { };
268 Iterator<PlatformOptions> it { value };
270 for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
271 for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
278 Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
283 if(p.options && !p.options.isEmpty)
290 property List<ProjectConfig> configurations
292 get { return project ? project.configurations : configurations; }
297 if(project.configurations)
299 project.configurations.Free();
300 delete project.configurations;
302 project.configurations = value;
306 if(configurations) { configurations.Free(); delete configurations; }
309 List<ProjectConfig> empty { };
310 Iterator<ProjectConfig> it { value };
311 configurations = value;
312 for(c : configurations)
314 bool somethingSet = c.options && !c.options.isEmpty;
315 // TODO: Implement isset keyword
316 if(!somethingSet && c.platforms && c.platforms.count)
320 if(p.options && !p.options.isEmpty)
330 for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
337 if(!parent) return true;
340 for(c : configurations)
342 bool somethingSet = c.options && !c.options.isEmpty;
343 if(!somethingSet && c.platforms && c.platforms.count)
347 if(p.options && !p.options.isEmpty)
362 ProjectOptions options;
363 Array<PlatformOptions> platforms;
364 List<ProjectConfig> configurations;
365 ProjectNodeType nodeType;
370 // This holds the absolute path of the .epj for the project topnode (without the filename)
371 // It holds a relative path to the topNode (project) for other nodes (folders and files)
372 // For folders, it includes the folder it refers to. If there is a name difference between the
373 // file system folder and the grouping folder of the project view, it maps to that folder.
383 // This is only set for Top Nodes
386 void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Array<Platform> platforms)
388 if(!platforms.Find(unknown)) // unknown is "Common"
390 // e.g. ifneq "$(or $(or $(OSX_TARGET),$(LINUX_TARGET)),$(WINDOWS_TARGET))"
393 for(i = 0; platforms.count && i < platforms.count - 1; i++)
401 f.Puts(PlatformToMakefileTargetVariable(p));
414 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
416 ProjectConfig nodeConfig = null;
417 if(property::configurations && prjConfig)
419 const char * configName = prjConfig.name;
420 for(cfg : property::configurations)
422 if(!strcmpi(cfg.name, configName))
432 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
434 property bool containsFile
443 if(child.type == file ||
444 ((child.type == folder || child.type == folderOpen) && child.containsFile))
457 char * GetFullFilePath(char * buffer)
461 strcpy(buffer, root.path);
462 PathCatSlash(buffer, path);
463 PathCatSlash(buffer, name);
468 char * GetFileSysMatchingPath(char * buffer)
472 ProjectNode n, root = this.root;
473 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
475 strcpy(buffer, root.path);
477 PathCatSlash(buffer, n.path);
478 if(FileExists(buffer).isDirectory)
481 if(!(n && (n.type == folder || n.type == project)))
487 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
489 ProjectNode node = null;
490 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
491 List<ProjectNode> nodeStack { };
493 for(node = this; node && node.parent; node = node.parent)
496 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
498 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
499 while((node = nodeStack.lastIterator.data))
501 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
502 ProjectOptions nodeOptions = node.property::options;
503 if(nodeOptions && nodeOptions.preprocessorDefinitions)
505 for(def : nodeOptions.preprocessorDefinitions)
506 perFilePreprocessorDefs.Add(CopyString(def));
508 if(config && config.options && config.options.preprocessorDefinitions)
510 for(def : config.options.preprocessorDefinitions)
511 perFilePreprocessorDefs.Add(CopyString(def));
513 if(nodeOptions && nodeOptions.includeDirs)
515 for(dir : nodeOptions.includeDirs)
516 perFileIncludeDirs.Add(CopySystemPath(dir));
518 if(config && config.options && config.options.includeDirs)
520 for(dir : config.options.includeDirs)
521 perFileIncludeDirs.Add(CopySystemPath(dir));
523 nodeStack.lastIterator.Remove();
529 property Project project
533 ProjectNode n = this;
534 while(n && n.type != project) n = n.parent;
535 return n ? (*&n.project) : null;
539 void RenameConfig(char * oldName, char * newName)
543 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
545 if(property::configurations)
547 for(c : property::configurations; !strcmp(c.name, oldName))
550 c.name = CopyString(newName);
555 void DeleteConfig(ProjectConfig configToDelete)
559 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
561 if(property::configurations)
563 Iterator<ProjectConfig> c { property::configurations };
566 ProjectConfig config = c.data;
567 if(!strcmp(configToDelete.name, config.name))
574 if(!property::configurations.count)
575 property::configurations = null;
581 ProjectNode backupNode { };
585 backupNode.files = { };
586 for(f : files) backupNode.files.Add(f.Backup());
588 if(property::options)
589 backupNode.options = property::options.Copy();
591 if(property::platforms)
593 backupNode.platforms = { };
594 for(p : property::platforms)
595 backupNode.platforms.Add(p.Copy());
598 if(property::configurations)
600 backupNode.configurations = { };
601 for(c : property::configurations)
602 backupNode.configurations.Add(c.Copy());
607 void Revert(ProjectNode backupNode)
611 Iterator<ProjectNode> it { backupNode.files };
619 property::options = backupNode.options ? backupNode.options.Copy() : null;
620 if(backupNode.platforms)
622 Array<PlatformOptions> platforms { };
623 property::platforms = platforms;
625 for(p : backupNode.platforms)
626 platforms.Add(p.Copy());
628 if(backupNode.configurations)
630 List<ProjectConfig> configurations { };
631 property::configurations = configurations;
632 for(c : backupNode.configurations)
633 configurations.Add(c.Copy());
637 void FixupNode(char * parentPath)
643 else if(nodeType == file)
648 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
651 else if(nodeType == folder)
657 char temp[MAX_LOCATION];
658 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
659 PathCatSlash(temp, name);
660 path = CopyString(temp);
664 indent = parent ? parent.indent + 1 : 0;
667 icon = NodeIcons::SelectFileIcon(name);
669 icon = NodeIcons::SelectNodeIcon(type);
678 parentPath[0] = '\0';
679 else if(type == resources || type == folder)
680 strcpy(parentPath, path);
682 f.FixupNode(parentPath);
687 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
691 // TOCHECK: Called from JSON writer
692 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
694 strcpy(tempString, "\"");
695 strcat(tempString, property::fileName);
696 strcat(tempString, "\"");
703 // TOCHECK: Called from ProjectView rendering
704 return name ? name : "";
717 if(!project && platforms)
722 if(!project && configurations)
724 configurations.Free();
725 delete configurations;
728 /////////////////////////////
734 property bool isInResources
739 for(node = this; node; node = node.parent)
741 if(node.type == resources)
748 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
750 TwoStrings result { a = CopyString(""), b = CopyString("") };
751 // note: unknown platform is for common
752 Map<Platform, SetBool> exclusionInfo { };
753 MapNode<Platform, SetBool> mn;
758 CollectExclusionInfo(exclusionInfo, prjConfig);
759 common = exclusionInfo[unknown];
761 Map<Platform, SetBool> cleaned { };
762 SetBool opposite = common == true ? false : true;
763 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
765 if(mn.key == unknown || mn.value == opposite)
766 cleaned[mn.key] = mn.value;
768 delete exclusionInfo;
769 exclusionInfo = cleaned;
772 if(exclusionInfo.count > 1)
774 if(exclusionInfo.count > 2)
777 len = strlen(exp) + strlen("$(if $(or ");
778 exp = renew exp char[len+1];
779 strcat(exp, "$(if $(or ");
782 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
784 if(mn.key != unknown)
786 char * comma = mn.next ? "," : "";
788 var = PlatformToMakefileTargetVariable(mn.key);
791 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
792 exp = renew exp char[len+1];
802 len = strlen(exp) + strlen("),");
803 exp = renew exp char[len+1];
807 if(exclusionInfo.root.minimum.key != unknown)
808 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
810 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
813 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
814 exp = renew exp char[len+1];
815 strcat(exp, "$(if $(");
822 exp = common == true ? result.b : result.a;
823 len = strlen(exp) + strlen(",");
824 exp = renew exp char[len+1];
826 if(common == true) result.b = exp; else result.a = exp;
829 len = strlen(exp) + strlen(")");
830 exp = renew exp char[len+1];
834 delete exclusionInfo;
839 bool GetIsExcluded(ProjectConfig prjConfig)
842 // note: unknown platform is for common
843 Map<Platform, SetBool> exclusionInfo { };
844 CollectExclusionInfo(exclusionInfo, prjConfig);
845 if(exclusionInfo.count == 0)
847 else if(exclusionInfo.count == 1)
848 result = exclusionInfo.root.minimum.value == true;
851 SetBool check = exclusionInfo.root.minimum.value;
852 MapNode<Platform, SetBool> mn;
853 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
855 if(check != mn.value)
858 if(!mn) // all are same
859 result = check == true;
863 delete exclusionInfo;
867 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
869 // note: unknown platform is for common
871 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
872 ProjectOptions options = property::options;
873 Array<PlatformOptions> platforms = property::platforms;
874 List<ProjectConfig> configurations = property::configurations;
877 parent.CollectExclusionInfo(output, prjConfig);
879 output[unknown] = unset;
881 if(options && options.excludeFromBuild)
882 output[unknown] = options.excludeFromBuild;
884 if(config && config.options && config.options.excludeFromBuild)
885 output[unknown] = config.options.excludeFromBuild;
891 if(p.options.excludeFromBuild && (platform = p.name))
892 output[platform] = p.options.excludeFromBuild;
895 if(config && config.platforms)
897 for(p : config.platforms)
899 if(p.options.excludeFromBuild && (platform = p.name))
900 output[platform] = p.options.excludeFromBuild;
908 parent.EnsureVisible();
909 row.collapsed = false;
915 parent.files.Delete(this);
918 ProjectNode Find(char * name, bool includeResources)
920 ProjectNode result = null;
925 if(includeResources || child.type != resources)
927 if(child.type != folder && child.name && !strcmpi(child.name, name))
932 result = child.Find(name, includeResources);
941 ProjectNode FindWithPath(char * name, bool includeResources)
943 ProjectNode result = null;
948 if(includeResources || child.type != resources)
950 char path[MAX_LOCATION];
951 strcpy(path, child.path);
952 if(child.type != folder && child.name)
954 PathCatSlash(path, child.name);
955 if(!strcmpi(path, name))
961 result = child.FindWithPath(name, includeResources);
970 ProjectNode FindByFullPath(char * path, bool includeResources)
972 ProjectNode result = null;
977 if(includeResources || child.type != resources)
979 if(child.type != folder && child.name)
981 char p[MAX_LOCATION];
982 child.GetFullFilePath(p);
983 if(!strcmpi(p, path))
989 result = child.FindByFullPath(path, includeResources);
998 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
1000 ProjectNode result = null;
1005 if(includeResources || child.type != resources)
1007 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1013 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1022 ProjectNode FindSameNameConflict(char * name, bool includeResources,
1023 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1025 ProjectNode result = null;
1026 Map<Platform, SetBool> compareExclusion { };
1027 SetBool common, commonComp;
1028 SetBool actual, actualComp;
1033 if(includeResources || child.type != resources)
1035 if(child.type != folder && child.name && !strcmpi(child.name, name))
1037 child.CollectExclusionInfo(compareExclusion, prjConfig);
1038 common = exclusionInfo[unknown];
1039 commonComp = compareExclusion[unknown];
1040 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1042 if(!(common == true || commonComp == true))
1051 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1054 actualComp = commonComp;
1055 if(exclusionInfo[platform] != unset)
1056 actual = exclusionInfo[platform];
1057 if(compareExclusion[platform] != unset)
1058 actualComp = compareExclusion[platform];
1059 if(!(actual == true || actualComp == true))
1067 compareExclusion.Free();
1070 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1074 compareExclusion.Free();
1076 delete compareExclusion;
1080 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1082 ProjectNode node = null;
1083 char temp[MAX_LOCATION];
1084 Map<Platform, SetBool> exclusionInfo { };
1086 GetLastDirectory(filePath, temp);
1087 //if(!checkIfExists || !project.topNode.Find(temp, false))
1089 // TOCHECK: Shouldn't this apply either for all configs or none?
1090 CollectExclusionInfo(exclusionInfo, project.config);
1091 if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1093 // Do the check for folder in the same parent or resource files only here
1094 if(type == folder || !checkIfExists)
1098 if(node.name && !strcmpi(node.name, temp))
1103 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1107 node.nodeType = folder;
1113 StripLastDirectory(filePath, temp);
1114 MakePathRelative(temp, project.topNode.path, temp);
1115 node.path = CopyUnixPath(temp);
1117 node.nodeType = file;
1121 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1122 PathCatSlash(temp, node.name);
1123 node.path = CopyString(temp);
1125 files.Insert(after, node);
1127 delete exclusionInfo;
1131 #ifndef MAKEFILE_GENERATOR
1132 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1134 char label[MAX_FILENAME];
1140 bool showConfig = true;
1145 projectView = ide.projectView;
1148 bmp = projectView.icons[icon].bitmap;
1149 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1151 GetLastDirectory(name, label);
1152 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1154 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1156 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1159 addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1160 if(strlen(addendum))
1162 strcat(label, " (");
1163 strcat(label, addendum);
1166 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1167 if(strlen(addendum))
1169 strcat(label, " (");
1170 strcat(label, addendum);
1176 else if(!projectView.drawingInProjectSettingsDialog)
1179 strcat(label, " *");
1180 if(type == project && info)
1182 int len = strlen(info) + 4;
1183 char * more = new char[len];
1184 sprintf(more, " (%s)", info);
1185 strcat(label, more);
1189 len = strlen(label);
1193 if(type == folder || type == folderOpen)
1194 surface.SetForeground(yellow);
1198 surface.TextOpacity(false);
1199 surface.TextExtent(label, len, &w, &h);
1202 // Draw the current row stipple
1203 if(displayFlags.selected)
1204 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1205 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1206 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1208 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1212 if(displayFlags.current)
1214 if(displayFlags.active)
1216 surface.LineStipple(0x5555);
1217 if(displayFlags.selected)
1218 surface.SetForeground(projectView.fileList.stippleColor);
1220 surface.SetForeground(projectView.fileList.foreground);
1224 surface.SetForeground(SELECTION_COLOR);
1226 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1227 surface.LineStipple(0);
1232 surface.SetForeground(white);
1233 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1239 int OnCompare(ProjectNode b)
1242 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1243 result = strcmpi(name, b.name);
1246 if(type == folder && b.type == file) result = -1;
1247 else if(type == file && b.type == folder) result = 1;
1252 bool ContainsFilesWithExtension(char * extension)
1256 char ext[MAX_EXTENSION];
1257 GetExtension(name, ext);
1258 if(!fstrcmp(ext, extension))
1263 bool needed = false;
1265 if(child.ContainsFilesWithExtension(extension))
1271 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1275 char extension[MAX_EXTENSION];
1276 GetExtension(name, extension);
1277 if(!strcmpi(extension, "ec") || !strcmpi(extension, "c") ||
1278 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1279 !strcmpi(extension, "cxx") || !strcmpi(extension, "m"))
1281 char moduleName[MAX_FILENAME];
1282 NameCollisionInfo info;
1283 ReplaceSpaces(moduleName, name);
1284 StripExtension(moduleName);
1285 info = namesInfo[moduleName];
1287 info = NameCollisionInfo { };
1288 info.count++; // += 1; unless this is for a bug?
1289 if(!strcmpi(extension, "ec"))
1291 else if(!strcmpi(extension, "c"))
1293 else if(!strcmpi(extension, "cpp"))
1295 else if(!strcmpi(extension, "cc"))
1297 else if(!strcmpi(extension, "cxx"))
1299 else if(!strcmpi(extension, "m"))
1301 namesInfo[moduleName] = info;
1308 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1309 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1314 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1315 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1316 ProjectConfig prjConfig, bool * containsCXX)
1322 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1323 char moduleName[MAX_FILENAME];
1324 char extension[MAX_EXTENSION];
1325 GetExtension(name, extension);
1326 if(printType == resources)
1329 char tempPath[MAX_LOCATION];
1330 char modulePath[MAX_LOCATION];
1333 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1336 PathCatSlash(tempPath, name);
1341 strcpy(tempPath, path);
1342 PathCatSlash(tempPath, name);
1344 ReplaceSpaces(modulePath, tempPath);
1345 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1346 items.Add(CopyString(s));
1348 else if(printType == sources)
1350 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1351 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1352 !strcmpi(extension, "m"))
1354 char modulePath[MAX_LOCATION];
1356 ReplaceSpaces(modulePath, path);
1357 ReplaceSpaces(moduleName, name);
1358 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1359 items.Add(CopyString(s));
1362 else if(printType == eCsources)
1364 if(!strcmpi(extension, "ec"))
1366 char modulePath[MAX_LOCATION];
1368 ReplaceUnwantedMakeChars(modulePath, path);
1369 ReplaceUnwantedMakeChars(moduleName, name);
1370 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1371 items.Add(CopyString(s));
1375 else if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1376 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1377 !strcmpi(extension, "m"))
1379 if(printType == objects)
1382 NameCollisionInfo info;
1384 ReplaceSpaces(moduleName, name);
1385 StripExtension(moduleName);
1386 info = namesInfo[moduleName];
1387 collision = info ? info.IsExtensionColliding(extension) : false;
1388 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1389 items.Add(CopyString(s));
1390 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1391 *containsCXX = true;
1400 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1401 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1407 void GenMakefilePrintSymbolRules(File f, Project project,
1408 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1409 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1412 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1413 //ProjectNode child;
1414 //char objDir[MAX_LOCATION];
1415 //ReplaceSpaces(objDir, config.objDir.dir);
1417 //eSystem_Log("Printing Symbol Rules\n");
1420 char extension[MAX_EXTENSION];
1421 char modulePath[MAX_LOCATION];
1422 char moduleName[MAX_FILENAME];
1424 GetExtension(name, extension);
1425 if(!strcmpi(extension, "ec"))
1430 ReplaceSpaces(moduleName, name);
1431 StripExtension(moduleName);
1433 ReplaceSpaces(modulePath, path);
1434 if(modulePath[0]) strcat(modulePath, SEPS);
1436 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1438 // *** Dependency command ***
1439 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1440 modulePath, moduleName, extension);
1442 // System Includes (from global settings)
1443 for(item : compiler.dirs[Includes])
1445 strcat(command, " -isystem ");
1446 if(strchr(item, ' '))
1448 strcat(command, "\"");
1449 strcat(command, item);
1450 strcat(command, "\"");
1453 strcat(command, item);
1456 for(item : project.includeDirs)
1458 strcat(command, " -I");
1459 if(strchr(item, ' '))
1461 strcat(command, "\"");
1462 strcat(command, item);
1463 strcat(command, "\"");
1466 strcat(command, item);
1468 for(item : project.preprocessorDefs)
1470 strcat(command, " -D");
1471 strcat(command, item);
1475 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1478 bool firstLine = true;
1481 // To do some time: auto save external dependencies?
1484 if(dep.GetLine(line, sizeof(line)-1))
1488 char * colon = strstr(line, ":");
1489 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1503 // If we failed to generate dependencies...
1507 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1508 moduleName, modulePath, moduleName, extension);
1512 f.Puts(" $(CFLAGS)");
1513 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1515 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1516 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1518 f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n",
1519 modulePath, moduleName, extension, moduleName);
1520 if(ifCount) f.Puts("endif\n");
1530 bool needed = false;
1531 if(ContainsFilesWithExtension("ec"))
1535 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1546 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1547 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1548 nodeCFlagsMapping, nodeECFlagsMapping);
1555 void GenMakefilePrintPrepecsRules(File f, Project project,
1556 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1557 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1560 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1561 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1562 //ProjectNode child;
1563 //char objDir[MAX_LOCATION];
1564 //ReplaceSpaces(objDir, config.objDir.dir);
1566 //eSystem_Log("Printing Symbol Rules\n");
1569 char extension[MAX_EXTENSION];
1570 char modulePath[MAX_LOCATION];
1571 char moduleName[MAX_FILENAME];
1573 GetExtension(name, extension);
1574 if(!strcmpi(extension, "ec"))
1579 ReplaceSpaces(moduleName, name);
1580 StripExtension(moduleName);
1582 ReplaceSpaces(modulePath, path);
1583 if(modulePath[0]) strcat(modulePath, SEPS);
1585 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1586 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1587 moduleName, modulePath, moduleName, extension);
1588 //$(CPP) -x c -E ../extras/gui/controls/DirectoriesBox.ec -o $(OBJ)DirectoriesBox$(EC)
1589 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1590 modulePath, moduleName, extension, moduleName);*/
1594 f.Puts(" $(CFLAGS)");
1595 //f.Puts(" $(CECFLAGS)");
1596 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1597 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1599 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1600 modulePath, moduleName, extension, moduleName);
1601 if(ifCount) f.Puts("endif\n");
1607 bool needed = false;
1608 if(ContainsFilesWithExtension("ec"))
1612 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1623 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1624 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1625 nodeCFlagsMapping, nodeECFlagsMapping);
1632 void GenMakefilePrintCObjectRules(File f, Project project,
1633 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1634 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1637 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1638 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1639 //ProjectNode child;
1640 //char objDir[MAX_LOCATION];
1641 //ReplaceSpaces(objDir, config.objDir.dir);
1642 //eSystem_Log("Printing C Object Rules\n");
1645 char extension[MAX_EXTENSION];
1646 char modulePath[MAX_LOCATION];
1647 char moduleName[MAX_FILENAME];
1649 GetExtension(name, extension);
1650 if(!strcmpi(extension, "ec"))
1655 ReplaceSpaces(moduleName, name);
1656 StripExtension(moduleName);
1658 ReplaceSpaces(modulePath, path);
1659 if(modulePath[0]) strcat(modulePath, SEPS);
1661 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1663 // *** Dependency command ***
1664 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1665 moduleName, modulePath, moduleName, extension);
1667 // System Includes (from global settings)
1668 for(item : compiler.dirs[Includes])
1670 strcat(command, " -isystem ");
1671 if(strchr(item, ' '))
1673 strcat(command, "\"");
1674 strcat(command, item);
1675 strcat(command, "\"");
1678 strcat(command, item);
1681 for(item : config.includeDirs)
1683 strcat(command, " -I");
1684 if(strchr(item, ' '))
1686 strcat(command, "\"");
1687 strcat(command, item);
1688 strcat(command, "\"");
1691 strcat(command, item);
1693 for(item : config.preprocessorDefs)
1695 strcat(command, " -D");
1696 strcat(command, item);
1700 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1704 bool firstLine = true;
1706 // To do some time: auto save external dependencies?
1709 if(dep.GetLine(line, sizeof(line)-1))
1713 char * colon = strstr(line, ":");
1714 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1728 // If we failed to generate dependencies...
1731 /* COMMENTED OUT FOR NOW
1732 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1733 moduleName, modulePath, moduleName, extension);
1736 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1737 moduleName, modulePath, moduleName, extension, moduleName);
1743 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1744 modulePath, moduleName, extension, moduleName);
1749 f.Puts(" $(CFLAGS)");
1750 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1751 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1752 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1753 f.Puts(" $(FVISIBILITY)");
1755 f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n",
1756 modulePath, moduleName, extension, moduleName);
1757 if(ifCount) f.Puts("endif\n");
1763 bool needed = false;
1764 if(ContainsFilesWithExtension("ec"))
1768 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1779 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1780 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1781 nodeCFlagsMapping, nodeECFlagsMapping);
1788 void GenMakefilePrintObjectRules(File f, Project project,
1789 Map<String, NameCollisionInfo> namesInfo,
1790 ProjectConfig prjConfig,
1791 //Map<Platform, bool> parentExcludedPlatforms,
1792 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1795 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1796 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1797 //ProjectNode child;
1798 //char objDir[MAX_LOCATION];
1799 //ReplaceSpaces(objDir, config.objDir.dir);
1800 //eSystem_Log("Printing Object Rules\n");
1804 char extension[MAX_EXTENSION];
1805 char modulePath[MAX_LOCATION];
1806 char moduleName[MAX_FILENAME];
1808 GetExtension(name, extension);
1809 /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1810 !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
1811 !strcmpi(extension, "cxx"))*/
1812 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1813 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1814 !strcmpi(extension, "m") || !strcmpi(extension, "ec"))
1818 NameCollisionInfo info;
1820 ReplaceSpaces(moduleName, name);
1821 StripExtension(moduleName);
1823 info = namesInfo[moduleName];
1824 collision = info ? info.IsExtensionColliding(extension) : false;
1826 ReplaceSpaces(modulePath, path);
1827 if(modulePath[0]) strcat(modulePath, SEPS);
1829 // *** Dependency command ***
1830 if(!strcmpi(extension, "ec"))
1831 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1833 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1834 moduleName, modulePath, moduleName, extension);
1836 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1839 if(!strcmpi(extension, "ec"))
1841 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1845 // System Includes (from global settings)
1846 for(item : compiler.dirs[includes])
1848 strcat(command, " -isystem ");
1849 if(strchr(item, ' '))
1851 strcat(command, "\"");
1852 strcat(command, item);
1853 strcat(command, "\"");
1856 strcat(command, item);
1859 for(item : config.includeDirs)
1861 strcat(command, " -I");
1862 if(strchr(item, ' '))
1864 strcat(command, "\"");
1865 strcat(command, item);
1866 strcat(command, "\"");
1869 strcat(command, item);
1871 for(item : config.preprocessorDefs)
1873 strcat(command, " -D");
1874 strcat(command, item);
1878 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1881 bool firstLine = true;
1884 // To do some time: auto save external dependencies?
1888 if(dep.GetLine(line, sizeof(line)-1))
1892 char * colon = strstr(line, ":");
1893 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1907 // If we failed to generate dependencies...
1916 if(!strcmpi(extension, "ec"))
1917 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1919 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
1920 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1921 f.Printf("\t$(%s)", (!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx")) ? "CXX" : "CC");
1923 f.Puts(" $(CFLAGS)");
1924 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1926 if(!strcmpi(extension, "ec"))
1927 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n", moduleName, moduleName);
1929 f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n",
1930 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1931 collision ? "." : "", collision ? extension : "");
1933 if(ifCount) f.Puts("endif\n");
1939 bool needed = false;
1942 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1952 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1953 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
1954 nodeCFlagsMapping, nodeECFlagsMapping);
1961 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
1968 //Iterator<ProjectNode> i { files };
1969 //Iterator<ProjectNode> prev { files };
1970 //for(child : files)
1972 for(c = 0; c < files.count; c++)
1974 ProjectNode child = files[c];
1975 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
1978 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
1981 char tempPath[MAX_LOCATION];
1982 char resPath[MAX_LOCATION];
1986 // $(EAR) aw%s --- /*quiet ? "q" : */""
1988 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
1991 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
1994 PathCatSlash(tempPath, child.name);
1999 strcpy(tempPath, child.path);
2000 PathCatSlash(tempPath, child.name);
2002 ReplaceSpaces(resPath, tempPath);
2003 if(strchr(tempPath, ' '))
2007 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", tempPath, quotes);
2010 if(count == 10 || (count > 0 && (ts || !child.next)))
2012 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2015 for(parent = this; parent.type == folder; parent = parent.parent)
2018 strcpy(path, parent.name);
2025 f.Printf(" \"%s\"%s\n", path, ts.b);
2037 if(child.type == folder)
2038 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2043 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2044 Map<String, int> cflagsVariations, Map<int, int> nodeCFlagsMapping,
2045 Map<String, int> ecflagsVariations, Map<int, int> nodeECFlagsMapping,
2046 Map<Platform, ProjectOptions> parentByPlatformOptions)
2048 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2049 if(type == file || type == folder || type == project)
2051 bool hasPerNodeOptions = type == project;
2052 if(!hasPerNodeOptions)
2054 if(options && !options.isEmpty)
2055 hasPerNodeOptions = true;
2056 else if(configurations)
2058 for(c : configurations)
2060 if(c.options && !c.options.isEmpty)
2062 hasPerNodeOptions = true;
2067 for(p : c.platforms)
2069 if(p.options && !p.options.isEmpty)
2071 hasPerNodeOptions = true;
2075 if(hasPerNodeOptions)
2080 if(!hasPerNodeOptions && platforms)
2084 if(p.options && !p.options.isEmpty)
2086 hasPerNodeOptions = true;
2093 if(hasPerNodeOptions)
2095 bool isEqual = false, isGreater = false;
2096 ComplexComparison complexCmp;
2098 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2099 ProjectOptions platformsCommonOptions;
2100 ProjectOptions byFileConfigPlatformProjectOptions;
2102 DynamicString cflags { };
2103 DynamicString ecflags { };
2107 byPlatformOptions = { };
2109 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2111 byFileConfigPlatformProjectOptions =
2112 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2113 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2116 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2118 byPlatformOptions[unknown] = platformsCommonOptions;
2120 if(parentByPlatformOptions)
2122 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2123 parentByPlatformOptions, additionsByPlatformOptions);
2124 isGreater = complexCmp == greater;
2125 isEqual = complexCmp == equal;
2130 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2132 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2134 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2136 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2139 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2141 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2145 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2147 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2150 if(!isGreater) cflags.concat(" \\\n\t");
2155 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2158 ecflags.concat(" \\\n\t");
2165 cflags.concat(" \\\n\t");
2166 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2170 additionsByPlatformOptions.Free();
2171 delete additionsByPlatformOptions;
2177 nodeCFlagsMapping[(int)this] = nodeCFlagsMapping[(int)parent];
2178 nodeECFlagsMapping[(int)this] = nodeECFlagsMapping[(int)parent];
2186 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2187 cflagsVariations[s] = variationNum = cflagsVariations.count;
2188 nodeCFlagsMapping[(int)this] = variationNum;
2191 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2192 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2193 nodeECFlagsMapping[(int)this] = variationNum;
2204 nodeCFlagsMapping[(int)this] = nodeCFlagsMapping[(int)parent];
2205 nodeECFlagsMapping[(int)this] = nodeECFlagsMapping[(int)parent];
2214 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2215 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2216 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2221 if(byPlatformOptions != parentByPlatformOptions)
2223 byPlatformOptions.Free();
2224 delete byPlatformOptions;
2228 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2230 Array<Platform> platforms { };
2231 Map<Platform, SetBool> exclusionInfo { };
2232 CollectExclusionInfo(exclusionInfo, prjConfig);
2234 if(exclusionInfo[unknown] == true)
2236 if(exclusionInfo.count > 1)
2237 for(p : exclusionInfo; p == false)
2242 bool onlyOnknown = true;
2243 for(p : exclusionInfo)
2244 if(&p != unknown && p == true)
2246 onlyOnknown = false;
2250 platforms.Add(unknown);
2254 for(p = unknown + 1; p < Platform::enumSize; p++)
2255 if(exclusionInfo[p] != true)
2259 delete exclusionInfo;
2263 void GetTargets(ProjectConfig prjConfig, char * objDir, DynamicString output)
2267 //output.concat(" $(OBJ)");
2268 output.concat(" \"");
2269 output.concat(objDir);
2272 char fileName[MAX_FILENAME];
2273 strcpy(fileName, name);
2274 // TODO/NOTE: this will not be correct for file.o instead of file.c.o when whe have both a file.c and a file.ec in a project.
2275 ChangeExtension(fileName, "o", fileName);
2276 output.concat(fileName);
2278 output.concat("\"");
2284 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2285 child.GetTargets(prjConfig, objDir, output);
2290 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig)
2294 char fileName[MAX_FILENAME];
2295 char extension[MAX_EXTENSION];
2296 Project prj = property::project;
2297 DirExpression objDir = prj.GetObjDir(compiler, prjConfig);
2299 strcpy(fileName, prj.topNode.path);
2300 PathCatSlash(fileName, objDir.dir);
2301 PathCatSlash(fileName, name);
2303 // TODO/NOTE: this will not delete file.c.o when whe have both a file.c and a file.ec in a project.
2304 ChangeExtension(fileName, "o", fileName);
2305 if(FileExists(fileName))
2306 DeleteFile(fileName);
2308 GetExtension(name, extension);
2309 if(!strcmp(extension, "ec"))
2311 ChangeExtension(fileName, "c", fileName);
2312 if(FileExists(fileName))
2313 DeleteFile(fileName);
2315 ChangeExtension(fileName, "sym", fileName);
2316 if(FileExists(fileName))
2317 DeleteFile(fileName);
2319 ChangeExtension(fileName, "imp", fileName);
2320 if(FileExists(fileName))
2321 DeleteFile(fileName);
2323 ChangeExtension(fileName, "bowl", fileName);
2324 if(FileExists(fileName))
2325 DeleteFile(fileName);
2334 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2335 child.DeleteIntermediateFiles(compiler, prjConfig);
2340 bool IsInNode(ProjectNode node)
2342 bool result = false;
2344 for(n = this; n; n = n.parent)
2356 // the code in this function is closely matched to OptionsBox::Load
2357 // and accompanying derivations of OptionBox and their use of OptionSet,
2358 // OptionCheck, LoadOption and FinalizeLoading methods.
2359 // output changing modification should be mirrored in both implementations
2360 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2362 ProjectOptions output { };
2364 // legend: e Element
2365 // o Option (of a ProjectOptions)
2366 // n Node (ProjectNode)
2368 // u Utility (GenericOptionTools)
2373 int includeDirsOption = OPTION(includeDirs);
2375 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2377 Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
2378 Array<bool> optionDone { size = OPTION(postbuildCommands) };
2379 Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
2381 GenericOptionTools<SetBool> utilSetBool {
2382 bool OptionCheck(ProjectOptions options, int option) {
2383 return *(SetBool*)((byte *)options + option) == true;
2385 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2386 if(options && (*(SetBool*)((byte *)options + option) == true))
2387 *(SetBool*)((byte *)output + option) = true;
2390 GenericOptionTools<String> utilString {
2391 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2392 String * string = (String*)((byte *)output + option);
2393 if(*string) delete *string;
2395 *string = CopyString(*(String*)((byte *)options + option));
2398 StringArrayOptionTools utilStringArrays {
2400 caseSensitive = true;
2401 bool OptionCheck(ProjectOptions options, int option) {
2402 String string = *(String*)((byte *)options + option);
2403 return string && string[0];
2405 bool OptionSet(ProjectOptions options, int option) {
2406 Array<String> strings = *(Array<String>*)((byte *)options + option);
2407 if(mergeValues && !configReplaces)
2408 return strings && strings.count;
2410 return strings != null;
2412 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2415 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2419 Array<String> tempStrings = optionTempStrings[option];
2421 optionTempStrings[option] = tempStrings = { };
2425 char priorityMark[10];
2428 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2429 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2430 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2436 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2437 Array<String> * strings = (Array<String>*)((byte *)output + option);
2438 if(*strings) { strings->Free(); delete *strings; }
2439 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2442 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2445 Array<String> tempStrings = optionTempStrings[option];
2446 Array<String> * strings = (Array<String>*)((byte *)output + option);
2447 if(*strings) { strings->Free(); delete *strings; }
2448 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2453 GenericOptionTools<WarningsOption> utilWarningsOption {
2454 bool OptionCheck(ProjectOptions options, int option) {
2455 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2456 return value && value != none;
2458 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2459 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2460 *(WarningsOption*)((byte *)output + option) = value;
2463 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2464 bool OptionCheck(ProjectOptions options, int option) {
2465 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2466 return value && value != none;
2468 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2469 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2470 *(OptimizationStrategy*)((byte *)output + option) = value;
2473 GenericOptionTools<BuildBitDepth> utilBuildBitDepth {
2474 bool OptionCheck(ProjectOptions options, int option) {
2475 BuildBitDepth value = *(BuildBitDepth*)((byte *)options + option);
2476 return value && value != all;
2478 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2479 BuildBitDepth value = options ? *(BuildBitDepth*)((byte *)options + option) : (BuildBitDepth)0;
2480 *(BuildBitDepth*)((byte *)output + option) = value;
2484 Map<int, GenericOptionTools> ot { };
2486 // The following are compiler options
2488 ot[OPTION(debug)] = utilSetBool;
2489 ot[OPTION(memoryGuard)] = utilSetBool;
2490 ot[OPTION(profile)] = utilSetBool;
2491 ot[OPTION(noLineNumbers)] = utilSetBool;
2492 ot[OPTION(strictNameSpaces)] = utilSetBool;
2493 ot[OPTION(fastMath)] = utilSetBool;
2495 ot[OPTION(defaultNameSpace)] = utilString;
2497 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2498 ot[OPTION(includeDirs)] = utilStringArrays;
2500 ot[OPTION(warnings)] = utilWarningsOption;
2502 ot[OPTION(optimization)] = utilOptimizationStrategy;
2504 ot[OPTION(buildBitDepth)] = utilBuildBitDepth;
2506 for(n = node; n; n = n.parent)
2508 ProjectConfig nodeConfig = null;
2510 priority = (priority / 10 + 1) * 10;
2513 if(projectConfig && n.configurations)
2515 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2517 if(platform && c.platforms)
2519 for(p : c.platforms; !strcmpi(p.name, platformName))
2523 GenericOptionTools u = uu;
2525 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2527 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2528 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2529 optionConfigXplatformSet[o] = true;
2541 GenericOptionTools u = uu;
2545 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2547 for(p : n.platforms; !strcmpi(p.name, platformName))
2549 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2551 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2552 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2557 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2558 ((u.mergeValues && !u.configReplaces) ?
2559 u.OptionCheck(nodeConfig.options, o) :
2560 u.OptionSet(nodeConfig.options, o)))
2562 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2563 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2567 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2569 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2570 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2574 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2575 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2583 GenericOptionTools u = uu;
2586 u.FinalizeLoading(o, optionTempStrings, output);
2589 delete optionConfigXplatformSet;
2591 delete optionTempStrings;
2595 delete utilStringArrays;
2596 delete utilWarningsOption;
2597 delete utilOptimizationStrategy;
2598 delete utilBuildBitDepth;
2605 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2609 ProjectOptions first;
2610 ProjectOptions commonOptions;
2612 Map<String, int> countIncludeDirs { };
2613 Map<String, int> countPreprocessorDefinitions { };
2614 Map<String, bool> commonIncludeDirs { };
2615 Map<String, bool> commonPreprocessorDefinitions { };
2617 for(options : byPlatformOptions) { first = options; break; }
2619 *platformsCommonOptions = commonOptions = first.Copy();
2621 if(commonOptions.includeDirs)
2622 commonOptions.includeDirs.Free();
2623 if(commonOptions.preprocessorDefinitions)
2624 commonOptions.preprocessorDefinitions.Free();
2626 for(options : byPlatformOptions)
2628 if(options != first)
2630 if(commonOptions.debug && options.debug != commonOptions.debug)
2631 commonOptions.debug = unset;
2632 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2633 commonOptions.memoryGuard = unset;
2634 if(commonOptions.profile && options.profile != commonOptions.profile)
2635 commonOptions.profile = unset;
2636 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2637 commonOptions.noLineNumbers = unset;
2638 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2639 commonOptions.strictNameSpaces = unset;
2640 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2641 commonOptions.fastMath = unset;
2643 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2644 commonOptions.warnings = unset;
2645 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2646 commonOptions.optimization = unset;
2647 if(commonOptions.buildBitDepth && options.buildBitDepth != commonOptions.buildBitDepth)
2648 commonOptions.buildBitDepth = all;
2650 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2651 delete commonOptions.defaultNameSpace;
2654 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2655 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2658 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2659 commonIncludeDirs, commonOptions.includeDirs);
2660 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2661 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2663 for(options : byPlatformOptions)
2665 if(options.debug && options.debug == commonOptions.debug)
2666 options.debug = unset;
2667 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2668 options.memoryGuard = unset;
2669 if(options.profile && options.profile == commonOptions.profile)
2670 options.profile = unset;
2671 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2672 options.noLineNumbers = unset;
2673 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2674 options.strictNameSpaces = unset;
2675 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2676 options.fastMath = unset;
2678 if(options.warnings && options.warnings == commonOptions.warnings)
2679 options.warnings = unset;
2680 if(options.optimization && options.optimization == commonOptions.optimization)
2681 options.optimization = unset;
2682 if(options.buildBitDepth && options.buildBitDepth == commonOptions.buildBitDepth)
2683 options.buildBitDepth = all;
2685 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2686 delete options.defaultNameSpace;
2688 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2689 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2692 delete countIncludeDirs;
2693 delete countPreprocessorDefinitions;
2694 delete commonIncludeDirs;
2695 delete commonPreprocessorDefinitions;
2698 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2699 Map<Platform, ProjectOptions> parentByPlatformOptions,
2700 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2702 ComplexComparison result = equal;
2703 ComplexComparison compare;
2705 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2707 ProjectOptions additionalOptions;
2708 additionsByPlatformOptions[platform] = { };
2709 additionalOptions = additionsByPlatformOptions[platform];
2710 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2711 if(compare == greater && result == equal)
2713 else if(compare == different)
2722 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2724 ComplexComparison result = equal;
2725 if(options.debug != parentOptions.debug ||
2726 options.memoryGuard != parentOptions.memoryGuard ||
2727 options.profile != parentOptions.profile ||
2728 options.noLineNumbers != parentOptions.noLineNumbers ||
2729 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2730 options.fastMath != parentOptions.fastMath ||
2731 options.warnings != parentOptions.warnings ||
2732 options.optimization != parentOptions.optimization ||
2733 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2734 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2738 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2739 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2741 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2742 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2748 enum ComplexComparison { different/*, smaller*/, equal, greater };
2750 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2753 if((!strings || !strings.count) && originals && originals.count)
2755 else if(strings && strings.count && (!originals || !originals.count))
2760 additions->Add(CopyString(s));
2762 else if(strings && strings.count && originals && originals.count)
2764 Map<String, String> map { };
2765 MapIterator<String, bool> mit { map = map };
2768 char * s = strstr(it, "\n");
2774 char * s = strstr(it, "\n");
2776 if(!mit.Index(s, false))
2791 additions->Add(CopyString(it));
2799 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2812 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
2820 strings.Add(CopyString(s));
2826 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
2830 Array<String> tmp { };
2831 MapIterator<String, bool> mit { map = common };
2835 if(!mit.Index(s, false))
2836 tmp.Add(CopyString(s));
2842 strings.Add(CopyString(s));
2849 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<int, int> nodeFlagsMapping, String variableName, File f)
2852 customFlags = nodeFlagsMapping[(int)node];
2854 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2856 f.Printf(" $(%s)", variableName);
2859 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<int, int> nodeFlagsMapping, String variableName, DynamicString s)
2862 customFlags = nodeFlagsMapping[(int)node];
2864 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2866 s.concatf(" $(%s)", variableName);
2869 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
2875 if(options.optimization == speed || options.optimization == size ||
2876 options.fastMath == true || options.debug == true)
2878 if(options.debug != true)
2880 s.concat(" $(if $(DEBUG),");
2884 switch(options.optimization)
2886 case speed: s.concat(" -O2"); break;
2887 case size: s.concat(" -Os"); break;
2889 if(options.fastMath == true)
2890 s.concat(" -ffast-math");
2891 if(options.debug == true)
2893 if(options.debug != true)
2896 else if(commonOptions)
2897 s.concat(" $(if $(DEBUG),-g)");
2898 if(options.buildBitDepth || (commonOptions && prjWithEcFiles))
2899 s.concatf(" %s", (!options || !options.buildBitDepth || options.buildBitDepth == bits32) ? "$(FORCE_32_BIT)" : "$(FORCE_64_BIT)");
2901 s.concat(" $(FPIC)");
2903 switch(options.warnings)
2905 case all: s.concat(" -Wall"); break;
2906 case none: s.concat(" -w"); break;
2912 if(options && options.preprocessorDefinitions)
2913 ListOptionToDynamicString("D", options.preprocessorDefinitions, false, lineEach, "\t\t\t", false, s);
2914 if(options && options.includeDirs)
2915 ListOptionToDynamicString("I", options.includeDirs, true, lineEach, "\t\t\t", true, s);
2918 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
2920 if(options.memoryGuard == true)
2921 s.concat(" -memguard");
2922 if(options.noLineNumbers == true)
2923 s.concat(" -nolinenumbers");
2924 if(options.strictNameSpaces == true)
2925 s.concat(" -strictns");
2926 if(options.defaultNameSpace && options.defaultNameSpace[0])
2927 s.concatf(" -defaultns %s", options.defaultNameSpace);
2930 static void ListOptionToDynamicString(char * option, Array<String> list, bool prioritize,
2931 ListOutputMethod method, String newLineStart, bool noSpace, DynamicString s)
2935 if(method == newLine)
2938 s.concat(newLineStart);
2942 Map<String, int> sortedList { };
2943 MapNode<String, int> mn;
2945 sortedList[item] = 1;
2946 for(mn = sortedList.root.minimum; mn; mn = mn.next)
2948 char * start = strstr(mn.key, "\n");
2949 if(method == lineEach)
2952 s.concat(newLineStart);
2957 StringNoSpaceToDynamicString(s, start ? start+1 : mn.key);
2959 s.concat(start ? start+1 : mn.key);
2967 if(method == lineEach)
2970 s.concat(newLineStart);
2975 StringNoSpaceToDynamicString(s, item);
2983 class GenericOptionTools<class X>
2985 bool mergeValues, configReplaces;
2987 virtual bool OptionSet(ProjectOptions options, int option) {
2988 if(*(X*)((byte *)options + option))
2993 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
2995 virtual bool OptionCheck(ProjectOptions options, int option) {
2996 return OptionSet(options, option);
2999 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3000 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3003 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3008 class NameCollisionInfo
3018 bool IsExtensionColliding(char * extension)
3021 if(count > 1 && ((!strcmpi(extension, "c") && ec) ||
3022 (!strcmpi(extension, "cpp") && (ec || c)) ||
3023 (!strcmpi(extension, "cc") && (ec || c || cpp)) ||
3024 (!strcmpi(extension, "cxx") && (ec || c || cpp || cc)) ||
3025 !strcmpi(extension, "m")))