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 class ProjectNode : ListItem
185 set { return { fileName = value }; }
186 // TOCHECK: Is this isset necessary at all?
187 isset { return nodeType == file && !options && !configurations && !platforms && !files; }
189 property String folder
194 if(strchr(value, '/'))
196 char p[MAX_LOCATION];
197 char n[MAX_FILENAME];
198 GetLastDirectory(value, n);
199 StripLastDirectory(value, p);
200 name = CopyString(n);
201 path = CopyString(p);
204 name = CopyString(value);
208 // TOCHECK: Non Reentrant
209 static char insidePath[MAX_LOCATION];
211 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
212 PathCatSlash(insidePath, name);
214 if(!fstrcmp(path, insidePath))
218 strcpy(insidePath, path);
219 if(!insidePath[0]) strcpy(insidePath, ".");
220 PathCatSlash(insidePath, name);
224 isset { return nodeType == folder; }
226 property String fileName
231 if(strchr(value, '/'))
233 char p[MAX_LOCATION];
234 char n[MAX_FILENAME];
235 GetLastDirectory(value, n);
236 StripLastDirectory(value, p);
237 name = CopyValidateMakefilePath(n);
238 path = CopyValidateMakefilePath(p);
241 name = CopyValidateMakefilePath(value);
245 // TOCHECK: Non Reentrant
246 static char insidePath[MAX_LOCATION];
248 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
249 if(!fstrcmp(path, insidePath))
253 strcpy(insidePath, path);
254 if(!insidePath[0]) strcpy(insidePath, ".");
255 PathCatSlash(insidePath, name);
259 isset { return nodeType == file && (options || configurations || platforms); }
262 LinkList<ProjectNode> files;
263 property ProjectOptions options
265 get { return project ? project.options : options; }
266 set { if(project) { delete project.options; project.options = value; } else { delete options; options = value; } }
267 isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
269 property Array<PlatformOptions> platforms
271 get { return project ? project.platforms : platforms; }
274 if(project) { project.platforms = value; }
277 if(platforms) { platforms.Free(); delete platforms; }
280 List<PlatformOptions> empty { };
281 Iterator<PlatformOptions> it { value };
283 for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
284 for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
291 Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
296 if(p.options && !p.options.isEmpty)
303 property List<ProjectConfig> configurations
305 get { return project ? project.configurations : configurations; }
310 if(project.configurations)
312 project.configurations.Free();
313 delete project.configurations;
315 project.configurations = value;
319 if(configurations) { configurations.Free(); delete configurations; }
322 List<ProjectConfig> empty { };
323 Iterator<ProjectConfig> it { value };
324 configurations = value;
325 for(c : configurations)
327 bool somethingSet = c.options && !c.options.isEmpty;
328 // TODO: Implement isset keyword
329 if(!somethingSet && c.platforms && c.platforms.count)
333 if(p.options && !p.options.isEmpty)
343 for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
350 if(!parent) return true;
353 for(c : configurations)
355 bool somethingSet = c.options && !c.options.isEmpty;
356 if(!somethingSet && c.platforms && c.platforms.count)
360 if(p.options && !p.options.isEmpty)
375 ProjectOptions options;
376 Array<PlatformOptions> platforms;
377 List<ProjectConfig> configurations;
378 ProjectNodeType nodeType;
383 // This holds the absolute path of the .epj for the project topnode (without the filename)
384 // It holds a relative path to the topNode (project) for other nodes (folders and files)
385 // For folders, it includes the folder it refers to. If there is a name difference between the
386 // file system folder and the grouping folder of the project view, it maps to that folder.
396 // This is only set for Top Nodes
399 void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Array<Platform> platforms)
401 if(!platforms.Find(unknown)) // unknown is "Common"
403 // e.g. ifneq "$(or $(or $(OSX_TARGET),$(LINUX_TARGET)),$(WINDOWS_TARGET))"
406 for(i = 0; platforms.count && i < platforms.count - 1; i++)
414 f.Puts(PlatformToMakefileTargetVariable(p));
427 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
429 ProjectConfig nodeConfig = null;
430 if(property::configurations && prjConfig)
432 const char * configName = prjConfig.name;
433 for(cfg : property::configurations)
435 if(!strcmpi(cfg.name, configName))
445 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
447 property bool containsFile
456 if(child.type == file ||
457 ((child.type == folder || child.type == folderOpen) && child.containsFile))
470 char * GetFullFilePath(char * buffer)
474 strcpy(buffer, root.path);
475 PathCatSlash(buffer, path);
476 PathCatSlash(buffer, name);
481 char * GetFileSysMatchingPath(char * buffer)
485 ProjectNode n, root = this.root;
486 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
488 strcpy(buffer, root.path);
490 PathCatSlash(buffer, n.path);
491 if(FileExists(buffer).isDirectory)
494 if(!(n && (n.type == folder || n.type == project)))
500 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
502 ProjectNode node = null;
503 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
504 List<ProjectNode> nodeStack { };
506 for(node = this; node && node.parent; node = node.parent)
509 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
511 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
512 while((node = nodeStack.lastIterator.data))
514 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
515 ProjectOptions nodeOptions = node.property::options;
516 if(nodeOptions && nodeOptions.preprocessorDefinitions)
518 for(def : nodeOptions.preprocessorDefinitions)
519 perFilePreprocessorDefs.Add(CopyString(def));
521 if(config && config.options && config.options.preprocessorDefinitions)
523 for(def : config.options.preprocessorDefinitions)
524 perFilePreprocessorDefs.Add(CopyString(def));
526 if(nodeOptions && nodeOptions.includeDirs)
528 for(dir : nodeOptions.includeDirs)
529 perFileIncludeDirs.Add(CopySystemPath(dir));
531 if(config && config.options && config.options.includeDirs)
533 for(dir : config.options.includeDirs)
534 perFileIncludeDirs.Add(CopySystemPath(dir));
536 nodeStack.lastIterator.Remove();
542 property Project project
546 ProjectNode n = this;
547 while(n && n.type != project) n = n.parent;
548 return n ? (*&n.project) : null;
552 void RenameConfig(char * oldName, char * newName)
556 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
558 if(property::configurations)
560 for(c : property::configurations; !strcmp(c.name, oldName))
563 c.name = CopyString(newName);
568 void DeleteConfig(ProjectConfig configToDelete)
572 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
574 if(property::configurations)
576 Iterator<ProjectConfig> c { property::configurations };
579 ProjectConfig config = c.data;
580 if(!strcmp(configToDelete.name, config.name))
587 if(!property::configurations.count)
588 property::configurations = null;
594 ProjectNode backupNode { };
598 backupNode.files = { };
599 for(f : files) backupNode.files.Add(f.Backup());
601 if(property::options)
602 backupNode.options = property::options.Copy();
604 if(property::platforms)
606 backupNode.platforms = { };
607 for(p : property::platforms)
608 backupNode.platforms.Add(p.Copy());
611 if(property::configurations)
613 backupNode.configurations = { };
614 for(c : property::configurations)
615 backupNode.configurations.Add(c.Copy());
620 void Revert(ProjectNode backupNode)
624 Iterator<ProjectNode> it { backupNode.files };
632 property::options = backupNode.options ? backupNode.options.Copy() : null;
633 if(backupNode.platforms)
635 Array<PlatformOptions> platforms { };
636 property::platforms = platforms;
638 for(p : backupNode.platforms)
639 platforms.Add(p.Copy());
641 if(backupNode.configurations)
643 List<ProjectConfig> configurations { };
644 property::configurations = configurations;
645 for(c : backupNode.configurations)
646 configurations.Add(c.Copy());
650 void FixupNode(char * parentPath)
656 else if(nodeType == file)
661 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
664 else if(nodeType == folder)
670 char temp[MAX_LOCATION];
671 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
672 PathCatSlash(temp, name);
673 path = CopyString(temp);
677 indent = parent ? parent.indent + 1 : 0;
680 icon = NodeIcons::SelectFileIcon(name);
682 icon = NodeIcons::SelectNodeIcon(type);
691 parentPath[0] = '\0';
692 else if(type == resources || type == folder)
693 strcpy(parentPath, path);
695 f.FixupNode(parentPath);
700 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
704 // TOCHECK: Called from JSON writer
705 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
707 strcpy(tempString, "\"");
708 strcat(tempString, property::fileName);
709 strcat(tempString, "\"");
716 // TOCHECK: Called from ProjectView rendering
717 return name ? name : "";
730 if(!project && platforms)
735 if(!project && configurations)
737 configurations.Free();
738 delete configurations;
741 /////////////////////////////
747 property bool isInResources
752 for(node = this; node; node = node.parent)
754 if(node.type == resources)
761 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
763 TwoStrings result { a = CopyString(""), b = CopyString("") };
764 // note: unknown platform is for common
765 Map<Platform, SetBool> exclusionInfo { };
766 MapNode<Platform, SetBool> mn;
771 CollectExclusionInfo(exclusionInfo, prjConfig);
772 common = exclusionInfo[unknown];
774 Map<Platform, SetBool> cleaned { };
775 SetBool opposite = common == true ? false : true;
776 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
778 if(mn.key == unknown || mn.value == opposite)
779 cleaned[mn.key] = mn.value;
781 delete exclusionInfo;
782 exclusionInfo = cleaned;
785 if(exclusionInfo.count > 1)
787 if(exclusionInfo.count > 2)
790 len = strlen(exp) + strlen("$(if $(or ");
791 exp = renew exp char[len+1];
792 strcat(exp, "$(if $(or ");
795 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
797 if(mn.key != unknown)
799 char * comma = mn.next ? "," : "";
801 var = PlatformToMakefileTargetVariable(mn.key);
804 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
805 exp = renew exp char[len+1];
815 len = strlen(exp) + strlen("),");
816 exp = renew exp char[len+1];
820 if(exclusionInfo.root.minimum.key != unknown)
821 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
823 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
826 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
827 exp = renew exp char[len+1];
828 strcat(exp, "$(if $(");
835 exp = common == true ? result.b : result.a;
836 len = strlen(exp) + strlen(",");
837 exp = renew exp char[len+1];
839 if(common == true) result.b = exp; else result.a = exp;
842 len = strlen(exp) + strlen(")");
843 exp = renew exp char[len+1];
847 delete exclusionInfo;
852 bool GetIsExcluded(ProjectConfig prjConfig)
855 // note: unknown platform is for common
856 Map<Platform, SetBool> exclusionInfo { };
857 CollectExclusionInfo(exclusionInfo, prjConfig);
858 if(exclusionInfo.count == 0)
860 else if(exclusionInfo.count == 1)
861 result = exclusionInfo.root.minimum.value == true;
864 SetBool check = exclusionInfo.root.minimum.value;
865 MapNode<Platform, SetBool> mn;
866 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
868 if(check != mn.value)
871 if(!mn) // all are same
872 result = check == true;
876 delete exclusionInfo;
880 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
882 // note: unknown platform is for common
884 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
885 ProjectOptions options = property::options;
886 Array<PlatformOptions> platforms = property::platforms;
887 List<ProjectConfig> configurations = property::configurations;
890 parent.CollectExclusionInfo(output, prjConfig);
892 output[unknown] = unset;
894 if(options && options.excludeFromBuild)
895 output[unknown] = options.excludeFromBuild;
897 if(config && config.options && config.options.excludeFromBuild)
898 output[unknown] = config.options.excludeFromBuild;
904 if(p.options.excludeFromBuild && (platform = p.name))
905 output[platform] = p.options.excludeFromBuild;
908 if(config && config.platforms)
910 for(p : config.platforms)
912 if(p.options.excludeFromBuild && (platform = p.name))
913 output[platform] = p.options.excludeFromBuild;
921 parent.EnsureVisible();
922 row.collapsed = false;
928 parent.files.Delete(this);
931 ProjectNode Find(char * name, bool includeResources)
933 ProjectNode result = null;
938 if(includeResources || child.type != resources)
940 if(child.type != folder && child.name && !strcmpi(child.name, name))
945 result = child.Find(name, includeResources);
954 ProjectNode FindWithPath(char * name, bool includeResources)
956 ProjectNode result = null;
961 if(includeResources || child.type != resources)
963 char path[MAX_LOCATION];
964 strcpy(path, child.path);
965 if(child.type != folder && child.name)
967 PathCatSlash(path, child.name);
968 if(!strcmpi(path, name))
974 result = child.FindWithPath(name, includeResources);
983 ProjectNode FindByFullPath(char * path, bool includeResources)
985 ProjectNode result = null;
990 if(includeResources || child.type != resources)
992 if(child.type != folder && child.name)
994 char p[MAX_LOCATION];
995 child.GetFullFilePath(p);
996 if(!strcmpi(p, path))
1002 result = child.FindByFullPath(path, includeResources);
1011 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
1013 ProjectNode result = null;
1018 if(includeResources || child.type != resources)
1020 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1026 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1035 ProjectNode FindSameNameConflict(char * name, bool includeResources,
1036 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1038 ProjectNode result = null;
1039 Map<Platform, SetBool> compareExclusion { };
1040 SetBool common, commonComp;
1041 SetBool actual, actualComp;
1046 if(includeResources || child.type != resources)
1048 if(child.type != folder && child.name && !strcmpi(child.name, name))
1050 child.CollectExclusionInfo(compareExclusion, prjConfig);
1051 common = exclusionInfo[unknown];
1052 commonComp = compareExclusion[unknown];
1053 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1055 if(!(common == true || commonComp == true))
1064 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1067 actualComp = commonComp;
1068 if(exclusionInfo[platform] != unset)
1069 actual = exclusionInfo[platform];
1070 if(compareExclusion[platform] != unset)
1071 actualComp = compareExclusion[platform];
1072 if(!(actual == true || actualComp == true))
1080 compareExclusion.Free();
1083 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1087 compareExclusion.Free();
1089 delete compareExclusion;
1093 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1095 ProjectNode node = null;
1096 char temp[MAX_LOCATION];
1097 Map<Platform, SetBool> exclusionInfo { };
1099 GetLastDirectory(filePath, temp);
1100 //if(!checkIfExists || !project.topNode.Find(temp, false))
1102 // TOCHECK: Shouldn't this apply either for all configs or none?
1103 CollectExclusionInfo(exclusionInfo, project.config);
1104 if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1106 // Do the check for folder in the same parent or resource files only here
1107 if(type == folder || !checkIfExists)
1111 if(node.name && !strcmpi(node.name, temp))
1116 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1120 node.nodeType = folder;
1126 StripLastDirectory(filePath, temp);
1127 MakePathRelative(temp, project.topNode.path, temp);
1128 node.path = CopyUnixPath(temp);
1130 node.nodeType = file;
1134 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1135 PathCatSlash(temp, node.name);
1136 node.path = CopyString(temp);
1138 files.Insert(after, node);
1140 delete exclusionInfo;
1144 #ifndef MAKEFILE_GENERATOR
1145 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1147 char label[MAX_FILENAME];
1153 bool showConfig = true;
1158 projectView = ide.projectView;
1161 bmp = projectView.icons[icon].bitmap;
1162 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1164 GetLastDirectory(name, label);
1165 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1167 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1169 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1172 addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1173 if(strlen(addendum))
1175 strcat(label, " (");
1176 strcat(label, addendum);
1179 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1180 if(strlen(addendum))
1182 strcat(label, " (");
1183 strcat(label, addendum);
1189 else if(!projectView.drawingInProjectSettingsDialog)
1192 strcat(label, " *");
1193 if(type == project && info)
1195 int len = strlen(info) + 4;
1196 char * more = new char[len];
1197 sprintf(more, " (%s)", info);
1198 strcat(label, more);
1202 len = strlen(label);
1206 if(type == folder || type == folderOpen)
1207 surface.SetForeground(yellow);
1211 surface.TextOpacity(false);
1212 surface.TextExtent(label, len, &w, &h);
1215 // Draw the current row stipple
1216 if(displayFlags.selected)
1217 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1218 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1219 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1221 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1225 if(displayFlags.current)
1227 if(displayFlags.active)
1229 surface.LineStipple(0x5555);
1230 if(displayFlags.selected)
1231 surface.SetForeground(projectView.fileList.stippleColor);
1233 surface.SetForeground(projectView.fileList.foreground);
1237 surface.SetForeground(SELECTION_COLOR);
1239 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1240 surface.LineStipple(0);
1245 surface.SetForeground(white);
1246 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1252 int OnCompare(ProjectNode b)
1255 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1256 result = strcmpi(name, b.name);
1259 if(type == folder && b.type == file) result = -1;
1260 else if(type == file && b.type == folder) result = 1;
1265 bool ContainsFilesWithExtension(char * extension)
1269 char ext[MAX_EXTENSION];
1270 GetExtension(name, ext);
1271 if(!fstrcmp(ext, extension))
1276 bool needed = false;
1278 if(child.ContainsFilesWithExtension(extension))
1284 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1288 char extension[MAX_EXTENSION];
1289 GetExtension(name, extension);
1290 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1291 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1292 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1294 char moduleName[MAX_FILENAME];
1295 NameCollisionInfo info;
1296 ReplaceSpaces(moduleName, name);
1297 StripExtension(moduleName);
1298 info = namesInfo[moduleName];
1300 info = NameCollisionInfo { };
1301 info.count++; // += 1; unless this is for a bug?
1302 if(!strcmpi(extension, "ec"))
1304 else if(!strcmpi(extension, "s"))
1306 else if(!strcmpi(extension, "c"))
1308 else if(!strcmpi(extension, "rc"))
1310 else if(!strcmpi(extension, "cpp"))
1312 else if(!strcmpi(extension, "cc"))
1314 else if(!strcmpi(extension, "cxx"))
1316 else if(!strcmpi(extension, "m"))
1318 else if(!strcmpi(extension, "mm"))
1320 namesInfo[moduleName] = info;
1327 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1328 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1333 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1334 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1335 ProjectConfig prjConfig, bool * containsCXX)
1341 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1342 char moduleName[MAX_FILENAME];
1343 char extension[MAX_EXTENSION];
1344 GetExtension(name, extension);
1345 if(printType == resources)
1348 char tempPath[MAX_LOCATION];
1349 char modulePath[MAX_LOCATION];
1352 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1355 PathCatSlash(tempPath, name);
1360 strcpy(tempPath, path);
1361 PathCatSlash(tempPath, name);
1363 ReplaceSpaces(modulePath, tempPath);
1364 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1365 items.Add(CopyString(s));
1367 else if(printType == sources)
1369 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1370 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1371 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1373 char modulePath[MAX_LOCATION];
1374 ReplaceSpaces(modulePath, path);
1375 ReplaceSpaces(moduleName, name);
1376 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1377 items.Add(CopyString(s));
1380 else if(printType == eCsources)
1382 if(!strcmpi(extension, "ec"))
1384 char modulePath[MAX_LOCATION];
1385 ReplaceUnwantedMakeChars(modulePath, path);
1386 ReplaceUnwantedMakeChars(moduleName, name);
1387 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1388 items.Add(CopyString(s));
1392 else if(printType == rcSources)
1394 if(!strcmpi(extension, "rc"))
1396 char modulePath[MAX_LOCATION];
1397 ReplaceUnwantedMakeChars(modulePath, path);
1398 ReplaceUnwantedMakeChars(moduleName, name);
1399 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1400 items.Add(CopyString(s));
1404 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1405 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1406 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1408 if(printType == objects)
1411 NameCollisionInfo info;
1413 ReplaceSpaces(moduleName, name);
1414 StripExtension(moduleName);
1415 info = namesInfo[moduleName];
1416 collision = info ? info.IsExtensionColliding(extension) : false;
1417 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1418 items.Add(CopyString(s));
1419 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1420 *containsCXX = true;
1429 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1430 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1436 void GenMakefilePrintSymbolRules(File f, Project project,
1437 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1438 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1441 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1442 //ProjectNode child;
1443 //char objDir[MAX_LOCATION];
1444 //ReplaceSpaces(objDir, config.objDir.dir);
1446 //eSystem_Log("Printing Symbol Rules\n");
1449 char extension[MAX_EXTENSION];
1450 char modulePath[MAX_LOCATION];
1451 char moduleName[MAX_FILENAME];
1453 GetExtension(name, extension);
1454 if(!strcmpi(extension, "ec"))
1459 ReplaceSpaces(moduleName, name);
1460 StripExtension(moduleName);
1462 ReplaceSpaces(modulePath, path);
1463 if(modulePath[0]) strcat(modulePath, SEPS);
1465 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1467 // *** Dependency command ***
1468 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1469 modulePath, moduleName, extension);
1471 // System Includes (from global settings)
1472 for(item : compiler.dirs[Includes])
1474 strcat(command, " -isystem ");
1475 if(strchr(item, ' '))
1477 strcat(command, "\"");
1478 strcat(command, item);
1479 strcat(command, "\"");
1482 strcat(command, item);
1485 for(item : project.includeDirs)
1487 strcat(command, " -I");
1488 if(strchr(item, ' '))
1490 strcat(command, "\"");
1491 strcat(command, item);
1492 strcat(command, "\"");
1495 strcat(command, item);
1497 for(item : project.preprocessorDefs)
1499 strcat(command, " -D");
1500 strcat(command, item);
1504 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1507 bool firstLine = true;
1510 // To do some time: auto save external dependencies?
1513 if(dep.GetLine(line, sizeof(line)-1))
1517 char * colon = strstr(line, ":");
1518 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1532 // If we failed to generate dependencies...
1536 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1537 moduleName, modulePath, moduleName, extension);
1541 f.Puts(" $(CFLAGS)");
1542 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1544 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1545 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1547 f.Printf(" -c %s%s.%s -o $@\n",
1548 modulePath, moduleName, extension, moduleName);
1549 if(ifCount) f.Puts("endif\n");
1559 bool needed = false;
1560 if(ContainsFilesWithExtension("ec"))
1564 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1575 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1576 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1577 nodeCFlagsMapping, nodeECFlagsMapping);
1584 void GenMakefilePrintPrepecsRules(File f, Project project,
1585 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1586 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1589 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1590 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1591 //ProjectNode child;
1592 //char objDir[MAX_LOCATION];
1593 //ReplaceSpaces(objDir, config.objDir.dir);
1595 //eSystem_Log("Printing Symbol Rules\n");
1598 char extension[MAX_EXTENSION];
1599 char modulePath[MAX_LOCATION];
1600 char moduleName[MAX_FILENAME];
1602 GetExtension(name, extension);
1603 if(!strcmpi(extension, "ec"))
1608 ReplaceSpaces(moduleName, name);
1609 StripExtension(moduleName);
1611 ReplaceSpaces(modulePath, path);
1612 if(modulePath[0]) strcat(modulePath, SEPS);
1614 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1615 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1616 moduleName, modulePath, moduleName, extension);
1617 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1618 modulePath, moduleName, extension, moduleName);*/
1622 f.Puts(" $(CFLAGS)");
1623 //f.Puts(" $(CECFLAGS)");
1624 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1625 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1627 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1628 modulePath, moduleName, extension, moduleName);
1629 if(ifCount) f.Puts("endif\n");
1635 bool needed = false;
1636 if(ContainsFilesWithExtension("ec"))
1640 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1651 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1652 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1653 nodeCFlagsMapping, nodeECFlagsMapping);
1660 void GenMakefilePrintCObjectRules(File f, Project project,
1661 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1662 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1665 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1666 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1667 //ProjectNode child;
1668 //char objDir[MAX_LOCATION];
1669 //ReplaceSpaces(objDir, config.objDir.dir);
1670 //eSystem_Log("Printing C Object Rules\n");
1673 char extension[MAX_EXTENSION];
1674 char modulePath[MAX_LOCATION];
1675 char moduleName[MAX_FILENAME];
1677 GetExtension(name, extension);
1678 if(!strcmpi(extension, "ec"))
1683 ReplaceSpaces(moduleName, name);
1684 StripExtension(moduleName);
1686 ReplaceSpaces(modulePath, path);
1687 if(modulePath[0]) strcat(modulePath, SEPS);
1689 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1691 // *** Dependency command ***
1692 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1693 moduleName, modulePath, moduleName, extension);
1695 // System Includes (from global settings)
1696 for(item : compiler.dirs[Includes])
1698 strcat(command, " -isystem ");
1699 if(strchr(item, ' '))
1701 strcat(command, "\"");
1702 strcat(command, item);
1703 strcat(command, "\"");
1706 strcat(command, item);
1709 for(item : config.includeDirs)
1711 strcat(command, " -I");
1712 if(strchr(item, ' '))
1714 strcat(command, "\"");
1715 strcat(command, item);
1716 strcat(command, "\"");
1719 strcat(command, item);
1721 for(item : config.preprocessorDefs)
1723 strcat(command, " -D");
1724 strcat(command, item);
1728 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1732 bool firstLine = true;
1734 // To do some time: auto save external dependencies?
1737 if(dep.GetLine(line, sizeof(line)-1))
1741 char * colon = strstr(line, ":");
1742 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1756 // If we failed to generate dependencies...
1759 /* COMMENTED OUT FOR NOW
1760 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1761 moduleName, modulePath, moduleName, extension);
1764 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1765 moduleName, modulePath, moduleName, extension, moduleName);
1771 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1772 modulePath, moduleName, extension, moduleName);
1777 f.Puts(" $(CFLAGS)");
1778 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1779 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1780 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1781 f.Puts(" $(FVISIBILITY)");
1783 f.Printf(" -c %s%s.%s -o $@ -symbols $(OBJ)\n",
1784 modulePath, moduleName, extension, moduleName);
1785 if(ifCount) f.Puts("endif\n");
1791 bool needed = false;
1792 if(ContainsFilesWithExtension("ec"))
1796 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1807 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1808 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1809 nodeCFlagsMapping, nodeECFlagsMapping);
1816 void GenMakefilePrintObjectRules(File f, Project project,
1817 Map<String, NameCollisionInfo> namesInfo,
1818 ProjectConfig prjConfig,
1819 //Map<Platform, bool> parentExcludedPlatforms,
1820 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1823 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1824 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1825 //ProjectNode child;
1826 //char objDir[MAX_LOCATION];
1827 //ReplaceSpaces(objDir, config.objDir.dir);
1828 //eSystem_Log("Printing Object Rules\n");
1832 char extension[MAX_EXTENSION];
1833 char modulePath[MAX_LOCATION];
1834 char moduleName[MAX_FILENAME];
1836 GetExtension(name, extension);
1837 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1838 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1839 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1843 NameCollisionInfo info;
1845 ReplaceSpaces(moduleName, name);
1846 StripExtension(moduleName);
1848 info = namesInfo[moduleName];
1849 collision = info ? info.IsExtensionColliding(extension) : false;
1851 ReplaceSpaces(modulePath, path);
1852 if(modulePath[0]) strcat(modulePath, SEPS);
1856 // *** Dependency command ***
1857 if(!strcmpi(extension, "ec"))
1858 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1860 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1861 moduleName, modulePath, moduleName, extension);
1863 if(!strcmpi(extension, "ec"))
1865 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1869 // System Includes (from global settings)
1870 for(item : compiler.dirs[includes])
1872 strcat(command, " -isystem ");
1873 if(strchr(item, ' '))
1875 strcat(command, "\"");
1876 strcat(command, item);
1877 strcat(command, "\"");
1880 strcat(command, item);
1883 for(item : config.includeDirs)
1885 strcat(command, " -I");
1886 if(strchr(item, ' '))
1888 strcat(command, "\"");
1889 strcat(command, item);
1890 strcat(command, "\"");
1893 strcat(command, item);
1895 for(item : config.preprocessorDefs)
1897 strcat(command, " -D");
1898 strcat(command, item);
1902 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1905 bool firstLine = true;
1908 // To do some time: auto save external dependencies?
1912 if(dep.GetLine(line, sizeof(line)-1))
1916 char * colon = strstr(line, ":");
1917 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1931 // If we failed to generate dependencies...
1940 if(!strcmpi(extension, "rc"))
1943 f.Puts("ifdef WINDOWS_TARGET\n\n");
1946 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1948 if(!strcmpi(extension, "ec"))
1949 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1951 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
1952 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1953 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
1954 f.Printf("\t$(CXX)");
1955 else if(!strcmpi(extension, "rc"))
1956 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< $@\n");
1958 f.Printf("\t$(CC)");
1960 if(strcmpi(extension, "rc") != 0)
1962 f.Puts(" $(CFLAGS)");
1963 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1965 if(!strcmpi(extension, "ec"))
1966 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $@\n", moduleName, moduleName);
1968 f.Printf(" -c %s%s.%s -o $@\n",
1969 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1970 collision ? "." : "", collision ? extension : "");
1972 if(ifCount) f.Puts("endif\n");
1978 bool needed = false;
1981 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1991 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1992 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
1993 nodeCFlagsMapping, nodeECFlagsMapping);
2000 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2007 //Iterator<ProjectNode> i { files };
2008 //Iterator<ProjectNode> prev { files };
2009 //for(child : files)
2011 for(c = 0; c < files.count; c++)
2013 ProjectNode child = files[c];
2014 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2017 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2020 char tempPath[MAX_LOCATION];
2021 char resPath[MAX_LOCATION];
2025 // $(EAR) aw%s --- /*quiet ? "q" : */""
2027 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2030 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2033 PathCatSlash(tempPath, child.name);
2038 strcpy(tempPath, child.path);
2039 PathCatSlash(tempPath, child.name);
2041 ReplaceSpaces(resPath, tempPath);
2042 if(strchr(tempPath, ' '))
2046 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", tempPath, quotes);
2049 if(count == 10 || (count > 0 && (ts || !child.next)))
2051 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2054 for(parent = this; parent.type == folder; parent = parent.parent)
2057 strcpy(path, parent.name);
2064 f.Printf(" \"%s\"%s\n", path, ts.b);
2076 if(child.type == folder)
2077 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2082 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2083 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2084 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2085 Map<Platform, ProjectOptions> parentByPlatformOptions)
2087 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2088 if(type == file || type == folder || type == project)
2090 bool hasPerNodeOptions = type == project;
2091 if(!hasPerNodeOptions)
2093 if(options && !options.isEmpty)
2094 hasPerNodeOptions = true;
2095 else if(configurations)
2097 for(c : configurations)
2099 if(c.options && !c.options.isEmpty)
2101 hasPerNodeOptions = true;
2106 for(p : c.platforms)
2108 if(p.options && !p.options.isEmpty)
2110 hasPerNodeOptions = true;
2114 if(hasPerNodeOptions)
2119 if(!hasPerNodeOptions && platforms)
2123 if(p.options && !p.options.isEmpty)
2125 hasPerNodeOptions = true;
2132 if(hasPerNodeOptions)
2134 bool isEqual = false, isGreater = false;
2135 ComplexComparison complexCmp;
2137 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2138 ProjectOptions platformsCommonOptions;
2139 ProjectOptions byFileConfigPlatformProjectOptions;
2141 DynamicString cflags { };
2142 DynamicString ecflags { };
2146 byPlatformOptions = { };
2148 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2150 byFileConfigPlatformProjectOptions =
2151 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2152 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2155 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2157 byPlatformOptions[unknown] = platformsCommonOptions;
2159 if(parentByPlatformOptions)
2161 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2162 parentByPlatformOptions, additionsByPlatformOptions);
2163 isGreater = complexCmp == greater;
2164 isEqual = complexCmp == equal;
2169 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2171 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2173 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2175 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2178 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2180 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2184 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2186 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2189 if(!isGreater) cflags.concat(" \\\n\t");
2194 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2197 ecflags.concat(" \\\n\t");
2204 cflags.concat(" \\\n\t");
2205 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2209 additionsByPlatformOptions.Free();
2210 delete additionsByPlatformOptions;
2216 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2217 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2225 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2226 cflagsVariations[s] = variationNum = cflagsVariations.count;
2227 nodeCFlagsMapping[(intptr)this] = variationNum;
2230 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2231 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2232 nodeECFlagsMapping[(intptr)this] = variationNum;
2243 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2244 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2253 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2254 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2255 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2260 if(byPlatformOptions != parentByPlatformOptions)
2262 byPlatformOptions.Free();
2263 delete byPlatformOptions;
2267 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2269 Array<Platform> platforms { };
2270 Map<Platform, SetBool> exclusionInfo { };
2271 CollectExclusionInfo(exclusionInfo, prjConfig);
2273 if(exclusionInfo[unknown] == true)
2275 if(exclusionInfo.count > 1)
2276 for(p : exclusionInfo; p == false)
2281 bool onlyOnknown = true;
2282 for(p : exclusionInfo)
2283 if(&p != unknown && p == true)
2285 onlyOnknown = false;
2289 platforms.Add(unknown);
2293 for(p = unknown + 1; p < Platform::enumSize; p++)
2294 if(exclusionInfo[p] != true)
2298 delete exclusionInfo;
2302 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2304 char moduleName[MAX_FILENAME];
2307 bool headerAltFailed = false;
2309 char extension[MAX_EXTENSION];
2310 NameCollisionInfo info;
2311 Project prj = property::project;
2312 Map<String, String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2314 GetExtension(name, extension);
2315 ReplaceSpaces(moduleName, name);
2316 StripExtension(moduleName);
2317 info = namesInfo[moduleName];
2318 collision = info ? info.IsExtensionColliding(extension) : false;
2320 for(h2s : headerToSource)
2322 if(!strcmpi(extension, &h2s))
2324 char filePath[MAX_LOCATION];
2325 GetFullFilePath(filePath);
2326 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2327 ChangeExtension(moduleName, h2s, moduleName);
2328 if(prj.topNode.Find(moduleName, false))
2330 strcpy(extension, h2s);
2331 collision = info ? info.IsExtensionColliding(extension) : false;
2332 ChangeExtension(filePath, h2s, filePath);
2333 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2334 StripExtension(moduleName);
2338 headerAltFailed = true;
2339 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2340 StripExtension(moduleName);
2346 if(!headerAltFailed)
2348 output.concat(" \"");
2349 output.concat(objDir); //.concat(" $(OBJ)");
2354 strcat(moduleName, ".");
2355 strcat(moduleName, extension);
2357 strcat(moduleName, ".o");
2358 output.concat(moduleName);
2359 output.concat("\"");
2362 else if(type == project && ContainsFilesWithExtension("ec"))
2364 Project prj = property::project;
2366 strcpy(moduleName, prj.moduleName);
2367 strcat(moduleName, ".main.ec");
2368 output.concat(" \"");
2369 output.concat(objDir);
2371 output.concat(moduleName);
2372 output.concat("\"");
2374 ChangeExtension(moduleName, "c", moduleName);
2375 output.concat(" \"");
2376 output.concat(objDir);
2378 output.concat(moduleName);
2379 output.concat("\"");
2381 ChangeExtension(moduleName, "o", moduleName);
2382 output.concat(" \"");
2383 output.concat(objDir);
2385 output.concat(moduleName);
2386 output.concat("\"");
2392 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2393 child.GetTargets(prjConfig, namesInfo, objDir, output);
2398 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2403 char extension[MAX_EXTENSION];
2404 char fileName[MAX_FILENAME];
2405 char moduleName[MAX_FILENAME];
2406 NameCollisionInfo info;
2407 Project prj = property::project;
2408 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2410 GetExtension(name, extension);
2411 ReplaceSpaces(moduleName, name);
2412 StripExtension(moduleName);
2413 info = namesInfo[moduleName];
2414 collision = info ? info.IsExtensionColliding(extension) : false;
2416 strcpy(fileName, prj.topNode.path);
2417 PathCatSlash(fileName, objDir.dir);
2418 PathCatSlash(fileName, name);
2420 if(!onlyCObject && !strcmp(extension, "ec"))
2422 ChangeExtension(fileName, "c", fileName);
2423 if(FileExists(fileName)) DeleteFile(fileName);
2424 ChangeExtension(fileName, "sym", fileName);
2425 if(FileExists(fileName)) DeleteFile(fileName);
2426 ChangeExtension(fileName, "imp", fileName);
2427 if(FileExists(fileName)) DeleteFile(fileName);
2428 ChangeExtension(fileName, "bowl", fileName);
2429 if(FileExists(fileName)) DeleteFile(fileName);
2430 ChangeExtension(fileName, "ec", fileName);
2434 strcat(fileName, ".o");
2436 ChangeExtension(fileName, "o", fileName);
2437 if(FileExists(fileName)) DeleteFile(fileName);
2445 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2446 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2451 bool IsInNode(ProjectNode node)
2453 bool result = false;
2455 for(n = this; n; n = n.parent)
2467 // the code in this function is closely matched to OptionsBox::Load
2468 // and accompanying derivations of OptionBox and their use of OptionSet,
2469 // OptionCheck, LoadOption and FinalizeLoading methods.
2470 // output changing modification should be mirrored in both implementations
2471 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2473 ProjectOptions output { };
2475 // legend: e Element
2476 // o Option (of a ProjectOptions)
2477 // n Node (ProjectNode)
2479 // u Utility (GenericOptionTools)
2484 int includeDirsOption = OPTION(includeDirs);
2486 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2488 Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
2489 Array<bool> optionDone { size = OPTION(postbuildCommands) };
2490 Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
2492 GenericOptionTools<SetBool> utilSetBool {
2493 bool OptionCheck(ProjectOptions options, int option) {
2494 return *(SetBool*)((byte *)options + option) == true;
2496 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2497 if(options && (*(SetBool*)((byte *)options + option) == true))
2498 *(SetBool*)((byte *)output + option) = true;
2501 GenericOptionTools<String> utilString {
2502 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2503 String * string = (String*)((byte *)output + option);
2504 if(*string) delete *string;
2506 *string = CopyString(*(String*)((byte *)options + option));
2509 StringArrayOptionTools utilStringArrays {
2511 caseSensitive = true;
2512 bool OptionCheck(ProjectOptions options, int option) {
2513 Array<String> strings = *(Array<String>*)((byte *)options + option);
2514 return strings && strings.count;
2516 bool OptionSet(ProjectOptions options, int option) {
2517 Array<String> strings = *(Array<String>*)((byte *)options + option);
2518 if(mergeValues && !configReplaces)
2519 return strings && strings.count;
2521 return strings != null;
2523 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2526 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2530 Array<String> tempStrings = optionTempStrings[option];
2532 optionTempStrings[option] = tempStrings = { };
2536 char priorityMark[10];
2539 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2540 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2541 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2547 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2548 Array<String> * strings = (Array<String>*)((byte *)output + option);
2549 if(*strings) { strings->Free(); delete *strings; }
2550 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2553 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2556 Array<String> tempStrings = optionTempStrings[option];
2557 Array<String> * strings = (Array<String>*)((byte *)output + option);
2558 if(*strings) { strings->Free(); delete *strings; }
2559 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2564 GenericOptionTools<WarningsOption> utilWarningsOption {
2565 bool OptionCheck(ProjectOptions options, int option) {
2566 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2567 return value && value != none;
2569 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2570 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2571 *(WarningsOption*)((byte *)output + option) = value;
2574 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2575 bool OptionCheck(ProjectOptions options, int option) {
2576 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2577 return value && value != none;
2579 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2580 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2581 *(OptimizationStrategy*)((byte *)output + option) = value;
2585 Map<int, GenericOptionTools> ot { };
2587 // The following are compiler options
2589 ot[OPTION(debug)] = utilSetBool;
2590 ot[OPTION(memoryGuard)] = utilSetBool;
2591 ot[OPTION(profile)] = utilSetBool;
2592 ot[OPTION(noLineNumbers)] = utilSetBool;
2593 ot[OPTION(strictNameSpaces)] = utilSetBool;
2594 ot[OPTION(fastMath)] = utilSetBool;
2596 ot[OPTION(defaultNameSpace)] = utilString;
2598 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2599 ot[OPTION(includeDirs)] = utilStringArrays;
2601 ot[OPTION(warnings)] = utilWarningsOption;
2603 ot[OPTION(optimization)] = utilOptimizationStrategy;
2605 for(n = node; n; n = n.parent)
2607 ProjectConfig nodeConfig = null;
2609 priority = (priority / 10 + 1) * 10;
2612 if(projectConfig && n.configurations)
2614 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2616 if(platform && c.platforms)
2618 for(p : c.platforms; !strcmpi(p.name, platformName))
2622 GenericOptionTools u = uu;
2624 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2626 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2627 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2628 optionConfigXplatformSet[o] = true;
2640 GenericOptionTools u = uu;
2644 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2646 for(p : n.platforms; !strcmpi(p.name, platformName))
2648 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2650 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2651 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2656 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2657 ((u.mergeValues && !u.configReplaces) ?
2658 u.OptionCheck(nodeConfig.options, o) :
2659 u.OptionSet(nodeConfig.options, o)))
2661 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2662 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2666 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2668 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2669 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2673 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2674 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2682 GenericOptionTools u = uu;
2685 u.FinalizeLoading(o, optionTempStrings, output);
2688 delete optionConfigXplatformSet;
2690 delete optionTempStrings;
2694 delete utilStringArrays;
2695 delete utilWarningsOption;
2696 delete utilOptimizationStrategy;
2703 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2707 ProjectOptions first;
2708 ProjectOptions commonOptions;
2710 Map<String, int> countIncludeDirs { };
2711 Map<String, int> countPreprocessorDefinitions { };
2712 Map<String, bool> commonIncludeDirs { };
2713 Map<String, bool> commonPreprocessorDefinitions { };
2715 for(options : byPlatformOptions) { first = options; break; }
2717 *platformsCommonOptions = commonOptions = first.Copy();
2719 if(commonOptions.includeDirs)
2720 commonOptions.includeDirs.Free();
2721 if(commonOptions.preprocessorDefinitions)
2722 commonOptions.preprocessorDefinitions.Free();
2724 for(options : byPlatformOptions)
2726 if(options != first)
2728 if(commonOptions.debug && options.debug != commonOptions.debug)
2729 commonOptions.debug = unset;
2730 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2731 commonOptions.memoryGuard = unset;
2732 if(commonOptions.profile && options.profile != commonOptions.profile)
2733 commonOptions.profile = unset;
2734 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2735 commonOptions.noLineNumbers = unset;
2736 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2737 commonOptions.strictNameSpaces = unset;
2738 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2739 commonOptions.fastMath = unset;
2741 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2742 commonOptions.warnings = unset;
2743 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2744 commonOptions.optimization = unset;
2746 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2747 delete commonOptions.defaultNameSpace;
2750 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2751 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2754 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2755 commonIncludeDirs, commonOptions.includeDirs);
2756 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2757 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2759 for(options : byPlatformOptions)
2761 if(options.debug && options.debug == commonOptions.debug)
2762 options.debug = unset;
2763 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2764 options.memoryGuard = unset;
2765 if(options.profile && options.profile == commonOptions.profile)
2766 options.profile = unset;
2767 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2768 options.noLineNumbers = unset;
2769 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2770 options.strictNameSpaces = unset;
2771 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2772 options.fastMath = unset;
2774 if(options.warnings && options.warnings == commonOptions.warnings)
2775 options.warnings = unset;
2776 if(options.optimization && options.optimization == commonOptions.optimization)
2777 options.optimization = unset;
2779 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2780 delete options.defaultNameSpace;
2782 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2783 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2786 delete countIncludeDirs;
2787 delete countPreprocessorDefinitions;
2788 delete commonIncludeDirs;
2789 delete commonPreprocessorDefinitions;
2792 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2793 Map<Platform, ProjectOptions> parentByPlatformOptions,
2794 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2796 ComplexComparison result = equal;
2797 ComplexComparison compare;
2799 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2801 ProjectOptions additionalOptions;
2802 additionsByPlatformOptions[platform] = { };
2803 additionalOptions = additionsByPlatformOptions[platform];
2804 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2805 if(compare == greater && result == equal)
2807 else if(compare == different)
2816 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2818 ComplexComparison result = equal;
2819 if(options.debug != parentOptions.debug ||
2820 options.memoryGuard != parentOptions.memoryGuard ||
2821 options.profile != parentOptions.profile ||
2822 options.noLineNumbers != parentOptions.noLineNumbers ||
2823 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2824 options.fastMath != parentOptions.fastMath ||
2825 options.warnings != parentOptions.warnings ||
2826 options.optimization != parentOptions.optimization ||
2827 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2828 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2832 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2833 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2835 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2836 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2842 enum ComplexComparison { different/*, smaller*/, equal, greater };
2844 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2847 if((!strings || !strings.count) && originals && originals.count)
2849 else if(strings && strings.count && (!originals || !originals.count))
2854 additions->Add(CopyString(s));
2856 else if(strings && strings.count && originals && originals.count)
2858 Map<String, String> map { };
2859 MapIterator<String, bool> mit { map = map };
2862 char * s = strstr(it, "\n");
2868 char * s = strstr(it, "\n");
2870 if(!mit.Index(s, false))
2885 additions->Add(CopyString(it));
2893 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2906 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
2914 strings.Add(CopyString(s));
2920 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
2924 Array<String> tmp { };
2925 MapIterator<String, bool> mit { map = common };
2929 if(!mit.Index(s, false))
2930 tmp.Add(CopyString(s));
2936 strings.Add(CopyString(s));
2943 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, File f)
2946 customFlags = nodeFlagsMapping[(intptr)node];
2948 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2950 f.Printf(" $(%s)", variableName);
2953 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, DynamicString s)
2956 customFlags = nodeFlagsMapping[(intptr)node];
2958 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2960 s.concatf(" $(%s)", variableName);
2963 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
2969 if(options.optimization == speed || options.optimization == size ||
2970 options.fastMath == true || options.debug == true)
2972 if(options.debug != true)
2974 s.concat(" $(if $(DEBUG),");
2978 switch(options.optimization)
2980 case speed: s.concat(" -O2"); break;
2981 case size: s.concat(" -Os"); break;
2983 if(options.fastMath == true)
2984 s.concat(" -ffast-math");
2985 if(options.debug == true)
2987 if(options.debug != true)
2990 else if(commonOptions)
2991 s.concat(" $(if $(DEBUG),-g)");
2993 s.concat(" $(FPIC)");
2995 switch(options.warnings)
2997 case all: s.concat(" -Wall"); break;
2998 case none: s.concat(" -w"); break;
3004 if(options && options.preprocessorDefinitions)
3005 ListOptionToDynamicString("D", options.preprocessorDefinitions, false, lineEach, "\t\t\t", false, s);
3006 if(options && options.includeDirs)
3007 ListOptionToDynamicString("I", options.includeDirs, true, lineEach, "\t\t\t", true, s);
3010 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3012 if(options.memoryGuard == true)
3013 s.concat(" -memguard");
3014 if(options.noLineNumbers == true)
3015 s.concat(" -nolinenumbers");
3016 if(options.strictNameSpaces == true)
3017 s.concat(" -strictns");
3018 if(options.defaultNameSpace && options.defaultNameSpace[0])
3019 s.concatf(" -defaultns %s", options.defaultNameSpace);
3022 static void ListOptionToDynamicString(char * option, Array<String> list, bool prioritize,
3023 ListOutputMethod method, String newLineStart, bool noSpace, DynamicString s)
3027 if(method == newLine)
3030 s.concat(newLineStart);
3034 Map<String, int> sortedList { };
3035 MapNode<String, int> mn;
3037 sortedList[item] = 1;
3038 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3040 char * start = strstr(mn.key, "\n");
3041 if(method == lineEach)
3044 s.concat(newLineStart);
3049 StringNoSpaceToDynamicString(s, start ? start+1 : mn.key);
3051 s.concat(start ? start+1 : mn.key);
3059 if(method == lineEach)
3062 s.concat(newLineStart);
3067 StringNoSpaceToDynamicString(s, item);
3075 class GenericOptionTools<class X>
3077 bool mergeValues, configReplaces;
3079 virtual bool OptionSet(ProjectOptions options, int option) {
3080 if(*(X*)((byte *)options + option))
3085 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3087 virtual bool OptionCheck(ProjectOptions options, int option) {
3088 return OptionSet(options, option);
3091 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3092 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3095 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3100 class NameCollisionInfo
3113 bool IsExtensionColliding(char * extension)
3117 ((!strcmpi(extension, "c") && ec) ||
3118 (!strcmpi(extension, "rc") && (ec || c)) ||
3119 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3120 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3121 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3122 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3123 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3124 !strcmpi(extension, "mm")))