1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(&((ProjectOptions)0).x))
17 static void OutputLog(char * string)
19 #ifdef MAKEFILE_GENERATOR
22 ide.outputView.buildBox.Log(string);
26 bool eString_PathInsideOfMore(char * path, char * of, char * pathRest)
28 if(!path[0] || !of[0])
29 return false; // What to do here? Ever used?
32 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
33 char pathPart[MAX_FILENAME]; //, pathRest[MAX_LOCATION];
35 strcpy(pathRest, path);
36 for(; ofRest[0] && pathRest[0];)
38 SplitDirectory(ofRest, ofPart, ofRest);
39 SplitDirectory(pathRest, pathPart, pathRest);
40 if(fstrcmp(pathPart, ofPart))
43 if(!ofRest[0] && !pathRest[0])
45 else if(!pathRest[0]) // not inside of, it's the other way around
51 enum NodeTypes { project, file, folder, resources, folderOpen };
54 genFile, ewsFile, epjFile, folder, openFolder, ecFile, ehFile,
55 sFile, cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile,
56 archiveFile, packageFile, opticalMediaImageFile, mFile, mmFile;
58 NodeIcons ::SelectFileIcon(char * filePath)
61 if(filePath && filePath[0])
63 char extension[MAX_EXTENSION];
64 GetExtension(filePath, extension);
67 if(!strcmpi(extension, WorkspaceExtension))
69 else if(!strcmpi(extension, ProjectExtension))
71 else if(!strcmpi(extension, "ec"))
73 else if(!strcmpi(extension, "eh"))
75 else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
76 !strcmpi(extension, "cxx"))
78 else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
79 !strcmpi(extension, "hxx"))
81 else if(!strcmpi(extension, "s"))
83 else if(!strcmpi(extension, "c"))
85 else if(!strcmpi(extension, "h"))
87 else if(!strcmpi(extension, "m"))
89 else if(!strcmpi(extension, "mm"))
91 else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
92 !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
94 else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
95 !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
96 !strcmpi(extension, "js"))
98 else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
99 !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
100 !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
101 !strcmpi(extension, "ico"))
103 else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
104 !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
106 else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
107 !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
108 !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
109 !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
110 !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
111 !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
113 else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
114 !strcmpi(extension, "rpm"))
116 else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
117 !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
118 !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
119 !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
120 icon = opticalMediaImageFile;
128 icon = genFile; // tocheck: error icon?
132 NodeIcons ::SelectNodeIcon(NodeTypes type)
151 #define SELECTION_COLOR Color { 10, 36, 106 }
157 // this is so not working, why!
159 // return result was not even executed (did not step on while debugging)
160 class TwoStrings : struct
182 //property char * { set { } }
183 DotMain ::FromFileName(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 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(char * oldName, 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 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;
868 CollectExclusionInfo(exclusionInfo, prjConfig);
869 common = exclusionInfo[unknown];
871 Map<Platform, SetBool> cleaned { };
872 SetBool opposite = common == true ? false : true;
873 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
875 if(mn.key == unknown || mn.value == opposite)
876 cleaned[mn.key] = mn.value;
878 delete exclusionInfo;
879 exclusionInfo = cleaned;
882 if(exclusionInfo.count > 1)
884 if(exclusionInfo.count > 2)
887 len = strlen(exp) + strlen("$(if $(or ");
888 exp = renew exp char[len+1];
889 strcat(exp, "$(if $(or ");
892 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
894 if(mn.key != unknown)
896 char * comma = mn.next ? "," : "";
898 var = PlatformToMakefileTargetVariable(mn.key);
901 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
902 exp = renew exp char[len+1];
912 len = strlen(exp) + strlen("),");
913 exp = renew exp char[len+1];
917 if(exclusionInfo.root.minimum.key != unknown)
918 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
920 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
923 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
924 exp = renew exp char[len+1];
925 strcat(exp, "$(if $(");
932 exp = common == true ? result.b : result.a;
933 len = strlen(exp) + strlen(",");
934 exp = renew exp char[len+1];
936 if(common == true) result.b = exp; else result.a = exp;
939 len = strlen(exp) + strlen(")");
940 exp = renew exp char[len+1];
944 delete exclusionInfo;
949 bool GetIsExcluded(ProjectConfig prjConfig)
952 // note: unknown platform is for common
953 Map<Platform, SetBool> exclusionInfo { };
954 CollectExclusionInfo(exclusionInfo, prjConfig);
955 if(exclusionInfo.count == 0)
957 else if(exclusionInfo.count == 1)
958 result = exclusionInfo.root.minimum.value == true;
961 SetBool check = exclusionInfo.root.minimum.value;
962 MapNode<Platform, SetBool> mn;
963 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
965 if(check != mn.value)
968 if(!mn) // all are same
969 result = check == true;
973 delete exclusionInfo;
977 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
979 // note: unknown platform is for common
981 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
982 ProjectOptions options = property::options;
983 Array<PlatformOptions> platforms = property::platforms;
984 List<ProjectConfig> configurations = property::configurations;
987 parent.CollectExclusionInfo(output, prjConfig);
989 output[unknown] = unset;
991 if(options && options.excludeFromBuild)
992 output[unknown] = options.excludeFromBuild;
994 if(config && config.options && config.options.excludeFromBuild)
995 output[unknown] = config.options.excludeFromBuild;
1001 if(p.options.excludeFromBuild && (platform = p.name))
1002 output[platform] = p.options.excludeFromBuild;
1005 if(config && config.platforms)
1007 for(p : config.platforms)
1009 if(p.options.excludeFromBuild && (platform = p.name))
1010 output[platform] = p.options.excludeFromBuild;
1015 void EnsureVisible()
1018 parent.EnsureVisible();
1019 row.collapsed = false;
1025 parent.files.Delete(this);
1028 ProjectNode Find(char * name, bool includeResources)
1030 ProjectNode result = null;
1035 if(includeResources || child.type != resources)
1037 if(child.type != folder && child.name && !strcmpi(child.name, name))
1042 result = child.Find(name, includeResources);
1051 ProjectNode FindWithPath(char * name, bool includeResources)
1053 ProjectNode result = null;
1058 if(includeResources || child.type != resources)
1060 char path[MAX_LOCATION];
1061 strcpy(path, child.path);
1062 if(child.type != folder && child.name)
1064 PathCatSlash(path, child.name);
1065 if(!strcmpi(path, name))
1071 result = child.FindWithPath(name, includeResources);
1080 ProjectNode FindByFullPath(char * path, bool includeResources)
1084 char name[MAX_FILENAME];
1085 GetLastDirectory(path, name);
1086 return InternalFindByFullPath(path, includeResources, name);
1091 ProjectNode InternalFindByFullPath(char * path, bool includeResources, char * lastDirName)
1093 ProjectNode result = null;
1098 if(includeResources || child.type != resources)
1100 if(child.type != file)
1101 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1102 else if(child.name && !fstrcmp(lastDirName, child.name))
1104 char p[MAX_LOCATION];
1105 child.GetFullFilePath(p);
1106 if(!fstrcmp(p, path))
1120 ProjectNode FindByObjectFileName(char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo)
1122 char p[MAX_LOCATION];
1123 ProjectNode result = null;
1124 if(dotMain == true && this.type == project)
1126 GetObjectFileName(p, namesInfo, type, dotMain);
1127 if(!fstrcmp(p, fileName))
1132 for(child : files; child.type != resources)
1134 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo)))
1136 else if(child.type == file && child.name)
1138 child.GetObjectFileName(p, namesInfo, type, dotMain);
1139 if(!fstrcmp(p, fileName))
1150 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
1152 ProjectNode result = null;
1157 if(includeResources || child.type != resources)
1159 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1165 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1174 ProjectNode FindSameNameConflict(char * name, bool includeResources,
1175 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1177 ProjectNode result = null;
1178 Map<Platform, SetBool> compareExclusion { };
1179 SetBool common, commonComp;
1180 SetBool actual, actualComp;
1185 if(includeResources || child.type != resources)
1187 if(child.type != folder && child.name && !strcmpi(child.name, name))
1189 child.CollectExclusionInfo(compareExclusion, prjConfig);
1190 common = exclusionInfo[unknown];
1191 commonComp = compareExclusion[unknown];
1192 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1194 if(!(common == true || commonComp == true))
1203 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1206 actualComp = commonComp;
1207 if(exclusionInfo[platform] != unset)
1208 actual = exclusionInfo[platform];
1209 if(compareExclusion[platform] != unset)
1210 actualComp = compareExclusion[platform];
1211 if(!(actual == true || actualComp == true))
1219 compareExclusion.Free();
1222 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1226 compareExclusion.Free();
1228 delete compareExclusion;
1232 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1234 ProjectNode node = null;
1235 if(!project.topNode.FindByFullPath(filePath, true))
1237 char temp[MAX_LOCATION];
1238 Map<Platform, SetBool> exclusionInfo { };
1240 GetLastDirectory(filePath, temp);
1241 //if(!checkIfExists || !project.topNode.Find(temp, false))
1243 // TOCHECK: Shouldn't this apply either for all configs or none?
1244 CollectExclusionInfo(exclusionInfo, project.config);
1245 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1247 // Do the check for folder in the same parent or resource files only here
1248 if(type == folder || !checkIfExists)
1252 if(node.name && !strcmpi(node.name, temp))
1257 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1261 node.nodeType = folder;
1267 StripLastDirectory(filePath, temp);
1268 MakePathRelative(temp, project.topNode.path, temp);
1269 node.path = CopyUnixPath(temp);
1271 node.nodeType = file;
1275 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1276 PathCatSlash(temp, node.name);
1277 node.path = CopyString(temp);
1279 files.Insert(after, node);
1281 delete exclusionInfo;
1286 #ifndef MAKEFILE_GENERATOR
1287 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1289 char label[MAX_FILENAME];
1295 bool showConfig = true;
1300 projectView = ide.projectView;
1303 bmp = projectView.icons[icon].bitmap;
1304 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1306 GetLastDirectory(name, label);
1307 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1309 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1311 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1314 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(char * extension)
1411 char ext[MAX_EXTENSION];
1412 GetExtension(name, ext);
1413 if(!fstrcmp(ext, extension))
1418 bool needed = false;
1420 if(child.ContainsFilesWithExtension(extension))
1426 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1430 char extension[MAX_EXTENSION];
1431 GetExtension(name, extension);
1432 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1433 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1434 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1436 char moduleName[MAX_FILENAME];
1437 NameCollisionInfo info;
1438 ReplaceSpaces(moduleName, name);
1439 StripExtension(moduleName);
1440 info = namesInfo[moduleName];
1442 info = NameCollisionInfo { };
1443 info.count++; // += 1; unless this is for a bug?
1444 if(!strcmpi(extension, "ec"))
1446 else if(!strcmpi(extension, "s"))
1448 else if(!strcmpi(extension, "c"))
1450 else if(!strcmpi(extension, "rc"))
1452 else if(!strcmpi(extension, "cpp"))
1454 else if(!strcmpi(extension, "cc"))
1456 else if(!strcmpi(extension, "cxx"))
1458 else if(!strcmpi(extension, "m"))
1460 else if(!strcmpi(extension, "mm"))
1462 namesInfo[moduleName] = info;
1469 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1470 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1475 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1476 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1477 ProjectConfig prjConfig, bool * containsCXX)
1483 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1484 char moduleName[MAX_FILENAME];
1485 char extension[MAX_EXTENSION];
1486 GetExtension(name, extension);
1487 if(printType == resources)
1490 char tempPath[MAX_LOCATION];
1491 char modulePath[MAX_LOCATION];
1494 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1497 PathCatSlash(tempPath, name);
1502 strcpy(tempPath, path);
1503 PathCatSlash(tempPath, name);
1505 EscapeForMake(modulePath, tempPath, false, true, false);
1506 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1507 items.Add(CopyString(s));
1509 else if(printType == sources)
1511 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1512 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1513 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1515 char modulePath[MAX_LOCATION];
1516 EscapeForMake(modulePath, path, false, true, false);
1517 EscapeForMake(moduleName, name, false, true, false);
1518 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1519 items.Add(CopyString(s));
1522 else if(printType == eCsources)
1524 if(!strcmpi(extension, "ec"))
1526 char modulePath[MAX_LOCATION];
1527 EscapeForMake(modulePath, path, true, true, false);
1528 EscapeForMake(moduleName, name, true, true, false);
1529 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1530 items.Add(CopyString(s));
1534 else if(printType == rcSources)
1536 if(!strcmpi(extension, "rc"))
1538 char modulePath[MAX_LOCATION];
1539 EscapeForMake(modulePath, path, false, true, false);
1540 EscapeForMake(moduleName, name, false, true, false);
1541 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1542 items.Add(CopyString(s));
1546 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1547 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1548 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1550 if(printType == objects)
1553 NameCollisionInfo info;
1555 EscapeForMake(moduleName, name, false, true, false);
1556 StripExtension(moduleName);
1557 info = namesInfo[moduleName];
1558 collision = info ? info.IsExtensionColliding(extension) : false;
1559 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1560 items.Add(CopyString(s));
1561 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1562 *containsCXX = true;
1571 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1572 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1578 void GenMakefilePrintSymbolRules(File f, Project project,
1579 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1580 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1583 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1584 //ProjectNode child;
1585 //char objDir[MAX_LOCATION];
1586 //ReplaceSpaces(objDir, config.objDir.dir);
1588 //eSystem_Log("Printing Symbol Rules\n");
1591 char extension[MAX_EXTENSION];
1592 char modulePath[MAX_LOCATION];
1593 char moduleName[MAX_FILENAME];
1595 GetExtension(name, extension);
1596 if(!strcmpi(extension, "ec"))
1601 ReplaceSpaces(moduleName, name);
1602 StripExtension(moduleName);
1604 ReplaceSpaces(modulePath, path);
1605 if(modulePath[0]) strcat(modulePath, SEPS);
1607 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1609 // *** Dependency command ***
1610 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1611 modulePath, moduleName, extension);
1613 // System Includes (from global settings)
1614 for(item : compiler.dirs[Includes])
1616 strcat(command, " -isystem ");
1617 if(strchr(item, ' '))
1619 strcat(command, "\"");
1620 strcat(command, item);
1621 strcat(command, "\"");
1624 strcat(command, item);
1627 for(item : project.includeDirs)
1629 strcat(command, " -I");
1630 if(strchr(item, ' '))
1632 strcat(command, "\"");
1633 strcat(command, item);
1634 strcat(command, "\"");
1637 strcat(command, item);
1639 for(item : project.preprocessorDefs)
1641 strcat(command, " -D");
1642 strcat(command, item);
1646 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1649 bool firstLine = true;
1652 // To do some time: auto save external dependencies?
1655 if(dep.GetLine(line, sizeof(line)-1))
1659 char * colon = strstr(line, ":");
1660 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1674 // If we failed to generate dependencies...
1678 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1679 moduleName, modulePath, moduleName, extension);
1683 f.Puts(" $(CFLAGS)");
1684 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1686 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1687 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1689 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1690 modulePath, moduleName, extension);
1691 if(ifCount) f.Puts("endif\n");
1701 bool needed = false;
1702 if(ContainsFilesWithExtension("ec"))
1706 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1717 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1718 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1719 nodeCFlagsMapping, nodeECFlagsMapping);
1726 void GenMakefilePrintPrepecsRules(File f, Project project,
1727 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1728 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1731 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1732 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1733 //ProjectNode child;
1734 //char objDir[MAX_LOCATION];
1735 //ReplaceSpaces(objDir, config.objDir.dir);
1737 //eSystem_Log("Printing Symbol Rules\n");
1740 char extension[MAX_EXTENSION];
1741 char modulePath[MAX_LOCATION];
1742 char moduleName[MAX_FILENAME];
1744 GetExtension(name, extension);
1745 if(!strcmpi(extension, "ec"))
1750 ReplaceSpaces(moduleName, name);
1751 StripExtension(moduleName);
1753 ReplaceSpaces(modulePath, path);
1754 if(modulePath[0]) strcat(modulePath, SEPS);
1756 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1757 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1758 moduleName, modulePath, moduleName, extension);
1759 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1760 modulePath, moduleName, extension, moduleName);*/
1764 f.Puts(" $(CFLAGS)");
1765 //f.Puts(" $(CECFLAGS)");
1766 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1767 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1769 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1770 modulePath, moduleName, extension, moduleName);
1771 if(ifCount) f.Puts("endif\n");
1777 bool needed = false;
1778 if(ContainsFilesWithExtension("ec"))
1782 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1793 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1794 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1795 nodeCFlagsMapping, nodeECFlagsMapping);
1802 void GenMakefilePrintCObjectRules(File f, Project project,
1803 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1804 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1807 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1808 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1809 //ProjectNode child;
1810 //char objDir[MAX_LOCATION];
1811 //ReplaceSpaces(objDir, config.objDir.dir);
1812 //eSystem_Log("Printing C Object Rules\n");
1815 char extension[MAX_EXTENSION];
1816 char modulePath[MAX_LOCATION];
1817 char moduleName[MAX_FILENAME];
1819 GetExtension(name, extension);
1820 if(!strcmpi(extension, "ec"))
1825 ReplaceSpaces(moduleName, name);
1826 StripExtension(moduleName);
1828 ReplaceSpaces(modulePath, path);
1829 if(modulePath[0]) strcat(modulePath, SEPS);
1831 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1833 // *** Dependency command ***
1834 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1835 moduleName, modulePath, moduleName, extension);
1837 // System Includes (from global settings)
1838 for(item : compiler.dirs[Includes])
1840 strcat(command, " -isystem ");
1841 if(strchr(item, ' '))
1843 strcat(command, "\"");
1844 strcat(command, item);
1845 strcat(command, "\"");
1848 strcat(command, item);
1851 for(item : config.includeDirs)
1853 strcat(command, " -I");
1854 if(strchr(item, ' '))
1856 strcat(command, "\"");
1857 strcat(command, item);
1858 strcat(command, "\"");
1861 strcat(command, item);
1863 for(item : config.preprocessorDefs)
1865 strcat(command, " -D");
1866 strcat(command, item);
1870 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1874 bool firstLine = true;
1876 // To do some time: auto save external dependencies?
1879 if(dep.GetLine(line, sizeof(line)-1))
1883 char * colon = strstr(line, ":");
1884 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1898 // If we failed to generate dependencies...
1901 /* COMMENTED OUT FOR NOW
1902 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1903 moduleName, modulePath, moduleName, extension);
1906 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1907 moduleName, modulePath, moduleName, extension, moduleName);
1913 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1914 modulePath, moduleName, extension, moduleName);
1919 f.Puts(" $(CFLAGS)");
1920 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1921 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1922 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1923 f.Puts(" $(FVISIBILITY)");
1925 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1926 modulePath, moduleName, extension);
1927 if(ifCount) f.Puts("endif\n");
1933 bool needed = false;
1934 if(ContainsFilesWithExtension("ec"))
1938 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1949 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1950 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1951 nodeCFlagsMapping, nodeECFlagsMapping);
1958 void GenMakefilePrintObjectRules(File f, Project project,
1959 Map<String, NameCollisionInfo> namesInfo,
1960 ProjectConfig prjConfig,
1961 //Map<Platform, bool> parentExcludedPlatforms,
1962 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1965 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1966 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1967 //ProjectNode child;
1968 //char objDir[MAX_LOCATION];
1969 //ReplaceSpaces(objDir, config.objDir.dir);
1970 //eSystem_Log("Printing Object Rules\n");
1974 char extension[MAX_EXTENSION];
1975 char modulePath[MAX_LOCATION];
1976 char moduleName[MAX_FILENAME];
1978 GetExtension(name, extension);
1979 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1980 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1981 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1985 NameCollisionInfo info;
1987 ReplaceSpaces(moduleName, name);
1988 StripExtension(moduleName);
1990 info = namesInfo[moduleName];
1991 collision = info ? info.IsExtensionColliding(extension) : false;
1993 ReplaceSpaces(modulePath, path);
1994 if(modulePath[0]) strcat(modulePath, SEPS);
1998 // *** Dependency command ***
1999 if(!strcmpi(extension, "ec"))
2000 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
2002 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
2003 moduleName, modulePath, moduleName, extension);
2005 if(!strcmpi(extension, "ec"))
2007 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2011 // System Includes (from global settings)
2012 for(item : compiler.dirs[includes])
2014 strcat(command, " -isystem ");
2015 if(strchr(item, ' '))
2017 strcat(command, "\"");
2018 strcat(command, item);
2019 strcat(command, "\"");
2022 strcat(command, item);
2025 for(item : config.includeDirs)
2027 strcat(command, " -I");
2028 if(strchr(item, ' '))
2030 strcat(command, "\"");
2031 strcat(command, item);
2032 strcat(command, "\"");
2035 strcat(command, item);
2037 for(item : config.preprocessorDefs)
2039 strcat(command, " -D");
2040 strcat(command, item);
2044 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2047 bool firstLine = true;
2050 // To do some time: auto save external dependencies?
2054 if(dep.GetLine(line, sizeof(line)-1))
2058 char * colon = strstr(line, ":");
2059 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2073 // If we failed to generate dependencies...
2082 if(!strcmpi(extension, "rc"))
2085 f.Puts("ifdef WINDOWS_TARGET\n\n");
2088 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2090 if(!strcmpi(extension, "ec"))
2091 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2093 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
2094 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
2095 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2096 f.Printf("\t$(CXX)");
2097 else if(!strcmpi(extension, "rc"))
2098 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2100 f.Printf("\t$(CC)");
2102 if(strcmpi(extension, "rc") != 0)
2104 f.Puts(" $(CFLAGS)");
2105 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2107 if(!strcmpi(extension, "ec"))
2108 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n", moduleName);
2110 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2111 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2113 if(ifCount) f.Puts("endif\n");
2119 bool needed = false;
2122 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2132 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2133 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2134 nodeCFlagsMapping, nodeECFlagsMapping);
2141 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2148 //Iterator<ProjectNode> i { files };
2149 //Iterator<ProjectNode> prev { files };
2150 //for(child : files)
2152 for(c = 0; c < files.count; c++)
2154 ProjectNode child = files[c];
2155 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2158 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2161 char tempPath[MAX_LOCATION];
2162 char resPath[MAX_LOCATION];
2164 // $(EAR) aw%s --- /*quiet ? "q" : */""
2166 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2169 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2172 PathCatSlash(tempPath, child.name);
2177 strcpy(tempPath, child.path);
2178 PathCatSlash(tempPath, child.name);
2180 EscapeForMake(resPath, tempPath, false, true, false);
2181 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2184 if(count == 10 || (count > 0 && (ts || !child.next)))
2186 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2189 for(parent = this; parent.type == folder; parent = parent.parent)
2192 strcpy(path, parent.name);
2199 f.Printf(" \"%s\"%s\n", path, ts.b);
2211 if(child.type == folder)
2212 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2217 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2218 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2219 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2220 Map<Platform, ProjectOptions> parentByPlatformOptions)
2222 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2223 if(type == file || type == folder || type == project)
2225 bool hasPerNodeOptions = type == project;
2226 if(!hasPerNodeOptions)
2228 if(options && !options.isEmpty)
2229 hasPerNodeOptions = true;
2230 else if(configurations)
2232 for(c : configurations)
2234 if(c.options && !c.options.isEmpty)
2236 hasPerNodeOptions = true;
2241 for(p : c.platforms)
2243 if(p.options && !p.options.isEmpty)
2245 hasPerNodeOptions = true;
2249 if(hasPerNodeOptions)
2254 if(!hasPerNodeOptions && platforms)
2258 if(p.options && !p.options.isEmpty)
2260 hasPerNodeOptions = true;
2267 if(hasPerNodeOptions)
2269 bool isEqual = false, isGreater = false;
2270 ComplexComparison complexCmp;
2272 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2273 ProjectOptions platformsCommonOptions;
2274 ProjectOptions byFileConfigPlatformProjectOptions;
2276 DynamicString cflags { };
2277 DynamicString ecflags { };
2281 byPlatformOptions = { };
2283 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2285 byFileConfigPlatformProjectOptions =
2286 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2287 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2290 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2292 byPlatformOptions[unknown] = platformsCommonOptions;
2294 if(parentByPlatformOptions)
2296 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2297 parentByPlatformOptions, additionsByPlatformOptions);
2298 isGreater = complexCmp == greater;
2299 isEqual = complexCmp == equal;
2304 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2306 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2308 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2310 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2313 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2315 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2319 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2321 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2324 if(!isGreater) cflags.concat(" \\\n\t");
2329 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2332 ecflags.concat(" \\\n\t");
2339 cflags.concat(" \\\n\t");
2340 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2344 additionsByPlatformOptions.Free();
2345 delete additionsByPlatformOptions;
2351 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2352 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2360 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2361 cflagsVariations[s] = variationNum = cflagsVariations.count;
2362 nodeCFlagsMapping[(intptr)this] = variationNum;
2365 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2366 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2367 nodeECFlagsMapping[(intptr)this] = variationNum;
2378 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2379 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2388 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2389 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2390 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2395 if(byPlatformOptions != parentByPlatformOptions)
2397 byPlatformOptions.Free();
2398 delete byPlatformOptions;
2402 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2404 Array<Platform> platforms { };
2405 Map<Platform, SetBool> exclusionInfo { };
2406 CollectExclusionInfo(exclusionInfo, prjConfig);
2408 if(exclusionInfo[unknown] == true)
2410 if(exclusionInfo.count > 1)
2411 for(p : exclusionInfo; p == false)
2416 bool onlyOnknown = true;
2417 for(p : exclusionInfo)
2418 if(&p != unknown && p == true)
2420 onlyOnknown = false;
2424 platforms.Add(unknown);
2428 for(p = unknown + 1; p < Platform::enumSize; p++)
2429 if(exclusionInfo[p] != true)
2433 delete exclusionInfo;
2437 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2439 char moduleName[MAX_FILENAME];
2442 bool headerAltFailed = false;
2444 char extension[MAX_EXTENSION];
2445 NameCollisionInfo info;
2446 Project prj = property::project;
2447 Map<String, String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2449 GetExtension(name, extension);
2450 strcpy(moduleName, name);
2451 StripExtension(moduleName);
2452 info = namesInfo[moduleName];
2453 collision = info ? info.IsExtensionColliding(extension) : false;
2455 for(h2s : headerToSource)
2457 if(!strcmpi(extension, &h2s))
2459 char filePath[MAX_LOCATION];
2460 GetFullFilePath(filePath);
2461 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2462 ChangeExtension(moduleName, h2s, moduleName);
2463 if(prj.topNode.Find(moduleName, false))
2465 strcpy(extension, h2s);
2466 collision = info ? info.IsExtensionColliding(extension) : false;
2467 ChangeExtension(filePath, h2s, filePath);
2468 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2469 StripExtension(moduleName);
2473 headerAltFailed = true;
2474 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2475 StripExtension(moduleName);
2481 if(!headerAltFailed)
2483 output.concat(" \"");
2484 output.concat(objDir); //.concat(" $(OBJ)");
2489 strcat(moduleName, ".");
2490 strcat(moduleName, extension);
2492 strcat(moduleName, ".o");
2493 output.concat(moduleName);
2494 output.concat("\"");
2497 else if(type == project && ContainsFilesWithExtension("ec"))
2499 Project prj = property::project;
2501 ReplaceSpaces(moduleName, prj.moduleName);
2502 strcat(moduleName, ".main.ec");
2503 output.concat(" \"");
2504 output.concat(objDir);
2506 output.concat(moduleName);
2507 output.concat("\"");
2509 ChangeExtension(moduleName, "c", moduleName);
2510 output.concat(" \"");
2511 output.concat(objDir);
2513 output.concat(moduleName);
2514 output.concat("\"");
2516 ChangeExtension(moduleName, "o", moduleName);
2517 output.concat(" \"");
2518 output.concat(objDir);
2520 output.concat(moduleName);
2521 output.concat("\"");
2527 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2528 child.GetTargets(prjConfig, namesInfo, objDir, output);
2533 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2538 char extension[MAX_EXTENSION];
2539 char fileName[MAX_FILENAME];
2540 char moduleName[MAX_FILENAME];
2541 NameCollisionInfo info;
2542 Project prj = property::project;
2543 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2545 GetExtension(name, extension);
2546 ReplaceSpaces(moduleName, name);
2547 StripExtension(moduleName);
2548 info = namesInfo[moduleName];
2549 collision = info ? info.IsExtensionColliding(extension) : false;
2551 strcpy(fileName, prj.topNode.path);
2552 PathCatSlash(fileName, objDir.dir);
2553 PathCatSlash(fileName, name);
2555 if(!onlyCObject && !strcmp(extension, "ec"))
2557 ChangeExtension(fileName, "c", fileName);
2558 if(FileExists(fileName)) DeleteFile(fileName);
2559 ChangeExtension(fileName, "sym", fileName);
2560 if(FileExists(fileName)) DeleteFile(fileName);
2561 ChangeExtension(fileName, "imp", fileName);
2562 if(FileExists(fileName)) DeleteFile(fileName);
2563 ChangeExtension(fileName, "bowl", fileName);
2564 if(FileExists(fileName)) DeleteFile(fileName);
2565 ChangeExtension(fileName, "ec", fileName);
2569 strcat(fileName, ".o");
2571 ChangeExtension(fileName, "o", fileName);
2572 if(FileExists(fileName)) DeleteFile(fileName);
2580 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2581 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2586 bool IsInNode(ProjectNode node)
2588 bool result = false;
2590 for(n = this; n; n = n.parent)
2602 // the code in this function is closely matched to OptionsBox::Load
2603 // and accompanying derivations of OptionBox and their use of OptionSet,
2604 // OptionCheck, LoadOption and FinalizeLoading methods.
2605 // output changing modification should be mirrored in both implementations
2606 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2608 ProjectOptions output { };
2610 // legend: e Element
2611 // o Option (of a ProjectOptions)
2612 // n Node (ProjectNode)
2614 // u Utility (GenericOptionTools)
2619 int includeDirsOption = OPTION(includeDirs);
2621 char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2623 // OPTION(ProjectOptions' last member) for size
2624 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2625 Array<bool> optionDone { size = OPTION(installCommands) };
2626 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2628 GenericOptionTools<SetBool> utilSetBool {
2629 bool OptionCheck(ProjectOptions options, int option) {
2630 return *(SetBool*)((byte *)options + option) == true;
2632 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2633 if(options && (*(SetBool*)((byte *)options + option) == true))
2634 *(SetBool*)((byte *)output + option) = true;
2637 GenericOptionTools<String> utilString {
2638 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2639 String * string = (String*)((byte *)output + option);
2640 if(*string) delete *string;
2642 *string = CopyString(*(String*)((byte *)options + option));
2645 StringArrayOptionTools utilStringArrays {
2647 caseSensitive = true;
2648 bool OptionCheck(ProjectOptions options, int option) {
2649 Array<String> strings = *(Array<String>*)((byte *)options + option);
2650 return strings && strings.count;
2652 bool OptionSet(ProjectOptions options, int option) {
2653 Array<String> strings = *(Array<String>*)((byte *)options + option);
2654 if(mergeValues && !configReplaces)
2655 return strings && strings.count;
2657 return strings != null;
2659 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2662 Array<String> strings = options ? *((Array<String>*)((byte *)options + option) : null;
2666 Array<String> tempStrings = optionTempStrings[option];
2668 optionTempStrings[option] = tempStrings = { };
2672 char priorityMark[10];
2675 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2676 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2677 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2683 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2684 Array<String> * strings = (Array<String>*)((byte *)output + option);
2685 if(*strings) { strings->Free(); delete *strings; }
2686 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2689 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2692 Array<String> tempStrings = optionTempStrings[option];
2693 Array<String> * strings = (Array<String>*)((byte *)output + option);
2694 if(*strings) { strings->Free(); delete *strings; }
2695 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2700 GenericOptionTools<WarningsOption> utilWarningsOption {
2701 bool OptionCheck(ProjectOptions options, int option) {
2702 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2703 return value && value != none;
2705 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2706 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2707 *(WarningsOption*)((byte *)output + option) = value;
2710 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2711 bool OptionCheck(ProjectOptions options, int option) {
2712 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2713 return value && value != none;
2715 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2716 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2717 *(OptimizationStrategy*)((byte *)output + option) = value;
2721 Map<int, GenericOptionTools> ot { };
2723 // The following are compiler options
2725 ot[OPTION(debug)] = utilSetBool;
2726 ot[OPTION(memoryGuard)] = utilSetBool;
2727 ot[OPTION(profile)] = utilSetBool;
2728 ot[OPTION(noLineNumbers)] = utilSetBool;
2729 ot[OPTION(strictNameSpaces)] = utilSetBool;
2730 ot[OPTION(fastMath)] = utilSetBool;
2732 ot[OPTION(defaultNameSpace)] = utilString;
2734 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2735 ot[OPTION(includeDirs)] = utilStringArrays;
2737 ot[OPTION(warnings)] = utilWarningsOption;
2739 ot[OPTION(optimization)] = utilOptimizationStrategy;
2741 for(n = node; n; n = n.parent)
2743 ProjectConfig nodeConfig = null;
2745 priority = (priority / 10 + 1) * 10;
2748 if(projectConfig && n.configurations)
2750 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2752 if(platform && c.platforms)
2754 for(p : c.platforms; !strcmpi(p.name, platformName))
2758 GenericOptionTools u = uu;
2760 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2762 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2763 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2764 optionConfigXplatformSet[o] = true;
2776 GenericOptionTools u = uu;
2780 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2782 for(p : n.platforms; !strcmpi(p.name, platformName))
2784 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2786 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2787 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2792 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2793 ((u.mergeValues && !u.configReplaces) ?
2794 u.OptionCheck(nodeConfig.options, o) :
2795 u.OptionSet(nodeConfig.options, o)))
2797 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2798 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2802 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2804 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2805 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2809 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2810 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2818 GenericOptionTools u = uu;
2821 u.FinalizeLoading(o, optionTempStrings, output);
2824 delete optionConfigXplatformSet;
2826 delete optionTempStrings;
2830 delete utilStringArrays;
2831 delete utilWarningsOption;
2832 delete utilOptimizationStrategy;
2839 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2843 ProjectOptions first;
2844 ProjectOptions commonOptions;
2846 Map<String, int> countIncludeDirs { };
2847 Map<String, int> countPreprocessorDefinitions { };
2848 Map<String, bool> commonIncludeDirs { };
2849 Map<String, bool> commonPreprocessorDefinitions { };
2851 for(options : byPlatformOptions) { first = options; break; }
2853 *platformsCommonOptions = commonOptions = first.Copy();
2855 if(commonOptions.includeDirs)
2856 commonOptions.includeDirs.Free();
2857 if(commonOptions.preprocessorDefinitions)
2858 commonOptions.preprocessorDefinitions.Free();
2860 for(options : byPlatformOptions)
2862 if(options != first)
2864 if(commonOptions.debug && options.debug != commonOptions.debug)
2865 commonOptions.debug = unset;
2866 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2867 commonOptions.memoryGuard = unset;
2868 if(commonOptions.profile && options.profile != commonOptions.profile)
2869 commonOptions.profile = unset;
2870 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2871 commonOptions.noLineNumbers = unset;
2872 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2873 commonOptions.strictNameSpaces = unset;
2874 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2875 commonOptions.fastMath = unset;
2877 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2878 commonOptions.warnings = unset;
2879 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2880 commonOptions.optimization = unset;
2882 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2883 delete commonOptions.defaultNameSpace;
2886 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2887 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2890 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2891 commonIncludeDirs, commonOptions.includeDirs);
2892 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2893 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2895 for(options : byPlatformOptions)
2897 if(options.debug && options.debug == commonOptions.debug)
2898 options.debug = unset;
2899 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2900 options.memoryGuard = unset;
2901 if(options.profile && options.profile == commonOptions.profile)
2902 options.profile = unset;
2903 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2904 options.noLineNumbers = unset;
2905 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2906 options.strictNameSpaces = unset;
2907 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2908 options.fastMath = unset;
2910 if(options.warnings && options.warnings == commonOptions.warnings)
2911 options.warnings = unset;
2912 if(options.optimization && options.optimization == commonOptions.optimization)
2913 options.optimization = unset;
2915 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2916 delete options.defaultNameSpace;
2918 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2919 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2922 delete countIncludeDirs;
2923 delete countPreprocessorDefinitions;
2924 delete commonIncludeDirs;
2925 delete commonPreprocessorDefinitions;
2928 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2929 Map<Platform, ProjectOptions> parentByPlatformOptions,
2930 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2932 ComplexComparison result = equal;
2933 ComplexComparison compare;
2935 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2937 ProjectOptions additionalOptions;
2938 additionsByPlatformOptions[platform] = { };
2939 additionalOptions = additionsByPlatformOptions[platform];
2940 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2941 if(compare == greater && result == equal)
2943 else if(compare == different)
2952 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2954 ComplexComparison result = equal;
2955 if(options.debug != parentOptions.debug ||
2956 options.memoryGuard != parentOptions.memoryGuard ||
2957 options.profile != parentOptions.profile ||
2958 options.noLineNumbers != parentOptions.noLineNumbers ||
2959 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2960 options.fastMath != parentOptions.fastMath ||
2961 options.warnings != parentOptions.warnings ||
2962 options.optimization != parentOptions.optimization ||
2963 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2964 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2968 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2969 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2971 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2972 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2978 enum ComplexComparison { different/*, smaller*/, equal, greater };
2980 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2983 if((!strings || !strings.count) && originals && originals.count)
2985 else if(strings && strings.count && (!originals || !originals.count))
2990 additions->Add(CopyString(s));
2992 else if(strings && strings.count && originals && originals.count)
2994 Map<String, String> map { };
2995 MapIterator<String, bool> mit { map = map };
2998 char * s = strstr(it, "\n");
3004 char * s = strstr(it, "\n");
3006 if(!mit.Index(s, false))
3021 additions->Add(CopyString(it));
3029 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3042 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3050 strings.Add(CopyString(s));
3056 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3060 Array<String> tmp { };
3061 MapIterator<String, bool> mit { map = common };
3065 if(!mit.Index(s, false))
3066 tmp.Add(CopyString(s));
3072 strings.Add(CopyString(s));
3079 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, File f)
3082 customFlags = nodeFlagsMapping[(intptr)node];
3084 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3086 f.Printf(" $(%s)", variableName);
3089 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, String variableName, DynamicString s)
3092 customFlags = nodeFlagsMapping[(intptr)node];
3094 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3096 s.concatf(" $(%s)", variableName);
3099 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3105 if(options.optimization == speed || options.optimization == size ||
3106 options.fastMath == true || options.debug == true)
3108 if(options.debug != true)
3110 s.concat(" $(if $(DEBUG),");
3114 switch(options.optimization)
3116 case speed: s.concat(" -O2"); break;
3117 case size: s.concat(" -Os"); break;
3119 if(options.fastMath == true)
3120 s.concat(" -ffast-math");
3121 if(options.debug == true)
3123 if(options.debug != true)
3126 else if(commonOptions)
3127 s.concat(" $(if $(DEBUG),-g)");
3129 s.concat(" $(FPIC)");
3131 switch(options.warnings)
3133 case all: s.concat(" -Wall"); break;
3134 case none: s.concat(" -w"); break;
3139 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3142 if(options && options.preprocessorDefinitions)
3143 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3144 if(options && options.includeDirs)
3145 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3148 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3150 if(options.memoryGuard == true)
3151 s.concat(" -memguard");
3152 if(options.noLineNumbers == true)
3153 s.concat(" -nolinenumbers");
3154 if(options.strictNameSpaces == true)
3155 s.concat(" -strictns");
3156 if(options.defaultNameSpace && options.defaultNameSpace[0])
3157 s.concatf(" -defaultns %s", options.defaultNameSpace);
3160 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3161 LineOutputMethod lineMethod, String newLineStart)
3165 if(lineMethod == newLine)
3167 output.concat(" \\\n");
3168 output.concat(newLineStart);
3172 Map<String, int> sortedList { };
3173 MapNode<String, int> mn;
3175 sortedList[item] = 1;
3176 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3178 char * start = strstr(mn.key, "\n");
3179 if(lineMethod == lineEach)
3181 output.concat(" \\\n");
3182 output.concat(newLineStart);
3185 output.concat(flagNames[flag]);
3186 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3194 if(lineMethod == lineEach)
3196 output.concat(" \\\n");
3197 output.concat(newLineStart);
3200 output.concat(flagNames[flag]);
3201 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3207 class GenericOptionTools<class X>
3209 bool mergeValues, configReplaces;
3211 virtual bool OptionSet(ProjectOptions options, int option) {
3212 if(*(X*)((byte *)options + option))
3217 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3219 virtual bool OptionCheck(ProjectOptions options, int option) {
3220 return OptionSet(options, option);
3223 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3224 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3227 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3232 class NameCollisionInfo
3245 bool IsExtensionColliding(char * extension)
3249 ((!strcmpi(extension, "c") && ec) ||
3250 (!strcmpi(extension, "rc") && (ec || c)) ||
3251 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3252 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3253 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3254 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3255 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3256 !strcmpi(extension, "mm")))