1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(&((ProjectOptions)0).x))
17 static void OutputLog(const char * string)
19 #ifdef MAKEFILE_GENERATOR
22 ide.outputView.buildBox.Log(string);
26 bool eString_PathInsideOfMore(const char * path, const 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(const 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
182 //property char * { set { } }
183 DotMain ::FromFileName(const char * fileName)
185 DotMain dotMain = false;
186 if(fileName && fileName[0])
188 char ext[MAX_EXTENSION];
189 GetExtension(fileName, ext);
190 if(!strcmp(ext, "c") || !strcmp(ext, "ec"))
192 char stripExt[MAX_LOCATION];
193 strcpy(stripExt, fileName);
194 StripExtension(stripExt);
195 GetExtension(stripExt, ext);
196 if(!strcmp(ext, "main"))
204 enum IntermediateFileType
206 none, ec, c, sym, imp, bowl, o;
208 //property char * { set { } }
209 IntermediateFileType ::FromExtension(char * extension)
211 IntermediateFileType type = none;
212 if(extension && extension[0])
214 if(!fstrcmp(extension, "ec"))
216 else if(!fstrcmp(extension, "c"))
218 else if(!fstrcmp(extension, "sym"))
220 else if(!fstrcmp(extension, "imp"))
222 else if(!fstrcmp(extension, "bowl"))
224 else if(!fstrcmp(extension, "o"))
231 class ProjectNode : ListItem
236 set { return { fileName = value }; }
237 // TOCHECK: Is this isset necessary at all?
238 isset { return nodeType == file && !options && !configurations && !platforms && !files; }
240 property String folder
245 if(strchr(value, '/'))
247 char p[MAX_LOCATION];
248 char n[MAX_FILENAME];
249 GetLastDirectory(value, n);
250 StripLastDirectory(value, p);
251 name = CopyString(n);
252 path = CopyString(p);
255 name = CopyString(value);
259 // TOCHECK: Non Reentrant
260 static char insidePath[MAX_LOCATION];
262 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
263 PathCatSlash(insidePath, name);
265 if(!fstrcmp(path, insidePath))
269 strcpy(insidePath, path);
270 if(!insidePath[0]) strcpy(insidePath, ".");
271 PathCatSlash(insidePath, name);
275 isset { return nodeType == folder; }
277 property const String fileName
282 if(strchr(value, '/'))
284 char p[MAX_LOCATION];
285 char n[MAX_FILENAME];
286 GetLastDirectory(value, n);
287 StripLastDirectory(value, p);
288 name = CopyValidateMakefilePath(n);
289 path = CopyValidateMakefilePath(p);
292 name = CopyValidateMakefilePath(value);
296 // TOCHECK: Non Reentrant
297 static char insidePath[MAX_LOCATION];
299 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
300 if(!fstrcmp(path, insidePath))
304 strcpy(insidePath, path);
305 if(!insidePath[0]) strcpy(insidePath, ".");
306 PathCatSlash(insidePath, name);
310 isset { return nodeType == file && (options || configurations || platforms); }
313 LinkList<ProjectNode> files;
314 property ProjectOptions options
316 get { return project ? project.options : options; }
317 set { if(project) { delete project.options; project.options = value; } else { delete options; options = value; } }
318 isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
320 property Array<PlatformOptions> platforms
322 get { return project ? project.platforms : platforms; }
325 if(project) { project.platforms = value; }
328 if(platforms) { platforms.Free(); delete platforms; }
331 List<PlatformOptions> empty { };
332 Iterator<PlatformOptions> it { value };
334 for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
335 for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
342 Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
347 if(p.options && !p.options.isEmpty)
354 property List<ProjectConfig> configurations
356 get { return project ? project.configurations : configurations; }
361 if(project.configurations)
363 project.configurations.Free();
364 delete project.configurations;
366 project.configurations = value;
370 if(configurations) { configurations.Free(); delete configurations; }
373 List<ProjectConfig> empty { };
374 Iterator<ProjectConfig> it { value };
375 configurations = value;
376 for(c : configurations)
378 bool somethingSet = c.options && !c.options.isEmpty;
379 // TODO: Implement isset keyword
380 if(!somethingSet && c.platforms && c.platforms.count)
384 if(p.options && !p.options.isEmpty)
394 for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
401 if(!parent) return true;
404 for(c : configurations)
406 bool somethingSet = c.options && !c.options.isEmpty;
407 if(!somethingSet && c.platforms && c.platforms.count)
411 if(p.options && !p.options.isEmpty)
426 ProjectOptions options;
427 Array<PlatformOptions> platforms;
428 List<ProjectConfig> configurations;
429 ProjectNodeType nodeType;
434 // This holds the absolute path of the .epj for the project topnode (without the filename)
435 // It holds a relative path to the topNode (project) for other nodes (folders and files)
436 // For folders, it includes the folder it refers to. If there is a name difference between the
437 // file system folder and the grouping folder of the project view, it maps to that folder.
447 // This is only set for Top Nodes
450 void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Array<Platform> platforms)
452 if(!platforms.Find(unknown)) // unknown is "Common"
454 // e.g. ifneq "$(or $(or $(OSX_TARGET),$(LINUX_TARGET)),$(WINDOWS_TARGET))"
457 for(i = 0; platforms.count && i < platforms.count - 1; i++)
465 f.Puts(PlatformToMakefileTargetVariable(p));
478 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
480 ProjectConfig nodeConfig = null;
481 if(property::configurations && prjConfig)
483 const char * configName = prjConfig.name;
484 for(cfg : property::configurations)
486 if(!strcmpi(cfg.name, configName))
496 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
498 property bool containsFile
507 if(child.type == file ||
508 ((child.type == folder || child.type == folderOpen) && child.containsFile))
521 char * GetFullFilePath(char * buffer)
525 strcpy(buffer, root.path);
526 PathCatSlash(buffer, path);
527 PathCatSlash(buffer, name);
532 char * GetObjectFileName(char * buffer, Map<String, NameCollisionInfo> namesInfo, IntermediateFileType type, bool dotMain)
534 if(buffer && (this.type == file || (this.type == project && dotMain == true)))
537 char extension[MAX_EXTENSION];
538 char moduleName[MAX_FILENAME];
539 NameCollisionInfo info;
541 GetExtension(name, extension);
542 ReplaceSpaces(moduleName, name);
543 StripExtension(moduleName);
544 info = namesInfo[moduleName];
545 collision = info ? info.IsExtensionColliding(extension) : false;
549 Project prj = property::project;
550 ReplaceSpaces(buffer, prj.moduleName);
551 StripExtension(buffer);
552 strcat(buffer, ".main.ec");
555 strcpy(buffer, name);
556 if(!strcmp(extension, "ec") || dotMain)
559 ChangeExtension(buffer, "c", buffer);
561 ChangeExtension(buffer, "sym", buffer);
563 ChangeExtension(buffer, "imp", buffer);
564 else if(type == bowl)
565 ChangeExtension(buffer, "bowl", buffer);
570 strcat(buffer, ".o");
572 ChangeExtension(buffer, "o", buffer);
578 char * GetFileSysMatchingPath(char * buffer)
582 ProjectNode n, root = this.root;
583 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
585 strcpy(buffer, root.path);
587 PathCatSlash(buffer, n.path);
588 if(FileExists(buffer).isDirectory)
591 if(!(n && (n.type == folder || n.type == project)))
597 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
599 ProjectNode node = null;
600 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
601 List<ProjectNode> nodeStack { };
603 for(node = this; node && node.parent; node = node.parent)
606 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
608 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
609 while((node = nodeStack.lastIterator.data))
611 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
612 ProjectOptions nodeOptions = node.property::options;
613 if(nodeOptions && nodeOptions.preprocessorDefinitions)
615 for(def : nodeOptions.preprocessorDefinitions)
616 perFilePreprocessorDefs.Add(CopyString(def));
618 if(config && config.options && config.options.preprocessorDefinitions)
620 for(def : config.options.preprocessorDefinitions)
621 perFilePreprocessorDefs.Add(CopyString(def));
623 if(nodeOptions && nodeOptions.includeDirs)
625 for(dir : nodeOptions.includeDirs)
626 perFileIncludeDirs.Add(CopySystemPath(dir));
628 if(config && config.options && config.options.includeDirs)
630 for(dir : config.options.includeDirs)
631 perFileIncludeDirs.Add(CopySystemPath(dir));
633 nodeStack.lastIterator.Remove();
639 property Project project
643 ProjectNode n = this;
644 while(n && n.type != project) n = n.parent;
645 return n ? (*&n.project) : null;
649 void RenameConfig(const char * oldName, const char * newName)
653 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
655 if(property::configurations)
657 for(c : property::configurations; !strcmp(c.name, oldName))
660 c.name = CopyString(newName);
665 void DeleteConfig(ProjectConfig configToDelete)
669 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
671 if(property::configurations)
673 Iterator<ProjectConfig> c { property::configurations };
676 ProjectConfig config = c.data;
677 if(!strcmp(configToDelete.name, config.name))
684 if(!property::configurations.count)
685 property::configurations = null;
691 ProjectNode backupNode { };
695 backupNode.files = { };
696 for(f : files) backupNode.files.Add(f.Backup());
698 if(property::options)
699 backupNode.options = property::options.Copy();
701 if(property::platforms)
703 backupNode.platforms = { };
704 for(p : property::platforms)
705 backupNode.platforms.Add(p.Copy());
708 if(property::configurations)
710 backupNode.configurations = { };
711 for(c : property::configurations)
712 backupNode.configurations.Add(c.Copy());
717 void Revert(ProjectNode backupNode)
721 Iterator<ProjectNode> it { backupNode.files };
729 property::options = backupNode.options ? backupNode.options.Copy() : null;
730 if(backupNode.platforms)
732 Array<PlatformOptions> platforms { };
733 property::platforms = platforms;
735 for(p : backupNode.platforms)
736 platforms.Add(p.Copy());
738 if(backupNode.configurations)
740 List<ProjectConfig> configurations { };
741 property::configurations = configurations;
742 for(c : backupNode.configurations)
743 configurations.Add(c.Copy());
747 void FixupNode(char * parentPath)
753 else if(nodeType == file)
758 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
761 else if(nodeType == folder)
767 char temp[MAX_LOCATION];
768 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
769 PathCatSlash(temp, name);
770 path = CopyString(temp);
774 indent = parent ? parent.indent + 1 : 0;
777 icon = NodeIcons::SelectFileIcon(name);
779 icon = NodeIcons::SelectNodeIcon(type);
788 parentPath[0] = '\0';
789 else if(type == resources || type == folder)
790 strcpy(parentPath, path);
792 f.FixupNode(parentPath);
797 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
801 // TOCHECK: Called from JSON writer
802 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
804 strcpy(tempString, "\"");
805 strcat(tempString, property::fileName);
806 strcat(tempString, "\"");
813 // TOCHECK: Called from ProjectView rendering
814 return name ? name : "";
827 if(!project && platforms)
832 if(!project && configurations)
834 configurations.Free();
835 delete configurations;
838 /////////////////////////////
844 property bool isInResources
849 for(node = this; node; node = node.parent)
851 if(node.type == resources)
858 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
860 TwoStrings result { a = CopyString(""), b = CopyString("") };
861 // note: unknown platform is for common
862 Map<Platform, SetBool> exclusionInfo { };
863 MapNode<Platform, SetBool> mn;
869 CollectExclusionInfo(exclusionInfo, prjConfig);
870 common = exclusionInfo[unknown];
872 Map<Platform, SetBool> cleaned { };
873 SetBool opposite = common == true ? false : true;
874 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
876 if(mn.key == unknown || mn.value == opposite)
877 cleaned[mn.key] = mn.value;
879 delete exclusionInfo;
880 exclusionInfo = cleaned;
883 if(exclusionInfo.count > 1)
885 if(exclusionInfo.count > 2)
888 len = strlen(exp) + strlen("$(if $(or ");
889 exp = renew exp char[len+1];
890 strcat(exp, "$(if $(or ");
893 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
895 if(mn.key != unknown)
897 const char * comma = mn.next ? "," : "";
899 var = PlatformToMakefileTargetVariable(mn.key);
902 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
903 exp = renew exp char[len+1];
913 len = strlen(exp) + strlen("),");
914 exp = renew exp char[len+1];
918 if(exclusionInfo.root.minimum.key != unknown)
919 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
921 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
924 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
925 exp = renew exp char[len+1];
926 strcat(exp, "$(if $(");
933 exp = common == true ? result.b : result.a;
934 len = strlen(exp) + strlen(",");
935 exp = renew exp char[len+1];
937 if(common == true) result.b = exp; else result.a = exp;
940 len = strlen(exp) + strlen(")");
941 exp = renew exp char[len+1];
945 delete exclusionInfo;
950 bool GetIsExcluded(ProjectConfig prjConfig)
953 // note: unknown platform is for common
954 Map<Platform, SetBool> exclusionInfo { };
955 CollectExclusionInfo(exclusionInfo, prjConfig);
956 if(exclusionInfo.count == 0)
958 else if(exclusionInfo.count == 1)
959 result = exclusionInfo.root.minimum.value == true;
962 SetBool check = exclusionInfo.root.minimum.value;
963 MapNode<Platform, SetBool> mn;
964 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
966 if(check != mn.value)
969 if(!mn) // all are same
970 result = check == true;
974 delete exclusionInfo;
978 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
980 // note: unknown platform is for common
982 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
983 ProjectOptions options = property::options;
984 Array<PlatformOptions> platforms = property::platforms;
985 List<ProjectConfig> configurations = property::configurations;
988 parent.CollectExclusionInfo(output, prjConfig);
990 output[unknown] = unset;
992 if(options && options.excludeFromBuild)
993 output[unknown] = options.excludeFromBuild;
995 if(config && config.options && config.options.excludeFromBuild)
996 output[unknown] = config.options.excludeFromBuild;
1002 if(p.options.excludeFromBuild && (platform = p.name))
1003 output[platform] = p.options.excludeFromBuild;
1006 if(config && config.platforms)
1008 for(p : config.platforms)
1010 if(p.options.excludeFromBuild && (platform = p.name))
1011 output[platform] = p.options.excludeFromBuild;
1016 void EnsureVisible()
1019 parent.EnsureVisible();
1020 row.collapsed = false;
1026 parent.files.Delete(this);
1029 ProjectNode Find(const char * name, bool includeResources)
1031 ProjectNode result = null;
1036 if(includeResources || child.type != resources)
1038 if(child.type != folder && child.name && !strcmpi(child.name, name))
1043 result = child.Find(name, includeResources);
1052 ProjectNode FindWithPath(const char * name, bool includeResources)
1054 ProjectNode result = null;
1059 if(includeResources || child.type != resources)
1061 char path[MAX_LOCATION];
1062 strcpy(path, child.path);
1063 if(child.type != folder && child.name)
1065 PathCatSlash(path, child.name);
1066 if(!strcmpi(path, name))
1072 result = child.FindWithPath(name, includeResources);
1081 ProjectNode FindByFullPath(const char * path, bool includeResources)
1085 char name[MAX_FILENAME];
1086 GetLastDirectory(path, name);
1087 return InternalFindByFullPath(path, includeResources, name);
1092 ProjectNode InternalFindByFullPath(const char * path, bool includeResources, const char * lastDirName)
1094 ProjectNode result = null;
1099 if(includeResources || child.type != resources)
1101 if(child.type != file)
1102 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1103 else if(child.name && !fstrcmp(lastDirName, child.name))
1105 char p[MAX_LOCATION];
1106 child.GetFullFilePath(p);
1107 if(!fstrcmp(p, path))
1121 ProjectNode FindByObjectFileName(const char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo)
1123 char p[MAX_LOCATION];
1124 ProjectNode result = null;
1125 if(dotMain == true && this.type == project)
1127 GetObjectFileName(p, namesInfo, type, dotMain);
1128 if(!fstrcmp(p, fileName))
1133 for(child : files; child.type != resources)
1135 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo)))
1137 else if(child.type == file && child.name)
1139 child.GetObjectFileName(p, namesInfo, type, dotMain);
1140 if(!fstrcmp(p, fileName))
1151 ProjectNode FindSpecial(const char * name, bool recursive, bool includeResources, bool includeFolders)
1153 ProjectNode result = null;
1158 if(includeResources || child.type != resources)
1160 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1166 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1175 ProjectNode FindSameNameConflict(const char * name, bool includeResources,
1176 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1178 ProjectNode result = null;
1179 Map<Platform, SetBool> compareExclusion { };
1180 SetBool common, commonComp;
1181 SetBool actual, actualComp;
1186 if(includeResources || child.type != resources)
1188 if(child.type != folder && child.name && !strcmpi(child.name, name))
1190 child.CollectExclusionInfo(compareExclusion, prjConfig);
1191 common = exclusionInfo[unknown];
1192 commonComp = compareExclusion[unknown];
1193 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1195 if(!(common == true || commonComp == true))
1204 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1207 actualComp = commonComp;
1208 if(exclusionInfo[platform] != unset)
1209 actual = exclusionInfo[platform];
1210 if(compareExclusion[platform] != unset)
1211 actualComp = compareExclusion[platform];
1212 if(!(actual == true || actualComp == true))
1220 compareExclusion.Free();
1223 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1227 compareExclusion.Free();
1229 delete compareExclusion;
1233 ProjectNode Add(Project project, const char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1235 ProjectNode node = null;
1236 if(!project.topNode.FindByFullPath(filePath, true))
1238 char temp[MAX_LOCATION];
1239 Map<Platform, SetBool> exclusionInfo { };
1241 GetLastDirectory(filePath, temp);
1242 //if(!checkIfExists || !project.topNode.Find(temp, false))
1244 // TOCHECK: Shouldn't this apply either for all configs or none?
1245 CollectExclusionInfo(exclusionInfo, project.config);
1246 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1248 // Do the check for folder in the same parent or resource files only here
1249 if(type == folder || !checkIfExists)
1253 if(node.name && !strcmpi(node.name, temp))
1258 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1262 node.nodeType = folder;
1268 StripLastDirectory(filePath, temp);
1269 MakePathRelative(temp, project.topNode.path, temp);
1270 node.path = CopyUnixPath(temp);
1272 node.nodeType = file;
1276 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1277 PathCatSlash(temp, node.name);
1278 node.path = CopyString(temp);
1280 files.Insert(after, node);
1282 delete exclusionInfo;
1287 #ifndef MAKEFILE_GENERATOR
1288 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1290 char label[MAX_FILENAME];
1296 bool showConfig = true;
1301 projectView = ide.projectView;
1304 bmp = projectView.icons[icon].bitmap;
1305 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1307 GetLastDirectory(name, label);
1308 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1310 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1312 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1314 const char * addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1315 if(strlen(addendum))
1317 strcat(label, " (");
1318 strcat(label, addendum);
1321 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1322 if(strlen(addendum))
1324 strcat(label, " (");
1325 strcat(label, addendum);
1331 else if(!projectView.drawingInProjectSettingsDialog)
1334 strcat(label, " *");
1335 if(type == project && info)
1337 int len = strlen(info) + 4;
1338 char * more = new char[len];
1339 sprintf(more, " (%s)", info);
1340 strcat(label, more);
1344 len = strlen(label);
1348 if(type == folder || type == folderOpen)
1349 surface.SetForeground(yellow);
1353 surface.TextOpacity(false);
1354 surface.TextExtent(label, len, &w, &h);
1357 // Draw the current row stipple
1358 if(displayFlags.selected)
1359 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1360 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1361 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1363 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1367 if(displayFlags.current)
1369 if(displayFlags.active)
1371 surface.LineStipple(0x5555);
1372 if(displayFlags.selected)
1373 surface.SetForeground(projectView.fileList.stippleColor);
1375 surface.SetForeground(projectView.fileList.foreground);
1379 surface.SetForeground(SELECTION_COLOR);
1381 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1382 surface.LineStipple(0);
1387 surface.SetForeground(white);
1388 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1394 int OnCompare(ProjectNode b)
1397 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1398 result = strcmpi(name, b.name);
1401 if(type == folder && b.type == file) result = -1;
1402 else if(type == file && b.type == folder) result = 1;
1407 bool ContainsFilesWithExtension(const char * extension, ProjectConfig prjConfig)
1411 char ext[MAX_EXTENSION];
1412 GetExtension(name, ext);
1413 if(!fstrcmp(ext, extension))
1420 if(child.type != resources && (child.type == folder || !prjConfig || !child.GetIsExcluded(prjConfig)))
1422 if(child.ContainsFilesWithExtension(extension, prjConfig))
1430 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1434 char extension[MAX_EXTENSION];
1435 GetExtension(name, extension);
1436 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1437 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1438 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1440 char moduleName[MAX_FILENAME];
1441 NameCollisionInfo info;
1442 ReplaceSpaces(moduleName, name);
1443 StripExtension(moduleName);
1444 info = namesInfo[moduleName];
1446 info = NameCollisionInfo { };
1447 info.count++; // += 1; unless this is for a bug?
1448 if(!strcmpi(extension, "ec"))
1450 else if(!strcmpi(extension, "s"))
1452 else if(!strcmpi(extension, "c"))
1454 else if(!strcmpi(extension, "rc"))
1456 else if(!strcmpi(extension, "cpp"))
1458 else if(!strcmpi(extension, "cc"))
1460 else if(!strcmpi(extension, "cxx"))
1462 else if(!strcmpi(extension, "m"))
1464 else if(!strcmpi(extension, "mm"))
1466 namesInfo[moduleName] = info;
1473 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1474 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1479 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1480 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1481 ProjectConfig prjConfig, bool * containsCXX)
1487 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1488 char moduleName[MAX_FILENAME];
1489 char extension[MAX_EXTENSION];
1490 GetExtension(name, extension);
1491 if(printType == resources)
1494 char tempPath[MAX_LOCATION];
1495 char modulePath[MAX_LOCATION];
1498 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1501 PathCatSlash(tempPath, name);
1506 strcpy(tempPath, path);
1507 PathCatSlash(tempPath, name);
1509 EscapeForMake(modulePath, tempPath, false, true, false);
1510 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1511 items.Add(CopyString(s));
1513 else if(printType == sources)
1515 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1516 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1517 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1519 char modulePath[MAX_LOCATION];
1520 EscapeForMake(modulePath, path, false, true, false);
1521 EscapeForMake(moduleName, name, false, true, false);
1522 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1523 items.Add(CopyString(s));
1526 else if(printType == eCsources)
1528 if(!strcmpi(extension, "ec"))
1530 char modulePath[MAX_LOCATION];
1531 EscapeForMake(modulePath, path, true, true, false);
1532 EscapeForMake(moduleName, name, true, true, false);
1533 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1534 items.Add(CopyString(s));
1538 else if(printType == rcSources)
1540 if(!strcmpi(extension, "rc"))
1542 char modulePath[MAX_LOCATION];
1543 EscapeForMake(modulePath, path, false, true, false);
1544 EscapeForMake(moduleName, name, false, true, false);
1545 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1546 items.Add(CopyString(s));
1550 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1551 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1552 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1554 if(printType == objects)
1557 NameCollisionInfo info;
1559 EscapeForMake(moduleName, name, false, true, false);
1560 StripExtension(moduleName);
1561 info = namesInfo[moduleName];
1562 collision = info ? info.IsExtensionColliding(extension) : false;
1563 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1564 items.Add(CopyString(s));
1565 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1566 *containsCXX = true;
1575 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1576 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1582 void GenMakefilePrintSymbolRules(File f, Project project,
1583 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1584 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1587 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1588 //ProjectNode child;
1589 //char objDir[MAX_LOCATION];
1590 //ReplaceSpaces(objDir, config.objDir.dir);
1592 //eSystem_Log("Printing Symbol Rules\n");
1595 char extension[MAX_EXTENSION];
1596 char modulePath[MAX_LOCATION];
1597 char moduleName[MAX_FILENAME];
1599 GetExtension(name, extension);
1600 if(!strcmpi(extension, "ec"))
1605 ReplaceSpaces(moduleName, name);
1606 StripExtension(moduleName);
1608 ReplaceSpaces(modulePath, path);
1609 if(modulePath[0]) strcat(modulePath, SEPS);
1611 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1613 // *** Dependency command ***
1614 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1615 modulePath, moduleName, extension);
1617 // System Includes (from global settings)
1618 for(item : compiler.dirs[Includes])
1620 strcat(command, " -isystem ");
1621 if(strchr(item, ' '))
1623 strcat(command, "\"");
1624 strcat(command, item);
1625 strcat(command, "\"");
1628 strcat(command, item);
1631 for(item : project.includeDirs)
1633 strcat(command, " -I");
1634 if(strchr(item, ' '))
1636 strcat(command, "\"");
1637 strcat(command, item);
1638 strcat(command, "\"");
1641 strcat(command, item);
1643 for(item : project.preprocessorDefs)
1645 strcat(command, " -D");
1646 strcat(command, item);
1650 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1653 bool firstLine = true;
1656 // To do some time: auto save external dependencies?
1659 if(dep.GetLine(line, sizeof(line)-1))
1663 char * colon = strstr(line, ":");
1664 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1678 // If we failed to generate dependencies...
1682 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1683 moduleName, modulePath, moduleName, extension);
1687 f.Puts(" $(CFLAGS)");
1688 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1690 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1691 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1693 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1694 modulePath, moduleName, extension);
1695 if(ifCount) f.Puts("endif\n");
1705 if(ContainsFilesWithExtension("ec", prjConfig))
1709 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1710 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1711 nodeCFlagsMapping, nodeECFlagsMapping);
1718 void GenMakefilePrintPrepecsRules(File f, Project project,
1719 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1720 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1723 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1724 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1725 //ProjectNode child;
1726 //char objDir[MAX_LOCATION];
1727 //ReplaceSpaces(objDir, config.objDir.dir);
1729 //eSystem_Log("Printing Symbol Rules\n");
1732 char extension[MAX_EXTENSION];
1733 char modulePath[MAX_LOCATION];
1734 char moduleName[MAX_FILENAME];
1736 GetExtension(name, extension);
1737 if(!strcmpi(extension, "ec"))
1742 ReplaceSpaces(moduleName, name);
1743 StripExtension(moduleName);
1745 ReplaceSpaces(modulePath, path);
1746 if(modulePath[0]) strcat(modulePath, SEPS);
1748 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1749 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1750 moduleName, modulePath, moduleName, extension);
1751 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1752 modulePath, moduleName, extension, moduleName);*/
1756 f.Puts(" $(CFLAGS)");
1757 //f.Puts(" $(CECFLAGS)");
1758 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1759 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1761 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1762 modulePath, moduleName, extension, moduleName);
1763 if(ifCount) f.Puts("endif\n");
1769 if(ContainsFilesWithExtension("ec", prjConfig))
1773 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1774 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1775 nodeCFlagsMapping, nodeECFlagsMapping);
1782 void GenMakefilePrintCObjectRules(File f, Project project,
1783 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1784 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1787 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1788 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1789 //ProjectNode child;
1790 //char objDir[MAX_LOCATION];
1791 //ReplaceSpaces(objDir, config.objDir.dir);
1792 //eSystem_Log("Printing C Object Rules\n");
1795 char extension[MAX_EXTENSION];
1796 char modulePath[MAX_LOCATION];
1797 char moduleName[MAX_FILENAME];
1799 GetExtension(name, extension);
1800 if(!strcmpi(extension, "ec"))
1805 ReplaceSpaces(moduleName, name);
1806 StripExtension(moduleName);
1808 ReplaceSpaces(modulePath, path);
1809 if(modulePath[0]) strcat(modulePath, SEPS);
1811 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1813 // *** Dependency command ***
1814 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1815 moduleName, modulePath, moduleName, extension);
1817 // System Includes (from global settings)
1818 for(item : compiler.dirs[Includes])
1820 strcat(command, " -isystem ");
1821 if(strchr(item, ' '))
1823 strcat(command, "\"");
1824 strcat(command, item);
1825 strcat(command, "\"");
1828 strcat(command, item);
1831 for(item : config.includeDirs)
1833 strcat(command, " -I");
1834 if(strchr(item, ' '))
1836 strcat(command, "\"");
1837 strcat(command, item);
1838 strcat(command, "\"");
1841 strcat(command, item);
1843 for(item : config.preprocessorDefs)
1845 strcat(command, " -D");
1846 strcat(command, item);
1850 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1854 bool firstLine = true;
1856 // To do some time: auto save external dependencies?
1859 if(dep.GetLine(line, sizeof(line)-1))
1863 char * colon = strstr(line, ":");
1864 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1878 // If we failed to generate dependencies...
1881 /* COMMENTED OUT FOR NOW
1882 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1883 moduleName, modulePath, moduleName, extension);
1886 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1887 moduleName, modulePath, moduleName, extension, moduleName);
1893 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1894 modulePath, moduleName, extension, moduleName);
1899 f.Puts(" $(CFLAGS)");
1900 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1901 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1902 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1903 f.Puts(" $(FVISIBILITY)");
1905 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1906 modulePath, moduleName, extension);
1907 if(ifCount) f.Puts("endif\n");
1913 if(ContainsFilesWithExtension("ec", prjConfig))
1917 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1918 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1919 nodeCFlagsMapping, nodeECFlagsMapping);
1926 void GenMakefilePrintObjectRules(File f, Project project,
1927 Map<String, NameCollisionInfo> namesInfo,
1928 ProjectConfig prjConfig,
1929 //Map<Platform, bool> parentExcludedPlatforms,
1930 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1933 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1934 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1935 //ProjectNode child;
1936 //char objDir[MAX_LOCATION];
1937 //ReplaceSpaces(objDir, config.objDir.dir);
1938 //eSystem_Log("Printing Object Rules\n");
1942 char extension[MAX_EXTENSION];
1943 char modulePath[MAX_LOCATION];
1944 char moduleName[MAX_FILENAME];
1946 GetExtension(name, extension);
1947 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1948 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1949 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1953 NameCollisionInfo info;
1955 ReplaceSpaces(moduleName, name);
1956 StripExtension(moduleName);
1958 info = namesInfo[moduleName];
1959 collision = info ? info.IsExtensionColliding(extension) : false;
1961 ReplaceSpaces(modulePath, path);
1962 if(modulePath[0]) strcat(modulePath, SEPS);
1966 // *** Dependency command ***
1967 if(!strcmpi(extension, "ec"))
1968 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1970 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1971 moduleName, modulePath, moduleName, extension);
1973 if(!strcmpi(extension, "ec"))
1975 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1979 // System Includes (from global settings)
1980 for(item : compiler.dirs[includes])
1982 strcat(command, " -isystem ");
1983 if(strchr(item, ' '))
1985 strcat(command, "\"");
1986 strcat(command, item);
1987 strcat(command, "\"");
1990 strcat(command, item);
1993 for(item : config.includeDirs)
1995 strcat(command, " -I");
1996 if(strchr(item, ' '))
1998 strcat(command, "\"");
1999 strcat(command, item);
2000 strcat(command, "\"");
2003 strcat(command, item);
2005 for(item : config.preprocessorDefs)
2007 strcat(command, " -D");
2008 strcat(command, item);
2012 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2015 bool firstLine = true;
2018 // To do some time: auto save external dependencies?
2022 if(dep.GetLine(line, sizeof(line)-1))
2026 char * colon = strstr(line, ":");
2027 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2041 // If we failed to generate dependencies...
2050 if(!strcmpi(extension, "rc"))
2053 f.Puts("ifdef WINDOWS_TARGET\n\n");
2056 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2058 if(!strcmpi(extension, "ec"))
2059 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2061 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
2062 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
2063 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2064 f.Printf("\t$(CXX)");
2065 else if(!strcmpi(extension, "rc"))
2066 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2068 f.Printf("\t$(CC)");
2070 if(strcmpi(extension, "rc") != 0)
2072 f.Puts(" $(CFLAGS)");
2073 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2075 if(!strcmpi(extension, "ec"))
2076 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n", moduleName);
2078 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2079 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2081 if(ifCount) f.Puts("endif\n");
2087 bool needed = false;
2090 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2100 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2101 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2102 nodeCFlagsMapping, nodeECFlagsMapping);
2109 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2116 //Iterator<ProjectNode> i { files };
2117 //Iterator<ProjectNode> prev { files };
2118 //for(child : files)
2120 for(c = 0; c < files.count; c++)
2122 ProjectNode child = files[c];
2123 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2126 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2129 char tempPath[MAX_LOCATION];
2130 char resPath[MAX_LOCATION];
2132 // $(EAR) aw%s --- /*quiet ? "q" : */""
2134 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2137 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2140 PathCatSlash(tempPath, child.name);
2145 strcpy(tempPath, child.path);
2146 PathCatSlash(tempPath, child.name);
2148 EscapeForMake(resPath, tempPath, false, true, false);
2149 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2152 if(count == 10 || (count > 0 && (ts || !child.next)))
2154 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2157 for(parent = this; parent.type == folder; parent = parent.parent)
2160 strcpy(path, parent.name);
2167 f.Printf(" \"%s\"%s\n", path, ts.b);
2179 if(child.type == folder)
2180 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2185 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2186 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2187 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2188 Map<Platform, ProjectOptions> parentByPlatformOptions)
2190 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2191 if(type == file || type == folder || type == project)
2193 bool hasPerNodeOptions = type == project;
2194 if(!hasPerNodeOptions)
2196 if(options && !options.isEmpty)
2197 hasPerNodeOptions = true;
2198 else if(configurations)
2200 for(c : configurations)
2202 if(c.options && !c.options.isEmpty)
2204 hasPerNodeOptions = true;
2209 for(p : c.platforms)
2211 if(p.options && !p.options.isEmpty)
2213 hasPerNodeOptions = true;
2217 if(hasPerNodeOptions)
2222 if(!hasPerNodeOptions && platforms)
2226 if(p.options && !p.options.isEmpty)
2228 hasPerNodeOptions = true;
2235 if(hasPerNodeOptions)
2237 bool isEqual = false, isGreater = false;
2238 ComplexComparison complexCmp;
2240 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2241 ProjectOptions platformsCommonOptions;
2242 ProjectOptions byFileConfigPlatformProjectOptions;
2244 DynamicString cflags { };
2245 DynamicString ecflags { };
2249 byPlatformOptions = { };
2251 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2253 byFileConfigPlatformProjectOptions =
2254 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2255 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2258 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2260 byPlatformOptions[unknown] = platformsCommonOptions;
2262 if(parentByPlatformOptions)
2264 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2265 parentByPlatformOptions, additionsByPlatformOptions);
2266 isGreater = complexCmp == greater;
2267 isEqual = complexCmp == equal;
2272 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2274 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2276 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2278 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2281 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2283 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2287 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2289 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2292 if(!isGreater) cflags.concat(" \\\n\t");
2297 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2300 ecflags.concat(" \\\n\t");
2307 cflags.concat(" \\\n\t");
2308 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2312 additionsByPlatformOptions.Free();
2313 delete additionsByPlatformOptions;
2319 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2320 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2328 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2329 cflagsVariations[s] = variationNum = cflagsVariations.count;
2330 nodeCFlagsMapping[(intptr)this] = variationNum;
2333 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2334 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2335 nodeECFlagsMapping[(intptr)this] = variationNum;
2346 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2347 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2356 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2357 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2358 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2363 if(byPlatformOptions != parentByPlatformOptions)
2365 byPlatformOptions.Free();
2366 delete byPlatformOptions;
2370 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2372 Array<Platform> platforms { };
2373 Map<Platform, SetBool> exclusionInfo { };
2374 CollectExclusionInfo(exclusionInfo, prjConfig);
2376 if(exclusionInfo[unknown] == true)
2378 if(exclusionInfo.count > 1)
2379 for(p : exclusionInfo; p == false)
2384 bool onlyOnknown = true;
2385 for(p : exclusionInfo)
2386 if(&p != unknown && p == true)
2388 onlyOnknown = false;
2392 platforms.Add(unknown);
2396 for(p = unknown + 1; p < Platform::enumSize; p++)
2397 if(exclusionInfo[p] != true)
2401 delete exclusionInfo;
2405 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2407 char moduleName[MAX_FILENAME];
2410 bool headerAltFailed = false;
2412 char extension[MAX_EXTENSION];
2413 NameCollisionInfo info;
2414 Project prj = property::project;
2415 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2417 GetExtension(name, extension);
2418 strcpy(moduleName, name);
2419 StripExtension(moduleName);
2420 info = namesInfo[moduleName];
2421 collision = info ? info.IsExtensionColliding(extension) : false;
2423 for(h2s : headerToSource)
2425 if(!strcmpi(extension, &h2s))
2427 char filePath[MAX_LOCATION];
2428 GetFullFilePath(filePath);
2429 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2430 ChangeExtension(moduleName, h2s, moduleName);
2431 if(prj.topNode.Find(moduleName, false))
2433 strcpy(extension, h2s);
2434 collision = info ? info.IsExtensionColliding(extension) : false;
2435 ChangeExtension(filePath, h2s, filePath);
2436 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2437 StripExtension(moduleName);
2441 headerAltFailed = true;
2442 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2443 StripExtension(moduleName);
2449 if(!headerAltFailed)
2451 output.concat(" \"");
2452 output.concat(objDir); //.concat(" $(OBJ)");
2457 strcat(moduleName, ".");
2458 strcat(moduleName, extension);
2460 strcat(moduleName, ".o");
2461 output.concat(moduleName);
2462 output.concat("\"");
2465 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2467 Project prj = property::project;
2469 ReplaceSpaces(moduleName, prj.moduleName);
2470 strcat(moduleName, ".main.ec");
2471 output.concat(" \"");
2472 output.concat(objDir);
2474 output.concat(moduleName);
2475 output.concat("\"");
2477 ChangeExtension(moduleName, "c", moduleName);
2478 output.concat(" \"");
2479 output.concat(objDir);
2481 output.concat(moduleName);
2482 output.concat("\"");
2484 ChangeExtension(moduleName, "o", moduleName);
2485 output.concat(" \"");
2486 output.concat(objDir);
2488 output.concat(moduleName);
2489 output.concat("\"");
2495 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2496 child.GetTargets(prjConfig, namesInfo, objDir, output);
2501 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2506 char extension[MAX_EXTENSION];
2507 char fileName[MAX_FILENAME];
2508 char moduleName[MAX_FILENAME];
2509 NameCollisionInfo info;
2510 Project prj = property::project;
2511 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2513 GetExtension(name, extension);
2514 ReplaceSpaces(moduleName, name);
2515 StripExtension(moduleName);
2516 info = namesInfo[moduleName];
2517 collision = info ? info.IsExtensionColliding(extension) : false;
2519 strcpy(fileName, prj.topNode.path);
2520 PathCatSlash(fileName, objDir.dir);
2521 PathCatSlash(fileName, name);
2523 if(!onlyCObject && !strcmp(extension, "ec"))
2525 ChangeExtension(fileName, "c", fileName);
2526 if(FileExists(fileName)) DeleteFile(fileName);
2527 ChangeExtension(fileName, "sym", fileName);
2528 if(FileExists(fileName)) DeleteFile(fileName);
2529 ChangeExtension(fileName, "imp", fileName);
2530 if(FileExists(fileName)) DeleteFile(fileName);
2531 ChangeExtension(fileName, "bowl", fileName);
2532 if(FileExists(fileName)) DeleteFile(fileName);
2533 ChangeExtension(fileName, "ec", fileName);
2537 strcat(fileName, ".o");
2539 ChangeExtension(fileName, "o", fileName);
2540 if(FileExists(fileName)) DeleteFile(fileName);
2548 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2549 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2554 bool IsInNode(ProjectNode node)
2556 bool result = false;
2558 for(n = this; n; n = n.parent)
2570 // the code in this function is closely matched to OptionsBox::Load
2571 // and accompanying derivations of OptionBox and their use of OptionSet,
2572 // OptionCheck, LoadOption and FinalizeLoading methods.
2573 // output changing modification should be mirrored in both implementations
2574 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2576 ProjectOptions output { };
2578 // legend: e Element
2579 // o Option (of a ProjectOptions)
2580 // n Node (ProjectNode)
2582 // u Utility (GenericOptionTools)
2587 int includeDirsOption = OPTION(includeDirs);
2589 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2591 // OPTION(ProjectOptions' last member) for size
2592 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2593 Array<bool> optionDone { size = OPTION(installCommands) };
2594 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2596 GenericOptionTools<SetBool> utilSetBool {
2597 bool OptionCheck(ProjectOptions options, int option) {
2598 return *(SetBool*)((byte *)options + option) == true;
2600 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2601 if(options && (*(SetBool*)((byte *)options + option) == true))
2602 *(SetBool*)((byte *)output + option) = true;
2605 GenericOptionTools<String> utilString {
2606 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2607 String * string = (String*)((byte *)output + option);
2608 if(*string) delete *string;
2610 *string = CopyString(*(String*)((byte *)options + option));
2613 StringArrayOptionTools utilStringArrays {
2615 caseSensitive = true;
2616 bool OptionCheck(ProjectOptions options, int option) {
2617 Array<String> strings = *(Array<String>*)((byte *)options + option);
2618 return strings && strings.count;
2620 bool OptionSet(ProjectOptions options, int option) {
2621 Array<String> strings = *(Array<String>*)((byte *)options + option);
2622 if(mergeValues && !configReplaces)
2623 return strings && strings.count;
2625 return strings != null;
2627 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2630 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2634 Array<String> tempStrings = optionTempStrings[option];
2636 optionTempStrings[option] = tempStrings = { };
2640 char priorityMark[10];
2643 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2644 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2645 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2651 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2652 Array<String> * strings = (Array<String>*)((byte *)output + option);
2653 if(*strings) { strings->Free(); delete *strings; }
2654 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2657 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2660 Array<String> tempStrings = optionTempStrings[option];
2661 Array<String> * strings = (Array<String>*)((byte *)output + option);
2662 if(*strings) { strings->Free(); delete *strings; }
2663 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2668 GenericOptionTools<WarningsOption> utilWarningsOption {
2669 bool OptionCheck(ProjectOptions options, int option) {
2670 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2671 return value && value != none;
2673 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2674 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2675 *(WarningsOption*)((byte *)output + option) = value;
2678 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2679 bool OptionCheck(ProjectOptions options, int option) {
2680 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2681 return value && value != none;
2683 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2684 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2685 *(OptimizationStrategy*)((byte *)output + option) = value;
2689 Map<int, GenericOptionTools> ot { };
2691 // The following are compiler options
2693 ot[OPTION(debug)] = utilSetBool;
2694 ot[OPTION(memoryGuard)] = utilSetBool;
2695 ot[OPTION(profile)] = utilSetBool;
2696 ot[OPTION(noLineNumbers)] = utilSetBool;
2697 ot[OPTION(strictNameSpaces)] = utilSetBool;
2698 ot[OPTION(fastMath)] = utilSetBool;
2700 ot[OPTION(defaultNameSpace)] = utilString;
2702 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2703 ot[OPTION(includeDirs)] = utilStringArrays;
2705 ot[OPTION(warnings)] = utilWarningsOption;
2707 ot[OPTION(optimization)] = utilOptimizationStrategy;
2709 for(n = node; n; n = n.parent)
2711 ProjectConfig nodeConfig = null;
2713 priority = (priority / 10 + 1) * 10;
2716 if(projectConfig && n.configurations)
2718 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2720 if(platform && c.platforms)
2722 for(p : c.platforms; !strcmpi(p.name, platformName))
2726 GenericOptionTools u = uu;
2728 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2730 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2731 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2732 optionConfigXplatformSet[o] = true;
2744 GenericOptionTools u = uu;
2748 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2750 for(p : n.platforms; !strcmpi(p.name, platformName))
2752 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2754 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2755 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2760 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2761 ((u.mergeValues && !u.configReplaces) ?
2762 u.OptionCheck(nodeConfig.options, o) :
2763 u.OptionSet(nodeConfig.options, o)))
2765 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2766 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2770 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2772 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2773 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2777 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2778 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2786 GenericOptionTools u = uu;
2789 u.FinalizeLoading(o, optionTempStrings, output);
2792 delete optionConfigXplatformSet;
2794 delete optionTempStrings;
2798 delete utilStringArrays;
2799 delete utilWarningsOption;
2800 delete utilOptimizationStrategy;
2807 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2811 ProjectOptions first;
2812 ProjectOptions commonOptions;
2814 Map<String, int> countIncludeDirs { };
2815 Map<String, int> countPreprocessorDefinitions { };
2816 Map<String, bool> commonIncludeDirs { };
2817 Map<String, bool> commonPreprocessorDefinitions { };
2819 for(options : byPlatformOptions) { first = options; break; }
2821 *platformsCommonOptions = commonOptions = first.Copy();
2823 if(commonOptions.includeDirs)
2824 commonOptions.includeDirs.Free();
2825 if(commonOptions.preprocessorDefinitions)
2826 commonOptions.preprocessorDefinitions.Free();
2828 for(options : byPlatformOptions)
2830 if(options != first)
2832 if(commonOptions.debug && options.debug != commonOptions.debug)
2833 commonOptions.debug = unset;
2834 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2835 commonOptions.memoryGuard = unset;
2836 if(commonOptions.profile && options.profile != commonOptions.profile)
2837 commonOptions.profile = unset;
2838 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2839 commonOptions.noLineNumbers = unset;
2840 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2841 commonOptions.strictNameSpaces = unset;
2842 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2843 commonOptions.fastMath = unset;
2845 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2846 commonOptions.warnings = unset;
2847 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2848 commonOptions.optimization = unset;
2850 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2851 delete commonOptions.defaultNameSpace;
2854 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2855 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2858 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2859 commonIncludeDirs, commonOptions.includeDirs);
2860 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2861 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2863 for(options : byPlatformOptions)
2865 if(options.debug && options.debug == commonOptions.debug)
2866 options.debug = unset;
2867 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2868 options.memoryGuard = unset;
2869 if(options.profile && options.profile == commonOptions.profile)
2870 options.profile = unset;
2871 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2872 options.noLineNumbers = unset;
2873 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2874 options.strictNameSpaces = unset;
2875 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2876 options.fastMath = unset;
2878 if(options.warnings && options.warnings == commonOptions.warnings)
2879 options.warnings = unset;
2880 if(options.optimization && options.optimization == commonOptions.optimization)
2881 options.optimization = unset;
2883 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2884 delete options.defaultNameSpace;
2886 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2887 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2890 delete countIncludeDirs;
2891 delete countPreprocessorDefinitions;
2892 delete commonIncludeDirs;
2893 delete commonPreprocessorDefinitions;
2896 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2897 Map<Platform, ProjectOptions> parentByPlatformOptions,
2898 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2900 ComplexComparison result = equal;
2901 ComplexComparison compare;
2903 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2905 ProjectOptions additionalOptions;
2906 additionsByPlatformOptions[platform] = { };
2907 additionalOptions = additionsByPlatformOptions[platform];
2908 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2909 if(compare == greater && result == equal)
2911 else if(compare == different)
2920 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2922 ComplexComparison result = equal;
2923 if(options.debug != parentOptions.debug ||
2924 options.memoryGuard != parentOptions.memoryGuard ||
2925 options.profile != parentOptions.profile ||
2926 options.noLineNumbers != parentOptions.noLineNumbers ||
2927 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2928 options.fastMath != parentOptions.fastMath ||
2929 options.warnings != parentOptions.warnings ||
2930 options.optimization != parentOptions.optimization ||
2931 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2932 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2936 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2937 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2939 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2940 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2946 enum ComplexComparison { different/*, smaller*/, equal, greater };
2948 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2951 if((!strings || !strings.count) && originals && originals.count)
2953 else if(strings && strings.count && (!originals || !originals.count))
2958 additions->Add(CopyString(s));
2960 else if(strings && strings.count && originals && originals.count)
2962 Map<String, String> map { };
2963 MapIterator<String, bool> mit { map = map };
2966 char * s = strstr(it, "\n");
2972 char * s = strstr(it, "\n");
2974 if(!mit.Index(s, false))
2989 additions->Add(CopyString(it));
2997 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3010 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3017 const char * s = ⁢
3018 strings.Add(CopyString(s));
3024 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3028 Array<String> tmp { };
3029 MapIterator<String, bool> mit { map = common };
3033 if(!mit.Index(s, false))
3034 tmp.Add(CopyString(s));
3040 strings.Add(CopyString(s));
3047 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3050 customFlags = nodeFlagsMapping[(intptr)node];
3052 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3054 f.Printf(" $(%s)", variableName);
3057 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3060 customFlags = nodeFlagsMapping[(intptr)node];
3062 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3064 s.concatf(" $(%s)", variableName);
3067 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3073 if(options.optimization == speed || options.optimization == size ||
3074 options.fastMath == true || options.debug == true)
3076 if(options.debug != true)
3078 s.concat(" $(if $(DEBUG),");
3082 switch(options.optimization)
3084 case speed: s.concat(" -O2"); break;
3085 case size: s.concat(" -Os"); break;
3087 if(options.fastMath == true)
3088 s.concat(" -ffast-math");
3089 if(options.debug == true)
3091 if(options.debug != true)
3094 else if(commonOptions)
3095 s.concat(" $(if $(DEBUG),-g)");
3097 s.concat(" $(FPIC)");
3099 switch(options.warnings)
3101 case all: s.concat(" -Wall"); break;
3102 case none: s.concat(" -w"); break;
3107 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3110 if(options && options.preprocessorDefinitions)
3111 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3112 if(options && options.includeDirs)
3113 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3116 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3118 if(options.memoryGuard == true)
3119 s.concat(" -memguard");
3120 if(options.noLineNumbers == true)
3121 s.concat(" -nolinenumbers");
3122 if(options.strictNameSpaces == true)
3123 s.concat(" -strictns");
3124 if(options.defaultNameSpace && options.defaultNameSpace[0])
3125 s.concatf(" -defaultns %s", options.defaultNameSpace);
3128 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3129 LineOutputMethod lineMethod, const String newLineStart)
3133 if(lineMethod == newLine)
3135 output.concat(" \\\n");
3136 output.concat(newLineStart);
3140 Map<String, int> sortedList { };
3141 MapNode<String, int> mn;
3143 sortedList[item] = 1;
3144 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3146 char * start = strstr(mn.key, "\n");
3147 if(lineMethod == lineEach)
3149 output.concat(" \\\n");
3150 output.concat(newLineStart);
3153 output.concat(flagNames[flag]);
3154 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3162 if(lineMethod == lineEach)
3164 output.concat(" \\\n");
3165 output.concat(newLineStart);
3168 output.concat(flagNames[flag]);
3169 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3175 class GenericOptionTools<class X>
3177 bool mergeValues, configReplaces;
3179 virtual bool OptionSet(ProjectOptions options, int option) {
3180 if(*(X*)((byte *)options + option))
3185 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3187 virtual bool OptionCheck(ProjectOptions options, int option) {
3188 return OptionSet(options, option);
3191 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3192 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3195 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3200 class NameCollisionInfo
3213 bool IsExtensionColliding(char * extension)
3217 ((!strcmpi(extension, "c") && ec) ||
3218 (!strcmpi(extension, "rc") && (ec || c)) ||
3219 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3220 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3221 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3222 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3223 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3224 !strcmpi(extension, "mm")))