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, "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, "cpp"))
1310 else if(!strcmpi(extension, "cc"))
1312 else if(!strcmpi(extension, "cxx"))
1314 else if(!strcmpi(extension, "m"))
1316 else if(!strcmpi(extension, "mm"))
1318 namesInfo[moduleName] = info;
1325 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1326 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1331 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1332 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1333 ProjectConfig prjConfig, bool * containsCXX)
1339 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1340 char moduleName[MAX_FILENAME];
1341 char extension[MAX_EXTENSION];
1342 GetExtension(name, extension);
1343 if(printType == resources)
1346 char tempPath[MAX_LOCATION];
1347 char modulePath[MAX_LOCATION];
1350 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1353 PathCatSlash(tempPath, name);
1358 strcpy(tempPath, path);
1359 PathCatSlash(tempPath, name);
1361 ReplaceSpaces(modulePath, tempPath);
1362 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1363 items.Add(CopyString(s));
1365 else if(printType == sources)
1367 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1368 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1369 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1371 char modulePath[MAX_LOCATION];
1373 ReplaceSpaces(modulePath, path);
1374 ReplaceSpaces(moduleName, name);
1375 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1376 items.Add(CopyString(s));
1379 else if(printType == eCsources)
1381 if(!strcmpi(extension, "ec"))
1383 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(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1393 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1394 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1396 if(printType == objects)
1399 NameCollisionInfo info;
1401 ReplaceSpaces(moduleName, name);
1402 StripExtension(moduleName);
1403 info = namesInfo[moduleName];
1404 collision = info ? info.IsExtensionColliding(extension) : false;
1405 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1406 items.Add(CopyString(s));
1407 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1408 *containsCXX = true;
1417 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1418 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1424 void GenMakefilePrintSymbolRules(File f, Project project,
1425 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1426 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1429 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1430 //ProjectNode child;
1431 //char objDir[MAX_LOCATION];
1432 //ReplaceSpaces(objDir, config.objDir.dir);
1434 //eSystem_Log("Printing Symbol Rules\n");
1437 char extension[MAX_EXTENSION];
1438 char modulePath[MAX_LOCATION];
1439 char moduleName[MAX_FILENAME];
1441 GetExtension(name, extension);
1442 if(!strcmpi(extension, "ec"))
1447 ReplaceSpaces(moduleName, name);
1448 StripExtension(moduleName);
1450 ReplaceSpaces(modulePath, path);
1451 if(modulePath[0]) strcat(modulePath, SEPS);
1453 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1455 // *** Dependency command ***
1456 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1457 modulePath, moduleName, extension);
1459 // System Includes (from global settings)
1460 for(item : compiler.dirs[Includes])
1462 strcat(command, " -isystem ");
1463 if(strchr(item, ' '))
1465 strcat(command, "\"");
1466 strcat(command, item);
1467 strcat(command, "\"");
1470 strcat(command, item);
1473 for(item : project.includeDirs)
1475 strcat(command, " -I");
1476 if(strchr(item, ' '))
1478 strcat(command, "\"");
1479 strcat(command, item);
1480 strcat(command, "\"");
1483 strcat(command, item);
1485 for(item : project.preprocessorDefs)
1487 strcat(command, " -D");
1488 strcat(command, item);
1492 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1495 bool firstLine = true;
1498 // To do some time: auto save external dependencies?
1501 if(dep.GetLine(line, sizeof(line)-1))
1505 char * colon = strstr(line, ":");
1506 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1520 // If we failed to generate dependencies...
1524 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1525 moduleName, modulePath, moduleName, extension);
1529 f.Puts(" $(CFLAGS)");
1530 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1532 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1533 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1535 f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n",
1536 modulePath, moduleName, extension, moduleName);
1537 if(ifCount) f.Puts("endif\n");
1547 bool needed = false;
1548 if(ContainsFilesWithExtension("ec"))
1552 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1563 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1564 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1565 nodeCFlagsMapping, nodeECFlagsMapping);
1572 void GenMakefilePrintPrepecsRules(File f, Project project,
1573 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1574 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1577 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1578 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1579 //ProjectNode child;
1580 //char objDir[MAX_LOCATION];
1581 //ReplaceSpaces(objDir, config.objDir.dir);
1583 //eSystem_Log("Printing Symbol Rules\n");
1586 char extension[MAX_EXTENSION];
1587 char modulePath[MAX_LOCATION];
1588 char moduleName[MAX_FILENAME];
1590 GetExtension(name, extension);
1591 if(!strcmpi(extension, "ec"))
1596 ReplaceSpaces(moduleName, name);
1597 StripExtension(moduleName);
1599 ReplaceSpaces(modulePath, path);
1600 if(modulePath[0]) strcat(modulePath, SEPS);
1602 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1603 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1604 moduleName, modulePath, moduleName, extension);
1605 //$(CPP) -x c -E ../extras/gui/controls/DirectoriesBox.ec -o $(OBJ)DirectoriesBox$(EC)
1606 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1607 modulePath, moduleName, extension, moduleName);*/
1611 f.Puts(" $(CFLAGS)");
1612 //f.Puts(" $(CECFLAGS)");
1613 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1614 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1616 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1617 modulePath, moduleName, extension, moduleName);
1618 if(ifCount) f.Puts("endif\n");
1624 bool needed = false;
1625 if(ContainsFilesWithExtension("ec"))
1629 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1640 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1641 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1642 nodeCFlagsMapping, nodeECFlagsMapping);
1649 void GenMakefilePrintCObjectRules(File f, Project project,
1650 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1651 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1654 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1655 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1656 //ProjectNode child;
1657 //char objDir[MAX_LOCATION];
1658 //ReplaceSpaces(objDir, config.objDir.dir);
1659 //eSystem_Log("Printing C Object Rules\n");
1662 char extension[MAX_EXTENSION];
1663 char modulePath[MAX_LOCATION];
1664 char moduleName[MAX_FILENAME];
1666 GetExtension(name, extension);
1667 if(!strcmpi(extension, "ec"))
1672 ReplaceSpaces(moduleName, name);
1673 StripExtension(moduleName);
1675 ReplaceSpaces(modulePath, path);
1676 if(modulePath[0]) strcat(modulePath, SEPS);
1678 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1680 // *** Dependency command ***
1681 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1682 moduleName, modulePath, moduleName, extension);
1684 // System Includes (from global settings)
1685 for(item : compiler.dirs[Includes])
1687 strcat(command, " -isystem ");
1688 if(strchr(item, ' '))
1690 strcat(command, "\"");
1691 strcat(command, item);
1692 strcat(command, "\"");
1695 strcat(command, item);
1698 for(item : config.includeDirs)
1700 strcat(command, " -I");
1701 if(strchr(item, ' '))
1703 strcat(command, "\"");
1704 strcat(command, item);
1705 strcat(command, "\"");
1708 strcat(command, item);
1710 for(item : config.preprocessorDefs)
1712 strcat(command, " -D");
1713 strcat(command, item);
1717 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1721 bool firstLine = true;
1723 // To do some time: auto save external dependencies?
1726 if(dep.GetLine(line, sizeof(line)-1))
1730 char * colon = strstr(line, ":");
1731 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1745 // If we failed to generate dependencies...
1748 /* COMMENTED OUT FOR NOW
1749 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1750 moduleName, modulePath, moduleName, extension);
1753 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1754 moduleName, modulePath, moduleName, extension, moduleName);
1760 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1761 modulePath, moduleName, extension, moduleName);
1766 f.Puts(" $(CFLAGS)");
1767 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1768 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1769 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1770 f.Puts(" $(FVISIBILITY)");
1772 f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n",
1773 modulePath, moduleName, extension, moduleName);
1774 if(ifCount) f.Puts("endif\n");
1780 bool needed = false;
1781 if(ContainsFilesWithExtension("ec"))
1785 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1796 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1797 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1798 nodeCFlagsMapping, nodeECFlagsMapping);
1805 void GenMakefilePrintObjectRules(File f, Project project,
1806 Map<String, NameCollisionInfo> namesInfo,
1807 ProjectConfig prjConfig,
1808 //Map<Platform, bool> parentExcludedPlatforms,
1809 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1812 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1813 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1814 //ProjectNode child;
1815 //char objDir[MAX_LOCATION];
1816 //ReplaceSpaces(objDir, config.objDir.dir);
1817 //eSystem_Log("Printing Object Rules\n");
1821 char extension[MAX_EXTENSION];
1822 char modulePath[MAX_LOCATION];
1823 char moduleName[MAX_FILENAME];
1825 GetExtension(name, extension);
1826 /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1827 !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
1828 !strcmpi(extension, "cxx"))*/
1829 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1830 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1831 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1835 NameCollisionInfo info;
1837 ReplaceSpaces(moduleName, name);
1838 StripExtension(moduleName);
1840 info = namesInfo[moduleName];
1841 collision = info ? info.IsExtensionColliding(extension) : false;
1843 ReplaceSpaces(modulePath, path);
1844 if(modulePath[0]) strcat(modulePath, SEPS);
1846 // *** Dependency command ***
1847 if(!strcmpi(extension, "ec"))
1848 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1850 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1851 moduleName, modulePath, moduleName, extension);
1853 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1856 if(!strcmpi(extension, "ec"))
1858 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1862 // System Includes (from global settings)
1863 for(item : compiler.dirs[includes])
1865 strcat(command, " -isystem ");
1866 if(strchr(item, ' '))
1868 strcat(command, "\"");
1869 strcat(command, item);
1870 strcat(command, "\"");
1873 strcat(command, item);
1876 for(item : config.includeDirs)
1878 strcat(command, " -I");
1879 if(strchr(item, ' '))
1881 strcat(command, "\"");
1882 strcat(command, item);
1883 strcat(command, "\"");
1886 strcat(command, item);
1888 for(item : config.preprocessorDefs)
1890 strcat(command, " -D");
1891 strcat(command, item);
1895 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1898 bool firstLine = true;
1901 // To do some time: auto save external dependencies?
1905 if(dep.GetLine(line, sizeof(line)-1))
1909 char * colon = strstr(line, ":");
1910 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1924 // If we failed to generate dependencies...
1933 if(!strcmpi(extension, "ec"))
1934 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1936 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
1937 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1938 f.Printf("\t$(%s)", (!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx")) ? "CXX" : "CC");
1940 f.Puts(" $(CFLAGS)");
1941 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1943 if(!strcmpi(extension, "ec"))
1944 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n", moduleName, moduleName);
1946 f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n",
1947 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1948 collision ? "." : "", collision ? extension : "");
1950 if(ifCount) f.Puts("endif\n");
1956 bool needed = false;
1959 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1969 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1970 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
1971 nodeCFlagsMapping, nodeECFlagsMapping);
1978 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
1985 //Iterator<ProjectNode> i { files };
1986 //Iterator<ProjectNode> prev { files };
1987 //for(child : files)
1989 for(c = 0; c < files.count; c++)
1991 ProjectNode child = files[c];
1992 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
1995 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
1998 char tempPath[MAX_LOCATION];
1999 char resPath[MAX_LOCATION];
2003 // $(EAR) aw%s --- /*quiet ? "q" : */""
2005 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2008 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2011 PathCatSlash(tempPath, child.name);
2016 strcpy(tempPath, child.path);
2017 PathCatSlash(tempPath, child.name);
2019 ReplaceSpaces(resPath, tempPath);
2020 if(strchr(tempPath, ' '))
2024 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", tempPath, quotes);
2027 if(count == 10 || (count > 0 && (ts || !child.next)))
2029 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2032 for(parent = this; parent.type == folder; parent = parent.parent)
2035 strcpy(path, parent.name);
2042 f.Printf(" \"%s\"%s\n", path, ts.b);
2054 if(child.type == folder)
2055 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2060 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2061 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2062 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2063 Map<Platform, ProjectOptions> parentByPlatformOptions)
2065 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2066 if(type == file || type == folder || type == project)
2068 bool hasPerNodeOptions = type == project;
2069 if(!hasPerNodeOptions)
2071 if(options && !options.isEmpty)
2072 hasPerNodeOptions = true;
2073 else if(configurations)
2075 for(c : configurations)
2077 if(c.options && !c.options.isEmpty)
2079 hasPerNodeOptions = true;
2084 for(p : c.platforms)
2086 if(p.options && !p.options.isEmpty)
2088 hasPerNodeOptions = true;
2092 if(hasPerNodeOptions)
2097 if(!hasPerNodeOptions && platforms)
2101 if(p.options && !p.options.isEmpty)
2103 hasPerNodeOptions = true;
2110 if(hasPerNodeOptions)
2112 bool isEqual = false, isGreater = false;
2113 ComplexComparison complexCmp;
2115 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2116 ProjectOptions platformsCommonOptions;
2117 ProjectOptions byFileConfigPlatformProjectOptions;
2119 DynamicString cflags { };
2120 DynamicString ecflags { };
2124 byPlatformOptions = { };
2126 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2128 byFileConfigPlatformProjectOptions =
2129 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2130 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2133 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2135 byPlatformOptions[unknown] = platformsCommonOptions;
2137 if(parentByPlatformOptions)
2139 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2140 parentByPlatformOptions, additionsByPlatformOptions);
2141 isGreater = complexCmp == greater;
2142 isEqual = complexCmp == equal;
2147 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2149 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2151 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2153 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2156 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2158 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2162 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2164 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2167 if(!isGreater) cflags.concat(" \\\n\t");
2172 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2175 ecflags.concat(" \\\n\t");
2182 cflags.concat(" \\\n\t");
2183 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2187 additionsByPlatformOptions.Free();
2188 delete additionsByPlatformOptions;
2194 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2195 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2203 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2204 cflagsVariations[s] = variationNum = cflagsVariations.count;
2205 nodeCFlagsMapping[(intptr)this] = variationNum;
2208 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2209 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2210 nodeECFlagsMapping[(intptr)this] = variationNum;
2221 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2222 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2231 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2232 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2233 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2238 if(byPlatformOptions != parentByPlatformOptions)
2240 byPlatformOptions.Free();
2241 delete byPlatformOptions;
2245 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2247 Array<Platform> platforms { };
2248 Map<Platform, SetBool> exclusionInfo { };
2249 CollectExclusionInfo(exclusionInfo, prjConfig);
2251 if(exclusionInfo[unknown] == true)
2253 if(exclusionInfo.count > 1)
2254 for(p : exclusionInfo; p == false)
2259 bool onlyOnknown = true;
2260 for(p : exclusionInfo)
2261 if(&p != unknown && p == true)
2263 onlyOnknown = false;
2267 platforms.Add(unknown);
2271 for(p = unknown + 1; p < Platform::enumSize; p++)
2272 if(exclusionInfo[p] != true)
2276 delete exclusionInfo;
2280 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2284 bool headerAltFailed = false;
2286 char extension[MAX_EXTENSION];
2287 char moduleName[MAX_FILENAME];
2288 NameCollisionInfo info;
2289 Project prj = property::project;
2290 Map<String, String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2292 GetExtension(name, extension);
2293 ReplaceSpaces(moduleName, name);
2294 StripExtension(moduleName);
2295 info = namesInfo[moduleName];
2296 collision = info ? info.IsExtensionColliding(extension) : false;
2298 for(h2s : headerToSource)
2300 if(!strcmpi(extension, &h2s))
2302 char filePath[MAX_LOCATION];
2303 GetFullFilePath(filePath);
2304 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2305 ChangeExtension(moduleName, h2s, moduleName);
2306 if(prj.topNode.Find(moduleName, false))
2308 strcpy(extension, h2s);
2309 collision = info ? info.IsExtensionColliding(extension) : false;
2310 ChangeExtension(filePath, h2s, filePath);
2311 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2312 StripExtension(moduleName);
2316 headerAltFailed = true;
2317 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2318 StripExtension(moduleName);
2324 if(!headerAltFailed)
2326 output.concat(" \"");
2327 output.concat(objDir); //.concat(" $(OBJ)");
2332 strcat(moduleName, ".");
2333 strcat(moduleName, extension);
2335 strcat(moduleName, ".o");
2336 output.concat(moduleName);
2337 output.concat("\"");
2344 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2345 child.GetTargets(prjConfig, namesInfo, objDir, output);
2350 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2355 char extension[MAX_EXTENSION];
2356 char fileName[MAX_FILENAME];
2357 char moduleName[MAX_FILENAME];
2358 NameCollisionInfo info;
2359 Project prj = property::project;
2360 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2362 GetExtension(name, extension);
2363 ReplaceSpaces(moduleName, name);
2364 StripExtension(moduleName);
2365 info = namesInfo[moduleName];
2366 collision = info ? info.IsExtensionColliding(extension) : false;
2368 strcpy(fileName, prj.topNode.path);
2369 PathCatSlash(fileName, objDir.dir);
2370 PathCatSlash(fileName, name);
2372 if(!onlyCObject && !strcmp(extension, "ec"))
2374 ChangeExtension(fileName, "c", fileName);
2375 if(FileExists(fileName)) DeleteFile(fileName);
2376 ChangeExtension(fileName, "sym", fileName);
2377 if(FileExists(fileName)) DeleteFile(fileName);
2378 ChangeExtension(fileName, "imp", fileName);
2379 if(FileExists(fileName)) DeleteFile(fileName);
2380 ChangeExtension(fileName, "bowl", fileName);
2381 if(FileExists(fileName)) DeleteFile(fileName);
2382 ChangeExtension(fileName, "ec", fileName);
2386 strcat(fileName, ".o");
2388 ChangeExtension(fileName, "o", fileName);
2389 if(FileExists(fileName)) DeleteFile(fileName);
2397 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2398 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2403 bool IsInNode(ProjectNode node)
2405 bool result = false;
2407 for(n = this; n; n = n.parent)
2419 // the code in this function is closely matched to OptionsBox::Load
2420 // and accompanying derivations of OptionBox and their use of OptionSet,
2421 // OptionCheck, LoadOption and FinalizeLoading methods.
2422 // output changing modification should be mirrored in both implementations
2423 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2425 ProjectOptions output { };
2427 // legend: e Element
2428 // o Option (of a ProjectOptions)
2429 // n Node (ProjectNode)
2431 // u Utility (GenericOptionTools)
2436 int includeDirsOption = OPTION(includeDirs);
2438 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2440 Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
2441 Array<bool> optionDone { size = OPTION(postbuildCommands) };
2442 Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
2444 GenericOptionTools<SetBool> utilSetBool {
2445 bool OptionCheck(ProjectOptions options, int option) {
2446 return *(SetBool*)((byte *)options + option) == true;
2448 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2449 if(options && (*(SetBool*)((byte *)options + option) == true))
2450 *(SetBool*)((byte *)output + option) = true;
2453 GenericOptionTools<String> utilString {
2454 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2455 String * string = (String*)((byte *)output + option);
2456 if(*string) delete *string;
2458 *string = CopyString(*(String*)((byte *)options + option));
2461 StringArrayOptionTools utilStringArrays {
2463 caseSensitive = true;
2464 bool OptionCheck(ProjectOptions options, int option) {
2465 Array<String> strings = *(Array<String>*)((byte *)options + option);
2466 return strings && strings.count;
2468 bool OptionSet(ProjectOptions options, int option) {
2469 Array<String> strings = *(Array<String>*)((byte *)options + option);
2470 if(mergeValues && !configReplaces)
2471 return strings && strings.count;
2473 return strings != null;
2475 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2478 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2482 Array<String> tempStrings = optionTempStrings[option];
2484 optionTempStrings[option] = tempStrings = { };
2488 char priorityMark[10];
2491 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2492 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2493 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2499 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2500 Array<String> * strings = (Array<String>*)((byte *)output + option);
2501 if(*strings) { strings->Free(); delete *strings; }
2502 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2505 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2508 Array<String> tempStrings = optionTempStrings[option];
2509 Array<String> * strings = (Array<String>*)((byte *)output + option);
2510 if(*strings) { strings->Free(); delete *strings; }
2511 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2516 GenericOptionTools<WarningsOption> utilWarningsOption {
2517 bool OptionCheck(ProjectOptions options, int option) {
2518 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2519 return value && value != none;
2521 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2522 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2523 *(WarningsOption*)((byte *)output + option) = value;
2526 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2527 bool OptionCheck(ProjectOptions options, int option) {
2528 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2529 return value && value != none;
2531 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2532 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2533 *(OptimizationStrategy*)((byte *)output + option) = value;
2537 Map<int, GenericOptionTools> ot { };
2539 // The following are compiler options
2541 ot[OPTION(debug)] = utilSetBool;
2542 ot[OPTION(memoryGuard)] = utilSetBool;
2543 ot[OPTION(profile)] = utilSetBool;
2544 ot[OPTION(noLineNumbers)] = utilSetBool;
2545 ot[OPTION(strictNameSpaces)] = utilSetBool;
2546 ot[OPTION(fastMath)] = utilSetBool;
2548 ot[OPTION(defaultNameSpace)] = utilString;
2550 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2551 ot[OPTION(includeDirs)] = utilStringArrays;
2553 ot[OPTION(warnings)] = utilWarningsOption;
2555 ot[OPTION(optimization)] = utilOptimizationStrategy;
2557 for(n = node; n; n = n.parent)
2559 ProjectConfig nodeConfig = null;
2561 priority = (priority / 10 + 1) * 10;
2564 if(projectConfig && n.configurations)
2566 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2568 if(platform && c.platforms)
2570 for(p : c.platforms; !strcmpi(p.name, platformName))
2574 GenericOptionTools u = uu;
2576 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2578 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2579 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2580 optionConfigXplatformSet[o] = true;
2592 GenericOptionTools u = uu;
2596 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2598 for(p : n.platforms; !strcmpi(p.name, platformName))
2600 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2602 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2603 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2608 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2609 ((u.mergeValues && !u.configReplaces) ?
2610 u.OptionCheck(nodeConfig.options, o) :
2611 u.OptionSet(nodeConfig.options, o)))
2613 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2614 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2618 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2620 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2621 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2625 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2626 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2634 GenericOptionTools u = uu;
2637 u.FinalizeLoading(o, optionTempStrings, output);
2640 delete optionConfigXplatformSet;
2642 delete optionTempStrings;
2646 delete utilStringArrays;
2647 delete utilWarningsOption;
2648 delete utilOptimizationStrategy;
2655 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2659 ProjectOptions first;
2660 ProjectOptions commonOptions;
2662 Map<String, int> countIncludeDirs { };
2663 Map<String, int> countPreprocessorDefinitions { };
2664 Map<String, bool> commonIncludeDirs { };
2665 Map<String, bool> commonPreprocessorDefinitions { };
2667 for(options : byPlatformOptions) { first = options; break; }
2669 *platformsCommonOptions = commonOptions = first.Copy();
2671 if(commonOptions.includeDirs)
2672 commonOptions.includeDirs.Free();
2673 if(commonOptions.preprocessorDefinitions)
2674 commonOptions.preprocessorDefinitions.Free();
2676 for(options : byPlatformOptions)
2678 if(options != first)
2680 if(commonOptions.debug && options.debug != commonOptions.debug)
2681 commonOptions.debug = unset;
2682 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2683 commonOptions.memoryGuard = unset;
2684 if(commonOptions.profile && options.profile != commonOptions.profile)
2685 commonOptions.profile = unset;
2686 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2687 commonOptions.noLineNumbers = unset;
2688 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2689 commonOptions.strictNameSpaces = unset;
2690 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2691 commonOptions.fastMath = unset;
2693 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2694 commonOptions.warnings = unset;
2695 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2696 commonOptions.optimization = unset;
2698 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2699 delete commonOptions.defaultNameSpace;
2702 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2703 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2706 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2707 commonIncludeDirs, commonOptions.includeDirs);
2708 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2709 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2711 for(options : byPlatformOptions)
2713 if(options.debug && options.debug == commonOptions.debug)
2714 options.debug = unset;
2715 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2716 options.memoryGuard = unset;
2717 if(options.profile && options.profile == commonOptions.profile)
2718 options.profile = unset;
2719 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2720 options.noLineNumbers = unset;
2721 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2722 options.strictNameSpaces = unset;
2723 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2724 options.fastMath = unset;
2726 if(options.warnings && options.warnings == commonOptions.warnings)
2727 options.warnings = unset;
2728 if(options.optimization && options.optimization == commonOptions.optimization)
2729 options.optimization = unset;
2731 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2732 delete options.defaultNameSpace;
2734 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2735 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2738 delete countIncludeDirs;
2739 delete countPreprocessorDefinitions;
2740 delete commonIncludeDirs;
2741 delete commonPreprocessorDefinitions;
2744 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2745 Map<Platform, ProjectOptions> parentByPlatformOptions,
2746 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2748 ComplexComparison result = equal;
2749 ComplexComparison compare;
2751 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2753 ProjectOptions additionalOptions;
2754 additionsByPlatformOptions[platform] = { };
2755 additionalOptions = additionsByPlatformOptions[platform];
2756 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2757 if(compare == greater && result == equal)
2759 else if(compare == different)
2768 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2770 ComplexComparison result = equal;
2771 if(options.debug != parentOptions.debug ||
2772 options.memoryGuard != parentOptions.memoryGuard ||
2773 options.profile != parentOptions.profile ||
2774 options.noLineNumbers != parentOptions.noLineNumbers ||
2775 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2776 options.fastMath != parentOptions.fastMath ||
2777 options.warnings != parentOptions.warnings ||
2778 options.optimization != parentOptions.optimization ||
2779 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2780 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2784 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2785 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2787 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2788 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2794 enum ComplexComparison { different/*, smaller*/, equal, greater };
2796 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2799 if((!strings || !strings.count) && originals && originals.count)
2801 else if(strings && strings.count && (!originals || !originals.count))
2806 additions->Add(CopyString(s));
2808 else if(strings && strings.count && originals && originals.count)
2810 Map<String, String> map { };
2811 MapIterator<String, bool> mit { map = map };
2814 char * s = strstr(it, "\n");
2820 char * s = strstr(it, "\n");
2822 if(!mit.Index(s, false))
2837 additions->Add(CopyString(it));
2845 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2858 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
2866 strings.Add(CopyString(s));
2872 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
2876 Array<String> tmp { };
2877 MapIterator<String, bool> mit { map = common };
2881 if(!mit.Index(s, false))
2882 tmp.Add(CopyString(s));
2888 strings.Add(CopyString(s));
2895 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, File f)
2898 customFlags = nodeFlagsMapping[(intptr)node];
2900 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2902 f.Printf(" $(%s)", variableName);
2905 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, DynamicString s)
2908 customFlags = nodeFlagsMapping[(intptr)node];
2910 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2912 s.concatf(" $(%s)", variableName);
2915 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
2921 if(options.optimization == speed || options.optimization == size ||
2922 options.fastMath == true || options.debug == true)
2924 if(options.debug != true)
2926 s.concat(" $(if $(DEBUG),");
2930 switch(options.optimization)
2932 case speed: s.concat(" -O2"); break;
2933 case size: s.concat(" -Os"); break;
2935 if(options.fastMath == true)
2936 s.concat(" -ffast-math");
2937 if(options.debug == true)
2939 if(options.debug != true)
2942 else if(commonOptions)
2943 s.concat(" $(if $(DEBUG),-g)");
2945 s.concat(" $(FPIC)");
2947 switch(options.warnings)
2949 case all: s.concat(" -Wall"); break;
2950 case none: s.concat(" -w"); break;
2956 if(options && options.preprocessorDefinitions)
2957 ListOptionToDynamicString("D", options.preprocessorDefinitions, false, lineEach, "\t\t\t", false, s);
2958 if(options && options.includeDirs)
2959 ListOptionToDynamicString("I", options.includeDirs, true, lineEach, "\t\t\t", true, s);
2962 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
2964 if(options.memoryGuard == true)
2965 s.concat(" -memguard");
2966 if(options.noLineNumbers == true)
2967 s.concat(" -nolinenumbers");
2968 if(options.strictNameSpaces == true)
2969 s.concat(" -strictns");
2970 if(options.defaultNameSpace && options.defaultNameSpace[0])
2971 s.concatf(" -defaultns %s", options.defaultNameSpace);
2974 static void ListOptionToDynamicString(char * option, Array<String> list, bool prioritize,
2975 ListOutputMethod method, String newLineStart, bool noSpace, DynamicString s)
2979 if(method == newLine)
2982 s.concat(newLineStart);
2986 Map<String, int> sortedList { };
2987 MapNode<String, int> mn;
2989 sortedList[item] = 1;
2990 for(mn = sortedList.root.minimum; mn; mn = mn.next)
2992 char * start = strstr(mn.key, "\n");
2993 if(method == lineEach)
2996 s.concat(newLineStart);
3001 StringNoSpaceToDynamicString(s, start ? start+1 : mn.key);
3003 s.concat(start ? start+1 : mn.key);
3011 if(method == lineEach)
3014 s.concat(newLineStart);
3019 StringNoSpaceToDynamicString(s, item);
3027 class GenericOptionTools<class X>
3029 bool mergeValues, configReplaces;
3031 virtual bool OptionSet(ProjectOptions options, int option) {
3032 if(*(X*)((byte *)options + option))
3037 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3039 virtual bool OptionCheck(ProjectOptions options, int option) {
3040 return OptionSet(options, option);
3043 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3044 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3047 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3052 class NameCollisionInfo
3064 bool IsExtensionColliding(char * extension)
3068 ((!strcmpi(extension, "c") && ec) ||
3069 (!strcmpi(extension, "s") && (ec || c)) ||
3070 (!strcmpi(extension, "cpp") && (ec || c || s)) ||
3071 (!strcmpi(extension, "cc") && (ec || c || s || cpp)) ||
3072 (!strcmpi(extension, "cxx") && (ec || c || s || cpp || cc)) ||
3073 (!strcmpi(extension, "m") && (ec || c || s || cpp || cc || m)) ||
3074 !strcmpi(extension, "mm")))