1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(&((ProjectOptions)0).x))
17 bool eString_PathInsideOfMore(char * path, char * of, char * pathRest)
19 if(!path[0] || !of[0])
20 return false; // What to do here? Ever used?
23 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
24 char pathPart[MAX_FILENAME]; //, pathRest[MAX_LOCATION];
26 strcpy(pathRest, path);
27 for(; ofRest[0] && pathRest[0];)
29 SplitDirectory(ofRest, ofPart, ofRest);
30 SplitDirectory(pathRest, pathPart, pathRest);
31 if(fstrcmp(pathPart, ofPart))
34 if(!ofRest[0] && !pathRest[0])
36 else if(!pathRest[0]) // not inside of, it's the other way around
42 enum NodeTypes { project, file, folder, resources, folderOpen };
45 genFile, ewsFile, epjFile, folder, openFolder, ecFile, ehFile,
46 sFile, cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile,
47 archiveFile, packageFile, opticalMediaImageFile, mFile;
49 NodeIcons ::SelectFileIcon(char * filePath)
52 if(filePath && filePath[0])
54 char extension[MAX_EXTENSION];
55 GetExtension(filePath, extension);
58 if(!strcmpi(extension, WorkspaceExtension))
60 else if(!strcmpi(extension, ProjectExtension))
62 else if(!strcmpi(extension, "ec"))
64 else if(!strcmpi(extension, "eh"))
66 else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
67 !strcmpi(extension, "cxx"))
69 else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
70 !strcmpi(extension, "hxx"))
72 else if(!strcmpi(extension, "s"))
74 else if(!strcmpi(extension, "c"))
76 else if(!strcmpi(extension, "h"))
78 else if(!strcmpi(extension, "m"))
80 else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
81 !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
83 else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
84 !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
85 !strcmpi(extension, "js"))
87 else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
88 !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
89 !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
90 !strcmpi(extension, "ico"))
92 else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
93 !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
95 else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
96 !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
97 !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
98 !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
99 !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
100 !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
102 else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
103 !strcmpi(extension, "rpm"))
105 else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
106 !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
107 !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
108 !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
109 icon = opticalMediaImageFile;
117 icon = genFile; // tocheck: error icon?
121 NodeIcons ::SelectNodeIcon(NodeTypes type)
140 #define SELECTION_COLOR Color { 10, 36, 106 }
146 // this is so not working, why!
148 // return result was not even executed (did not step on while debugging)
149 class TwoStrings : struct
169 class ProjectNode : ListItem
174 set { return { fileName = value }; }
175 // TOCHECK: Is this isset necessary at all?
176 isset { return nodeType == file && !options && !configurations && !platforms && !files; }
178 property String folder
183 if(strchr(value, '/'))
185 char p[MAX_LOCATION];
186 char n[MAX_FILENAME];
187 GetLastDirectory(value, n);
188 StripLastDirectory(value, p);
189 name = CopyString(n);
190 path = CopyString(p);
193 name = CopyString(value);
197 // TOCHECK: Non Reentrant
198 static char insidePath[MAX_LOCATION];
200 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
201 PathCatSlash(insidePath, name);
203 if(!fstrcmp(path, insidePath))
207 strcpy(insidePath, path);
208 if(!insidePath[0]) strcpy(insidePath, ".");
209 PathCatSlash(insidePath, name);
213 isset { return nodeType == folder; }
215 property String fileName
220 if(strchr(value, '/'))
222 char p[MAX_LOCATION];
223 char n[MAX_FILENAME];
224 GetLastDirectory(value, n);
225 StripLastDirectory(value, p);
226 name = CopyValidateMakefilePath(n);
227 path = CopyValidateMakefilePath(p);
230 name = CopyValidateMakefilePath(value);
234 // TOCHECK: Non Reentrant
235 static char insidePath[MAX_LOCATION];
237 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
238 if(!fstrcmp(path, insidePath))
242 strcpy(insidePath, path);
243 if(!insidePath[0]) strcpy(insidePath, ".");
244 PathCatSlash(insidePath, name);
248 isset { return nodeType == file && (options || configurations || platforms); }
251 LinkList<ProjectNode> files;
252 property ProjectOptions options
254 get { return project ? project.options : options; }
255 set { if(project) { delete project.options; project.options = value; } else { delete options; options = value; } }
256 isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
258 property Array<PlatformOptions> platforms
260 get { return project ? project.platforms : platforms; }
263 if(project) { project.platforms = value; }
266 if(platforms) { platforms.Free(); delete platforms; }
269 List<PlatformOptions> empty { };
270 Iterator<PlatformOptions> it { value };
272 for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
273 for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
280 Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
285 if(p.options && !p.options.isEmpty)
292 property List<ProjectConfig> configurations
294 get { return project ? project.configurations : configurations; }
299 if(project.configurations)
301 project.configurations.Free();
302 delete project.configurations;
304 project.configurations = value;
308 if(configurations) { configurations.Free(); delete configurations; }
311 List<ProjectConfig> empty { };
312 Iterator<ProjectConfig> it { value };
313 configurations = value;
314 for(c : configurations)
316 bool somethingSet = c.options && !c.options.isEmpty;
317 // TODO: Implement isset keyword
318 if(!somethingSet && c.platforms && c.platforms.count)
322 if(p.options && !p.options.isEmpty)
332 for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
339 if(!parent) return true;
342 for(c : configurations)
344 bool somethingSet = c.options && !c.options.isEmpty;
345 if(!somethingSet && c.platforms && c.platforms.count)
349 if(p.options && !p.options.isEmpty)
364 ProjectOptions options;
365 Array<PlatformOptions> platforms;
366 List<ProjectConfig> configurations;
367 ProjectNodeType nodeType;
372 // This holds the absolute path of the .epj for the project topnode (without the filename)
373 // It holds a relative path to the topNode (project) for other nodes (folders and files)
374 // For folders, it includes the folder it refers to. If there is a name difference between the
375 // file system folder and the grouping folder of the project view, it maps to that folder.
385 // This is only set for Top Nodes
388 void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Array<Platform> platforms)
390 if(!platforms.Find(unknown)) // unknown is "Common"
392 // e.g. ifneq "$(or $(or $(OSX_TARGET),$(LINUX_TARGET)),$(WINDOWS_TARGET))"
395 for(i = 0; platforms.count && i < platforms.count - 1; i++)
403 f.Puts(PlatformToMakefileTargetVariable(p));
416 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
418 ProjectConfig nodeConfig = null;
419 if(property::configurations && prjConfig)
421 const char * configName = prjConfig.name;
422 for(cfg : property::configurations)
424 if(!strcmpi(cfg.name, configName))
434 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
436 property bool containsFile
445 if(child.type == file ||
446 ((child.type == folder || child.type == folderOpen) && child.containsFile))
459 char * GetFullFilePath(char * buffer)
463 strcpy(buffer, root.path);
464 PathCatSlash(buffer, path);
465 PathCatSlash(buffer, name);
470 char * GetFileSysMatchingPath(char * buffer)
474 ProjectNode n, root = this.root;
475 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
477 strcpy(buffer, root.path);
479 PathCatSlash(buffer, n.path);
480 if(FileExists(buffer).isDirectory)
483 if(!(n && (n.type == folder || n.type == project)))
489 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
491 ProjectNode node = null;
492 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
493 List<ProjectNode> nodeStack { };
495 for(node = this; node && node.parent; node = node.parent)
498 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
500 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
501 while((node = nodeStack.lastIterator.data))
503 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
504 ProjectOptions nodeOptions = node.property::options;
505 if(nodeOptions && nodeOptions.preprocessorDefinitions)
507 for(def : nodeOptions.preprocessorDefinitions)
508 perFilePreprocessorDefs.Add(CopyString(def));
510 if(config && config.options && config.options.preprocessorDefinitions)
512 for(def : config.options.preprocessorDefinitions)
513 perFilePreprocessorDefs.Add(CopyString(def));
515 if(nodeOptions && nodeOptions.includeDirs)
517 for(dir : nodeOptions.includeDirs)
518 perFileIncludeDirs.Add(CopySystemPath(dir));
520 if(config && config.options && config.options.includeDirs)
522 for(dir : config.options.includeDirs)
523 perFileIncludeDirs.Add(CopySystemPath(dir));
525 nodeStack.lastIterator.Remove();
531 property Project project
535 ProjectNode n = this;
536 while(n && n.type != project) n = n.parent;
537 return n ? (*&n.project) : null;
541 void RenameConfig(char * oldName, char * newName)
545 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
547 if(property::configurations)
549 for(c : property::configurations; !strcmp(c.name, oldName))
552 c.name = CopyString(newName);
557 void DeleteConfig(ProjectConfig configToDelete)
561 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
563 if(property::configurations)
565 Iterator<ProjectConfig> c { property::configurations };
568 ProjectConfig config = c.data;
569 if(!strcmp(configToDelete.name, config.name))
576 if(!property::configurations.count)
577 property::configurations = null;
583 ProjectNode backupNode { };
587 backupNode.files = { };
588 for(f : files) backupNode.files.Add(f.Backup());
590 if(property::options)
591 backupNode.options = property::options.Copy();
593 if(property::platforms)
595 backupNode.platforms = { };
596 for(p : property::platforms)
597 backupNode.platforms.Add(p.Copy());
600 if(property::configurations)
602 backupNode.configurations = { };
603 for(c : property::configurations)
604 backupNode.configurations.Add(c.Copy());
609 void Revert(ProjectNode backupNode)
613 Iterator<ProjectNode> it { backupNode.files };
621 property::options = backupNode.options ? backupNode.options.Copy() : null;
622 if(backupNode.platforms)
624 Array<PlatformOptions> platforms { };
625 property::platforms = platforms;
627 for(p : backupNode.platforms)
628 platforms.Add(p.Copy());
630 if(backupNode.configurations)
632 List<ProjectConfig> configurations { };
633 property::configurations = configurations;
634 for(c : backupNode.configurations)
635 configurations.Add(c.Copy());
639 void FixupNode(char * parentPath)
645 else if(nodeType == file)
650 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
653 else if(nodeType == folder)
659 char temp[MAX_LOCATION];
660 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
661 PathCatSlash(temp, name);
662 path = CopyString(temp);
666 indent = parent ? parent.indent + 1 : 0;
669 icon = NodeIcons::SelectFileIcon(name);
671 icon = NodeIcons::SelectNodeIcon(type);
680 parentPath[0] = '\0';
681 else if(type == resources || type == folder)
682 strcpy(parentPath, path);
684 f.FixupNode(parentPath);
689 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
693 // TOCHECK: Called from JSON writer
694 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
696 strcpy(tempString, "\"");
697 strcat(tempString, property::fileName);
698 strcat(tempString, "\"");
705 // TOCHECK: Called from ProjectView rendering
706 return name ? name : "";
719 if(!project && platforms)
724 if(!project && configurations)
726 configurations.Free();
727 delete configurations;
730 /////////////////////////////
736 property bool isInResources
741 for(node = this; node; node = node.parent)
743 if(node.type == resources)
750 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
752 TwoStrings result { a = CopyString(""), b = CopyString("") };
753 // note: unknown platform is for common
754 Map<Platform, SetBool> exclusionInfo { };
755 MapNode<Platform, SetBool> mn;
760 CollectExclusionInfo(exclusionInfo, prjConfig);
761 common = exclusionInfo[unknown];
763 Map<Platform, SetBool> cleaned { };
764 SetBool opposite = common == true ? false : true;
765 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
767 if(mn.key == unknown || mn.value == opposite)
768 cleaned[mn.key] = mn.value;
770 delete exclusionInfo;
771 exclusionInfo = cleaned;
774 if(exclusionInfo.count > 1)
776 if(exclusionInfo.count > 2)
779 len = strlen(exp) + strlen("$(if $(or ");
780 exp = renew exp char[len+1];
781 strcat(exp, "$(if $(or ");
784 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
786 if(mn.key != unknown)
788 char * comma = mn.next ? "," : "";
790 var = PlatformToMakefileTargetVariable(mn.key);
793 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
794 exp = renew exp char[len+1];
804 len = strlen(exp) + strlen("),");
805 exp = renew exp char[len+1];
809 if(exclusionInfo.root.minimum.key != unknown)
810 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
812 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
815 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
816 exp = renew exp char[len+1];
817 strcat(exp, "$(if $(");
824 exp = common == true ? result.b : result.a;
825 len = strlen(exp) + strlen(",");
826 exp = renew exp char[len+1];
828 if(common == true) result.b = exp; else result.a = exp;
831 len = strlen(exp) + strlen(")");
832 exp = renew exp char[len+1];
836 delete exclusionInfo;
841 bool GetIsExcluded(ProjectConfig prjConfig)
844 // note: unknown platform is for common
845 Map<Platform, SetBool> exclusionInfo { };
846 CollectExclusionInfo(exclusionInfo, prjConfig);
847 if(exclusionInfo.count == 0)
849 else if(exclusionInfo.count == 1)
850 result = exclusionInfo.root.minimum.value == true;
853 SetBool check = exclusionInfo.root.minimum.value;
854 MapNode<Platform, SetBool> mn;
855 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
857 if(check != mn.value)
860 if(!mn) // all are same
861 result = check == true;
865 delete exclusionInfo;
869 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
871 // note: unknown platform is for common
873 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
874 ProjectOptions options = property::options;
875 Array<PlatformOptions> platforms = property::platforms;
876 List<ProjectConfig> configurations = property::configurations;
879 parent.CollectExclusionInfo(output, prjConfig);
881 output[unknown] = unset;
883 if(options && options.excludeFromBuild)
884 output[unknown] = options.excludeFromBuild;
886 if(config && config.options && config.options.excludeFromBuild)
887 output[unknown] = config.options.excludeFromBuild;
893 if(p.options.excludeFromBuild && (platform = p.name))
894 output[platform] = p.options.excludeFromBuild;
897 if(config && config.platforms)
899 for(p : config.platforms)
901 if(p.options.excludeFromBuild && (platform = p.name))
902 output[platform] = p.options.excludeFromBuild;
910 parent.EnsureVisible();
911 row.collapsed = false;
917 parent.files.Delete(this);
920 ProjectNode Find(char * name, bool includeResources)
922 ProjectNode result = null;
927 if(includeResources || child.type != resources)
929 if(child.type != folder && child.name && !strcmpi(child.name, name))
934 result = child.Find(name, includeResources);
943 ProjectNode FindWithPath(char * name, bool includeResources)
945 ProjectNode result = null;
950 if(includeResources || child.type != resources)
952 char path[MAX_LOCATION];
953 strcpy(path, child.path);
954 if(child.type != folder && child.name)
956 PathCatSlash(path, child.name);
957 if(!strcmpi(path, name))
963 result = child.FindWithPath(name, includeResources);
972 ProjectNode FindByFullPath(char * path, bool includeResources)
974 ProjectNode result = null;
979 if(includeResources || child.type != resources)
981 if(child.type != folder && child.name)
983 char p[MAX_LOCATION];
984 child.GetFullFilePath(p);
985 if(!strcmpi(p, path))
991 result = child.FindByFullPath(path, includeResources);
1000 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
1002 ProjectNode result = null;
1007 if(includeResources || child.type != resources)
1009 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1015 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1024 ProjectNode FindSameNameConflict(char * name, bool includeResources,
1025 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1027 ProjectNode result = null;
1028 Map<Platform, SetBool> compareExclusion { };
1029 SetBool common, commonComp;
1030 SetBool actual, actualComp;
1035 if(includeResources || child.type != resources)
1037 if(child.type != folder && child.name && !strcmpi(child.name, name))
1039 child.CollectExclusionInfo(compareExclusion, prjConfig);
1040 common = exclusionInfo[unknown];
1041 commonComp = compareExclusion[unknown];
1042 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1044 if(!(common == true || commonComp == true))
1053 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1056 actualComp = commonComp;
1057 if(exclusionInfo[platform] != unset)
1058 actual = exclusionInfo[platform];
1059 if(compareExclusion[platform] != unset)
1060 actualComp = compareExclusion[platform];
1061 if(!(actual == true || actualComp == true))
1069 compareExclusion.Free();
1072 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1076 compareExclusion.Free();
1078 delete compareExclusion;
1082 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1084 ProjectNode node = null;
1085 char temp[MAX_LOCATION];
1086 Map<Platform, SetBool> exclusionInfo { };
1088 GetLastDirectory(filePath, temp);
1089 //if(!checkIfExists || !project.topNode.Find(temp, false))
1091 // TOCHECK: Shouldn't this apply either for all configs or none?
1092 CollectExclusionInfo(exclusionInfo, project.config);
1093 if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1095 // Do the check for folder in the same parent or resource files only here
1096 if(type == folder || !checkIfExists)
1100 if(node.name && !strcmpi(node.name, temp))
1105 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1109 node.nodeType = folder;
1115 StripLastDirectory(filePath, temp);
1116 MakePathRelative(temp, project.topNode.path, temp);
1117 node.path = CopyUnixPath(temp);
1119 node.nodeType = file;
1123 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1124 PathCatSlash(temp, node.name);
1125 node.path = CopyString(temp);
1127 files.Insert(after, node);
1129 delete exclusionInfo;
1133 #ifndef MAKEFILE_GENERATOR
1134 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1136 char label[MAX_FILENAME];
1142 bool showConfig = true;
1147 projectView = ide.projectView;
1150 bmp = projectView.icons[icon].bitmap;
1151 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1153 GetLastDirectory(name, label);
1154 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1156 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1158 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1161 addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1162 if(strlen(addendum))
1164 strcat(label, " (");
1165 strcat(label, addendum);
1168 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1169 if(strlen(addendum))
1171 strcat(label, " (");
1172 strcat(label, addendum);
1178 else if(!projectView.drawingInProjectSettingsDialog)
1181 strcat(label, " *");
1182 if(type == project && info)
1184 int len = strlen(info) + 4;
1185 char * more = new char[len];
1186 sprintf(more, " (%s)", info);
1187 strcat(label, more);
1191 len = strlen(label);
1195 if(type == folder || type == folderOpen)
1196 surface.SetForeground(yellow);
1200 surface.TextOpacity(false);
1201 surface.TextExtent(label, len, &w, &h);
1204 // Draw the current row stipple
1205 if(displayFlags.selected)
1206 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1207 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1208 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1210 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1214 if(displayFlags.current)
1216 if(displayFlags.active)
1218 surface.LineStipple(0x5555);
1219 if(displayFlags.selected)
1220 surface.SetForeground(projectView.fileList.stippleColor);
1222 surface.SetForeground(projectView.fileList.foreground);
1226 surface.SetForeground(SELECTION_COLOR);
1228 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1229 surface.LineStipple(0);
1234 surface.SetForeground(white);
1235 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1241 int OnCompare(ProjectNode b)
1244 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1245 result = strcmpi(name, b.name);
1248 if(type == folder && b.type == file) result = -1;
1249 else if(type == file && b.type == folder) result = 1;
1254 bool ContainsFilesWithExtension(char * extension)
1258 char ext[MAX_EXTENSION];
1259 GetExtension(name, ext);
1260 if(!fstrcmp(ext, extension))
1265 bool needed = false;
1267 if(child.ContainsFilesWithExtension(extension))
1273 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1277 char extension[MAX_EXTENSION];
1278 GetExtension(name, extension);
1279 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1280 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1281 !strcmpi(extension, "cxx") || !strcmpi(extension, "m"))
1283 char moduleName[MAX_FILENAME];
1284 NameCollisionInfo info;
1285 ReplaceSpaces(moduleName, name);
1286 StripExtension(moduleName);
1287 info = namesInfo[moduleName];
1289 info = NameCollisionInfo { };
1290 info.count++; // += 1; unless this is for a bug?
1291 if(!strcmpi(extension, "ec"))
1293 else if(!strcmpi(extension, "s"))
1295 else if(!strcmpi(extension, "c"))
1297 else if(!strcmpi(extension, "cpp"))
1299 else if(!strcmpi(extension, "cc"))
1301 else if(!strcmpi(extension, "cxx"))
1303 else if(!strcmpi(extension, "m"))
1305 namesInfo[moduleName] = info;
1312 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1313 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1318 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1319 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1320 ProjectConfig prjConfig, bool * containsCXX)
1326 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1327 char moduleName[MAX_FILENAME];
1328 char extension[MAX_EXTENSION];
1329 GetExtension(name, extension);
1330 if(printType == resources)
1333 char tempPath[MAX_LOCATION];
1334 char modulePath[MAX_LOCATION];
1337 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1340 PathCatSlash(tempPath, name);
1345 strcpy(tempPath, path);
1346 PathCatSlash(tempPath, name);
1348 ReplaceSpaces(modulePath, tempPath);
1349 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1350 items.Add(CopyString(s));
1352 else if(printType == sources)
1354 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1355 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1356 !strcmpi(extension, "m"))
1358 char modulePath[MAX_LOCATION];
1360 ReplaceSpaces(modulePath, path);
1361 ReplaceSpaces(moduleName, name);
1362 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1363 items.Add(CopyString(s));
1366 else if(printType == eCsources)
1368 if(!strcmpi(extension, "ec"))
1370 char modulePath[MAX_LOCATION];
1372 ReplaceUnwantedMakeChars(modulePath, path);
1373 ReplaceUnwantedMakeChars(moduleName, name);
1374 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1375 items.Add(CopyString(s));
1379 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1380 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1381 !strcmpi(extension, "m"))
1383 if(printType == objects)
1386 NameCollisionInfo info;
1388 ReplaceSpaces(moduleName, name);
1389 StripExtension(moduleName);
1390 info = namesInfo[moduleName];
1391 collision = info ? info.IsExtensionColliding(extension) : false;
1392 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1393 items.Add(CopyString(s));
1394 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1395 *containsCXX = true;
1404 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1405 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1411 void GenMakefilePrintSymbolRules(File f, Project project,
1412 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1413 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1416 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1417 //ProjectNode child;
1418 //char objDir[MAX_LOCATION];
1419 //ReplaceSpaces(objDir, config.objDir.dir);
1421 //eSystem_Log("Printing Symbol Rules\n");
1424 char extension[MAX_EXTENSION];
1425 char modulePath[MAX_LOCATION];
1426 char moduleName[MAX_FILENAME];
1428 GetExtension(name, extension);
1429 if(!strcmpi(extension, "ec"))
1434 ReplaceSpaces(moduleName, name);
1435 StripExtension(moduleName);
1437 ReplaceSpaces(modulePath, path);
1438 if(modulePath[0]) strcat(modulePath, SEPS);
1440 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1442 // *** Dependency command ***
1443 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1444 modulePath, moduleName, extension);
1446 // System Includes (from global settings)
1447 for(item : compiler.dirs[Includes])
1449 strcat(command, " -isystem ");
1450 if(strchr(item, ' '))
1452 strcat(command, "\"");
1453 strcat(command, item);
1454 strcat(command, "\"");
1457 strcat(command, item);
1460 for(item : project.includeDirs)
1462 strcat(command, " -I");
1463 if(strchr(item, ' '))
1465 strcat(command, "\"");
1466 strcat(command, item);
1467 strcat(command, "\"");
1470 strcat(command, item);
1472 for(item : project.preprocessorDefs)
1474 strcat(command, " -D");
1475 strcat(command, item);
1479 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1482 bool firstLine = true;
1485 // To do some time: auto save external dependencies?
1488 if(dep.GetLine(line, sizeof(line)-1))
1492 char * colon = strstr(line, ":");
1493 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1507 // If we failed to generate dependencies...
1511 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1512 moduleName, modulePath, moduleName, extension);
1516 f.Puts(" $(CFLAGS)");
1517 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1519 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1520 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1522 f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n",
1523 modulePath, moduleName, extension, moduleName);
1524 if(ifCount) f.Puts("endif\n");
1534 bool needed = false;
1535 if(ContainsFilesWithExtension("ec"))
1539 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1550 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1551 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1552 nodeCFlagsMapping, nodeECFlagsMapping);
1559 void GenMakefilePrintPrepecsRules(File f, Project project,
1560 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1561 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1564 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1565 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1566 //ProjectNode child;
1567 //char objDir[MAX_LOCATION];
1568 //ReplaceSpaces(objDir, config.objDir.dir);
1570 //eSystem_Log("Printing Symbol Rules\n");
1573 char extension[MAX_EXTENSION];
1574 char modulePath[MAX_LOCATION];
1575 char moduleName[MAX_FILENAME];
1577 GetExtension(name, extension);
1578 if(!strcmpi(extension, "ec"))
1583 ReplaceSpaces(moduleName, name);
1584 StripExtension(moduleName);
1586 ReplaceSpaces(modulePath, path);
1587 if(modulePath[0]) strcat(modulePath, SEPS);
1589 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1590 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1591 moduleName, modulePath, moduleName, extension);
1592 //$(CPP) -x c -E ../extras/gui/controls/DirectoriesBox.ec -o $(OBJ)DirectoriesBox$(EC)
1593 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1594 modulePath, moduleName, extension, moduleName);*/
1598 f.Puts(" $(CFLAGS)");
1599 //f.Puts(" $(CECFLAGS)");
1600 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1601 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1603 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1604 modulePath, moduleName, extension, moduleName);
1605 if(ifCount) f.Puts("endif\n");
1611 bool needed = false;
1612 if(ContainsFilesWithExtension("ec"))
1616 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1627 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1628 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1629 nodeCFlagsMapping, nodeECFlagsMapping);
1636 void GenMakefilePrintCObjectRules(File f, Project project,
1637 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1638 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1641 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1642 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1643 //ProjectNode child;
1644 //char objDir[MAX_LOCATION];
1645 //ReplaceSpaces(objDir, config.objDir.dir);
1646 //eSystem_Log("Printing C Object Rules\n");
1649 char extension[MAX_EXTENSION];
1650 char modulePath[MAX_LOCATION];
1651 char moduleName[MAX_FILENAME];
1653 GetExtension(name, extension);
1654 if(!strcmpi(extension, "ec"))
1659 ReplaceSpaces(moduleName, name);
1660 StripExtension(moduleName);
1662 ReplaceSpaces(modulePath, path);
1663 if(modulePath[0]) strcat(modulePath, SEPS);
1665 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1667 // *** Dependency command ***
1668 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1669 moduleName, modulePath, moduleName, extension);
1671 // System Includes (from global settings)
1672 for(item : compiler.dirs[Includes])
1674 strcat(command, " -isystem ");
1675 if(strchr(item, ' '))
1677 strcat(command, "\"");
1678 strcat(command, item);
1679 strcat(command, "\"");
1682 strcat(command, item);
1685 for(item : config.includeDirs)
1687 strcat(command, " -I");
1688 if(strchr(item, ' '))
1690 strcat(command, "\"");
1691 strcat(command, item);
1692 strcat(command, "\"");
1695 strcat(command, item);
1697 for(item : config.preprocessorDefs)
1699 strcat(command, " -D");
1700 strcat(command, item);
1704 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1708 bool firstLine = true;
1710 // To do some time: auto save external dependencies?
1713 if(dep.GetLine(line, sizeof(line)-1))
1717 char * colon = strstr(line, ":");
1718 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1732 // If we failed to generate dependencies...
1735 /* COMMENTED OUT FOR NOW
1736 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1737 moduleName, modulePath, moduleName, extension);
1740 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1741 moduleName, modulePath, moduleName, extension, moduleName);
1747 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1748 modulePath, moduleName, extension, moduleName);
1753 f.Puts(" $(CFLAGS)");
1754 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1755 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1756 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1757 f.Puts(" $(FVISIBILITY)");
1759 f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n",
1760 modulePath, moduleName, extension, moduleName);
1761 if(ifCount) f.Puts("endif\n");
1767 bool needed = false;
1768 if(ContainsFilesWithExtension("ec"))
1772 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1783 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1784 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1785 nodeCFlagsMapping, nodeECFlagsMapping);
1792 void GenMakefilePrintObjectRules(File f, Project project,
1793 Map<String, NameCollisionInfo> namesInfo,
1794 ProjectConfig prjConfig,
1795 //Map<Platform, bool> parentExcludedPlatforms,
1796 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1799 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1800 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1801 //ProjectNode child;
1802 //char objDir[MAX_LOCATION];
1803 //ReplaceSpaces(objDir, config.objDir.dir);
1804 //eSystem_Log("Printing Object Rules\n");
1808 char extension[MAX_EXTENSION];
1809 char modulePath[MAX_LOCATION];
1810 char moduleName[MAX_FILENAME];
1812 GetExtension(name, extension);
1813 /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1814 !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
1815 !strcmpi(extension, "cxx"))*/
1816 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1817 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1818 !strcmpi(extension, "m") || !strcmpi(extension, "ec"))
1822 NameCollisionInfo info;
1824 ReplaceSpaces(moduleName, name);
1825 StripExtension(moduleName);
1827 info = namesInfo[moduleName];
1828 collision = info ? info.IsExtensionColliding(extension) : false;
1830 ReplaceSpaces(modulePath, path);
1831 if(modulePath[0]) strcat(modulePath, SEPS);
1833 // *** Dependency command ***
1834 if(!strcmpi(extension, "ec"))
1835 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1837 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1838 moduleName, modulePath, moduleName, extension);
1840 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1843 if(!strcmpi(extension, "ec"))
1845 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1849 // System Includes (from global settings)
1850 for(item : compiler.dirs[includes])
1852 strcat(command, " -isystem ");
1853 if(strchr(item, ' '))
1855 strcat(command, "\"");
1856 strcat(command, item);
1857 strcat(command, "\"");
1860 strcat(command, item);
1863 for(item : config.includeDirs)
1865 strcat(command, " -I");
1866 if(strchr(item, ' '))
1868 strcat(command, "\"");
1869 strcat(command, item);
1870 strcat(command, "\"");
1873 strcat(command, item);
1875 for(item : config.preprocessorDefs)
1877 strcat(command, " -D");
1878 strcat(command, item);
1882 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1885 bool firstLine = true;
1888 // To do some time: auto save external dependencies?
1892 if(dep.GetLine(line, sizeof(line)-1))
1896 char * colon = strstr(line, ":");
1897 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1911 // If we failed to generate dependencies...
1920 if(!strcmpi(extension, "ec"))
1921 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1923 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
1924 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1925 f.Printf("\t$(%s)", (!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx")) ? "CXX" : "CC");
1927 f.Puts(" $(CFLAGS)");
1928 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1930 if(!strcmpi(extension, "ec"))
1931 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n", moduleName, moduleName);
1933 f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n",
1934 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1935 collision ? "." : "", collision ? extension : "");
1937 if(ifCount) f.Puts("endif\n");
1943 bool needed = false;
1946 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1956 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1957 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
1958 nodeCFlagsMapping, nodeECFlagsMapping);
1965 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
1972 //Iterator<ProjectNode> i { files };
1973 //Iterator<ProjectNode> prev { files };
1974 //for(child : files)
1976 for(c = 0; c < files.count; c++)
1978 ProjectNode child = files[c];
1979 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
1982 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
1985 char tempPath[MAX_LOCATION];
1986 char resPath[MAX_LOCATION];
1990 // $(EAR) aw%s --- /*quiet ? "q" : */""
1992 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
1995 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
1998 PathCatSlash(tempPath, child.name);
2003 strcpy(tempPath, child.path);
2004 PathCatSlash(tempPath, child.name);
2006 ReplaceSpaces(resPath, tempPath);
2007 if(strchr(tempPath, ' '))
2011 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", tempPath, quotes);
2014 if(count == 10 || (count > 0 && (ts || !child.next)))
2016 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2019 for(parent = this; parent.type == folder; parent = parent.parent)
2022 strcpy(path, parent.name);
2029 f.Printf(" \"%s\"%s\n", path, ts.b);
2041 if(child.type == folder)
2042 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2047 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2048 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2049 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2050 Map<Platform, ProjectOptions> parentByPlatformOptions)
2052 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2053 if(type == file || type == folder || type == project)
2055 bool hasPerNodeOptions = type == project;
2056 if(!hasPerNodeOptions)
2058 if(options && !options.isEmpty)
2059 hasPerNodeOptions = true;
2060 else if(configurations)
2062 for(c : configurations)
2064 if(c.options && !c.options.isEmpty)
2066 hasPerNodeOptions = true;
2071 for(p : c.platforms)
2073 if(p.options && !p.options.isEmpty)
2075 hasPerNodeOptions = true;
2079 if(hasPerNodeOptions)
2084 if(!hasPerNodeOptions && platforms)
2088 if(p.options && !p.options.isEmpty)
2090 hasPerNodeOptions = true;
2097 if(hasPerNodeOptions)
2099 bool isEqual = false, isGreater = false;
2100 ComplexComparison complexCmp;
2102 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2103 ProjectOptions platformsCommonOptions;
2104 ProjectOptions byFileConfigPlatformProjectOptions;
2106 DynamicString cflags { };
2107 DynamicString ecflags { };
2111 byPlatformOptions = { };
2113 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2115 byFileConfigPlatformProjectOptions =
2116 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2117 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2120 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2122 byPlatformOptions[unknown] = platformsCommonOptions;
2124 if(parentByPlatformOptions)
2126 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2127 parentByPlatformOptions, additionsByPlatformOptions);
2128 isGreater = complexCmp == greater;
2129 isEqual = complexCmp == equal;
2134 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2136 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2138 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2140 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2143 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2145 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2149 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2151 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2154 if(!isGreater) cflags.concat(" \\\n\t");
2159 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2162 ecflags.concat(" \\\n\t");
2169 cflags.concat(" \\\n\t");
2170 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2174 additionsByPlatformOptions.Free();
2175 delete additionsByPlatformOptions;
2181 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2182 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2190 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2191 cflagsVariations[s] = variationNum = cflagsVariations.count;
2192 nodeCFlagsMapping[(intptr)this] = variationNum;
2195 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2196 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2197 nodeECFlagsMapping[(intptr)this] = variationNum;
2208 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2209 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2218 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2219 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2220 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2225 if(byPlatformOptions != parentByPlatformOptions)
2227 byPlatformOptions.Free();
2228 delete byPlatformOptions;
2232 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2234 Array<Platform> platforms { };
2235 Map<Platform, SetBool> exclusionInfo { };
2236 CollectExclusionInfo(exclusionInfo, prjConfig);
2238 if(exclusionInfo[unknown] == true)
2240 if(exclusionInfo.count > 1)
2241 for(p : exclusionInfo; p == false)
2246 bool onlyOnknown = true;
2247 for(p : exclusionInfo)
2248 if(&p != unknown && p == true)
2250 onlyOnknown = false;
2254 platforms.Add(unknown);
2258 for(p = unknown + 1; p < Platform::enumSize; p++)
2259 if(exclusionInfo[p] != true)
2263 delete exclusionInfo;
2267 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2272 char extension[MAX_EXTENSION];
2273 char moduleName[MAX_FILENAME];
2274 NameCollisionInfo info;
2275 Project prj = property::project;
2277 GetExtension(name, extension);
2278 ReplaceSpaces(moduleName, name);
2279 StripExtension(moduleName);
2280 info = namesInfo[moduleName];
2281 collision = info ? info.IsExtensionColliding(extension) : false;
2283 output.concat(" \"");
2284 output.concat(objDir); //.concat(" $(OBJ)");
2288 strcat(moduleName, ".");
2289 strcat(moduleName, extension);
2291 strcat(moduleName, ".o");
2292 output.concat(moduleName);
2293 output.concat("\"");
2299 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2300 child.GetTargets(prjConfig, namesInfo, objDir, output);
2305 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2310 char extension[MAX_EXTENSION];
2311 char fileName[MAX_FILENAME];
2312 char moduleName[MAX_FILENAME];
2313 NameCollisionInfo info;
2314 Project prj = property::project;
2315 DirExpression objDir = prj.GetObjDir(compiler, prjConfig);
2317 GetExtension(name, extension);
2318 ReplaceSpaces(moduleName, name);
2319 StripExtension(moduleName);
2320 info = namesInfo[moduleName];
2321 collision = info ? info.IsExtensionColliding(extension) : false;
2323 strcpy(fileName, prj.topNode.path);
2324 PathCatSlash(fileName, objDir.dir);
2325 PathCatSlash(fileName, name);
2327 if(!onlyCObject && !strcmp(extension, "ec"))
2329 ChangeExtension(fileName, "c", fileName);
2330 if(FileExists(fileName)) DeleteFile(fileName);
2331 ChangeExtension(fileName, "sym", fileName);
2332 if(FileExists(fileName)) DeleteFile(fileName);
2333 ChangeExtension(fileName, "imp", fileName);
2334 if(FileExists(fileName)) DeleteFile(fileName);
2335 ChangeExtension(fileName, "bowl", fileName);
2336 if(FileExists(fileName)) DeleteFile(fileName);
2337 ChangeExtension(fileName, "ec", fileName);
2341 strcat(fileName, ".o");
2343 ChangeExtension(fileName, "o", fileName);
2344 if(FileExists(fileName)) DeleteFile(fileName);
2352 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2353 child.DeleteIntermediateFiles(compiler, prjConfig, namesInfo, onlyCObject);
2358 bool IsInNode(ProjectNode node)
2360 bool result = false;
2362 for(n = this; n; n = n.parent)
2374 // the code in this function is closely matched to OptionsBox::Load
2375 // and accompanying derivations of OptionBox and their use of OptionSet,
2376 // OptionCheck, LoadOption and FinalizeLoading methods.
2377 // output changing modification should be mirrored in both implementations
2378 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2380 ProjectOptions output { };
2382 // legend: e Element
2383 // o Option (of a ProjectOptions)
2384 // n Node (ProjectNode)
2386 // u Utility (GenericOptionTools)
2391 int includeDirsOption = OPTION(includeDirs);
2393 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2395 Array<bool> optionConfigXplatformSet { size = OPTION(postbuildCommands) };
2396 Array<bool> optionDone { size = OPTION(postbuildCommands) };
2397 Array<Array<String>> optionTempStrings { size = OPTION(postbuildCommands) };
2399 GenericOptionTools<SetBool> utilSetBool {
2400 bool OptionCheck(ProjectOptions options, int option) {
2401 return *(SetBool*)((byte *)options + option) == true;
2403 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2404 if(options && (*(SetBool*)((byte *)options + option) == true))
2405 *(SetBool*)((byte *)output + option) = true;
2408 GenericOptionTools<String> utilString {
2409 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2410 String * string = (String*)((byte *)output + option);
2411 if(*string) delete *string;
2413 *string = CopyString(*(String*)((byte *)options + option));
2416 StringArrayOptionTools utilStringArrays {
2418 caseSensitive = true;
2419 bool OptionCheck(ProjectOptions options, int option) {
2420 Array<String> strings = *(Array<String>*)((byte *)options + option);
2421 return strings && strings.count;
2423 bool OptionSet(ProjectOptions options, int option) {
2424 Array<String> strings = *(Array<String>*)((byte *)options + option);
2425 if(mergeValues && !configReplaces)
2426 return strings && strings.count;
2428 return strings != null;
2430 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2433 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2437 Array<String> tempStrings = optionTempStrings[option];
2439 optionTempStrings[option] = tempStrings = { };
2443 char priorityMark[10];
2446 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2447 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2448 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2454 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2455 Array<String> * strings = (Array<String>*)((byte *)output + option);
2456 if(*strings) { strings->Free(); delete *strings; }
2457 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2460 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2463 Array<String> tempStrings = optionTempStrings[option];
2464 Array<String> * strings = (Array<String>*)((byte *)output + option);
2465 if(*strings) { strings->Free(); delete *strings; }
2466 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2471 GenericOptionTools<WarningsOption> utilWarningsOption {
2472 bool OptionCheck(ProjectOptions options, int option) {
2473 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2474 return value && value != none;
2476 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2477 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2478 *(WarningsOption*)((byte *)output + option) = value;
2481 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2482 bool OptionCheck(ProjectOptions options, int option) {
2483 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2484 return value && value != none;
2486 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2487 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2488 *(OptimizationStrategy*)((byte *)output + option) = value;
2491 GenericOptionTools<BuildBitDepth> utilBuildBitDepth {
2492 bool OptionCheck(ProjectOptions options, int option) {
2493 BuildBitDepth value = *(BuildBitDepth*)((byte *)options + option);
2494 return value && value != all;
2496 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2497 BuildBitDepth value = options ? *(BuildBitDepth*)((byte *)options + option) : (BuildBitDepth)0;
2498 *(BuildBitDepth*)((byte *)output + option) = value;
2502 Map<int, GenericOptionTools> ot { };
2504 // The following are compiler options
2506 ot[OPTION(debug)] = utilSetBool;
2507 ot[OPTION(memoryGuard)] = utilSetBool;
2508 ot[OPTION(profile)] = utilSetBool;
2509 ot[OPTION(noLineNumbers)] = utilSetBool;
2510 ot[OPTION(strictNameSpaces)] = utilSetBool;
2511 ot[OPTION(fastMath)] = utilSetBool;
2513 ot[OPTION(defaultNameSpace)] = utilString;
2515 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2516 ot[OPTION(includeDirs)] = utilStringArrays;
2518 ot[OPTION(warnings)] = utilWarningsOption;
2520 ot[OPTION(optimization)] = utilOptimizationStrategy;
2522 ot[OPTION(buildBitDepth)] = utilBuildBitDepth;
2524 for(n = node; n; n = n.parent)
2526 ProjectConfig nodeConfig = null;
2528 priority = (priority / 10 + 1) * 10;
2531 if(projectConfig && n.configurations)
2533 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2535 if(platform && c.platforms)
2537 for(p : c.platforms; !strcmpi(p.name, platformName))
2541 GenericOptionTools u = uu;
2543 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2545 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2546 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2547 optionConfigXplatformSet[o] = true;
2559 GenericOptionTools u = uu;
2563 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2565 for(p : n.platforms; !strcmpi(p.name, platformName))
2567 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2569 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2570 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2575 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2576 ((u.mergeValues && !u.configReplaces) ?
2577 u.OptionCheck(nodeConfig.options, o) :
2578 u.OptionSet(nodeConfig.options, o)))
2580 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2581 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2585 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2587 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2588 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2592 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2593 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2601 GenericOptionTools u = uu;
2604 u.FinalizeLoading(o, optionTempStrings, output);
2607 delete optionConfigXplatformSet;
2609 delete optionTempStrings;
2613 delete utilStringArrays;
2614 delete utilWarningsOption;
2615 delete utilOptimizationStrategy;
2616 delete utilBuildBitDepth;
2623 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2627 ProjectOptions first;
2628 ProjectOptions commonOptions;
2630 Map<String, int> countIncludeDirs { };
2631 Map<String, int> countPreprocessorDefinitions { };
2632 Map<String, bool> commonIncludeDirs { };
2633 Map<String, bool> commonPreprocessorDefinitions { };
2635 for(options : byPlatformOptions) { first = options; break; }
2637 *platformsCommonOptions = commonOptions = first.Copy();
2639 if(commonOptions.includeDirs)
2640 commonOptions.includeDirs.Free();
2641 if(commonOptions.preprocessorDefinitions)
2642 commonOptions.preprocessorDefinitions.Free();
2644 for(options : byPlatformOptions)
2646 if(options != first)
2648 if(commonOptions.debug && options.debug != commonOptions.debug)
2649 commonOptions.debug = unset;
2650 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2651 commonOptions.memoryGuard = unset;
2652 if(commonOptions.profile && options.profile != commonOptions.profile)
2653 commonOptions.profile = unset;
2654 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2655 commonOptions.noLineNumbers = unset;
2656 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2657 commonOptions.strictNameSpaces = unset;
2658 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2659 commonOptions.fastMath = unset;
2661 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2662 commonOptions.warnings = unset;
2663 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2664 commonOptions.optimization = unset;
2665 if(commonOptions.buildBitDepth && options.buildBitDepth != commonOptions.buildBitDepth)
2666 commonOptions.buildBitDepth = all;
2668 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2669 delete commonOptions.defaultNameSpace;
2672 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2673 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2676 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2677 commonIncludeDirs, commonOptions.includeDirs);
2678 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2679 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2681 for(options : byPlatformOptions)
2683 if(options.debug && options.debug == commonOptions.debug)
2684 options.debug = unset;
2685 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2686 options.memoryGuard = unset;
2687 if(options.profile && options.profile == commonOptions.profile)
2688 options.profile = unset;
2689 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2690 options.noLineNumbers = unset;
2691 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2692 options.strictNameSpaces = unset;
2693 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2694 options.fastMath = unset;
2696 if(options.warnings && options.warnings == commonOptions.warnings)
2697 options.warnings = unset;
2698 if(options.optimization && options.optimization == commonOptions.optimization)
2699 options.optimization = unset;
2700 if(options.buildBitDepth && options.buildBitDepth == commonOptions.buildBitDepth)
2701 options.buildBitDepth = all;
2703 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2704 delete options.defaultNameSpace;
2706 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2707 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2710 delete countIncludeDirs;
2711 delete countPreprocessorDefinitions;
2712 delete commonIncludeDirs;
2713 delete commonPreprocessorDefinitions;
2716 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2717 Map<Platform, ProjectOptions> parentByPlatformOptions,
2718 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2720 ComplexComparison result = equal;
2721 ComplexComparison compare;
2723 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2725 ProjectOptions additionalOptions;
2726 additionsByPlatformOptions[platform] = { };
2727 additionalOptions = additionsByPlatformOptions[platform];
2728 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2729 if(compare == greater && result == equal)
2731 else if(compare == different)
2740 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2742 ComplexComparison result = equal;
2743 if(options.debug != parentOptions.debug ||
2744 options.memoryGuard != parentOptions.memoryGuard ||
2745 options.profile != parentOptions.profile ||
2746 options.noLineNumbers != parentOptions.noLineNumbers ||
2747 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2748 options.fastMath != parentOptions.fastMath ||
2749 options.warnings != parentOptions.warnings ||
2750 options.optimization != parentOptions.optimization ||
2751 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2752 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2756 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2757 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2759 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2760 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2766 enum ComplexComparison { different/*, smaller*/, equal, greater };
2768 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2771 if((!strings || !strings.count) && originals && originals.count)
2773 else if(strings && strings.count && (!originals || !originals.count))
2778 additions->Add(CopyString(s));
2780 else if(strings && strings.count && originals && originals.count)
2782 Map<String, String> map { };
2783 MapIterator<String, bool> mit { map = map };
2786 char * s = strstr(it, "\n");
2792 char * s = strstr(it, "\n");
2794 if(!mit.Index(s, false))
2809 additions->Add(CopyString(it));
2817 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2830 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
2838 strings.Add(CopyString(s));
2844 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
2848 Array<String> tmp { };
2849 MapIterator<String, bool> mit { map = common };
2853 if(!mit.Index(s, false))
2854 tmp.Add(CopyString(s));
2860 strings.Add(CopyString(s));
2867 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, File f)
2870 customFlags = nodeFlagsMapping[(intptr)node];
2872 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2874 f.Printf(" $(%s)", variableName);
2877 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, DynamicString s)
2880 customFlags = nodeFlagsMapping[(intptr)node];
2882 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
2884 s.concatf(" $(%s)", variableName);
2887 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
2893 if(options.optimization == speed || options.optimization == size ||
2894 options.fastMath == true || options.debug == true)
2896 if(options.debug != true)
2898 s.concat(" $(if $(DEBUG),");
2902 switch(options.optimization)
2904 case speed: s.concat(" -O2"); break;
2905 case size: s.concat(" -Os"); break;
2907 if(options.fastMath == true)
2908 s.concat(" -ffast-math");
2909 if(options.debug == true)
2911 if(options.debug != true)
2914 else if(commonOptions)
2915 s.concat(" $(if $(DEBUG),-g)");
2916 if(options.buildBitDepth || (commonOptions && prjWithEcFiles))
2917 s.concatf(" %s", (!options || !options.buildBitDepth || options.buildBitDepth == bits32) ? "$(FORCE_32_BIT)" : "$(FORCE_64_BIT)");
2919 s.concat(" $(FPIC)");
2921 switch(options.warnings)
2923 case all: s.concat(" -Wall"); break;
2924 case none: s.concat(" -w"); break;
2930 if(options && options.preprocessorDefinitions)
2931 ListOptionToDynamicString("D", options.preprocessorDefinitions, false, lineEach, "\t\t\t", false, s);
2932 if(options && options.includeDirs)
2933 ListOptionToDynamicString("I", options.includeDirs, true, lineEach, "\t\t\t", true, s);
2936 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
2938 if(options.memoryGuard == true)
2939 s.concat(" -memguard");
2940 if(options.noLineNumbers == true)
2941 s.concat(" -nolinenumbers");
2942 if(options.strictNameSpaces == true)
2943 s.concat(" -strictns");
2944 if(options.defaultNameSpace && options.defaultNameSpace[0])
2945 s.concatf(" -defaultns %s", options.defaultNameSpace);
2948 static void ListOptionToDynamicString(char * option, Array<String> list, bool prioritize,
2949 ListOutputMethod method, String newLineStart, bool noSpace, DynamicString s)
2953 if(method == newLine)
2956 s.concat(newLineStart);
2960 Map<String, int> sortedList { };
2961 MapNode<String, int> mn;
2963 sortedList[item] = 1;
2964 for(mn = sortedList.root.minimum; mn; mn = mn.next)
2966 char * start = strstr(mn.key, "\n");
2967 if(method == lineEach)
2970 s.concat(newLineStart);
2975 StringNoSpaceToDynamicString(s, start ? start+1 : mn.key);
2977 s.concat(start ? start+1 : mn.key);
2985 if(method == lineEach)
2988 s.concat(newLineStart);
2993 StringNoSpaceToDynamicString(s, item);
3001 class GenericOptionTools<class X>
3003 bool mergeValues, configReplaces;
3005 virtual bool OptionSet(ProjectOptions options, int option) {
3006 if(*(X*)((byte *)options + option))
3011 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3013 virtual bool OptionCheck(ProjectOptions options, int option) {
3014 return OptionSet(options, option);
3017 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3018 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3021 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3026 class NameCollisionInfo
3037 bool IsExtensionColliding(char * extension)
3041 ((!strcmpi(extension, "c") && ec) ||
3042 (!strcmpi(extension, "s") && (ec || c)) ||
3043 (!strcmpi(extension, "cpp") && (ec || c || s)) ||
3044 (!strcmpi(extension, "cc") && (ec || c || s || cpp)) ||
3045 (!strcmpi(extension, "cxx") && (ec || c || s || cpp || cc)) ||
3046 !strcmpi(extension, "m")))