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 || !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 ReplaceUnwantedMakeChars(modulePath, tempPath);
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 ReplaceUnwantedMakeChars(modulePath, path);
1467 ReplaceUnwantedMakeChars(moduleName, name);
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 ReplaceUnwantedMakeChars(modulePath, path);
1478 ReplaceUnwantedMakeChars(moduleName, name);
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 ReplaceUnwantedMakeChars(modulePath, path);
1490 ReplaceUnwantedMakeChars(moduleName, name);
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 ReplaceUnwantedMakeChars(moduleName, name);
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 $@\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 $@ -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) $< $@\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 $@\n", moduleName);
2060 f.Printf(" -c %s%s.%s -o $@\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];
2116 // $(EAR) aw%s --- /*quiet ? "q" : */""
2118 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2121 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2124 PathCatSlash(tempPath, child.name);
2129 strcpy(tempPath, child.path);
2130 PathCatSlash(tempPath, child.name);
2132 ReplaceUnwantedMakeChars(resPath, tempPath);
2133 if(strchr(tempPath, ' '))
2137 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", resPath, quotes);
2140 if(count == 10 || (count > 0 && (ts || !child.next)))
2142 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2145 for(parent = this; parent.type == folder; parent = parent.parent)
2148 strcpy(path, parent.name);
2155 f.Printf(" \"%s\"%s\n", path, ts.b);
2167 if(child.type == folder)
2168 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2173 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2174 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2175 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2176 Map<Platform, ProjectOptions> parentByPlatformOptions)
2178 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2179 if(type == file || type == folder || type == project)
2181 bool hasPerNodeOptions = type == project;
2182 if(!hasPerNodeOptions)
2184 if(options && !options.isEmpty)
2185 hasPerNodeOptions = true;
2186 else if(configurations)
2188 for(c : configurations)
2190 if(c.options && !c.options.isEmpty)
2192 hasPerNodeOptions = true;
2197 for(p : c.platforms)
2199 if(p.options && !p.options.isEmpty)
2201 hasPerNodeOptions = true;
2205 if(hasPerNodeOptions)
2210 if(!hasPerNodeOptions && platforms)
2214 if(p.options && !p.options.isEmpty)
2216 hasPerNodeOptions = true;
2223 if(hasPerNodeOptions)
2225 bool isEqual = false, isGreater = false;
2226 ComplexComparison complexCmp;
2228 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2229 ProjectOptions platformsCommonOptions;
2230 ProjectOptions byFileConfigPlatformProjectOptions;
2232 DynamicString cflags { };
2233 DynamicString ecflags { };
2237 byPlatformOptions = { };
2239 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2241 byFileConfigPlatformProjectOptions =
2242 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2243 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2246 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2248 byPlatformOptions[unknown] = platformsCommonOptions;
2250 if(parentByPlatformOptions)
2252 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2253 parentByPlatformOptions, additionsByPlatformOptions);
2254 isGreater = complexCmp == greater;
2255 isEqual = complexCmp == equal;
2260 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2262 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2264 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2266 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2269 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2271 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2275 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2277 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2280 if(!isGreater) cflags.concat(" \\\n\t");
2285 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2288 ecflags.concat(" \\\n\t");
2295 cflags.concat(" \\\n\t");
2296 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2300 additionsByPlatformOptions.Free();
2301 delete additionsByPlatformOptions;
2307 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2308 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2316 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2317 cflagsVariations[s] = variationNum = cflagsVariations.count;
2318 nodeCFlagsMapping[(intptr)this] = variationNum;
2321 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2322 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2323 nodeECFlagsMapping[(intptr)this] = variationNum;
2334 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2335 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2344 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2345 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2346 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2351 if(byPlatformOptions != parentByPlatformOptions)
2353 byPlatformOptions.Free();
2354 delete byPlatformOptions;
2358 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2360 Array<Platform> platforms { };
2361 Map<Platform, SetBool> exclusionInfo { };
2362 CollectExclusionInfo(exclusionInfo, prjConfig);
2364 if(exclusionInfo[unknown] == true)
2366 if(exclusionInfo.count > 1)
2367 for(p : exclusionInfo; p == false)
2372 bool onlyOnknown = true;
2373 for(p : exclusionInfo)
2374 if(&p != unknown && p == true)
2376 onlyOnknown = false;
2380 platforms.Add(unknown);
2384 for(p = unknown + 1; p < Platform::enumSize; p++)
2385 if(exclusionInfo[p] != true)
2389 delete exclusionInfo;
2393 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2395 char moduleName[MAX_FILENAME];
2398 bool headerAltFailed = false;
2400 char extension[MAX_EXTENSION];
2401 NameCollisionInfo info;
2402 Project prj = property::project;
2403 Map<String, String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2405 GetExtension(name, extension);
2406 ReplaceSpaces(moduleName, name);
2407 StripExtension(moduleName);
2408 info = namesInfo[moduleName];
2409 collision = info ? info.IsExtensionColliding(extension) : false;
2411 for(h2s : headerToSource)
2413 if(!strcmpi(extension, &h2s))
2415 char filePath[MAX_LOCATION];
2416 GetFullFilePath(filePath);
2417 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2418 ChangeExtension(moduleName, h2s, moduleName);
2419 if(prj.topNode.Find(moduleName, false))
2421 strcpy(extension, h2s);
2422 collision = info ? info.IsExtensionColliding(extension) : false;
2423 ChangeExtension(filePath, h2s, filePath);
2424 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2425 StripExtension(moduleName);
2429 headerAltFailed = true;
2430 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2431 StripExtension(moduleName);
2437 if(!headerAltFailed)
2439 output.concat(" \"");
2440 output.concat(objDir); //.concat(" $(OBJ)");
2445 strcat(moduleName, ".");
2446 strcat(moduleName, extension);
2448 strcat(moduleName, ".o");
2449 output.concat(moduleName);
2450 output.concat("\"");
2453 else if(type == project && ContainsFilesWithExtension("ec"))
2455 Project prj = property::project;
2457 ReplaceSpaces(moduleName, prj.moduleName);
2458 strcat(moduleName, ".main.ec");
2459 output.concat(" \"");
2460 output.concat(objDir);
2462 output.concat(moduleName);
2463 output.concat("\"");
2465 ChangeExtension(moduleName, "c", moduleName);
2466 output.concat(" \"");
2467 output.concat(objDir);
2469 output.concat(moduleName);
2470 output.concat("\"");
2472 ChangeExtension(moduleName, "o", moduleName);
2473 output.concat(" \"");
2474 output.concat(objDir);
2476 output.concat(moduleName);
2477 output.concat("\"");
2483 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2484 child.GetTargets(prjConfig, namesInfo, objDir, output);
2489 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2494 char extension[MAX_EXTENSION];
2495 char fileName[MAX_FILENAME];
2496 char moduleName[MAX_FILENAME];
2497 NameCollisionInfo info;
2498 Project prj = property::project;
2499 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2501 GetExtension(name, extension);
2502 ReplaceSpaces(moduleName, name);
2503 StripExtension(moduleName);
2504 info = namesInfo[moduleName];
2505 collision = info ? info.IsExtensionColliding(extension) : false;
2507 strcpy(fileName, prj.topNode.path);
2508 PathCatSlash(fileName, objDir.dir);
2509 PathCatSlash(fileName, name);
2511 if(!onlyCObject && !strcmp(extension, "ec"))
2513 ChangeExtension(fileName, "c", fileName);
2514 if(FileExists(fileName)) DeleteFile(fileName);
2515 ChangeExtension(fileName, "sym", fileName);
2516 if(FileExists(fileName)) DeleteFile(fileName);
2517 ChangeExtension(fileName, "imp", fileName);
2518 if(FileExists(fileName)) DeleteFile(fileName);
2519 ChangeExtension(fileName, "bowl", fileName);
2520 if(FileExists(fileName)) DeleteFile(fileName);
2521 ChangeExtension(fileName, "ec", fileName);
2525 strcat(fileName, ".o");
2527 ChangeExtension(fileName, "o", fileName);
2528 if(FileExists(fileName)) DeleteFile(fileName);
2536 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2537 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2542 bool IsInNode(ProjectNode node)
2544 bool result = false;
2546 for(n = this; n; n = n.parent)
2558 // the code in this function is closely matched to OptionsBox::Load
2559 // and accompanying derivations of OptionBox and their use of OptionSet,
2560 // OptionCheck, LoadOption and FinalizeLoading methods.
2561 // output changing modification should be mirrored in both implementations
2562 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2564 ProjectOptions output { };
2566 // legend: e Element
2567 // o Option (of a ProjectOptions)
2568 // n Node (ProjectNode)
2570 // u Utility (GenericOptionTools)
2575 int includeDirsOption = OPTION(includeDirs);
2577 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2579 Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
2580 Array<bool> optionDone { size = OPTION(postbuildCommands) };
2581 Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
2583 GenericOptionTools<SetBool> utilSetBool {
2584 bool OptionCheck(ProjectOptions options, int option) {
2585 return *(SetBool*)((byte *)options + option) == true;
2587 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2588 if(options && (*(SetBool*)((byte *)options + option) == true))
2589 *(SetBool*)((byte *)output + option) = true;
2592 GenericOptionTools<String> utilString {
2593 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2594 String * string = (String*)((byte *)output + option);
2595 if(*string) delete *string;
2597 *string = CopyString(*(String*)((byte *)options + option));
2600 StringArrayOptionTools utilStringArrays {
2602 caseSensitive = true;
2603 bool OptionCheck(ProjectOptions options, int option) {
2604 Array<String> strings = *(Array<String>*)((byte *)options + option);
2605 return strings && strings.count;
2607 bool OptionSet(ProjectOptions options, int option) {
2608 Array<String> strings = *(Array<String>*)((byte *)options + option);
2609 if(mergeValues && !configReplaces)
2610 return strings && strings.count;
2612 return strings != null;
2614 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2617 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2621 Array<String> tempStrings = optionTempStrings[option];
2623 optionTempStrings[option] = tempStrings = { };
2627 char priorityMark[10];
2630 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2631 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2632 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2638 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2639 Array<String> * strings = (Array<String>*)((byte *)output + option);
2640 if(*strings) { strings->Free(); delete *strings; }
2641 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2644 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2647 Array<String> tempStrings = optionTempStrings[option];
2648 Array<String> * strings = (Array<String>*)((byte *)output + option);
2649 if(*strings) { strings->Free(); delete *strings; }
2650 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2655 GenericOptionTools<WarningsOption> utilWarningsOption {
2656 bool OptionCheck(ProjectOptions options, int option) {
2657 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2658 return value && value != none;
2660 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2661 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2662 *(WarningsOption*)((byte *)output + option) = value;
2665 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2666 bool OptionCheck(ProjectOptions options, int option) {
2667 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2668 return value && value != none;
2670 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2671 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2672 *(OptimizationStrategy*)((byte *)output + option) = value;
2676 Map<int, GenericOptionTools> ot { };
2678 // The following are compiler options
2680 ot[OPTION(debug)] = utilSetBool;
2681 ot[OPTION(memoryGuard)] = utilSetBool;
2682 ot[OPTION(profile)] = utilSetBool;
2683 ot[OPTION(noLineNumbers)] = utilSetBool;
2684 ot[OPTION(strictNameSpaces)] = utilSetBool;
2685 ot[OPTION(fastMath)] = utilSetBool;
2687 ot[OPTION(defaultNameSpace)] = utilString;
2689 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2690 ot[OPTION(includeDirs)] = utilStringArrays;
2692 ot[OPTION(warnings)] = utilWarningsOption;
2694 ot[OPTION(optimization)] = utilOptimizationStrategy;
2696 for(n = node; n; n = n.parent)
2698 ProjectConfig nodeConfig = null;
2700 priority = (priority / 10 + 1) * 10;
2703 if(projectConfig && n.configurations)
2705 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2707 if(platform && c.platforms)
2709 for(p : c.platforms; !strcmpi(p.name, platformName))
2713 GenericOptionTools u = uu;
2715 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2717 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2718 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2719 optionConfigXplatformSet[o] = true;
2731 GenericOptionTools u = uu;
2735 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2737 for(p : n.platforms; !strcmpi(p.name, platformName))
2739 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2741 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2742 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2747 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2748 ((u.mergeValues && !u.configReplaces) ?
2749 u.OptionCheck(nodeConfig.options, o) :
2750 u.OptionSet(nodeConfig.options, o)))
2752 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2753 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2757 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2759 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2760 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2764 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2765 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2773 GenericOptionTools u = uu;
2776 u.FinalizeLoading(o, optionTempStrings, output);
2779 delete optionConfigXplatformSet;
2781 delete optionTempStrings;
2785 delete utilStringArrays;
2786 delete utilWarningsOption;
2787 delete utilOptimizationStrategy;
2794 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2798 ProjectOptions first;
2799 ProjectOptions commonOptions;
2801 Map<String, int> countIncludeDirs { };
2802 Map<String, int> countPreprocessorDefinitions { };
2803 Map<String, bool> commonIncludeDirs { };
2804 Map<String, bool> commonPreprocessorDefinitions { };
2806 for(options : byPlatformOptions) { first = options; break; }
2808 *platformsCommonOptions = commonOptions = first.Copy();
2810 if(commonOptions.includeDirs)
2811 commonOptions.includeDirs.Free();
2812 if(commonOptions.preprocessorDefinitions)
2813 commonOptions.preprocessorDefinitions.Free();
2815 for(options : byPlatformOptions)
2817 if(options != first)
2819 if(commonOptions.debug && options.debug != commonOptions.debug)
2820 commonOptions.debug = unset;
2821 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2822 commonOptions.memoryGuard = unset;
2823 if(commonOptions.profile && options.profile != commonOptions.profile)
2824 commonOptions.profile = unset;
2825 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2826 commonOptions.noLineNumbers = unset;
2827 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2828 commonOptions.strictNameSpaces = unset;
2829 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2830 commonOptions.fastMath = unset;
2832 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2833 commonOptions.warnings = unset;
2834 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2835 commonOptions.optimization = unset;
2837 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2838 delete commonOptions.defaultNameSpace;
2841 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2842 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2845 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2846 commonIncludeDirs, commonOptions.includeDirs);
2847 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2848 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2850 for(options : byPlatformOptions)
2852 if(options.debug && options.debug == commonOptions.debug)
2853 options.debug = unset;
2854 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2855 options.memoryGuard = unset;
2856 if(options.profile && options.profile == commonOptions.profile)
2857 options.profile = unset;
2858 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2859 options.noLineNumbers = unset;
2860 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2861 options.strictNameSpaces = unset;
2862 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2863 options.fastMath = unset;
2865 if(options.warnings && options.warnings == commonOptions.warnings)
2866 options.warnings = unset;
2867 if(options.optimization && options.optimization == commonOptions.optimization)
2868 options.optimization = unset;
2870 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2871 delete options.defaultNameSpace;
2873 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2874 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2877 delete countIncludeDirs;
2878 delete countPreprocessorDefinitions;
2879 delete commonIncludeDirs;
2880 delete commonPreprocessorDefinitions;
2883 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2884 Map<Platform, ProjectOptions> parentByPlatformOptions,
2885 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2887 ComplexComparison result = equal;
2888 ComplexComparison compare;
2890 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2892 ProjectOptions additionalOptions;
2893 additionsByPlatformOptions[platform] = { };
2894 additionalOptions = additionsByPlatformOptions[platform];
2895 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2896 if(compare == greater && result == equal)
2898 else if(compare == different)
2907 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2909 ComplexComparison result = equal;
2910 if(options.debug != parentOptions.debug ||
2911 options.memoryGuard != parentOptions.memoryGuard ||
2912 options.profile != parentOptions.profile ||
2913 options.noLineNumbers != parentOptions.noLineNumbers ||
2914 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2915 options.fastMath != parentOptions.fastMath ||
2916 options.warnings != parentOptions.warnings ||
2917 options.optimization != parentOptions.optimization ||
2918 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2919 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2923 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2924 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2926 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2927 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2933 enum ComplexComparison { different/*, smaller*/, equal, greater };
2935 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2938 if((!strings || !strings.count) && originals && originals.count)
2940 else if(strings && strings.count && (!originals || !originals.count))
2945 additions->Add(CopyString(s));
2947 else if(strings && strings.count && originals && originals.count)
2949 Map<String, String> map { };
2950 MapIterator<String, bool> mit { map = map };
2953 char * s = strstr(it, "\n");
2959 char * s = strstr(it, "\n");
2961 if(!mit.Index(s, false))
2976 additions->Add(CopyString(it));
2984 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2997 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3005 strings.Add(CopyString(s));
3011 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3015 Array<String> tmp { };
3016 MapIterator<String, bool> mit { map = common };
3020 if(!mit.Index(s, false))
3021 tmp.Add(CopyString(s));
3027 strings.Add(CopyString(s));
3034 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, File f)
3037 customFlags = nodeFlagsMapping[(intptr)node];
3039 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3041 f.Printf(" $(%s)", variableName);
3044 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, DynamicString s)
3047 customFlags = nodeFlagsMapping[(intptr)node];
3049 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3051 s.concatf(" $(%s)", variableName);
3054 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3060 if(options.optimization == speed || options.optimization == size ||
3061 options.fastMath == true || options.debug == true)
3063 if(options.debug != true)
3065 s.concat(" $(if $(DEBUG),");
3069 switch(options.optimization)
3071 case speed: s.concat(" -O2"); break;
3072 case size: s.concat(" -Os"); break;
3074 if(options.fastMath == true)
3075 s.concat(" -ffast-math");
3076 if(options.debug == true)
3078 if(options.debug != true)
3081 else if(commonOptions)
3082 s.concat(" $(if $(DEBUG),-g)");
3084 s.concat(" $(FPIC)");
3086 switch(options.warnings)
3088 case all: s.concat(" -Wall"); break;
3089 case none: s.concat(" -w"); break;
3095 if(options && options.preprocessorDefinitions)
3096 ListOptionToDynamicString("D", options.preprocessorDefinitions, false, lineEach, "\t\t\t", false, s);
3097 if(options && options.includeDirs)
3098 ListOptionToDynamicString("I", options.includeDirs, true, lineEach, "\t\t\t", true, s);
3101 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3103 if(options.memoryGuard == true)
3104 s.concat(" -memguard");
3105 if(options.noLineNumbers == true)
3106 s.concat(" -nolinenumbers");
3107 if(options.strictNameSpaces == true)
3108 s.concat(" -strictns");
3109 if(options.defaultNameSpace && options.defaultNameSpace[0])
3110 s.concatf(" -defaultns %s", options.defaultNameSpace);
3113 static void ListOptionToDynamicString(char * option, Array<String> list, bool prioritize,
3114 ListOutputMethod method, String newLineStart, bool noSpace, DynamicString s)
3118 if(method == newLine)
3121 s.concat(newLineStart);
3125 Map<String, int> sortedList { };
3126 MapNode<String, int> mn;
3128 sortedList[item] = 1;
3129 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3131 char * start = strstr(mn.key, "\n");
3132 if(method == lineEach)
3135 s.concat(newLineStart);
3140 StringNoSpaceToDynamicString(s, start ? start+1 : mn.key);
3142 s.concat(start ? start+1 : mn.key);
3150 if(method == lineEach)
3153 s.concat(newLineStart);
3158 StringNoSpaceToDynamicString(s, item);
3166 class GenericOptionTools<class X>
3168 bool mergeValues, configReplaces;
3170 virtual bool OptionSet(ProjectOptions options, int option) {
3171 if(*(X*)((byte *)options + option))
3176 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3178 virtual bool OptionCheck(ProjectOptions options, int option) {
3179 return OptionSet(options, option);
3182 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3183 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3186 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3191 class NameCollisionInfo
3204 bool IsExtensionColliding(char * extension)
3208 ((!strcmpi(extension, "c") && ec) ||
3209 (!strcmpi(extension, "rc") && (ec || c)) ||
3210 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3211 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3212 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3213 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3214 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3215 !strcmpi(extension, "mm")))