1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(&((ProjectOptions)0).x))
17 static void OutputLog(char * string)
19 #ifdef MAKEFILE_GENERATOR
22 ide.outputView.buildBox.Log(string);
26 bool eString_PathInsideOfMore(char * path, char * of, char * pathRest)
28 if(!path[0] || !of[0])
29 return false; // What to do here? Ever used?
32 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
33 char pathPart[MAX_FILENAME]; //, pathRest[MAX_LOCATION];
35 strcpy(pathRest, path);
36 for(; ofRest[0] && pathRest[0];)
38 SplitDirectory(ofRest, ofPart, ofRest);
39 SplitDirectory(pathRest, pathPart, pathRest);
40 if(fstrcmp(pathPart, ofPart))
43 if(!ofRest[0] && !pathRest[0])
45 else if(!pathRest[0]) // not inside of, it's the other way around
51 enum NodeTypes { project, file, folder, resources, folderOpen };
54 genFile, ewsFile, epjFile, folder, openFolder, ecFile, ehFile,
55 sFile, cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile,
56 archiveFile, packageFile, opticalMediaImageFile, mFile, mmFile;
58 NodeIcons ::SelectFileIcon(char * filePath)
61 if(filePath && filePath[0])
63 char extension[MAX_EXTENSION];
64 GetExtension(filePath, extension);
67 if(!strcmpi(extension, WorkspaceExtension))
69 else if(!strcmpi(extension, ProjectExtension))
71 else if(!strcmpi(extension, "ec"))
73 else if(!strcmpi(extension, "eh"))
75 else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
76 !strcmpi(extension, "cxx"))
78 else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
79 !strcmpi(extension, "hxx"))
81 else if(!strcmpi(extension, "s"))
83 else if(!strcmpi(extension, "c"))
85 else if(!strcmpi(extension, "h"))
87 else if(!strcmpi(extension, "m"))
89 else if(!strcmpi(extension, "mm"))
91 else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
92 !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
94 else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
95 !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
96 !strcmpi(extension, "js"))
98 else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
99 !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
100 !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
101 !strcmpi(extension, "ico"))
103 else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
104 !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
106 else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
107 !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
108 !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
109 !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
110 !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
111 !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
113 else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
114 !strcmpi(extension, "rpm"))
116 else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
117 !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
118 !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
119 !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
120 icon = opticalMediaImageFile;
128 icon = genFile; // tocheck: error icon?
132 NodeIcons ::SelectNodeIcon(NodeTypes type)
151 #define SELECTION_COLOR Color { 10, 36, 106 }
157 // this is so not working, why!
159 // return result was not even executed (did not step on while debugging)
160 class TwoStrings : struct
180 enum IntermediateFileType { none, ec, c, sym, imp, bowl, o };
182 class ProjectNode : ListItem
187 set { return { fileName = value }; }
188 // TOCHECK: Is this isset necessary at all?
189 isset { return nodeType == file && !options && !configurations && !platforms && !files; }
191 property String folder
196 if(strchr(value, '/'))
198 char p[MAX_LOCATION];
199 char n[MAX_FILENAME];
200 GetLastDirectory(value, n);
201 StripLastDirectory(value, p);
202 name = CopyString(n);
203 path = CopyString(p);
206 name = CopyString(value);
210 // TOCHECK: Non Reentrant
211 static char insidePath[MAX_LOCATION];
213 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
214 PathCatSlash(insidePath, name);
216 if(!fstrcmp(path, insidePath))
220 strcpy(insidePath, path);
221 if(!insidePath[0]) strcpy(insidePath, ".");
222 PathCatSlash(insidePath, name);
226 isset { return nodeType == folder; }
228 property String fileName
233 if(strchr(value, '/'))
235 char p[MAX_LOCATION];
236 char n[MAX_FILENAME];
237 GetLastDirectory(value, n);
238 StripLastDirectory(value, p);
239 name = CopyValidateMakefilePath(n);
240 path = CopyValidateMakefilePath(p);
243 name = CopyValidateMakefilePath(value);
247 // TOCHECK: Non Reentrant
248 static char insidePath[MAX_LOCATION];
250 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
251 if(!fstrcmp(path, insidePath))
255 strcpy(insidePath, path);
256 if(!insidePath[0]) strcpy(insidePath, ".");
257 PathCatSlash(insidePath, name);
261 isset { return nodeType == file && (options || configurations || platforms); }
264 LinkList<ProjectNode> files;
265 property ProjectOptions options
267 get { return project ? project.options : options; }
268 set { if(project) { delete project.options; project.options = value; } else { delete options; options = value; } }
269 isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
271 property Array<PlatformOptions> platforms
273 get { return project ? project.platforms : platforms; }
276 if(project) { project.platforms = value; }
279 if(platforms) { platforms.Free(); delete platforms; }
282 List<PlatformOptions> empty { };
283 Iterator<PlatformOptions> it { value };
285 for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
286 for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
293 Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
298 if(p.options && !p.options.isEmpty)
305 property List<ProjectConfig> configurations
307 get { return project ? project.configurations : configurations; }
312 if(project.configurations)
314 project.configurations.Free();
315 delete project.configurations;
317 project.configurations = value;
321 if(configurations) { configurations.Free(); delete configurations; }
324 List<ProjectConfig> empty { };
325 Iterator<ProjectConfig> it { value };
326 configurations = value;
327 for(c : configurations)
329 bool somethingSet = c.options && !c.options.isEmpty;
330 // TODO: Implement isset keyword
331 if(!somethingSet && c.platforms && c.platforms.count)
335 if(p.options && !p.options.isEmpty)
345 for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
352 if(!parent) return true;
355 for(c : configurations)
357 bool somethingSet = c.options && !c.options.isEmpty;
358 if(!somethingSet && c.platforms && c.platforms.count)
362 if(p.options && !p.options.isEmpty)
377 ProjectOptions options;
378 Array<PlatformOptions> platforms;
379 List<ProjectConfig> configurations;
380 ProjectNodeType nodeType;
385 // This holds the absolute path of the .epj for the project topnode (without the filename)
386 // It holds a relative path to the topNode (project) for other nodes (folders and files)
387 // For folders, it includes the folder it refers to. If there is a name difference between the
388 // file system folder and the grouping folder of the project view, it maps to that folder.
398 // This is only set for Top Nodes
401 void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Array<Platform> platforms)
403 if(!platforms.Find(unknown)) // unknown is "Common"
405 // e.g. ifneq "$(or $(or $(OSX_TARGET),$(LINUX_TARGET)),$(WINDOWS_TARGET))"
408 for(i = 0; platforms.count && i < platforms.count - 1; i++)
416 f.Puts(PlatformToMakefileTargetVariable(p));
429 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
431 ProjectConfig nodeConfig = null;
432 if(property::configurations && prjConfig)
434 const char * configName = prjConfig.name;
435 for(cfg : property::configurations)
437 if(!strcmpi(cfg.name, configName))
447 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
449 property bool containsFile
458 if(child.type == file ||
459 ((child.type == folder || child.type == folderOpen) && child.containsFile))
472 char * GetFullFilePath(char * buffer)
476 strcpy(buffer, root.path);
477 PathCatSlash(buffer, path);
478 PathCatSlash(buffer, name);
483 char * GetObjectFileName(char * buffer, Map<String, NameCollisionInfo> namesInfo, IntermediateFileType type, bool dotMain)
485 if(buffer && (this.type == file || (this.type == project && dotMain == true)))
488 char extension[MAX_EXTENSION];
489 char moduleName[MAX_FILENAME];
490 NameCollisionInfo info;
492 GetExtension(name, extension);
493 ReplaceSpaces(moduleName, name);
494 StripExtension(moduleName);
495 info = namesInfo[moduleName];
496 collision = info ? info.IsExtensionColliding(extension) : false;
500 ReplaceSpaces(buffer, project.moduleName);
501 StripExtension(buffer);
502 strcat(buffer, ".main.ec");
505 strcpy(buffer, name);
506 if(!strcmp(extension, "ec") || dotMain)
509 ChangeExtension(buffer, "c", buffer);
511 ChangeExtension(buffer, "sym", buffer);
513 ChangeExtension(buffer, "imp", buffer);
514 else if(type == bowl)
515 ChangeExtension(buffer, "bowl", buffer);
520 strcat(buffer, ".o");
522 ChangeExtension(buffer, "o", buffer);
528 char * GetFileSysMatchingPath(char * buffer)
532 ProjectNode n, root = this.root;
533 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
535 strcpy(buffer, root.path);
537 PathCatSlash(buffer, n.path);
538 if(FileExists(buffer).isDirectory)
541 if(!(n && (n.type == folder || n.type == project)))
547 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
549 ProjectNode node = null;
550 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
551 List<ProjectNode> nodeStack { };
553 for(node = this; node && node.parent; node = node.parent)
556 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
558 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
559 while((node = nodeStack.lastIterator.data))
561 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
562 ProjectOptions nodeOptions = node.property::options;
563 if(nodeOptions && nodeOptions.preprocessorDefinitions)
565 for(def : nodeOptions.preprocessorDefinitions)
566 perFilePreprocessorDefs.Add(CopyString(def));
568 if(config && config.options && config.options.preprocessorDefinitions)
570 for(def : config.options.preprocessorDefinitions)
571 perFilePreprocessorDefs.Add(CopyString(def));
573 if(nodeOptions && nodeOptions.includeDirs)
575 for(dir : nodeOptions.includeDirs)
576 perFileIncludeDirs.Add(CopySystemPath(dir));
578 if(config && config.options && config.options.includeDirs)
580 for(dir : config.options.includeDirs)
581 perFileIncludeDirs.Add(CopySystemPath(dir));
583 nodeStack.lastIterator.Remove();
589 property Project project
593 ProjectNode n = this;
594 while(n && n.type != project) n = n.parent;
595 return n ? (*&n.project) : null;
599 void RenameConfig(char * oldName, char * newName)
603 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
605 if(property::configurations)
607 for(c : property::configurations; !strcmp(c.name, oldName))
610 c.name = CopyString(newName);
615 void DeleteConfig(ProjectConfig configToDelete)
619 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
621 if(property::configurations)
623 Iterator<ProjectConfig> c { property::configurations };
626 ProjectConfig config = c.data;
627 if(!strcmp(configToDelete.name, config.name))
634 if(!property::configurations.count)
635 property::configurations = null;
641 ProjectNode backupNode { };
645 backupNode.files = { };
646 for(f : files) backupNode.files.Add(f.Backup());
648 if(property::options)
649 backupNode.options = property::options.Copy();
651 if(property::platforms)
653 backupNode.platforms = { };
654 for(p : property::platforms)
655 backupNode.platforms.Add(p.Copy());
658 if(property::configurations)
660 backupNode.configurations = { };
661 for(c : property::configurations)
662 backupNode.configurations.Add(c.Copy());
667 void Revert(ProjectNode backupNode)
671 Iterator<ProjectNode> it { backupNode.files };
679 property::options = backupNode.options ? backupNode.options.Copy() : null;
680 if(backupNode.platforms)
682 Array<PlatformOptions> platforms { };
683 property::platforms = platforms;
685 for(p : backupNode.platforms)
686 platforms.Add(p.Copy());
688 if(backupNode.configurations)
690 List<ProjectConfig> configurations { };
691 property::configurations = configurations;
692 for(c : backupNode.configurations)
693 configurations.Add(c.Copy());
697 void FixupNode(char * parentPath)
703 else if(nodeType == file)
708 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
711 else if(nodeType == folder)
717 char temp[MAX_LOCATION];
718 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
719 PathCatSlash(temp, name);
720 path = CopyString(temp);
724 indent = parent ? parent.indent + 1 : 0;
727 icon = NodeIcons::SelectFileIcon(name);
729 icon = NodeIcons::SelectNodeIcon(type);
738 parentPath[0] = '\0';
739 else if(type == resources || type == folder)
740 strcpy(parentPath, path);
742 f.FixupNode(parentPath);
747 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
751 // TOCHECK: Called from JSON writer
752 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
754 strcpy(tempString, "\"");
755 strcat(tempString, property::fileName);
756 strcat(tempString, "\"");
763 // TOCHECK: Called from ProjectView rendering
764 return name ? name : "";
777 if(!project && platforms)
782 if(!project && configurations)
784 configurations.Free();
785 delete configurations;
788 /////////////////////////////
794 property bool isInResources
799 for(node = this; node; node = node.parent)
801 if(node.type == resources)
808 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
810 TwoStrings result { a = CopyString(""), b = CopyString("") };
811 // note: unknown platform is for common
812 Map<Platform, SetBool> exclusionInfo { };
813 MapNode<Platform, SetBool> mn;
818 CollectExclusionInfo(exclusionInfo, prjConfig);
819 common = exclusionInfo[unknown];
821 Map<Platform, SetBool> cleaned { };
822 SetBool opposite = common == true ? false : true;
823 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
825 if(mn.key == unknown || mn.value == opposite)
826 cleaned[mn.key] = mn.value;
828 delete exclusionInfo;
829 exclusionInfo = cleaned;
832 if(exclusionInfo.count > 1)
834 if(exclusionInfo.count > 2)
837 len = strlen(exp) + strlen("$(if $(or ");
838 exp = renew exp char[len+1];
839 strcat(exp, "$(if $(or ");
842 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
844 if(mn.key != unknown)
846 char * comma = mn.next ? "," : "";
848 var = PlatformToMakefileTargetVariable(mn.key);
851 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
852 exp = renew exp char[len+1];
862 len = strlen(exp) + strlen("),");
863 exp = renew exp char[len+1];
867 if(exclusionInfo.root.minimum.key != unknown)
868 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
870 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
873 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
874 exp = renew exp char[len+1];
875 strcat(exp, "$(if $(");
882 exp = common == true ? result.b : result.a;
883 len = strlen(exp) + strlen(",");
884 exp = renew exp char[len+1];
886 if(common == true) result.b = exp; else result.a = exp;
889 len = strlen(exp) + strlen(")");
890 exp = renew exp char[len+1];
894 delete exclusionInfo;
899 bool GetIsExcluded(ProjectConfig prjConfig)
902 // note: unknown platform is for common
903 Map<Platform, SetBool> exclusionInfo { };
904 CollectExclusionInfo(exclusionInfo, prjConfig);
905 if(exclusionInfo.count == 0)
907 else if(exclusionInfo.count == 1)
908 result = exclusionInfo.root.minimum.value == true;
911 SetBool check = exclusionInfo.root.minimum.value;
912 MapNode<Platform, SetBool> mn;
913 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
915 if(check != mn.value)
918 if(!mn) // all are same
919 result = check == true;
923 delete exclusionInfo;
927 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
929 // note: unknown platform is for common
931 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
932 ProjectOptions options = property::options;
933 Array<PlatformOptions> platforms = property::platforms;
934 List<ProjectConfig> configurations = property::configurations;
937 parent.CollectExclusionInfo(output, prjConfig);
939 output[unknown] = unset;
941 if(options && options.excludeFromBuild)
942 output[unknown] = options.excludeFromBuild;
944 if(config && config.options && config.options.excludeFromBuild)
945 output[unknown] = config.options.excludeFromBuild;
951 if(p.options.excludeFromBuild && (platform = p.name))
952 output[platform] = p.options.excludeFromBuild;
955 if(config && config.platforms)
957 for(p : config.platforms)
959 if(p.options.excludeFromBuild && (platform = p.name))
960 output[platform] = p.options.excludeFromBuild;
968 parent.EnsureVisible();
969 row.collapsed = false;
975 parent.files.Delete(this);
978 ProjectNode Find(char * name, bool includeResources)
980 ProjectNode result = null;
985 if(includeResources || child.type != resources)
987 if(child.type != folder && child.name && !strcmpi(child.name, name))
992 result = child.Find(name, includeResources);
1001 ProjectNode FindWithPath(char * name, bool includeResources)
1003 ProjectNode result = null;
1008 if(includeResources || child.type != resources)
1010 char path[MAX_LOCATION];
1011 strcpy(path, child.path);
1012 if(child.type != folder && child.name)
1014 PathCatSlash(path, child.name);
1015 if(!strcmpi(path, name))
1021 result = child.FindWithPath(name, includeResources);
1030 ProjectNode FindByFullPath(char * path, bool includeResources)
1034 char name[MAX_FILENAME];
1035 GetLastDirectory(path, name);
1036 return InternalFindByFullPath(path, includeResources, name);
1041 ProjectNode InternalFindByFullPath(char * path, bool includeResources, char * lastDirName)
1043 ProjectNode result = null;
1048 if(includeResources || child.type != resources)
1050 if(child.type != file)
1051 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1052 else if(child.name && !strcmpi(lastDirName, child.name))
1054 char p[MAX_LOCATION];
1055 child.GetFullFilePath(p);
1056 if(!strcmpi(p, path))
1070 ProjectNode FindByObjectFileName(char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo)
1072 char p[MAX_LOCATION];
1073 ProjectNode result = null;
1074 if(dotMain == true && this.type == project)
1076 GetObjectFileName(p, namesInfo, type, dotMain);
1077 if(!strcmpi(p, fileName))
1082 for(child : files; child.type != resources)
1084 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo)))
1086 else if(child.type == file && child.name)
1088 child.GetObjectFileName(p, namesInfo, type, dotMain);
1089 if(!strcmpi(p, fileName))
1100 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
1102 ProjectNode result = null;
1107 if(includeResources || child.type != resources)
1109 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1115 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1124 ProjectNode FindSameNameConflict(char * name, bool includeResources,
1125 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1127 ProjectNode result = null;
1128 Map<Platform, SetBool> compareExclusion { };
1129 SetBool common, commonComp;
1130 SetBool actual, actualComp;
1135 if(includeResources || child.type != resources)
1137 if(child.type != folder && child.name && !strcmpi(child.name, name))
1139 child.CollectExclusionInfo(compareExclusion, prjConfig);
1140 common = exclusionInfo[unknown];
1141 commonComp = compareExclusion[unknown];
1142 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1144 if(!(common == true || commonComp == true))
1153 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1156 actualComp = commonComp;
1157 if(exclusionInfo[platform] != unset)
1158 actual = exclusionInfo[platform];
1159 if(compareExclusion[platform] != unset)
1160 actualComp = compareExclusion[platform];
1161 if(!(actual == true || actualComp == true))
1169 compareExclusion.Free();
1172 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1176 compareExclusion.Free();
1178 delete compareExclusion;
1182 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1184 ProjectNode node = null;
1185 if(!project.topNode.FindByFullPath(filePath, true))
1187 char temp[MAX_LOCATION];
1188 Map<Platform, SetBool> exclusionInfo { };
1190 GetLastDirectory(filePath, temp);
1191 //if(!checkIfExists || !project.topNode.Find(temp, false))
1193 // TOCHECK: Shouldn't this apply either for all configs or none?
1194 CollectExclusionInfo(exclusionInfo, project.config);
1195 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1197 // Do the check for folder in the same parent or resource files only here
1198 if(type == folder || !checkIfExists)
1202 if(node.name && !strcmpi(node.name, temp))
1207 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1211 node.nodeType = folder;
1217 StripLastDirectory(filePath, temp);
1218 MakePathRelative(temp, project.topNode.path, temp);
1219 node.path = CopyUnixPath(temp);
1221 node.nodeType = file;
1225 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1226 PathCatSlash(temp, node.name);
1227 node.path = CopyString(temp);
1229 files.Insert(after, node);
1231 delete exclusionInfo;
1236 #ifndef MAKEFILE_GENERATOR
1237 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1239 char label[MAX_FILENAME];
1245 bool showConfig = true;
1250 projectView = ide.projectView;
1253 bmp = projectView.icons[icon].bitmap;
1254 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1256 GetLastDirectory(name, label);
1257 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1259 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1261 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1264 addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1265 if(strlen(addendum))
1267 strcat(label, " (");
1268 strcat(label, addendum);
1271 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1272 if(strlen(addendum))
1274 strcat(label, " (");
1275 strcat(label, addendum);
1281 else if(!projectView.drawingInProjectSettingsDialog)
1284 strcat(label, " *");
1285 if(type == project && info)
1287 int len = strlen(info) + 4;
1288 char * more = new char[len];
1289 sprintf(more, " (%s)", info);
1290 strcat(label, more);
1294 len = strlen(label);
1298 if(type == folder || type == folderOpen)
1299 surface.SetForeground(yellow);
1303 surface.TextOpacity(false);
1304 surface.TextExtent(label, len, &w, &h);
1307 // Draw the current row stipple
1308 if(displayFlags.selected)
1309 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1310 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1311 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1313 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1317 if(displayFlags.current)
1319 if(displayFlags.active)
1321 surface.LineStipple(0x5555);
1322 if(displayFlags.selected)
1323 surface.SetForeground(projectView.fileList.stippleColor);
1325 surface.SetForeground(projectView.fileList.foreground);
1329 surface.SetForeground(SELECTION_COLOR);
1331 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1332 surface.LineStipple(0);
1337 surface.SetForeground(white);
1338 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1344 int OnCompare(ProjectNode b)
1347 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1348 result = strcmpi(name, b.name);
1351 if(type == folder && b.type == file) result = -1;
1352 else if(type == file && b.type == folder) result = 1;
1357 bool ContainsFilesWithExtension(char * extension)
1361 char ext[MAX_EXTENSION];
1362 GetExtension(name, ext);
1363 if(!fstrcmp(ext, extension))
1368 bool needed = false;
1370 if(child.ContainsFilesWithExtension(extension))
1376 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1380 char extension[MAX_EXTENSION];
1381 GetExtension(name, extension);
1382 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1383 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1384 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1386 char moduleName[MAX_FILENAME];
1387 NameCollisionInfo info;
1388 ReplaceSpaces(moduleName, name);
1389 StripExtension(moduleName);
1390 info = namesInfo[moduleName];
1392 info = NameCollisionInfo { };
1393 info.count++; // += 1; unless this is for a bug?
1394 if(!strcmpi(extension, "ec"))
1396 else if(!strcmpi(extension, "s"))
1398 else if(!strcmpi(extension, "c"))
1400 else if(!strcmpi(extension, "rc"))
1402 else if(!strcmpi(extension, "cpp"))
1404 else if(!strcmpi(extension, "cc"))
1406 else if(!strcmpi(extension, "cxx"))
1408 else if(!strcmpi(extension, "m"))
1410 else if(!strcmpi(extension, "mm"))
1412 namesInfo[moduleName] = info;
1419 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1420 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1425 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1426 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1427 ProjectConfig prjConfig, bool * containsCXX)
1433 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1434 char moduleName[MAX_FILENAME];
1435 char extension[MAX_EXTENSION];
1436 GetExtension(name, extension);
1437 if(printType == resources)
1440 char tempPath[MAX_LOCATION];
1441 char modulePath[MAX_LOCATION];
1444 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1447 PathCatSlash(tempPath, name);
1452 strcpy(tempPath, path);
1453 PathCatSlash(tempPath, name);
1455 EscapeForMake(modulePath, tempPath, false, true, false);
1456 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1457 items.Add(CopyString(s));
1459 else if(printType == sources)
1461 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1462 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1463 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1465 char modulePath[MAX_LOCATION];
1466 EscapeForMake(modulePath, path, false, true, false);
1467 EscapeForMake(moduleName, name, false, true, false);
1468 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1469 items.Add(CopyString(s));
1472 else if(printType == eCsources)
1474 if(!strcmpi(extension, "ec"))
1476 char modulePath[MAX_LOCATION];
1477 EscapeForMake(modulePath, path, true, true, false);
1478 EscapeForMake(moduleName, name, true, true, false);
1479 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1480 items.Add(CopyString(s));
1484 else if(printType == rcSources)
1486 if(!strcmpi(extension, "rc"))
1488 char modulePath[MAX_LOCATION];
1489 EscapeForMake(modulePath, path, false, true, false);
1490 EscapeForMake(moduleName, name, false, true, false);
1491 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1492 items.Add(CopyString(s));
1496 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1497 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1498 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1500 if(printType == objects)
1503 NameCollisionInfo info;
1505 EscapeForMake(moduleName, name, false, true, false);
1506 StripExtension(moduleName);
1507 info = namesInfo[moduleName];
1508 collision = info ? info.IsExtensionColliding(extension) : false;
1509 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1510 items.Add(CopyString(s));
1511 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1512 *containsCXX = true;
1521 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1522 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1528 void GenMakefilePrintSymbolRules(File f, Project project,
1529 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1530 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1533 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1534 //ProjectNode child;
1535 //char objDir[MAX_LOCATION];
1536 //ReplaceSpaces(objDir, config.objDir.dir);
1538 //eSystem_Log("Printing Symbol Rules\n");
1541 char extension[MAX_EXTENSION];
1542 char modulePath[MAX_LOCATION];
1543 char moduleName[MAX_FILENAME];
1545 GetExtension(name, extension);
1546 if(!strcmpi(extension, "ec"))
1551 ReplaceSpaces(moduleName, name);
1552 StripExtension(moduleName);
1554 ReplaceSpaces(modulePath, path);
1555 if(modulePath[0]) strcat(modulePath, SEPS);
1557 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1559 // *** Dependency command ***
1560 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1561 modulePath, moduleName, extension);
1563 // System Includes (from global settings)
1564 for(item : compiler.dirs[Includes])
1566 strcat(command, " -isystem ");
1567 if(strchr(item, ' '))
1569 strcat(command, "\"");
1570 strcat(command, item);
1571 strcat(command, "\"");
1574 strcat(command, item);
1577 for(item : project.includeDirs)
1579 strcat(command, " -I");
1580 if(strchr(item, ' '))
1582 strcat(command, "\"");
1583 strcat(command, item);
1584 strcat(command, "\"");
1587 strcat(command, item);
1589 for(item : project.preprocessorDefs)
1591 strcat(command, " -D");
1592 strcat(command, item);
1596 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1599 bool firstLine = true;
1602 // To do some time: auto save external dependencies?
1605 if(dep.GetLine(line, sizeof(line)-1))
1609 char * colon = strstr(line, ":");
1610 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1624 // If we failed to generate dependencies...
1628 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1629 moduleName, modulePath, moduleName, extension);
1633 f.Puts(" $(CFLAGS)");
1634 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1636 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1637 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1639 f.Printf(" -c %s%s.%s -o $(call escspace,$@)\n",
1640 modulePath, moduleName, extension);
1641 if(ifCount) f.Puts("endif\n");
1651 bool needed = false;
1652 if(ContainsFilesWithExtension("ec"))
1656 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1667 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1668 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1669 nodeCFlagsMapping, nodeECFlagsMapping);
1676 void GenMakefilePrintPrepecsRules(File f, Project project,
1677 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1678 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1681 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1682 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1683 //ProjectNode child;
1684 //char objDir[MAX_LOCATION];
1685 //ReplaceSpaces(objDir, config.objDir.dir);
1687 //eSystem_Log("Printing Symbol Rules\n");
1690 char extension[MAX_EXTENSION];
1691 char modulePath[MAX_LOCATION];
1692 char moduleName[MAX_FILENAME];
1694 GetExtension(name, extension);
1695 if(!strcmpi(extension, "ec"))
1700 ReplaceSpaces(moduleName, name);
1701 StripExtension(moduleName);
1703 ReplaceSpaces(modulePath, path);
1704 if(modulePath[0]) strcat(modulePath, SEPS);
1706 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1707 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1708 moduleName, modulePath, moduleName, extension);
1709 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1710 modulePath, moduleName, extension, moduleName);*/
1714 f.Puts(" $(CFLAGS)");
1715 //f.Puts(" $(CECFLAGS)");
1716 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1717 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1719 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1720 modulePath, moduleName, extension, moduleName);
1721 if(ifCount) f.Puts("endif\n");
1727 bool needed = false;
1728 if(ContainsFilesWithExtension("ec"))
1732 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1743 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1744 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1745 nodeCFlagsMapping, nodeECFlagsMapping);
1752 void GenMakefilePrintCObjectRules(File f, Project project,
1753 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1754 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1757 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1758 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1759 //ProjectNode child;
1760 //char objDir[MAX_LOCATION];
1761 //ReplaceSpaces(objDir, config.objDir.dir);
1762 //eSystem_Log("Printing C Object Rules\n");
1765 char extension[MAX_EXTENSION];
1766 char modulePath[MAX_LOCATION];
1767 char moduleName[MAX_FILENAME];
1769 GetExtension(name, extension);
1770 if(!strcmpi(extension, "ec"))
1775 ReplaceSpaces(moduleName, name);
1776 StripExtension(moduleName);
1778 ReplaceSpaces(modulePath, path);
1779 if(modulePath[0]) strcat(modulePath, SEPS);
1781 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1783 // *** Dependency command ***
1784 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1785 moduleName, modulePath, moduleName, extension);
1787 // System Includes (from global settings)
1788 for(item : compiler.dirs[Includes])
1790 strcat(command, " -isystem ");
1791 if(strchr(item, ' '))
1793 strcat(command, "\"");
1794 strcat(command, item);
1795 strcat(command, "\"");
1798 strcat(command, item);
1801 for(item : config.includeDirs)
1803 strcat(command, " -I");
1804 if(strchr(item, ' '))
1806 strcat(command, "\"");
1807 strcat(command, item);
1808 strcat(command, "\"");
1811 strcat(command, item);
1813 for(item : config.preprocessorDefs)
1815 strcat(command, " -D");
1816 strcat(command, item);
1820 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1824 bool firstLine = true;
1826 // To do some time: auto save external dependencies?
1829 if(dep.GetLine(line, sizeof(line)-1))
1833 char * colon = strstr(line, ":");
1834 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1848 // If we failed to generate dependencies...
1851 /* COMMENTED OUT FOR NOW
1852 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1853 moduleName, modulePath, moduleName, extension);
1856 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1857 moduleName, modulePath, moduleName, extension, moduleName);
1863 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1864 modulePath, moduleName, extension, moduleName);
1869 f.Puts(" $(CFLAGS)");
1870 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1871 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1872 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1873 f.Puts(" $(FVISIBILITY)");
1875 f.Printf(" -c %s%s.%s -o $(call escspace,$@) -symbols $(OBJ)\n",
1876 modulePath, moduleName, extension);
1877 if(ifCount) f.Puts("endif\n");
1883 bool needed = false;
1884 if(ContainsFilesWithExtension("ec"))
1888 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1899 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1900 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1901 nodeCFlagsMapping, nodeECFlagsMapping);
1908 void GenMakefilePrintObjectRules(File f, Project project,
1909 Map<String, NameCollisionInfo> namesInfo,
1910 ProjectConfig prjConfig,
1911 //Map<Platform, bool> parentExcludedPlatforms,
1912 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1915 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1916 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1917 //ProjectNode child;
1918 //char objDir[MAX_LOCATION];
1919 //ReplaceSpaces(objDir, config.objDir.dir);
1920 //eSystem_Log("Printing Object Rules\n");
1924 char extension[MAX_EXTENSION];
1925 char modulePath[MAX_LOCATION];
1926 char moduleName[MAX_FILENAME];
1928 GetExtension(name, extension);
1929 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1930 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1931 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1935 NameCollisionInfo info;
1937 ReplaceSpaces(moduleName, name);
1938 StripExtension(moduleName);
1940 info = namesInfo[moduleName];
1941 collision = info ? info.IsExtensionColliding(extension) : false;
1943 ReplaceSpaces(modulePath, path);
1944 if(modulePath[0]) strcat(modulePath, SEPS);
1948 // *** Dependency command ***
1949 if(!strcmpi(extension, "ec"))
1950 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1952 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1953 moduleName, modulePath, moduleName, extension);
1955 if(!strcmpi(extension, "ec"))
1957 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1961 // System Includes (from global settings)
1962 for(item : compiler.dirs[includes])
1964 strcat(command, " -isystem ");
1965 if(strchr(item, ' '))
1967 strcat(command, "\"");
1968 strcat(command, item);
1969 strcat(command, "\"");
1972 strcat(command, item);
1975 for(item : config.includeDirs)
1977 strcat(command, " -I");
1978 if(strchr(item, ' '))
1980 strcat(command, "\"");
1981 strcat(command, item);
1982 strcat(command, "\"");
1985 strcat(command, item);
1987 for(item : config.preprocessorDefs)
1989 strcat(command, " -D");
1990 strcat(command, item);
1994 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
1997 bool firstLine = true;
2000 // To do some time: auto save external dependencies?
2004 if(dep.GetLine(line, sizeof(line)-1))
2008 char * colon = strstr(line, ":");
2009 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2023 // If we failed to generate dependencies...
2032 if(!strcmpi(extension, "rc"))
2035 f.Puts("ifdef WINDOWS_TARGET\n\n");
2038 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2040 if(!strcmpi(extension, "ec"))
2041 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2043 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
2044 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
2045 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2046 f.Printf("\t$(CXX)");
2047 else if(!strcmpi(extension, "rc"))
2048 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< $(call escspace,$@)\n");
2050 f.Printf("\t$(CC)");
2052 if(strcmpi(extension, "rc") != 0)
2054 f.Puts(" $(CFLAGS)");
2055 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2057 if(!strcmpi(extension, "ec"))
2058 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(call escspace,$@)\n", moduleName);
2060 f.Printf(" -c %s%s.%s -o $(call escspace,$@)\n",
2061 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2063 if(ifCount) f.Puts("endif\n");
2069 bool needed = false;
2072 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2082 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2083 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2084 nodeCFlagsMapping, nodeECFlagsMapping);
2091 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2098 //Iterator<ProjectNode> i { files };
2099 //Iterator<ProjectNode> prev { files };
2100 //for(child : files)
2102 for(c = 0; c < files.count; c++)
2104 ProjectNode child = files[c];
2105 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2108 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2111 char tempPath[MAX_LOCATION];
2112 char resPath[MAX_LOCATION];
2114 // $(EAR) aw%s --- /*quiet ? "q" : */""
2116 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2119 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2122 PathCatSlash(tempPath, child.name);
2127 strcpy(tempPath, child.path);
2128 PathCatSlash(tempPath, child.name);
2130 EscapeForMake(resPath, tempPath, false, true, false);
2131 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2134 if(count == 10 || (count > 0 && (ts || !child.next)))
2136 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2139 for(parent = this; parent.type == folder; parent = parent.parent)
2142 strcpy(path, parent.name);
2149 f.Printf(" \"%s\"%s\n", path, ts.b);
2161 if(child.type == folder)
2162 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2167 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2168 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2169 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2170 Map<Platform, ProjectOptions> parentByPlatformOptions)
2172 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2173 if(type == file || type == folder || type == project)
2175 bool hasPerNodeOptions = type == project;
2176 if(!hasPerNodeOptions)
2178 if(options && !options.isEmpty)
2179 hasPerNodeOptions = true;
2180 else if(configurations)
2182 for(c : configurations)
2184 if(c.options && !c.options.isEmpty)
2186 hasPerNodeOptions = true;
2191 for(p : c.platforms)
2193 if(p.options && !p.options.isEmpty)
2195 hasPerNodeOptions = true;
2199 if(hasPerNodeOptions)
2204 if(!hasPerNodeOptions && platforms)
2208 if(p.options && !p.options.isEmpty)
2210 hasPerNodeOptions = true;
2217 if(hasPerNodeOptions)
2219 bool isEqual = false, isGreater = false;
2220 ComplexComparison complexCmp;
2222 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2223 ProjectOptions platformsCommonOptions;
2224 ProjectOptions byFileConfigPlatformProjectOptions;
2226 DynamicString cflags { };
2227 DynamicString ecflags { };
2231 byPlatformOptions = { };
2233 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2235 byFileConfigPlatformProjectOptions =
2236 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2237 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2240 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2242 byPlatformOptions[unknown] = platformsCommonOptions;
2244 if(parentByPlatformOptions)
2246 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2247 parentByPlatformOptions, additionsByPlatformOptions);
2248 isGreater = complexCmp == greater;
2249 isEqual = complexCmp == equal;
2254 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2256 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2258 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2260 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2263 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2265 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2269 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2271 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2274 if(!isGreater) cflags.concat(" \\\n\t");
2279 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2282 ecflags.concat(" \\\n\t");
2289 cflags.concat(" \\\n\t");
2290 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2294 additionsByPlatformOptions.Free();
2295 delete additionsByPlatformOptions;
2301 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2302 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2310 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2311 cflagsVariations[s] = variationNum = cflagsVariations.count;
2312 nodeCFlagsMapping[(intptr)this] = variationNum;
2315 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2316 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2317 nodeECFlagsMapping[(intptr)this] = variationNum;
2328 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2329 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2338 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2339 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2340 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2345 if(byPlatformOptions != parentByPlatformOptions)
2347 byPlatformOptions.Free();
2348 delete byPlatformOptions;
2352 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2354 Array<Platform> platforms { };
2355 Map<Platform, SetBool> exclusionInfo { };
2356 CollectExclusionInfo(exclusionInfo, prjConfig);
2358 if(exclusionInfo[unknown] == true)
2360 if(exclusionInfo.count > 1)
2361 for(p : exclusionInfo; p == false)
2366 bool onlyOnknown = true;
2367 for(p : exclusionInfo)
2368 if(&p != unknown && p == true)
2370 onlyOnknown = false;
2374 platforms.Add(unknown);
2378 for(p = unknown + 1; p < Platform::enumSize; p++)
2379 if(exclusionInfo[p] != true)
2383 delete exclusionInfo;
2387 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2389 char moduleName[MAX_FILENAME];
2392 bool headerAltFailed = false;
2394 char extension[MAX_EXTENSION];
2395 NameCollisionInfo info;
2396 Project prj = property::project;
2397 Map<String, String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2399 GetExtension(name, extension);
2400 ReplaceSpaces(moduleName, name);
2401 StripExtension(moduleName);
2402 info = namesInfo[moduleName];
2403 collision = info ? info.IsExtensionColliding(extension) : false;
2405 for(h2s : headerToSource)
2407 if(!strcmpi(extension, &h2s))
2409 char filePath[MAX_LOCATION];
2410 GetFullFilePath(filePath);
2411 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2412 ChangeExtension(moduleName, h2s, moduleName);
2413 if(prj.topNode.Find(moduleName, false))
2415 strcpy(extension, h2s);
2416 collision = info ? info.IsExtensionColliding(extension) : false;
2417 ChangeExtension(filePath, h2s, filePath);
2418 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2419 StripExtension(moduleName);
2423 headerAltFailed = true;
2424 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2425 StripExtension(moduleName);
2431 if(!headerAltFailed)
2433 output.concat(" \"");
2434 output.concat(objDir); //.concat(" $(OBJ)");
2439 strcat(moduleName, ".");
2440 strcat(moduleName, extension);
2442 strcat(moduleName, ".o");
2443 output.concat(moduleName);
2444 output.concat("\"");
2447 else if(type == project && ContainsFilesWithExtension("ec"))
2449 Project prj = property::project;
2451 ReplaceSpaces(moduleName, prj.moduleName);
2452 strcat(moduleName, ".main.ec");
2453 output.concat(" \"");
2454 output.concat(objDir);
2456 output.concat(moduleName);
2457 output.concat("\"");
2459 ChangeExtension(moduleName, "c", moduleName);
2460 output.concat(" \"");
2461 output.concat(objDir);
2463 output.concat(moduleName);
2464 output.concat("\"");
2466 ChangeExtension(moduleName, "o", moduleName);
2467 output.concat(" \"");
2468 output.concat(objDir);
2470 output.concat(moduleName);
2471 output.concat("\"");
2477 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2478 child.GetTargets(prjConfig, namesInfo, objDir, output);
2483 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2488 char extension[MAX_EXTENSION];
2489 char fileName[MAX_FILENAME];
2490 char moduleName[MAX_FILENAME];
2491 NameCollisionInfo info;
2492 Project prj = property::project;
2493 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2495 GetExtension(name, extension);
2496 ReplaceSpaces(moduleName, name);
2497 StripExtension(moduleName);
2498 info = namesInfo[moduleName];
2499 collision = info ? info.IsExtensionColliding(extension) : false;
2501 strcpy(fileName, prj.topNode.path);
2502 PathCatSlash(fileName, objDir.dir);
2503 PathCatSlash(fileName, name);
2505 if(!onlyCObject && !strcmp(extension, "ec"))
2507 ChangeExtension(fileName, "c", fileName);
2508 if(FileExists(fileName)) DeleteFile(fileName);
2509 ChangeExtension(fileName, "sym", fileName);
2510 if(FileExists(fileName)) DeleteFile(fileName);
2511 ChangeExtension(fileName, "imp", fileName);
2512 if(FileExists(fileName)) DeleteFile(fileName);
2513 ChangeExtension(fileName, "bowl", fileName);
2514 if(FileExists(fileName)) DeleteFile(fileName);
2515 ChangeExtension(fileName, "ec", fileName);
2519 strcat(fileName, ".o");
2521 ChangeExtension(fileName, "o", fileName);
2522 if(FileExists(fileName)) DeleteFile(fileName);
2530 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2531 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2536 bool IsInNode(ProjectNode node)
2538 bool result = false;
2540 for(n = this; n; n = n.parent)
2552 // the code in this function is closely matched to OptionsBox::Load
2553 // and accompanying derivations of OptionBox and their use of OptionSet,
2554 // OptionCheck, LoadOption and FinalizeLoading methods.
2555 // output changing modification should be mirrored in both implementations
2556 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2558 ProjectOptions output { };
2560 // legend: e Element
2561 // o Option (of a ProjectOptions)
2562 // n Node (ProjectNode)
2564 // u Utility (GenericOptionTools)
2569 int includeDirsOption = OPTION(includeDirs);
2571 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2573 // OPTION(ProjectOptions' last member) for size
2574 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2575 Array<bool> optionDone { size = OPTION(installCommands) };
2576 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2578 GenericOptionTools<SetBool> utilSetBool {
2579 bool OptionCheck(ProjectOptions options, int option) {
2580 return *(SetBool*)((byte *)options + option) == true;
2582 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2583 if(options && (*(SetBool*)((byte *)options + option) == true))
2584 *(SetBool*)((byte *)output + option) = true;
2587 GenericOptionTools<String> utilString {
2588 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2589 String * string = (String*)((byte *)output + option);
2590 if(*string) delete *string;
2592 *string = CopyString(*(String*)((byte *)options + option));
2595 StringArrayOptionTools utilStringArrays {
2597 caseSensitive = true;
2598 bool OptionCheck(ProjectOptions options, int option) {
2599 Array<String> strings = *(Array<String>*)((byte *)options + option);
2600 return strings && strings.count;
2602 bool OptionSet(ProjectOptions options, int option) {
2603 Array<String> strings = *(Array<String>*)((byte *)options + option);
2604 if(mergeValues && !configReplaces)
2605 return strings && strings.count;
2607 return strings != null;
2609 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2612 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2616 Array<String> tempStrings = optionTempStrings[option];
2618 optionTempStrings[option] = tempStrings = { };
2622 char priorityMark[10];
2625 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2626 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2627 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2633 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2634 Array<String> * strings = (Array<String>*)((byte *)output + option);
2635 if(*strings) { strings->Free(); delete *strings; }
2636 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2639 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2642 Array<String> tempStrings = optionTempStrings[option];
2643 Array<String> * strings = (Array<String>*)((byte *)output + option);
2644 if(*strings) { strings->Free(); delete *strings; }
2645 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2650 GenericOptionTools<WarningsOption> utilWarningsOption {
2651 bool OptionCheck(ProjectOptions options, int option) {
2652 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2653 return value && value != none;
2655 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2656 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2657 *(WarningsOption*)((byte *)output + option) = value;
2660 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2661 bool OptionCheck(ProjectOptions options, int option) {
2662 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2663 return value && value != none;
2665 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2666 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2667 *(OptimizationStrategy*)((byte *)output + option) = value;
2671 Map<int, GenericOptionTools> ot { };
2673 // The following are compiler options
2675 ot[OPTION(debug)] = utilSetBool;
2676 ot[OPTION(memoryGuard)] = utilSetBool;
2677 ot[OPTION(profile)] = utilSetBool;
2678 ot[OPTION(noLineNumbers)] = utilSetBool;
2679 ot[OPTION(strictNameSpaces)] = utilSetBool;
2680 ot[OPTION(fastMath)] = utilSetBool;
2682 ot[OPTION(defaultNameSpace)] = utilString;
2684 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2685 ot[OPTION(includeDirs)] = utilStringArrays;
2687 ot[OPTION(warnings)] = utilWarningsOption;
2689 ot[OPTION(optimization)] = utilOptimizationStrategy;
2691 for(n = node; n; n = n.parent)
2693 ProjectConfig nodeConfig = null;
2695 priority = (priority / 10 + 1) * 10;
2698 if(projectConfig && n.configurations)
2700 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2702 if(platform && c.platforms)
2704 for(p : c.platforms; !strcmpi(p.name, platformName))
2708 GenericOptionTools u = uu;
2710 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2712 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2713 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2714 optionConfigXplatformSet[o] = true;
2726 GenericOptionTools u = uu;
2730 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2732 for(p : n.platforms; !strcmpi(p.name, platformName))
2734 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2736 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2737 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2742 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2743 ((u.mergeValues && !u.configReplaces) ?
2744 u.OptionCheck(nodeConfig.options, o) :
2745 u.OptionSet(nodeConfig.options, o)))
2747 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2748 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2752 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2754 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2755 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2759 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2760 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2768 GenericOptionTools u = uu;
2771 u.FinalizeLoading(o, optionTempStrings, output);
2774 delete optionConfigXplatformSet;
2776 delete optionTempStrings;
2780 delete utilStringArrays;
2781 delete utilWarningsOption;
2782 delete utilOptimizationStrategy;
2789 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2793 ProjectOptions first;
2794 ProjectOptions commonOptions;
2796 Map<String, int> countIncludeDirs { };
2797 Map<String, int> countPreprocessorDefinitions { };
2798 Map<String, bool> commonIncludeDirs { };
2799 Map<String, bool> commonPreprocessorDefinitions { };
2801 for(options : byPlatformOptions) { first = options; break; }
2803 *platformsCommonOptions = commonOptions = first.Copy();
2805 if(commonOptions.includeDirs)
2806 commonOptions.includeDirs.Free();
2807 if(commonOptions.preprocessorDefinitions)
2808 commonOptions.preprocessorDefinitions.Free();
2810 for(options : byPlatformOptions)
2812 if(options != first)
2814 if(commonOptions.debug && options.debug != commonOptions.debug)
2815 commonOptions.debug = unset;
2816 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2817 commonOptions.memoryGuard = unset;
2818 if(commonOptions.profile && options.profile != commonOptions.profile)
2819 commonOptions.profile = unset;
2820 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2821 commonOptions.noLineNumbers = unset;
2822 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2823 commonOptions.strictNameSpaces = unset;
2824 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2825 commonOptions.fastMath = unset;
2827 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2828 commonOptions.warnings = unset;
2829 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2830 commonOptions.optimization = unset;
2832 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2833 delete commonOptions.defaultNameSpace;
2836 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2837 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2840 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2841 commonIncludeDirs, commonOptions.includeDirs);
2842 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2843 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2845 for(options : byPlatformOptions)
2847 if(options.debug && options.debug == commonOptions.debug)
2848 options.debug = unset;
2849 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2850 options.memoryGuard = unset;
2851 if(options.profile && options.profile == commonOptions.profile)
2852 options.profile = unset;
2853 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2854 options.noLineNumbers = unset;
2855 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2856 options.strictNameSpaces = unset;
2857 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2858 options.fastMath = unset;
2860 if(options.warnings && options.warnings == commonOptions.warnings)
2861 options.warnings = unset;
2862 if(options.optimization && options.optimization == commonOptions.optimization)
2863 options.optimization = unset;
2865 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2866 delete options.defaultNameSpace;
2868 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2869 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2872 delete countIncludeDirs;
2873 delete countPreprocessorDefinitions;
2874 delete commonIncludeDirs;
2875 delete commonPreprocessorDefinitions;
2878 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2879 Map<Platform, ProjectOptions> parentByPlatformOptions,
2880 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2882 ComplexComparison result = equal;
2883 ComplexComparison compare;
2885 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2887 ProjectOptions additionalOptions;
2888 additionsByPlatformOptions[platform] = { };
2889 additionalOptions = additionsByPlatformOptions[platform];
2890 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2891 if(compare == greater && result == equal)
2893 else if(compare == different)
2902 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2904 ComplexComparison result = equal;
2905 if(options.debug != parentOptions.debug ||
2906 options.memoryGuard != parentOptions.memoryGuard ||
2907 options.profile != parentOptions.profile ||
2908 options.noLineNumbers != parentOptions.noLineNumbers ||
2909 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2910 options.fastMath != parentOptions.fastMath ||
2911 options.warnings != parentOptions.warnings ||
2912 options.optimization != parentOptions.optimization ||
2913 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2914 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2918 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2919 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2921 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2922 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2928 enum ComplexComparison { different/*, smaller*/, equal, greater };
2930 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2933 if((!strings || !strings.count) && originals && originals.count)
2935 else if(strings && strings.count && (!originals || !originals.count))
2940 additions->Add(CopyString(s));
2942 else if(strings && strings.count && originals && originals.count)
2944 Map<String, String> map { };
2945 MapIterator<String, bool> mit { map = map };
2948 char * s = strstr(it, "\n");
2954 char * s = strstr(it, "\n");
2956 if(!mit.Index(s, false))
2971 additions->Add(CopyString(it));
2979 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2992 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3000 strings.Add(CopyString(s));
3006 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3010 Array<String> tmp { };
3011 MapIterator<String, bool> mit { map = common };
3015 if(!mit.Index(s, false))
3016 tmp.Add(CopyString(s));
3022 strings.Add(CopyString(s));
3029 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, File f)
3032 customFlags = nodeFlagsMapping[(intptr)node];
3034 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3036 f.Printf(" $(%s)", variableName);
3039 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, DynamicString s)
3042 customFlags = nodeFlagsMapping[(intptr)node];
3044 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3046 s.concatf(" $(%s)", variableName);
3049 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3055 if(options.optimization == speed || options.optimization == size ||
3056 options.fastMath == true || options.debug == true)
3058 if(options.debug != true)
3060 s.concat(" $(if $(DEBUG),");
3064 switch(options.optimization)
3066 case speed: s.concat(" -O2"); break;
3067 case size: s.concat(" -Os"); break;
3069 if(options.fastMath == true)
3070 s.concat(" -ffast-math");
3071 if(options.debug == true)
3073 if(options.debug != true)
3076 else if(commonOptions)
3077 s.concat(" $(if $(DEBUG),-g)");
3079 s.concat(" $(FPIC)");
3081 switch(options.warnings)
3083 case all: s.concat(" -Wall"); break;
3084 case none: s.concat(" -w"); break;
3090 if(options && options.preprocessorDefinitions)
3091 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3092 if(options && options.includeDirs)
3093 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3096 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3098 if(options.memoryGuard == true)
3099 s.concat(" -memguard");
3100 if(options.noLineNumbers == true)
3101 s.concat(" -nolinenumbers");
3102 if(options.strictNameSpaces == true)
3103 s.concat(" -strictns");
3104 if(options.defaultNameSpace && options.defaultNameSpace[0])
3105 s.concatf(" -defaultns %s", options.defaultNameSpace);
3108 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3109 LineOutputMethod lineMethod, String newLineStart)
3113 if(lineMethod == newLine)
3115 output.concat(" \\\n");
3116 output.concat(newLineStart);
3120 Map<String, int> sortedList { };
3121 MapNode<String, int> mn;
3123 sortedList[item] = 1;
3124 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3126 char * start = strstr(mn.key, "\n");
3127 if(lineMethod == lineEach)
3129 output.concat(" \\\n");
3130 output.concat(newLineStart);
3133 output.concat(flagNames[flag]);
3134 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3142 if(lineMethod == lineEach)
3144 output.concat(" \\\n");
3145 output.concat(newLineStart);
3148 output.concat(flagNames[flag]);
3149 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3155 class GenericOptionTools<class X>
3157 bool mergeValues, configReplaces;
3159 virtual bool OptionSet(ProjectOptions options, int option) {
3160 if(*(X*)((byte *)options + option))
3165 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3167 virtual bool OptionCheck(ProjectOptions options, int option) {
3168 return OptionSet(options, option);
3171 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3172 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3175 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3180 class NameCollisionInfo
3193 bool IsExtensionColliding(char * extension)
3197 ((!strcmpi(extension, "c") && ec) ||
3198 (!strcmpi(extension, "rc") && (ec || c)) ||
3199 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3200 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3201 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3202 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3203 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3204 !strcmpi(extension, "mm")))