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 = 1, error = 1, input = 2 }, 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 = 1, error = 1, input = 2 }, 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 = 1, error = 1, input = 2 }, 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 Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
2574 Array<bool> optionDone { size = OPTION(postbuildCommands) };
2575 Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
2577 GenericOptionTools<SetBool> utilSetBool {
2578 bool OptionCheck(ProjectOptions options, int option) {
2579 return *(SetBool*)((byte *)options + option) == true;
2581 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2582 if(options && (*(SetBool*)((byte *)options + option) == true))
2583 *(SetBool*)((byte *)output + option) = true;
2586 GenericOptionTools<String> utilString {
2587 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2588 String * string = (String*)((byte *)output + option);
2589 if(*string) delete *string;
2591 *string = CopyString(*(String*)((byte *)options + option));
2594 StringArrayOptionTools utilStringArrays {
2596 caseSensitive = true;
2597 bool OptionCheck(ProjectOptions options, int option) {
2598 Array<String> strings = *(Array<String>*)((byte *)options + option);
2599 return strings && strings.count;
2601 bool OptionSet(ProjectOptions options, int option) {
2602 Array<String> strings = *(Array<String>*)((byte *)options + option);
2603 if(mergeValues && !configReplaces)
2604 return strings && strings.count;
2606 return strings != null;
2608 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2611 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2615 Array<String> tempStrings = optionTempStrings[option];
2617 optionTempStrings[option] = tempStrings = { };
2621 char priorityMark[10];
2624 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2625 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2626 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2632 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2633 Array<String> * strings = (Array<String>*)((byte *)output + option);
2634 if(*strings) { strings->Free(); delete *strings; }
2635 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2638 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2641 Array<String> tempStrings = optionTempStrings[option];
2642 Array<String> * strings = (Array<String>*)((byte *)output + option);
2643 if(*strings) { strings->Free(); delete *strings; }
2644 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2649 GenericOptionTools<WarningsOption> utilWarningsOption {
2650 bool OptionCheck(ProjectOptions options, int option) {
2651 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2652 return value && value != none;
2654 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2655 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2656 *(WarningsOption*)((byte *)output + option) = value;
2659 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2660 bool OptionCheck(ProjectOptions options, int option) {
2661 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2662 return value && value != none;
2664 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2665 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2666 *(OptimizationStrategy*)((byte *)output + option) = value;
2670 Map<int, GenericOptionTools> ot { };
2672 // The following are compiler options
2674 ot[OPTION(debug)] = utilSetBool;
2675 ot[OPTION(memoryGuard)] = utilSetBool;
2676 ot[OPTION(profile)] = utilSetBool;
2677 ot[OPTION(noLineNumbers)] = utilSetBool;
2678 ot[OPTION(strictNameSpaces)] = utilSetBool;
2679 ot[OPTION(fastMath)] = utilSetBool;
2681 ot[OPTION(defaultNameSpace)] = utilString;
2683 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2684 ot[OPTION(includeDirs)] = utilStringArrays;
2686 ot[OPTION(warnings)] = utilWarningsOption;
2688 ot[OPTION(optimization)] = utilOptimizationStrategy;
2690 for(n = node; n; n = n.parent)
2692 ProjectConfig nodeConfig = null;
2694 priority = (priority / 10 + 1) * 10;
2697 if(projectConfig && n.configurations)
2699 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2701 if(platform && c.platforms)
2703 for(p : c.platforms; !strcmpi(p.name, platformName))
2707 GenericOptionTools u = uu;
2709 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2711 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2712 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2713 optionConfigXplatformSet[o] = true;
2725 GenericOptionTools u = uu;
2729 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2731 for(p : n.platforms; !strcmpi(p.name, platformName))
2733 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2735 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2736 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2741 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2742 ((u.mergeValues && !u.configReplaces) ?
2743 u.OptionCheck(nodeConfig.options, o) :
2744 u.OptionSet(nodeConfig.options, o)))
2746 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2747 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2751 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2753 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2754 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2758 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2759 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2767 GenericOptionTools u = uu;
2770 u.FinalizeLoading(o, optionTempStrings, output);
2773 delete optionConfigXplatformSet;
2775 delete optionTempStrings;
2779 delete utilStringArrays;
2780 delete utilWarningsOption;
2781 delete utilOptimizationStrategy;
2788 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2792 ProjectOptions first;
2793 ProjectOptions commonOptions;
2795 Map<String, int> countIncludeDirs { };
2796 Map<String, int> countPreprocessorDefinitions { };
2797 Map<String, bool> commonIncludeDirs { };
2798 Map<String, bool> commonPreprocessorDefinitions { };
2800 for(options : byPlatformOptions) { first = options; break; }
2802 *platformsCommonOptions = commonOptions = first.Copy();
2804 if(commonOptions.includeDirs)
2805 commonOptions.includeDirs.Free();
2806 if(commonOptions.preprocessorDefinitions)
2807 commonOptions.preprocessorDefinitions.Free();
2809 for(options : byPlatformOptions)
2811 if(options != first)
2813 if(commonOptions.debug && options.debug != commonOptions.debug)
2814 commonOptions.debug = unset;
2815 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2816 commonOptions.memoryGuard = unset;
2817 if(commonOptions.profile && options.profile != commonOptions.profile)
2818 commonOptions.profile = unset;
2819 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2820 commonOptions.noLineNumbers = unset;
2821 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2822 commonOptions.strictNameSpaces = unset;
2823 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2824 commonOptions.fastMath = unset;
2826 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2827 commonOptions.warnings = unset;
2828 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2829 commonOptions.optimization = unset;
2831 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2832 delete commonOptions.defaultNameSpace;
2835 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2836 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2839 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2840 commonIncludeDirs, commonOptions.includeDirs);
2841 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2842 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2844 for(options : byPlatformOptions)
2846 if(options.debug && options.debug == commonOptions.debug)
2847 options.debug = unset;
2848 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2849 options.memoryGuard = unset;
2850 if(options.profile && options.profile == commonOptions.profile)
2851 options.profile = unset;
2852 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2853 options.noLineNumbers = unset;
2854 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2855 options.strictNameSpaces = unset;
2856 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2857 options.fastMath = unset;
2859 if(options.warnings && options.warnings == commonOptions.warnings)
2860 options.warnings = unset;
2861 if(options.optimization && options.optimization == commonOptions.optimization)
2862 options.optimization = unset;
2864 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2865 delete options.defaultNameSpace;
2867 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2868 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2871 delete countIncludeDirs;
2872 delete countPreprocessorDefinitions;
2873 delete commonIncludeDirs;
2874 delete commonPreprocessorDefinitions;
2877 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2878 Map<Platform, ProjectOptions> parentByPlatformOptions,
2879 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2881 ComplexComparison result = equal;
2882 ComplexComparison compare;
2884 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2886 ProjectOptions additionalOptions;
2887 additionsByPlatformOptions[platform] = { };
2888 additionalOptions = additionsByPlatformOptions[platform];
2889 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2890 if(compare == greater && result == equal)
2892 else if(compare == different)
2901 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2903 ComplexComparison result = equal;
2904 if(options.debug != parentOptions.debug ||
2905 options.memoryGuard != parentOptions.memoryGuard ||
2906 options.profile != parentOptions.profile ||
2907 options.noLineNumbers != parentOptions.noLineNumbers ||
2908 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2909 options.fastMath != parentOptions.fastMath ||
2910 options.warnings != parentOptions.warnings ||
2911 options.optimization != parentOptions.optimization ||
2912 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2913 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2917 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2918 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2920 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2921 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2927 enum ComplexComparison { different/*, smaller*/, equal, greater };
2929 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2932 if((!strings || !strings.count) && originals && originals.count)
2934 else if(strings && strings.count && (!originals || !originals.count))
2939 additions->Add(CopyString(s));
2941 else if(strings && strings.count && originals && originals.count)
2943 Map<String, String> map { };
2944 MapIterator<String, bool> mit { map = map };
2947 char * s = strstr(it, "\n");
2953 char * s = strstr(it, "\n");
2955 if(!mit.Index(s, false))
2970 additions->Add(CopyString(it));
2978 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2991 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
2999 strings.Add(CopyString(s));
3005 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3009 Array<String> tmp { };
3010 MapIterator<String, bool> mit { map = common };
3014 if(!mit.Index(s, false))
3015 tmp.Add(CopyString(s));
3021 strings.Add(CopyString(s));
3028 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, File f)
3031 customFlags = nodeFlagsMapping[(intptr)node];
3033 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3035 f.Printf(" $(%s)", variableName);
3038 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, DynamicString s)
3041 customFlags = nodeFlagsMapping[(intptr)node];
3043 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3045 s.concatf(" $(%s)", variableName);
3048 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3054 if(options.optimization == speed || options.optimization == size ||
3055 options.fastMath == true || options.debug == true)
3057 if(options.debug != true)
3059 s.concat(" $(if $(DEBUG),");
3063 switch(options.optimization)
3065 case speed: s.concat(" -O2"); break;
3066 case size: s.concat(" -Os"); break;
3068 if(options.fastMath == true)
3069 s.concat(" -ffast-math");
3070 if(options.debug == true)
3072 if(options.debug != true)
3075 else if(commonOptions)
3076 s.concat(" $(if $(DEBUG),-g)");
3078 s.concat(" $(FPIC)");
3080 switch(options.warnings)
3082 case all: s.concat(" -Wall"); break;
3083 case none: s.concat(" -w"); break;
3089 if(options && options.preprocessorDefinitions)
3090 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3091 if(options && options.includeDirs)
3092 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3095 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3097 if(options.memoryGuard == true)
3098 s.concat(" -memguard");
3099 if(options.noLineNumbers == true)
3100 s.concat(" -nolinenumbers");
3101 if(options.strictNameSpaces == true)
3102 s.concat(" -strictns");
3103 if(options.defaultNameSpace && options.defaultNameSpace[0])
3104 s.concatf(" -defaultns %s", options.defaultNameSpace);
3107 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3108 LineOutputMethod lineMethod, String newLineStart)
3112 if(lineMethod == newLine)
3114 output.concat(" \\\n");
3115 output.concat(newLineStart);
3119 Map<String, int> sortedList { };
3120 MapNode<String, int> mn;
3122 sortedList[item] = 1;
3123 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3125 char * start = strstr(mn.key, "\n");
3126 if(lineMethod == lineEach)
3128 output.concat(" \\\n");
3129 output.concat(newLineStart);
3132 output.concat(flagNames[flag]);
3133 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3141 if(lineMethod == lineEach)
3143 output.concat(" \\\n");
3144 output.concat(newLineStart);
3147 output.concat(flagNames[flag]);
3148 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3154 class GenericOptionTools<class X>
3156 bool mergeValues, configReplaces;
3158 virtual bool OptionSet(ProjectOptions options, int option) {
3159 if(*(X*)((byte *)options + option))
3164 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3166 virtual bool OptionCheck(ProjectOptions options, int option) {
3167 return OptionSet(options, option);
3170 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3171 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3174 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3179 class NameCollisionInfo
3192 bool IsExtensionColliding(char * extension)
3196 ((!strcmpi(extension, "c") && ec) ||
3197 (!strcmpi(extension, "rc") && (ec || c)) ||
3198 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3199 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3200 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3201 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3202 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3203 !strcmpi(extension, "mm")))