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 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
388 ProjectConfig nodeConfig = null;
389 if(property::configurations && prjConfig)
391 const char * configName = prjConfig.name;
392 for(cfg : property::configurations)
394 if(!strcmpi(cfg.name, configName))
404 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
406 property bool containsFile
415 if(child.type == file ||
416 ((child.type == folder || child.type == folderOpen) && child.containsFile))
429 char * GetFullFilePath(char * buffer)
433 strcpy(buffer, root.path);
434 PathCatSlash(buffer, path);
435 PathCatSlash(buffer, name);
440 char * GetFileSysMatchingPath(char * buffer)
444 ProjectNode n, root = this.root;
445 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
447 strcpy(buffer, root.path);
449 PathCatSlash(buffer, n.path);
450 if(FileExists(buffer).isDirectory)
453 if(!(n && (n.type == folder || n.type == project)))
459 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
461 ProjectNode node = null;
462 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
463 List<ProjectNode> nodeStack { };
465 for(node = this; node && node.parent; node = node.parent)
468 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
470 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
471 while((node = nodeStack.lastIterator.data))
473 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
474 ProjectOptions nodeOptions = node.property::options;
475 if(nodeOptions && nodeOptions.preprocessorDefinitions)
477 for(def : nodeOptions.preprocessorDefinitions)
478 perFilePreprocessorDefs.Add(CopyString(def));
480 if(config && config.options && config.options.preprocessorDefinitions)
482 for(def : config.options.preprocessorDefinitions)
483 perFilePreprocessorDefs.Add(CopyString(def));
485 if(nodeOptions && nodeOptions.includeDirs)
487 for(dir : nodeOptions.includeDirs)
488 perFileIncludeDirs.Add(CopySystemPath(dir));
490 if(config && config.options && config.options.includeDirs)
492 for(dir : config.options.includeDirs)
493 perFileIncludeDirs.Add(CopySystemPath(dir));
495 nodeStack.lastIterator.Remove();
501 property Project project
505 ProjectNode n = this;
506 while(n && n.type != project) n = n.parent;
507 return n ? (*&n.project) : null;
511 void RenameConfig(char * oldName, char * newName)
515 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
517 if(property::configurations)
519 for(c : property::configurations; !strcmp(c.name, oldName))
522 c.name = CopyString(newName);
527 void DeleteConfig(ProjectConfig configToDelete)
531 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
533 if(property::configurations)
535 Iterator<ProjectConfig> c { property::configurations };
538 ProjectConfig config = c.data;
539 if(!strcmp(configToDelete.name, config.name))
546 if(!property::configurations.count)
547 property::configurations = null;
553 ProjectNode backupNode { };
557 backupNode.files = { };
558 for(f : files) backupNode.files.Add(f.Backup());
560 if(property::options)
561 backupNode.options = property::options.Copy();
563 if(property::platforms)
565 backupNode.platforms = { };
566 for(p : property::platforms)
567 backupNode.platforms.Add(p.Copy());
570 if(property::configurations)
572 backupNode.configurations = { };
573 for(c : property::configurations)
574 backupNode.configurations.Add(c.Copy());
579 void Revert(ProjectNode backupNode)
583 Iterator<ProjectNode> it { backupNode.files };
591 property::options = backupNode.options ? backupNode.options.Copy() : null;
592 if(backupNode.platforms)
594 Array<PlatformOptions> platforms { };
595 property::platforms = platforms;
597 for(p : backupNode.platforms)
598 platforms.Add(p.Copy());
600 if(backupNode.configurations)
602 List<ProjectConfig> configurations { };
603 property::configurations = configurations;
604 for(c : backupNode.configurations)
605 configurations.Add(c.Copy());
609 void FixupNode(char * parentPath)
615 else if(nodeType == file)
620 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
623 else if(nodeType == folder)
629 char temp[MAX_LOCATION];
630 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
631 PathCatSlash(temp, name);
632 path = CopyString(temp);
636 indent = parent ? parent.indent + 1 : 0;
639 icon = NodeIcons::SelectFileIcon(name);
641 icon = NodeIcons::SelectNodeIcon(type);
650 parentPath[0] = '\0';
651 else if(type == resources || type == folder)
652 strcpy(parentPath, path);
654 f.FixupNode(parentPath);
659 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
663 // TOCHECK: Called from JSON writer
664 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
666 strcpy(tempString, "\"");
667 strcat(tempString, property::fileName);
668 strcat(tempString, "\"");
675 // TOCHECK: Called from ProjectView rendering
676 return name ? name : "";
689 if(!project && platforms)
694 if(!project && configurations)
696 configurations.Free();
697 delete configurations;
700 /////////////////////////////
706 property bool isInResources
711 for(node = this; node; node = node.parent)
713 if(node.type == resources)
720 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
722 TwoStrings result { a = CopyString(""), b = CopyString("") };
723 // note: unknown platform is for common
724 Map<Platform, SetBool> exclusionInfo { };
725 MapNode<Platform, SetBool> mn;
730 CollectExclusionInfo(exclusionInfo, prjConfig);
731 common = exclusionInfo[unknown];
733 Map<Platform, SetBool> cleaned { };
734 SetBool opposite = common == true ? false : true;
735 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
737 if(mn.key == unknown || mn.value == opposite)
738 cleaned[mn.key] = mn.value;
740 delete exclusionInfo;
741 exclusionInfo = cleaned;
744 if(exclusionInfo.count > 1)
746 if(exclusionInfo.count > 2)
749 len = strlen(exp) + strlen("$(if $(or ");
750 exp = renew exp char[len+1];
751 strcat(exp, "$(if $(or ");
754 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
756 if(mn.key != unknown)
758 char * comma = mn.next ? "," : "";
760 var = PlatformToMakefileTargetVariable(mn.key);
763 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
764 exp = renew exp char[len+1];
774 len = strlen(exp) + strlen("),");
775 exp = renew exp char[len+1];
779 if(exclusionInfo.root.minimum.key != unknown)
780 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
782 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
785 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
786 exp = renew exp char[len+1];
787 strcat(exp, "$(if $(");
794 exp = common == true ? result.b : result.a;
795 len = strlen(exp) + strlen(",");
796 exp = renew exp char[len+1];
798 if(common == true) result.b = exp; else result.a = exp;
801 len = strlen(exp) + strlen(")");
802 exp = renew exp char[len+1];
806 delete exclusionInfo;
811 bool GetIsExcluded(ProjectConfig prjConfig)
814 // note: unknown platform is for common
815 Map<Platform, SetBool> exclusionInfo { };
816 CollectExclusionInfo(exclusionInfo, prjConfig);
817 if(exclusionInfo.count == 0)
819 else if(exclusionInfo.count == 1)
820 result = exclusionInfo.root.minimum.value == true;
823 SetBool check = exclusionInfo.root.minimum.value;
824 MapNode<Platform, SetBool> mn;
825 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
827 if(check != mn.value)
830 if(!mn) // all are same
831 result = check == true;
835 delete exclusionInfo;
839 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
841 // note: unknown platform is for common
843 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
844 ProjectOptions options = property::options;
845 Array<PlatformOptions> platforms = property::platforms;
846 List<ProjectConfig> configurations = property::configurations;
849 parent.CollectExclusionInfo(output, prjConfig);
851 output[unknown] = unset;
853 if(options && options.excludeFromBuild)
854 output[unknown] = options.excludeFromBuild;
856 if(config && config.options && config.options.excludeFromBuild)
857 output[unknown] = config.options.excludeFromBuild;
863 if(p.options.excludeFromBuild && (platform = p.name))
864 output[platform] = p.options.excludeFromBuild;
867 if(config && config.platforms)
869 for(p : config.platforms)
871 if(p.options.excludeFromBuild && (platform = p.name))
872 output[platform] = p.options.excludeFromBuild;
880 parent.EnsureVisible();
881 row.collapsed = false;
887 parent.files.Delete(this);
890 ProjectNode Find(char * name, bool includeResources)
892 ProjectNode result = null;
897 if(includeResources || child.type != resources)
899 if(child.type != folder && child.name && !strcmpi(child.name, name))
904 result = child.Find(name, includeResources);
913 ProjectNode FindWithPath(char * name, bool includeResources)
915 ProjectNode result = null;
920 if(includeResources || child.type != resources)
922 char path[MAX_LOCATION];
923 strcpy(path, child.path);
924 if(child.type != folder && child.name)
926 PathCatSlash(path, child.name);
927 if(!strcmpi(path, name))
933 result = child.FindWithPath(name, includeResources);
942 ProjectNode FindByFullPath(char * path, bool includeResources)
944 ProjectNode result = null;
949 if(includeResources || child.type != resources)
951 if(child.type != folder && child.name)
953 char p[MAX_LOCATION];
954 child.GetFullFilePath(p);
955 if(!strcmpi(p, path))
961 result = child.FindByFullPath(path, includeResources);
970 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
972 ProjectNode result = null;
977 if(includeResources || child.type != resources)
979 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
985 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
994 ProjectNode FindSameNameConflict(char * name, bool includeResources,
995 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
997 ProjectNode result = null;
998 Map<Platform, SetBool> compareExclusion { };
999 SetBool common, commonComp;
1000 SetBool actual, actualComp;
1005 if(includeResources || child.type != resources)
1007 if(child.type != folder && child.name && !strcmpi(child.name, name))
1009 child.CollectExclusionInfo(compareExclusion, prjConfig);
1010 common = exclusionInfo[unknown];
1011 commonComp = compareExclusion[unknown];
1012 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1014 if(!(common == true || commonComp == true))
1023 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1026 actualComp = commonComp;
1027 if(exclusionInfo[platform] != unset)
1028 actual = exclusionInfo[platform];
1029 if(compareExclusion[platform] != unset)
1030 actualComp = compareExclusion[platform];
1031 if(!(actual == true || actualComp == true))
1039 compareExclusion.Free();
1042 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1046 compareExclusion.Free();
1048 delete compareExclusion;
1052 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1054 ProjectNode node = null;
1055 char temp[MAX_LOCATION];
1056 Map<Platform, SetBool> exclusionInfo { };
1058 GetLastDirectory(filePath, temp);
1059 //if(!checkIfExists || !project.topNode.Find(temp, false))
1061 // TOCHECK: Shouldn't this apply either for all configs or none?
1062 CollectExclusionInfo(exclusionInfo, project.config);
1063 if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1065 // Do the check for folder in the same parent or resource files only here
1066 if(type == folder || !checkIfExists)
1070 if(node.name && !strcmpi(node.name, temp))
1075 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1079 node.nodeType = folder;
1085 StripLastDirectory(filePath, temp);
1086 MakePathRelative(temp, project.topNode.path, temp);
1087 node.path = CopyUnixPath(temp);
1089 node.nodeType = file;
1093 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1094 PathCatSlash(temp, node.name);
1095 node.path = CopyString(temp);
1097 files.Insert(after, node);
1099 delete exclusionInfo;
1103 #ifndef MAKEFILE_GENERATOR
1104 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1106 char label[MAX_FILENAME];
1112 bool showConfig = true;
1117 projectView = ide.projectView;
1120 bmp = projectView.icons[icon].bitmap;
1121 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1123 GetLastDirectory(name, label);
1124 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1126 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1128 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1131 addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1132 if(strlen(addendum))
1134 strcat(label, " (");
1135 strcat(label, addendum);
1138 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1139 if(strlen(addendum))
1141 strcat(label, " (");
1142 strcat(label, addendum);
1148 else if(!projectView.drawingInProjectSettingsDialog)
1151 strcat(label, " *");
1152 if(type == project && info)
1154 int len = strlen(info) + 4;
1155 char * more = new char[len];
1156 sprintf(more, " (%s)", info);
1157 strcat(label, more);
1161 len = strlen(label);
1165 if(type == folder || type == folderOpen)
1166 surface.SetForeground(yellow);
1170 surface.TextOpacity(false);
1171 surface.TextExtent(label, len, &w, &h);
1174 // Draw the current row stipple
1175 if(displayFlags.selected)
1176 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1177 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1178 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1180 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1184 if(displayFlags.current)
1186 if(displayFlags.active)
1188 surface.LineStipple(0x5555);
1189 if(displayFlags.selected)
1190 surface.SetForeground(projectView.fileList.stippleColor);
1192 surface.SetForeground(projectView.fileList.foreground);
1196 surface.SetForeground(SELECTION_COLOR);
1198 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1199 surface.LineStipple(0);
1204 surface.SetForeground(white);
1205 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1211 int OnCompare(ProjectNode b)
1214 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1215 result = strcmpi(name, b.name);
1218 if(type == folder && b.type == file) result = -1;
1219 else if(type == file && b.type == folder) result = 1;
1224 bool ContainsFilesWithExtension(char * extension)
1228 char ext[MAX_EXTENSION];
1229 GetExtension(name, ext);
1230 if(!fstrcmp(ext, extension))
1235 bool needed = false;
1237 if(child.ContainsFilesWithExtension(extension))
1243 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1247 char extension[MAX_EXTENSION];
1248 GetExtension(name, extension);
1249 if(!strcmpi(extension, "ec") || !strcmpi(extension, "c") ||
1250 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1251 !strcmpi(extension, "cxx") || !strcmpi(extension, "m"))
1253 char moduleName[MAX_FILENAME];
1254 NameCollisionInfo info;
1255 ReplaceSpaces(moduleName, name);
1256 StripExtension(moduleName);
1257 info = namesInfo[moduleName];
1259 info = NameCollisionInfo { };
1260 info.count++; // += 1; unless this is for a bug?
1261 if(!strcmpi(extension, "ec"))
1263 else if(!strcmpi(extension, "c"))
1265 else if(!strcmpi(extension, "cpp"))
1267 else if(!strcmpi(extension, "cc"))
1269 else if(!strcmpi(extension, "cxx"))
1271 else if(!strcmpi(extension, "m"))
1273 namesInfo[moduleName] = info;
1280 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1281 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1286 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1287 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1288 ProjectConfig prjConfig, bool * containsCXX)
1294 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1295 char moduleName[MAX_FILENAME];
1296 char extension[MAX_EXTENSION];
1297 GetExtension(name, extension);
1298 if(printType == resources)
1301 char tempPath[MAX_LOCATION];
1302 char modulePath[MAX_LOCATION];
1305 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1308 PathCatSlash(tempPath, name);
1313 strcpy(tempPath, path);
1314 PathCatSlash(tempPath, name);
1316 ReplaceSpaces(modulePath, tempPath);
1317 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1318 items.Add(CopyString(s));
1320 else if(printType == sources)
1322 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1323 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1324 !strcmpi(extension, "m"))
1326 char modulePath[MAX_LOCATION];
1328 ReplaceSpaces(modulePath, path);
1329 ReplaceSpaces(moduleName, name);
1330 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1331 items.Add(CopyString(s));
1334 else if(printType == eCsources)
1336 if(!strcmpi(extension, "ec"))
1338 char modulePath[MAX_LOCATION];
1340 ReplaceUnwantedMakeChars(modulePath, path);
1341 ReplaceUnwantedMakeChars(moduleName, name);
1342 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1343 items.Add(CopyString(s));
1347 else if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1348 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1349 !strcmpi(extension, "m"))
1351 if(printType == objects)
1354 NameCollisionInfo info;
1356 ReplaceSpaces(moduleName, name);
1357 StripExtension(moduleName);
1358 info = namesInfo[moduleName];
1359 collision = info ? info.IsExtensionColliding(extension) : false;
1360 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1361 items.Add(CopyString(s));
1362 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1363 *containsCXX = true;
1372 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1373 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1379 void GenMakefilePrintSymbolRules(File f, Project project,
1380 ProjectConfig prjConfig, Map<Platform, bool> parentExcludedPlatforms,
1381 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1384 Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
1385 //ProjectNode child;
1386 //char objDir[MAX_LOCATION];
1387 //ReplaceSpaces(objDir, config.objDir.dir);
1389 //eSystem_Log("Printing Symbol Rules\n");
1392 char extension[MAX_EXTENSION];
1393 char modulePath[MAX_LOCATION];
1394 char moduleName[MAX_FILENAME];
1396 GetExtension(name, extension);
1397 if(!strcmpi(extension, "ec"))
1402 ReplaceSpaces(moduleName, name);
1403 StripExtension(moduleName);
1405 ReplaceSpaces(modulePath, path);
1406 if(modulePath[0]) strcat(modulePath, SEPS);
1409 // *** Dependency command ***
1410 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1411 modulePath, moduleName, extension);
1413 // System Includes (from global settings)
1414 for(item : compiler.dirs[Includes])
1416 strcat(command, " -isystem ");
1417 if(strchr(item, ' '))
1419 strcat(command, "\"");
1420 strcat(command, item);
1421 strcat(command, "\"");
1424 strcat(command, item);
1427 for(item : project.includeDirs)
1429 strcat(command, " -I");
1430 if(strchr(item, ' '))
1432 strcat(command, "\"");
1433 strcat(command, item);
1434 strcat(command, "\"");
1437 strcat(command, item);
1439 for(item : project.preprocessorDefs)
1441 strcat(command, " -D");
1442 strcat(command, item);
1446 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1449 bool firstLine = true;
1452 // To do some time: auto save external dependencies?
1455 if(dep.GetLine(line, sizeof(line)-1))
1459 char * colon = strstr(line, ":");
1460 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1474 // If we failed to generate dependencies...
1478 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
1479 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1480 moduleName, modulePath, moduleName, extension);
1486 f.Printf("\t$(ECP) %s%s.%s %s.sym\n\n",
1487 modulePath, moduleName, extension, moduleName);
1492 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1494 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1495 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
1497 f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n\n",
1498 modulePath, moduleName, extension, moduleName);
1499 CloseRulesPlatformExclusionIfs(f, ifCount);
1504 bool needed = false;
1505 if(ContainsFilesWithExtension("ec"))
1509 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1518 Map<Platform, bool> excludedPlatforms { };
1519 for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
1520 for(platform : platforms)
1522 OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
1525 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1526 child.GenMakefilePrintSymbolRules(f, project, prjConfig, excludedPlatforms,
1527 nodeCFlagsMapping, nodeECFlagsMapping);
1530 CloseRulesPlatformExclusionIfs(f, ifCount);
1531 delete excludedPlatforms;
1537 void GenMakefilePrintPrepecsRules(File f, Project project,
1538 ProjectConfig prjConfig, Map<Platform, bool> parentExcludedPlatforms,
1539 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1542 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1543 Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
1544 //ProjectNode child;
1545 //char objDir[MAX_LOCATION];
1546 //ReplaceSpaces(objDir, config.objDir.dir);
1548 //eSystem_Log("Printing Symbol Rules\n");
1551 char extension[MAX_EXTENSION];
1552 char modulePath[MAX_LOCATION];
1553 char moduleName[MAX_FILENAME];
1555 GetExtension(name, extension);
1556 if(!strcmpi(extension, "ec"))
1561 ReplaceSpaces(moduleName, name);
1562 StripExtension(moduleName);
1564 ReplaceSpaces(modulePath, path);
1565 if(modulePath[0]) strcat(modulePath, SEPS);
1567 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
1568 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1569 moduleName, modulePath, moduleName, extension);
1570 //$(CPP) -x c -E ../extras/gui/controls/DirectoriesBox.ec -o $(OBJ)DirectoriesBox$(EC)
1571 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1572 modulePath, moduleName, extension, moduleName);*/
1576 //f.Puts(" $(CECFLAGS)");
1577 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1578 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
1580 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n\n",
1581 modulePath, moduleName, extension, moduleName);
1582 CloseRulesPlatformExclusionIfs(f, ifCount);
1587 bool needed = false;
1588 if(ContainsFilesWithExtension("ec"))
1592 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1601 Map<Platform, bool> excludedPlatforms { };
1602 for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
1603 for(platform : platforms)
1605 OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
1608 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1609 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, excludedPlatforms,
1610 nodeCFlagsMapping, nodeECFlagsMapping);
1613 CloseRulesPlatformExclusionIfs(f, ifCount);
1614 delete excludedPlatforms;
1620 void GenMakefilePrintCObjectRules(File f, Project project,
1621 ProjectConfig prjConfig, Map<Platform, bool> parentExcludedPlatforms,
1622 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1625 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1626 Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
1627 //ProjectNode child;
1628 //char objDir[MAX_LOCATION];
1629 //ReplaceSpaces(objDir, config.objDir.dir);
1630 //eSystem_Log("Printing C Object Rules\n");
1633 char extension[MAX_EXTENSION];
1634 char modulePath[MAX_LOCATION];
1635 char moduleName[MAX_FILENAME];
1637 GetExtension(name, extension);
1638 if(!strcmpi(extension, "ec"))
1643 ReplaceSpaces(moduleName, name);
1644 StripExtension(moduleName);
1646 ReplaceSpaces(modulePath, path);
1647 if(modulePath[0]) strcat(modulePath, SEPS);
1650 // *** Dependency command ***
1651 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1652 moduleName, modulePath, moduleName, extension);
1654 // System Includes (from global settings)
1655 for(item : compiler.dirs[Includes])
1657 strcat(command, " -isystem ");
1658 if(strchr(item, ' '))
1660 strcat(command, "\"");
1661 strcat(command, item);
1662 strcat(command, "\"");
1665 strcat(command, item);
1668 for(item : config.includeDirs)
1670 strcat(command, " -I");
1671 if(strchr(item, ' '))
1673 strcat(command, "\"");
1674 strcat(command, item);
1675 strcat(command, "\"");
1678 strcat(command, item);
1680 for(item : config.preprocessorDefs)
1682 strcat(command, " -D");
1683 strcat(command, item);
1687 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1691 bool firstLine = true;
1693 // To do some time: auto save external dependencies?
1696 if(dep.GetLine(line, sizeof(line)-1))
1700 char * colon = strstr(line, ":");
1701 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1715 // If we failed to generate dependencies...
1718 /* COMMENTED OUT FOR NOW
1719 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1720 moduleName, modulePath, moduleName, extension);
1723 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
1724 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1725 moduleName, modulePath, moduleName, extension, moduleName);
1731 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1732 modulePath, moduleName, extension, moduleName);
1737 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1738 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1739 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
1740 f.Puts(" $(FVISIBILITY)");
1742 f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n\n",
1743 modulePath, moduleName, extension, moduleName);
1744 CloseRulesPlatformExclusionIfs(f, ifCount);
1749 bool needed = false;
1750 if(ContainsFilesWithExtension("ec"))
1754 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1763 Map<Platform, bool> excludedPlatforms { };
1764 for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
1765 for(platform : platforms)
1767 OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
1770 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1771 child.GenMakefilePrintCObjectRules(f, project, prjConfig, excludedPlatforms,
1772 nodeCFlagsMapping, nodeECFlagsMapping);
1775 CloseRulesPlatformExclusionIfs(f, ifCount);
1776 delete excludedPlatforms;
1782 void GenMakefilePrintObjectRules(File f, Project project,
1783 Map<String, NameCollisionInfo> namesInfo,
1784 ProjectConfig prjConfig,
1785 Map<Platform, bool> parentExcludedPlatforms,
1786 Map<int, int> nodeCFlagsMapping, Map<int, int> nodeECFlagsMapping)
1789 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1790 Array<Platform> platforms = GetPlatformsArrayFromExcluisionInfo(prjConfig);
1791 //ProjectNode child;
1792 //char objDir[MAX_LOCATION];
1793 //ReplaceSpaces(objDir, config.objDir.dir);
1794 //eSystem_Log("Printing Object Rules\n");
1798 char extension[MAX_EXTENSION];
1799 char modulePath[MAX_LOCATION];
1800 char moduleName[MAX_FILENAME];
1802 GetExtension(name, extension);
1803 /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1804 !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
1805 !strcmpi(extension, "cxx"))*/
1806 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1807 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1808 !strcmpi(extension, "m") || !strcmpi(extension, "ec"))
1812 NameCollisionInfo info;
1814 ReplaceSpaces(moduleName, name);
1815 StripExtension(moduleName);
1817 info = namesInfo[moduleName];
1818 collision = info ? info.IsExtensionColliding(extension) : false;
1820 ReplaceSpaces(modulePath, path);
1821 if(modulePath[0]) strcat(modulePath, SEPS);
1823 // *** Dependency command ***
1824 if(!strcmpi(extension, "ec"))
1825 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1827 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1828 moduleName, modulePath, moduleName, extension);
1830 if(!strcmpi(extension, "ec"))
1831 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1835 // System Includes (from global settings)
1836 for(item : compiler.dirs[includes])
1838 strcat(command, " -isystem ");
1839 if(strchr(item, ' '))
1841 strcat(command, "\"");
1842 strcat(command, item);
1843 strcat(command, "\"");
1846 strcat(command, item);
1849 for(item : config.includeDirs)
1851 strcat(command, " -I");
1852 if(strchr(item, ' '))
1854 strcat(command, "\"");
1855 strcat(command, item);
1856 strcat(command, "\"");
1859 strcat(command, item);
1861 for(item : config.preprocessorDefs)
1863 strcat(command, " -D");
1864 strcat(command, item);
1868 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1871 bool firstLine = true;
1874 // To do some time: auto save external dependencies?
1878 if(dep.GetLine(line, sizeof(line)-1))
1882 char * colon = strstr(line, ":");
1883 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1897 // If we failed to generate dependencies...
1901 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms[0], parentExcludedPlatforms, null);
1903 /*if(!strcmpi(extension, "ec"))
1904 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1906 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
1907 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1913 f.Printf("\t$(%s)", (!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx")) ? "CXX" : "CC");
1915 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "CFLAGS", f);
1917 if(!strcmpi(extension, "ec"))
1918 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n\n", moduleName, moduleName);
1920 f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n\n",
1921 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1922 collision ? "." : "", collision ? extension : "");
1923 CloseRulesPlatformExclusionIfs(f, ifCount);
1928 bool needed = false;
1931 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1939 Map<Platform, bool> excludedPlatforms { };
1940 for(mn : parentExcludedPlatforms) if(mn) excludedPlatforms[&mn] = true;
1941 for(platform : platforms)
1943 OpenRulesPlatformExclusionIfs(f, &ifCount, platform, parentExcludedPlatforms, excludedPlatforms);
1946 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1947 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, excludedPlatforms,
1948 nodeCFlagsMapping, nodeECFlagsMapping);
1951 CloseRulesPlatformExclusionIfs(f, ifCount);
1952 delete excludedPlatforms;
1958 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
1965 //Iterator<ProjectNode> i { files };
1966 //Iterator<ProjectNode> prev { files };
1967 //for(child : files)
1969 for(c = 0; c < files.count; c++)
1971 ProjectNode child = files[c];
1972 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
1975 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
1978 char tempPath[MAX_LOCATION];
1979 char resPath[MAX_LOCATION];
1983 // $(EAR) aw%s --- /*quiet ? "q" : */""
1985 f.Printf("\t%s$(EAR) $(EARFLAGS) $(TARGET)", ts.a);
1988 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
1991 PathCatSlash(tempPath, child.name);
1996 strcpy(tempPath, child.path);
1997 PathCatSlash(tempPath, child.name);
1999 ReplaceSpaces(resPath, tempPath);
2000 if(strchr(tempPath, ' '))
2004 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", tempPath, quotes);
2007 if(count == 10 || (count > 0 && (ts || !child.next)))
2009 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2012 for(parent = this; parent.type == folder; parent = parent.parent)
2015 strcpy(path, parent.name);
2022 f.Printf(" \"%s\"%s\n", path, ts.b);
2034 if(child.type == folder)
2035 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2040 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2041 Map<String, int> cflagsVariations, Map<int, int> nodeCFlagsMapping,
2042 Map<String, int> ecflagsVariations, Map<int, int> nodeECFlagsMapping,
2043 Map<Platform, ProjectOptions> parentByPlatformOptions)
2045 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2046 if(type == file || type == folder || type == project)
2048 bool hasPerNodeOptions = type == project;
2049 if(!hasPerNodeOptions)
2051 if(options && !options.isEmpty)
2052 hasPerNodeOptions = true;
2053 else if(configurations)
2055 for(c : configurations)
2057 if(c.options && !c.options.isEmpty)
2059 hasPerNodeOptions = true;
2064 for(p : c.platforms)
2066 if(p.options && !p.options.isEmpty)
2068 hasPerNodeOptions = true;
2072 if(hasPerNodeOptions)
2077 if(!hasPerNodeOptions && platforms)
2081 if(p.options && !p.options.isEmpty)
2083 hasPerNodeOptions = true;
2090 if(hasPerNodeOptions)
2092 bool isEqual = false, isGreater = false;
2093 ComplexComparison complexCmp;
2095 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2096 ProjectOptions platformsCommonOptions;
2097 ProjectOptions byFileConfigPlatformProjectOptions;
2099 DynamicString cflags { };
2100 DynamicString ecflags { };
2104 byPlatformOptions = { };
2106 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2108 byFileConfigPlatformProjectOptions =
2109 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2110 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2113 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2115 byPlatformOptions[unknown] = platformsCommonOptions;
2117 if(parentByPlatformOptions)
2119 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2120 parentByPlatformOptions, additionsByPlatformOptions);
2121 isGreater = complexCmp == greater;
2122 isEqual = complexCmp == equal;
2129 // absolutely common stuff outside of platform only, stuff that can't be changed by platform
2130 // This would normally go in crossplatform.mk (or compiler.cf if compiler-specific)
2131 // cflags.concatf(" \\\n\t $(if $(DEBIAN_PACKAGE),$(CPPFLAGS),) $(if $(DEBUG), -D_DEBUG,)");
2134 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2136 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2138 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2140 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2143 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2145 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2149 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2151 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2153 cflags.concatf(isGreater ? "%s" : " \\\n\t%s", (String)s);
2156 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2158 ecflags.concatf(" \\\n\t%s", (String)s);
2163 cflags.concatf(" \\\n\t");
2164 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "CFLAGS", cflags);
2168 additionsByPlatformOptions.Free();
2169 delete additionsByPlatformOptions;
2175 nodeCFlagsMapping[(int)this] = nodeCFlagsMapping[(int)parent];
2176 nodeECFlagsMapping[(int)this] = nodeECFlagsMapping[(int)parent];
2184 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2185 cflagsVariations[s] = variationNum = cflagsVariations.count;
2186 nodeCFlagsMapping[(int)this] = variationNum;
2189 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2190 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2191 nodeECFlagsMapping[(int)this] = variationNum;
2202 nodeCFlagsMapping[(int)this] = nodeCFlagsMapping[(int)parent];
2203 nodeECFlagsMapping[(int)this] = nodeECFlagsMapping[(int)parent];
2212 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2213 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2214 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2219 if(byPlatformOptions != parentByPlatformOptions)
2221 byPlatformOptions.Free();
2222 delete byPlatformOptions;
2226 Array<Platform> GetPlatformsArrayFromExcluisionInfo(ProjectConfig prjConfig)
2228 Array<Platform> platforms { };
2229 Map<Platform, SetBool> exclusionInfo { };
2230 CollectExclusionInfo(exclusionInfo, prjConfig);
2231 if(exclusionInfo[unknown] == true && exclusionInfo.count > 1)
2232 for(mn : exclusionInfo; mn == false)
2235 platforms.Add(unknown);
2236 delete exclusionInfo;
2241 // the code in this function is closely matched to OptionsBox::Load
2242 // and accompanying derivations of OptionBox and their use of OptionSet,
2243 // OptionCheck, LoadOption and FinalizeLoading methods.
2244 // output changing modification should be mirrored in both implementations
2245 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2247 ProjectOptions output { };
2249 // legend: e Element
2250 // o Option (of a ProjectOptions)
2251 // n Node (ProjectNode)
2253 // u Utility (GenericOptionTools)
2258 int includeDirsOption = OPTION(includeDirs);
2260 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2262 Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
2263 Array<bool> optionDone { size = OPTION(postbuildCommands) };
2264 Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
2266 GenericOptionTools<SetBool> utilSetBool {
2267 bool OptionCheck(ProjectOptions options, int option) {
2268 return *(SetBool*)((byte *)options + option) == true;
2270 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2271 if(options && (*(SetBool*)((byte *)options + option) == true))
2272 *(SetBool*)((byte *)output + option) = true;
2275 GenericOptionTools<String> utilString {
2276 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2277 String * string = (String*)((byte *)output + option);
2278 if(*string) delete *string;
2280 *string = CopyString(*(String*)((byte *)options + option));
2283 StringArrayOptionTools utilStringArrays {
2285 caseSensitive = true;
2286 bool OptionCheck(ProjectOptions options, int option) {
2287 String string = *(String*)((byte *)options + option);
2288 return string && string[0];
2290 bool OptionSet(ProjectOptions options, int option) {
2291 Array<String> strings = *(Array<String>*)((byte *)options + option);
2292 if(mergeValues && !configReplaces)
2293 return strings && strings.count;
2295 return strings != null;
2297 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2300 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2304 Array<String> tempStrings = optionTempStrings[option];
2306 optionTempStrings[option] = tempStrings = { };
2310 char priorityMark[10];
2313 sprintf(priorityMark, "%04d\n", priority * 100 + order);
2314 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2315 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2321 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2322 Array<String> * strings = (Array<String>*)((byte *)output + option);
2323 if(*strings) { strings->Free(); delete *strings; }
2324 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2327 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2330 Array<String> tempStrings = optionTempStrings[option];
2331 Array<String> * strings = (Array<String>*)((byte *)output + option);
2332 if(*strings) { strings->Free(); delete *strings; }
2333 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2338 GenericOptionTools<WarningsOption> utilWarningsOption {
2339 bool OptionCheck(ProjectOptions options, int option) {
2340 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2341 return value && value != none;
2343 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2344 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2345 *(WarningsOption*)((byte *)output + option) = value;
2348 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2349 bool OptionCheck(ProjectOptions options, int option) {
2350 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2351 return value && value != none;
2353 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2354 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2355 *(OptimizationStrategy*)((byte *)output + option) = value;
2358 GenericOptionTools<BuildBitDepth> utilBuildBitDepth {
2359 bool OptionCheck(ProjectOptions options, int option) {
2360 BuildBitDepth value = *(BuildBitDepth*)((byte *)options + option);
2361 return value && value != all;
2363 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2364 BuildBitDepth value = options ? *(BuildBitDepth*)((byte *)options + option) : (BuildBitDepth)0;
2365 *(BuildBitDepth*)((byte *)output + option) = value;
2369 Map<int, GenericOptionTools> ot { };
2371 // The following are compiler options
2373 ot[OPTION(debug)] = utilSetBool;
2374 ot[OPTION(memoryGuard)] = utilSetBool;
2375 ot[OPTION(profile)] = utilSetBool;
2376 ot[OPTION(noLineNumbers)] = utilSetBool;
2377 ot[OPTION(strictNameSpaces)] = utilSetBool;
2378 ot[OPTION(fastMath)] = utilSetBool;
2380 ot[OPTION(defaultNameSpace)] = utilString;
2382 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2383 ot[OPTION(includeDirs)] = utilStringArrays;
2385 ot[OPTION(warnings)] = utilWarningsOption;
2387 ot[OPTION(optimization)] = utilOptimizationStrategy;
2389 ot[OPTION(buildBitDepth)] = utilBuildBitDepth;
2391 for(n = node; n; n = n.parent)
2393 ProjectConfig nodeConfig = null;
2398 if(projectConfig && n.configurations)
2400 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2402 if(platform && c.platforms)
2404 for(p : c.platforms; !strcmpi(p.name, platformName))
2408 GenericOptionTools u = uu;
2410 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2412 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2413 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2414 optionConfigXplatformSet[o] = true;
2426 GenericOptionTools u = uu;
2430 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2432 for(p : n.platforms; !strcmpi(p.name, platformName))
2434 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2436 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2437 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2442 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2443 ((u.mergeValues && !u.configReplaces) ?
2444 u.OptionCheck(nodeConfig.options, o) :
2445 u.OptionSet(nodeConfig.options, o)))
2447 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2448 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2452 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2454 u.LoadOption(n.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2455 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2459 u.LoadOption(null, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2460 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2468 GenericOptionTools u = uu;
2471 u.FinalizeLoading(o, optionTempStrings, output);
2474 delete optionConfigXplatformSet;
2476 delete optionTempStrings;
2480 delete utilStringArrays;
2481 delete utilWarningsOption;
2482 delete utilOptimizationStrategy;
2483 delete utilBuildBitDepth;
2490 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2494 ProjectOptions first;
2495 ProjectOptions commonOptions;
2497 Map<String, int> countIncludeDirs { };
2498 Map<String, int> countPreprocessorDefinitions { };
2499 Map<String, bool> commonIncludeDirs { };
2500 Map<String, bool> commonPreprocessorDefinitions { };
2502 for(options : byPlatformOptions) { first = options; break; }
2504 *platformsCommonOptions = commonOptions = first.Copy();
2506 if(commonOptions.includeDirs)
2507 commonOptions.includeDirs.Free();
2508 if(commonOptions.preprocessorDefinitions)
2509 commonOptions.preprocessorDefinitions.Free();
2511 for(options : byPlatformOptions)
2513 if(options != first)
2515 if(commonOptions.debug && options.debug != commonOptions.debug)
2516 commonOptions.debug = unset;
2517 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2518 commonOptions.memoryGuard = unset;
2519 if(commonOptions.profile && options.profile != commonOptions.profile)
2520 commonOptions.profile = unset;
2521 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2522 commonOptions.noLineNumbers = unset;
2523 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2524 commonOptions.strictNameSpaces = unset;
2525 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2526 commonOptions.fastMath = unset;
2528 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2529 commonOptions.warnings = unset;
2530 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2531 commonOptions.optimization = unset;
2532 if(commonOptions.buildBitDepth && options.buildBitDepth != commonOptions.buildBitDepth)
2533 commonOptions.buildBitDepth = all;
2535 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2536 delete commonOptions.defaultNameSpace;
2539 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2540 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2543 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2544 commonIncludeDirs, commonOptions.includeDirs);
2545 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2546 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2548 for(options : byPlatformOptions)
2550 if(options.debug && options.debug == commonOptions.debug)
2551 options.debug = unset;
2552 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2553 options.memoryGuard = unset;
2554 if(options.profile && options.profile == commonOptions.profile)
2555 options.profile = unset;
2556 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2557 options.noLineNumbers = unset;
2558 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2559 options.strictNameSpaces = unset;
2560 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2561 options.fastMath = unset;
2563 if(options.warnings && options.warnings == commonOptions.warnings)
2564 options.warnings = unset;
2565 if(options.optimization && options.optimization == commonOptions.optimization)
2566 options.optimization = unset;
2567 if(options.buildBitDepth && options.buildBitDepth == commonOptions.buildBitDepth)
2568 options.buildBitDepth = all;
2570 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2571 delete options.defaultNameSpace;
2573 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2574 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2577 delete countIncludeDirs;
2578 delete countPreprocessorDefinitions;
2579 delete commonIncludeDirs;
2580 delete commonPreprocessorDefinitions;
2583 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2584 Map<Platform, ProjectOptions> parentByPlatformOptions,
2585 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2587 ComplexComparison result = equal;
2588 ComplexComparison compare;
2590 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2592 ProjectOptions additionalOptions;
2593 additionsByPlatformOptions[platform] = { };
2594 additionalOptions = additionsByPlatformOptions[platform];
2595 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2596 if(compare == greater && result == equal)
2598 else if(compare == different)
2607 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2609 ComplexComparison result = equal;
2610 if(options.debug != parentOptions.debug ||
2611 options.memoryGuard != parentOptions.memoryGuard ||
2612 options.profile != parentOptions.profile ||
2613 options.noLineNumbers != parentOptions.noLineNumbers ||
2614 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2615 options.fastMath != parentOptions.fastMath ||
2616 options.warnings != parentOptions.warnings ||
2617 options.optimization != parentOptions.optimization ||
2618 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2619 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2623 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2624 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2626 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2627 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2633 enum ComplexComparison { different/*, smaller*/, equal, greater };
2635 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2638 if((!strings || !strings.count) && originals && originals.count)
2640 else if(strings && strings.count && (!originals || !originals.count))
2645 additions->Add(CopyString(s));
2647 else if(strings && strings.count && originals && originals.count)
2649 Map<String, String> map { };
2650 MapIterator<String, bool> mit { map = map };
2653 char * s = strstr(it, "\n");
2659 char * s = strstr(it, "\n");
2661 if(!mit.Index(s, false))
2676 additions->Add(CopyString(it));
2684 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2697 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
2705 strings.Add(CopyString(s));
2711 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
2715 Array<String> tmp { };
2716 MapIterator<String, bool> mit { map = common };
2720 if(!mit.Index(s, false))
2721 tmp.Add(CopyString(s));
2727 strings.Add(CopyString(s));
2734 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<int, int> nodeFlagsMapping, String variableName, File f)
2737 customFlags = nodeFlagsMapping[(int)node];
2739 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2741 f.Printf(" $(%s)", variableName);
2744 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<int, int> nodeFlagsMapping, String variableName, DynamicString s)
2747 customFlags = nodeFlagsMapping[(int)node];
2749 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2751 s.concatf(" $(%s)", variableName);
2754 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
2760 if(options.optimization == speed || options.optimization == size ||
2761 options.fastMath == true || options.debug == true)
2763 if(options.debug != true)
2765 s.concatf(" $(if $(DEBUG),");
2769 switch(options.optimization)
2771 case speed: s.concatf(" -O2"); break;
2772 case size: s.concatf(" -Os"); break;
2774 if(options.fastMath == true)
2775 s.concatf(" -ffast-math");
2776 if(options.debug == true)
2778 if(options.debug != true)
2781 else if(commonOptions)
2782 s.concatf(" $(if $(DEBUG),-g)");
2783 if(options.buildBitDepth || (commonOptions && prjWithEcFiles))
2784 s.concatf(" %s", (!options || !options.buildBitDepth || options.buildBitDepth == bits32) ? "$(FORCE_32_BIT)" : "$(FORCE_64_BIT)");
2786 s.concatf(" $(FPIC)");
2788 switch(options.warnings)
2790 case all: s.concatf(" -Wall"); break;
2791 case none: s.concatf(" -w"); break;
2797 if(options && options.preprocessorDefinitions)
2798 ListOptionToDynamicString("D", options.preprocessorDefinitions, false, lineEach, "\t\t\t", false, s);
2799 if(options && options.includeDirs)
2800 ListOptionToDynamicString("I", options.includeDirs, true, lineEach, "\t\t\t", true, s);
2803 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
2805 if(options.memoryGuard == true)
2806 s.concat(" -memguard");
2807 if(options.noLineNumbers == true)
2808 s.concat(" -nolinenumbers");
2809 if(options.strictNameSpaces == true)
2810 s.concat(" -strictns");
2811 if(options.defaultNameSpace && options.defaultNameSpace[0])
2812 s.concatf(" -defaultns %s", options.defaultNameSpace);
2815 static void ListOptionToDynamicString(char * option, Array<String> list, bool prioritize,
2816 ListOutputMethod method, String newLineStart, bool noSpace, DynamicString s)
2820 if(method == newLine)
2821 s.concatf(" \\\n%s", newLineStart);
2824 Map<String, int> sortedList { };
2825 MapNode<String, int> mn;
2827 sortedList[item] = 1;
2828 for(mn = sortedList.root.minimum; mn; mn = mn.next)
2830 char * start = strstr(mn.key, "\n");
2831 if(method == lineEach)
2832 s.concatf(" \\\n%s", newLineStart);
2833 s.concatf(" -%s", option);
2835 StringNoSpaceToDynamicString(s, start ? start+1 : mn.key);
2837 s.concat(start ? start+1 : mn.key);
2845 if(method == lineEach)
2846 s.concatf(" \\\n%s", newLineStart);
2847 s.concatf(" -%s", option);
2849 StringNoSpaceToDynamicString(s, item);
2857 class GenericOptionTools<class X>
2859 bool mergeValues, configReplaces;
2861 virtual bool OptionSet(ProjectOptions options, int option) {
2862 if(*(X*)((byte *)options + option))
2867 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
2869 virtual bool OptionCheck(ProjectOptions options, int option) {
2870 return OptionSet(options, option);
2873 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
2874 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
2877 class StringArrayOptionTools : GenericOptionTools<Array<String>>
2882 class NameCollisionInfo
2892 bool IsExtensionColliding(char * extension)
2895 if(count > 1 && ((!strcmpi(extension, "c") && ec) ||
2896 (!strcmpi(extension, "cpp") && (ec || c)) ||
2897 (!strcmpi(extension, "cc") && (ec || c || cpp)) ||
2898 (!strcmpi(extension, "cxx") && (ec || c || cpp || cc)) ||
2899 !strcmpi(extension, "m")))
2907 static inline void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Platform platform,
2908 Map<Platform, bool> parentExcludedPlatforms, Map<Platform, bool> excludedPlatforms)
2910 if(platform != unknown && !parentExcludedPlatforms[platform])
2912 if(*ifCount) // we really need a if defined(a) || defined(b) here
2913 f.Puts("else\n"); // instead of repeating the rules for each platform
2914 (*ifCount)++; // hmm... what?
2915 f.Printf("ifdef %s\n\n", PlatformToMakefileTargetVariable(platform));
2916 if(excludedPlatforms)
2917 excludedPlatforms[platform] = true;
2921 static inline void CloseRulesPlatformExclusionIfs(File f, int ifCount)
2926 for(c = 0; c < ifCount; c++)