1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(uintptr)(&((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, const char * objectFileExt)
534 if(buffer && (this.type == file || (this.type == project && dotMain == true)))
537 char extension[MAX_EXTENSION];
538 char moduleName[MAX_FILENAME];
539 const char * objFileExt = objectFileExt ? objectFileExt : objectDefaultFileExt;
540 NameCollisionInfo info;
542 GetExtension(name, extension);
543 ReplaceSpaces(moduleName, name);
544 StripExtension(moduleName);
545 info = namesInfo[moduleName];
546 collision = info ? info.IsExtensionColliding(extension) : false;
550 Project prj = property::project;
551 ReplaceSpaces(buffer, prj.moduleName);
552 StripExtension(buffer);
553 strcat(buffer, ".main.ec");
556 strcpy(buffer, name);
557 if(!strcmp(extension, "ec") || dotMain)
560 ChangeExtension(buffer, "c", buffer);
562 ChangeExtension(buffer, "sym", buffer);
564 ChangeExtension(buffer, "imp", buffer);
565 else if(type == bowl)
566 ChangeExtension(buffer, "bowl", buffer);
573 strcat(buffer, objFileExt);
576 ChangeExtension(buffer, objFileExt, buffer);
582 char * GetFileSysMatchingPath(char * buffer)
586 ProjectNode n, root = this.root;
587 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
589 strcpy(buffer, root.path);
591 PathCatSlash(buffer, n.path);
592 if(FileExists(buffer).isDirectory)
595 if(!(n && (n.type == folder || n.type == project)))
601 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
603 ProjectNode node = null;
604 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
605 List<ProjectNode> nodeStack { };
607 for(node = this; node && node.parent; node = node.parent)
610 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
612 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
613 while((node = nodeStack.lastIterator.data))
615 ProjectOptions nodeOptions = node.property::options;
616 if(nodeOptions && nodeOptions.preprocessorDefinitions)
618 for(def : nodeOptions.preprocessorDefinitions)
619 perFilePreprocessorDefs.Add(CopyString(def));
621 if(config && config.options && config.options.preprocessorDefinitions)
623 for(def : config.options.preprocessorDefinitions)
624 perFilePreprocessorDefs.Add(CopyString(def));
626 if(nodeOptions && nodeOptions.includeDirs)
628 for(dir : nodeOptions.includeDirs)
629 perFileIncludeDirs.Add(CopySystemPath(dir));
631 if(config && config.options && config.options.includeDirs)
633 for(dir : config.options.includeDirs)
634 perFileIncludeDirs.Add(CopySystemPath(dir));
636 nodeStack.lastIterator.Remove();
642 property Project project
646 ProjectNode n = this;
647 while(n && n.type != project) n = n.parent;
648 return n ? (*&n.project) : null;
652 void RenameConfig(const char * oldName, const char * newName)
656 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
658 if(property::configurations)
660 for(c : property::configurations; !strcmp(c.name, oldName))
663 c.name = CopyString(newName);
668 void DeleteConfig(ProjectConfig configToDelete)
672 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
674 if(property::configurations)
676 Iterator<ProjectConfig> c { property::configurations };
679 ProjectConfig config = c.data;
680 if(!strcmp(configToDelete.name, config.name))
687 if(!property::configurations.count)
688 property::configurations = null;
694 ProjectNode backupNode { };
698 backupNode.files = { };
699 for(f : files) backupNode.files.Add(f.Backup());
701 if(property::options)
702 backupNode.options = property::options.Copy();
704 if(property::platforms)
706 backupNode.platforms = { };
707 for(p : property::platforms)
708 backupNode.platforms.Add(p.Copy());
711 if(property::configurations)
713 backupNode.configurations = { };
714 for(c : property::configurations)
715 backupNode.configurations.Add(c.Copy());
720 void Revert(ProjectNode backupNode)
724 Iterator<ProjectNode> it { backupNode.files };
732 property::options = backupNode.options ? backupNode.options.Copy() : null;
733 if(backupNode.platforms)
735 Array<PlatformOptions> platforms { };
736 property::platforms = platforms;
738 for(p : backupNode.platforms)
739 platforms.Add(p.Copy());
741 if(backupNode.configurations)
743 List<ProjectConfig> configurations { };
744 property::configurations = configurations;
745 for(c : backupNode.configurations)
746 configurations.Add(c.Copy());
750 void FixupNode(char * parentPath)
756 else if(nodeType == file)
761 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
764 else if(nodeType == folder)
770 char temp[MAX_LOCATION];
771 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
772 PathCatSlash(temp, name);
773 path = CopyString(temp);
777 indent = parent ? parent.indent + 1 : 0;
780 icon = NodeIcons::SelectFileIcon(name);
782 icon = NodeIcons::SelectNodeIcon(type);
791 parentPath[0] = '\0';
792 else if(type == resources || type == folder)
793 strcpy(parentPath, path);
795 f.FixupNode(parentPath);
800 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
804 // TOCHECK: Called from JSON writer
805 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
807 strcpy(tempString, "\"");
808 strcat(tempString, property::fileName);
809 strcat(tempString, "\"");
816 // TOCHECK: Called from ProjectView rendering
817 return name ? name : "";
830 if(!project && platforms)
835 if(!project && configurations)
837 configurations.Free();
838 delete configurations;
841 /////////////////////////////
847 property bool isInResources
852 for(node = this; node; node = node.parent)
854 if(node.type == resources)
861 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
863 TwoStrings result { a = CopyString(""), b = CopyString("") };
864 // note: unknown platform is for common
865 Map<Platform, SetBool> exclusionInfo { };
866 MapNode<Platform, SetBool> mn;
872 CollectExclusionInfo(exclusionInfo, prjConfig);
873 common = exclusionInfo[unknown];
875 Map<Platform, SetBool> cleaned { };
876 SetBool opposite = common == true ? false : true;
877 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
879 if(mn.key == unknown || mn.value == opposite)
880 cleaned[mn.key] = mn.value;
882 delete exclusionInfo;
883 exclusionInfo = cleaned;
886 if(exclusionInfo.count > 1)
888 if(exclusionInfo.count > 2)
891 len = strlen(exp) + strlen("$(if $(or ");
892 exp = renew exp char[len+1];
893 strcat(exp, "$(if $(or ");
896 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
898 if(mn.key != unknown)
900 const char * comma = mn.next ? "," : "";
902 var = PlatformToMakefileTargetVariable(mn.key);
905 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
906 exp = renew exp char[len+1];
916 len = strlen(exp) + strlen("),");
917 exp = renew exp char[len+1];
921 if(exclusionInfo.root.minimum.key != unknown)
922 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
924 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
927 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
928 exp = renew exp char[len+1];
929 strcat(exp, "$(if $(");
936 exp = common == true ? result.b : result.a;
937 len = strlen(exp) + strlen(",");
938 exp = renew exp char[len+1];
940 if(common == true) result.b = exp; else result.a = exp;
943 len = strlen(exp) + strlen(")");
944 exp = renew exp char[len+1];
948 delete exclusionInfo;
953 bool GetIsExcluded(ProjectConfig prjConfig)
956 // note: unknown platform is for common
957 Map<Platform, SetBool> exclusionInfo { };
958 CollectExclusionInfo(exclusionInfo, prjConfig);
959 if(exclusionInfo.count == 0)
961 else if(exclusionInfo.count == 1)
962 result = exclusionInfo.root.minimum.value == true;
965 SetBool check = exclusionInfo.root.minimum.value;
966 MapNode<Platform, SetBool> mn;
967 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
969 if(check != mn.value)
972 if(!mn) // all are same
973 result = check == true;
977 delete exclusionInfo;
981 bool GetIsExcludedForCompiler(ProjectConfig prjConfig, CompilerConfig compiler)
984 Map<Platform, SetBool> exclusionInfo { };
985 SetBool common, platform;
986 CollectExclusionInfo(exclusionInfo, prjConfig);
987 common = exclusionInfo[unknown];
988 platform = exclusionInfo[compiler.targetPlatform];
989 result = platform == true || (common == true && platform == unset);
990 delete exclusionInfo;
994 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
996 // note: unknown platform is for common
998 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
999 ProjectOptions options = property::options;
1000 Array<PlatformOptions> platforms = property::platforms;
1003 parent.CollectExclusionInfo(output, prjConfig);
1005 output[unknown] = unset;
1007 if(options && options.excludeFromBuild)
1008 output[unknown] = options.excludeFromBuild;
1010 if(config && config.options && config.options.excludeFromBuild)
1011 output[unknown] = config.options.excludeFromBuild;
1017 if(p.options.excludeFromBuild && (platform = p.name))
1018 output[platform] = p.options.excludeFromBuild;
1021 if(config && config.platforms)
1023 for(p : config.platforms)
1025 if(p.options.excludeFromBuild && (platform = p.name))
1026 output[platform] = p.options.excludeFromBuild;
1031 void EnsureVisible()
1034 parent.EnsureVisible();
1035 row.collapsed = false;
1041 parent.files.Delete(this);
1044 ProjectNode Find(const char * name, bool includeResources)
1046 ProjectNode result = null;
1051 if(includeResources || child.type != resources)
1053 if(child.type != folder && child.name && !strcmpi(child.name, name))
1058 result = child.Find(name, includeResources);
1067 ProjectNode FindWithPath(const char * name, bool includeResources)
1069 ProjectNode result = null;
1074 if(includeResources || child.type != resources)
1076 char path[MAX_LOCATION];
1077 strcpy(path, child.path);
1078 if(child.type != folder && child.name)
1080 PathCatSlash(path, child.name);
1081 if(!strcmpi(path, name))
1087 result = child.FindWithPath(name, includeResources);
1096 ProjectNode FindByFullPath(const char * path, bool includeResources)
1100 char name[MAX_FILENAME];
1101 GetLastDirectory(path, name);
1102 return InternalFindByFullPath(path, includeResources, name);
1107 ProjectNode InternalFindByFullPath(const char * path, bool includeResources, const char * lastDirName)
1109 ProjectNode result = null;
1114 if(includeResources || child.type != resources)
1116 if(child.type != file)
1117 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1118 else if(child.name && !fstrcmp(lastDirName, child.name))
1120 char p[MAX_LOCATION];
1121 child.GetFullFilePath(p);
1122 if(!fstrcmp(p, path))
1136 ProjectNode FindByObjectFileName(const char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo, const char * objectFileExt)
1138 char p[MAX_LOCATION];
1139 ProjectNode result = null;
1140 if(dotMain == true && this.type == project)
1142 GetObjectFileName(p, namesInfo, type, dotMain, objectFileExt);
1143 if(!fstrcmp(p, fileName))
1148 for(child : files; child.type != resources)
1150 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo, objectFileExt)))
1152 else if(child.type == file && child.name)
1154 child.GetObjectFileName(p, namesInfo, type, dotMain, objectFileExt);
1155 if(!fstrcmp(p, fileName))
1166 ProjectNode FindSpecial(const char * name, bool recursive, bool includeResources, bool includeFolders)
1168 ProjectNode result = null;
1173 if(includeResources || child.type != resources)
1175 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1181 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1190 ProjectNode FindSameNameConflict(const char * name, bool includeResources,
1191 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1193 ProjectNode result = null;
1194 Map<Platform, SetBool> compareExclusion { };
1195 SetBool common, commonComp;
1196 SetBool actual, actualComp;
1201 if(includeResources || child.type != resources)
1203 if(child.type != folder && child.name && !strcmpi(child.name, name))
1205 child.CollectExclusionInfo(compareExclusion, prjConfig);
1206 common = exclusionInfo[unknown];
1207 commonComp = compareExclusion[unknown];
1208 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1210 if(!(common == true || commonComp == true))
1219 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1222 actualComp = commonComp;
1223 if(exclusionInfo[platform] != unset)
1224 actual = exclusionInfo[platform];
1225 if(compareExclusion[platform] != unset)
1226 actualComp = compareExclusion[platform];
1227 if(!(actual == true || actualComp == true))
1235 compareExclusion.Free();
1238 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1242 compareExclusion.Free();
1244 delete compareExclusion;
1248 ProjectNode Add(Project project, const char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1250 ProjectNode node = null;
1251 if(!project.topNode.FindByFullPath(filePath, true))
1253 char temp[MAX_LOCATION];
1254 Map<Platform, SetBool> exclusionInfo { };
1256 GetLastDirectory(filePath, temp);
1257 //if(!checkIfExists || !project.topNode.Find(temp, false))
1259 // TOCHECK: Shouldn't this apply either for all configs or none?
1260 CollectExclusionInfo(exclusionInfo, project.config);
1261 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1263 // Do the check for folder in the same parent or resource files only here
1264 if(type == folder || !checkIfExists)
1268 if(node.name && !strcmpi(node.name, temp))
1273 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1277 node.nodeType = folder;
1283 StripLastDirectory(filePath, temp);
1284 MakePathRelative(temp, project.topNode.path, temp);
1285 node.path = CopyUnixPath(temp);
1287 node.nodeType = file;
1291 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1292 PathCatSlash(temp, node.name);
1293 node.path = CopyString(temp);
1295 files.Insert(after, node);
1297 delete exclusionInfo;
1302 #ifndef MAKEFILE_GENERATOR
1303 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1305 char label[MAX_FILENAME];
1310 bool showConfig = true;
1315 projectView = ide.projectView;
1318 bmp = projectView.icons[icon].bitmap;
1319 xStart = x + (bmp ? (bmp.width + 5) : 0);
1321 GetLastDirectory(name, label);
1322 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1324 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1326 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1328 const char * addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1329 if(strlen(addendum))
1331 strcat(label, " (");
1332 strcat(label, addendum);
1335 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1336 if(strlen(addendum))
1338 strcat(label, " (");
1339 strcat(label, addendum);
1345 else if(!projectView.drawingInProjectSettingsDialog)
1348 strcat(label, " *");
1349 if(type == project && info)
1351 int len = strlen(info) + 4;
1352 char * more = new char[len];
1353 sprintf(more, " (%s)", info);
1354 strcat(label, more);
1358 len = strlen(label);
1362 if(type == folder || type == folderOpen)
1363 surface.SetForeground(yellow);
1367 surface.TextOpacity(false);
1368 surface.TextExtent(label, len, &w, &h);
1371 // Draw the current row stipple
1372 if(displayFlags.selected)
1373 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1374 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1375 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1377 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1381 if(displayFlags.current)
1383 if(displayFlags.active)
1385 surface.LineStipple(0x5555);
1386 if(displayFlags.selected)
1387 surface.SetForeground(projectView.fileList.stippleColor);
1389 surface.SetForeground(projectView.fileList.foreground);
1393 surface.SetForeground(SELECTION_COLOR);
1395 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1396 surface.LineStipple(0);
1401 surface.SetForeground(white);
1402 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1408 int OnCompare(ProjectNode b)
1411 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1412 result = strcmpi(name, b.name);
1415 if(type == folder && b.type == file) result = -1;
1416 else if(type == file && b.type == folder) result = 1;
1421 bool ContainsFilesWithExtension(const char * extension, ProjectConfig prjConfig)
1423 if(type == file && name && name[0])
1425 char ext[MAX_EXTENSION];
1426 GetExtension(name, ext);
1427 if(!fstrcmp(ext, extension))
1434 if(child.type != resources && (child.type == folder || !prjConfig || !child.GetIsExcluded(prjConfig)))
1436 if(child.ContainsFilesWithExtension(extension, prjConfig))
1444 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1448 char extension[MAX_EXTENSION];
1449 GetExtension(name, extension);
1450 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1451 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1452 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1454 char moduleName[MAX_FILENAME];
1455 NameCollisionInfo info;
1456 ReplaceSpaces(moduleName, name);
1457 StripExtension(moduleName);
1458 info = namesInfo[moduleName];
1460 info = NameCollisionInfo { };
1461 info.count++; // += 1; unless this is for a bug?
1462 if(!strcmpi(extension, "ec"))
1464 else if(!strcmpi(extension, "s"))
1466 else if(!strcmpi(extension, "c"))
1468 else if(!strcmpi(extension, "rc"))
1470 else if(!strcmpi(extension, "cpp"))
1472 else if(!strcmpi(extension, "cc"))
1474 else if(!strcmpi(extension, "cxx"))
1476 else if(!strcmpi(extension, "m"))
1478 else if(!strcmpi(extension, "mm"))
1480 namesInfo[moduleName] = info;
1487 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1488 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1493 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1494 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1495 ProjectConfig prjConfig, bool * containsCXX)
1501 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1502 char moduleName[MAX_FILENAME];
1503 char extension[MAX_EXTENSION];
1504 GetExtension(name, extension);
1505 if(printType == resources)
1508 char tempPath[MAX_LOCATION];
1509 char modulePath[MAX_LOCATION];
1512 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1515 PathCatSlash(tempPath, name);
1520 strcpy(tempPath, path);
1521 PathCatSlash(tempPath, name);
1523 EscapeForMake(modulePath, tempPath, false, true, false);
1524 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1525 items.Add(CopyString(s));
1527 else if(printType == sources)
1529 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1530 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1531 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1533 char modulePath[MAX_LOCATION];
1534 EscapeForMake(modulePath, path, false, true, false);
1535 EscapeForMake(moduleName, name, false, true, false);
1536 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1537 items.Add(CopyString(s));
1540 else if(printType == eCsources)
1542 if(!strcmpi(extension, "ec"))
1544 char modulePath[MAX_LOCATION];
1545 EscapeForMake(modulePath, path, true, true, false);
1546 EscapeForMake(moduleName, name, true, true, false);
1547 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1548 items.Add(CopyString(s));
1552 else if(printType == rcSources)
1554 if(!strcmpi(extension, "rc"))
1556 char modulePath[MAX_LOCATION];
1557 EscapeForMake(modulePath, path, false, true, false);
1558 EscapeForMake(moduleName, name, false, true, false);
1559 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1560 items.Add(CopyString(s));
1564 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1565 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1566 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1568 if(printType == objects)
1571 NameCollisionInfo info;
1573 EscapeForMake(moduleName, name, false, true, false);
1574 StripExtension(moduleName);
1575 info = namesInfo[moduleName];
1576 collision = info ? info.IsExtensionColliding(extension) : false;
1577 sprintf(s, "%s$(OBJ)%s%s%s$(O)%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1578 items.Add(CopyString(s));
1579 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1580 *containsCXX = true;
1589 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1590 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1596 void GenMakefilePrintSymbolRules(File f, Project project,
1597 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1598 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1601 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1602 //ProjectNode child;
1603 //char objDir[MAX_LOCATION];
1604 //ReplaceSpaces(objDir, config.objDir.dir);
1606 //eSystem_Log("Printing Symbol Rules\n");
1609 char extension[MAX_EXTENSION];
1610 char modulePath[MAX_LOCATION];
1611 char moduleName[MAX_FILENAME];
1613 GetExtension(name, extension);
1614 if(!strcmpi(extension, "ec"))
1617 //char command[2048];
1619 ReplaceSpaces(moduleName, name);
1620 StripExtension(moduleName);
1622 ReplaceSpaces(modulePath, path);
1623 if(modulePath[0]) strcat(modulePath, SEPS);
1625 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1627 // *** Dependency command ***
1628 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1629 modulePath, moduleName, extension);
1631 // System Includes (from global settings)
1632 for(item : compiler.dirs[Includes])
1634 strcat(command, " -isystem ");
1635 if(strchr(item, ' '))
1637 strcat(command, "\"");
1638 strcat(command, item);
1639 strcat(command, "\"");
1642 strcat(command, item);
1645 for(item : project.includeDirs)
1647 strcat(command, " -I");
1648 if(strchr(item, ' '))
1650 strcat(command, "\"");
1651 strcat(command, item);
1652 strcat(command, "\"");
1655 strcat(command, item);
1657 for(item : project.preprocessorDefs)
1659 strcat(command, " -D");
1660 strcat(command, item);
1664 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1667 bool firstLine = true;
1670 // To do some time: auto save external dependencies?
1673 if(dep.GetLine(line, sizeof(line)-1))
1677 char * colon = strstr(line, ":");
1678 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1692 // If we failed to generate dependencies...
1696 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1697 moduleName, modulePath, moduleName, extension);
1701 f.Puts(" $(CFLAGS)");
1702 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1704 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1705 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1707 /*f.Printf(" %s$(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1708 emAltExt ? "" : "-c ",*/
1709 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1710 modulePath, moduleName, extension);
1711 if(ifCount) f.Puts("endif\n");
1721 if(ContainsFilesWithExtension("ec", prjConfig))
1725 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1726 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1727 nodeCFlagsMapping, nodeECFlagsMapping);
1734 void GenMakefilePrintPrepecsRules(File f, Project project,
1735 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1736 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1739 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1740 //ProjectNode child;
1741 //char objDir[MAX_LOCATION];
1742 //ReplaceSpaces(objDir, config.objDir.dir);
1744 //eSystem_Log("Printing Symbol Rules\n");
1747 char extension[MAX_EXTENSION];
1748 char modulePath[MAX_LOCATION];
1749 char moduleName[MAX_FILENAME];
1751 GetExtension(name, extension);
1752 if(!strcmpi(extension, "ec"))
1754 ReplaceSpaces(moduleName, name);
1755 StripExtension(moduleName);
1757 ReplaceSpaces(modulePath, path);
1758 if(modulePath[0]) strcat(modulePath, SEPS);
1760 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1761 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1762 moduleName, modulePath, moduleName, extension);
1763 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1764 modulePath, moduleName, extension, moduleName);*/
1768 f.Puts(" $(CFLAGS)");
1769 //f.Puts(" $(CECFLAGS)");
1770 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1771 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1773 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1774 modulePath, moduleName, extension, moduleName);
1775 if(ifCount) f.Puts("endif\n");
1781 if(ContainsFilesWithExtension("ec", prjConfig))
1785 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1786 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1787 nodeCFlagsMapping, nodeECFlagsMapping);
1794 void GenMakefilePrintCObjectRules(File f, Project project,
1795 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1796 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1799 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1800 //ProjectNode child;
1801 //char objDir[MAX_LOCATION];
1802 //ReplaceSpaces(objDir, config.objDir.dir);
1803 //eSystem_Log("Printing C Object Rules\n");
1806 char extension[MAX_EXTENSION];
1807 char modulePath[MAX_LOCATION];
1808 char moduleName[MAX_FILENAME];
1810 GetExtension(name, extension);
1811 if(!strcmpi(extension, "ec"))
1814 //char command[2048];
1816 ReplaceSpaces(moduleName, name);
1817 StripExtension(moduleName);
1819 ReplaceSpaces(modulePath, path);
1820 if(modulePath[0]) strcat(modulePath, SEPS);
1822 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1824 // *** Dependency command ***
1825 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1826 moduleName, modulePath, moduleName, extension);
1828 // System Includes (from global settings)
1829 for(item : compiler.dirs[Includes])
1831 strcat(command, " -isystem ");
1832 if(strchr(item, ' '))
1834 strcat(command, "\"");
1835 strcat(command, item);
1836 strcat(command, "\"");
1839 strcat(command, item);
1842 for(item : config.includeDirs)
1844 strcat(command, " -I");
1845 if(strchr(item, ' '))
1847 strcat(command, "\"");
1848 strcat(command, item);
1849 strcat(command, "\"");
1852 strcat(command, item);
1854 for(item : config.preprocessorDefs)
1856 strcat(command, " -D");
1857 strcat(command, item);
1861 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1865 bool firstLine = true;
1867 // To do some time: auto save external dependencies?
1870 if(dep.GetLine(line, sizeof(line)-1))
1874 char * colon = strstr(line, ":");
1875 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1889 // If we failed to generate dependencies...
1892 /* COMMENTED OUT FOR NOW
1893 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1894 moduleName, modulePath, moduleName, extension);
1897 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1898 moduleName, modulePath, moduleName, extension, moduleName);
1904 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1905 modulePath, moduleName, extension, moduleName);
1910 f.Puts(" $(CFLAGS)");
1911 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1912 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1913 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1914 f.Puts(" $(FVISIBILITY)");
1916 /*f.Printf(" %s$(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1917 emAltExt ? "" : "-c ",
1918 modulePath, moduleName, extension);*/
1919 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1920 modulePath, moduleName, extension);
1921 if(ifCount) f.Puts("endif\n");
1927 if(ContainsFilesWithExtension("ec", prjConfig))
1931 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1932 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1933 nodeCFlagsMapping, nodeECFlagsMapping);
1940 void GenMakefilePrintObjectRules(File f, Project project,
1941 Map<String, NameCollisionInfo> namesInfo,
1942 ProjectConfig prjConfig,
1943 //Map<Platform, bool> parentExcludedPlatforms,
1944 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1947 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1948 //ProjectNode child;
1949 //char objDir[MAX_LOCATION];
1950 //ReplaceSpaces(objDir, config.objDir.dir);
1951 //eSystem_Log("Printing Object Rules\n");
1955 char extension[MAX_EXTENSION];
1956 char modulePath[MAX_LOCATION];
1957 char moduleName[MAX_FILENAME];
1959 GetExtension(name, extension);
1960 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1961 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1962 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1965 //char command[2048];
1966 NameCollisionInfo info;
1968 ReplaceSpaces(moduleName, name);
1969 StripExtension(moduleName);
1971 info = namesInfo[moduleName];
1972 collision = info ? info.IsExtensionColliding(extension) : false;
1974 ReplaceSpaces(modulePath, path);
1975 if(modulePath[0]) strcat(modulePath, SEPS);
1979 // *** Dependency command ***
1980 if(!strcmpi(extension, "ec"))
1981 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1983 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1984 moduleName, modulePath, moduleName, extension);
1986 if(!strcmpi(extension, "ec"))
1988 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1992 // System Includes (from global settings)
1993 for(item : compiler.dirs[includes])
1995 strcat(command, " -isystem ");
1996 if(strchr(item, ' '))
1998 strcat(command, "\"");
1999 strcat(command, item);
2000 strcat(command, "\"");
2003 strcat(command, item);
2006 for(item : config.includeDirs)
2008 strcat(command, " -I");
2009 if(strchr(item, ' '))
2011 strcat(command, "\"");
2012 strcat(command, item);
2013 strcat(command, "\"");
2016 strcat(command, item);
2018 for(item : config.preprocessorDefs)
2020 strcat(command, " -D");
2021 strcat(command, item);
2025 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2028 bool firstLine = true;
2031 // To do some time: auto save external dependencies?
2035 if(dep.GetLine(line, sizeof(line)-1))
2039 char * colon = strstr(line, ":");
2040 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2054 // If we failed to generate dependencies...
2063 if(!strcmpi(extension, "rc"))
2066 f.Puts("ifdef WINDOWS_TARGET\n\n");
2069 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2071 if(!strcmpi(extension, "ec"))
2072 f.Printf("$(OBJ)%s$(O): $(OBJ)%s.c\n", moduleName, moduleName);
2074 f.Printf("$(OBJ)%s%s%s$(O): %s%s.%s\n",
2075 moduleName, collision ? "." : "", collision ? extension : "",
2076 modulePath, moduleName, extension);
2077 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2078 f.Printf("\t$(CXX)");
2079 else if(!strcmpi(extension, "rc"))
2080 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2082 f.Printf("\t$(CC)");
2084 if(strcmpi(extension, "rc") != 0)
2086 f.Puts(" $(CFLAGS)");
2087 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2089 if(!strcmpi(extension, "ec"))
2090 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n",
2093 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2094 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2096 if(ifCount) f.Puts("endif\n");
2102 bool needed = false;
2105 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2115 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2116 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2117 nodeCFlagsMapping, nodeECFlagsMapping);
2124 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2131 //Iterator<ProjectNode> i { files };
2132 //Iterator<ProjectNode> prev { files };
2133 //for(child : files)
2135 for(c = 0; c < files.count; c++)
2137 ProjectNode child = files[c];
2138 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2141 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2144 char tempPath[MAX_LOCATION];
2145 char resPath[MAX_LOCATION];
2147 // $(EAR) aw%s --- /*quiet ? "q" : */""
2149 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2152 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2155 PathCatSlash(tempPath, child.name);
2160 strcpy(tempPath, child.path);
2161 PathCatSlash(tempPath, child.name);
2163 EscapeForMake(resPath, tempPath, false, true, false);
2164 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2167 if(count == 10 || (count > 0 && (ts || !child.next)))
2169 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2172 for(parent = this; parent.type == folder; parent = parent.parent)
2175 strcpy(path, parent.name);
2182 f.Printf(" \"%s\"%s\n", path, ts.b);
2194 if(child.type == folder)
2195 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2200 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2201 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2202 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2203 Map<Platform, ProjectOptions> parentByPlatformOptions)
2205 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2206 if(type == file || type == folder || type == project)
2208 bool hasPerNodeOptions = type == project;
2209 if(!hasPerNodeOptions)
2211 if(options && !options.isEmpty)
2212 hasPerNodeOptions = true;
2213 else if(configurations)
2215 for(c : configurations)
2217 if(c.options && !c.options.isEmpty)
2219 hasPerNodeOptions = true;
2224 for(p : c.platforms)
2226 if(p.options && !p.options.isEmpty)
2228 hasPerNodeOptions = true;
2232 if(hasPerNodeOptions)
2237 if(!hasPerNodeOptions && platforms)
2241 if(p.options && !p.options.isEmpty)
2243 hasPerNodeOptions = true;
2250 if(hasPerNodeOptions)
2252 bool isEqual = false, isGreater = false;
2253 ComplexComparison complexCmp;
2255 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2256 ProjectOptions platformsCommonOptions;
2257 ProjectOptions byFileConfigPlatformProjectOptions;
2259 DynamicString cflags { };
2260 DynamicString ecflags { };
2264 byPlatformOptions = { };
2266 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2268 byFileConfigPlatformProjectOptions =
2269 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2270 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2273 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2275 byPlatformOptions[unknown] = platformsCommonOptions;
2277 if(parentByPlatformOptions)
2279 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2280 parentByPlatformOptions, additionsByPlatformOptions);
2281 isGreater = complexCmp == greater;
2282 isEqual = complexCmp == equal;
2287 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2289 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2291 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2293 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2296 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2298 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2302 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2304 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2307 if(!isGreater) cflags.concat(" \\\n\t");
2312 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2315 ecflags.concat(" \\\n\t");
2322 cflags.concat(" \\\n\t");
2323 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2327 additionsByPlatformOptions.Free();
2328 delete additionsByPlatformOptions;
2334 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2335 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2343 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2344 cflagsVariations[s] = variationNum = cflagsVariations.count;
2345 nodeCFlagsMapping[(intptr)this] = variationNum;
2348 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2349 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2350 nodeECFlagsMapping[(intptr)this] = variationNum;
2361 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2362 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2370 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2371 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2372 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2377 if(byPlatformOptions != parentByPlatformOptions)
2379 byPlatformOptions.Free();
2380 delete byPlatformOptions;
2384 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2386 Array<Platform> platforms { };
2387 Map<Platform, SetBool> exclusionInfo { };
2388 CollectExclusionInfo(exclusionInfo, prjConfig);
2390 if(exclusionInfo[unknown] == true)
2392 if(exclusionInfo.count > 1)
2393 for(p : exclusionInfo; p == false)
2398 bool onlyOnknown = true;
2399 for(p : exclusionInfo)
2400 if(&p != unknown && p == true)
2402 onlyOnknown = false;
2406 platforms.Add(unknown);
2410 for(p = unknown + 1; p < Platform::enumSize; p++)
2411 if(exclusionInfo[p] != true)
2415 delete exclusionInfo;
2419 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, const char * objectFileExt, DynamicString output)
2421 char moduleName[MAX_FILENAME];
2424 bool headerAltFailed = false;
2426 char extension[MAX_EXTENSION];
2427 NameCollisionInfo info;
2428 Project prj = property::project;
2429 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2431 GetExtension(name, extension);
2432 strcpy(moduleName, name);
2433 StripExtension(moduleName);
2434 info = namesInfo[moduleName];
2435 collision = info ? info.IsExtensionColliding(extension) : false;
2437 for(h2s : headerToSource)
2439 if(!strcmpi(extension, &h2s))
2441 char filePath[MAX_LOCATION];
2442 GetFullFilePath(filePath);
2443 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2444 ChangeExtension(moduleName, h2s, moduleName);
2445 if(prj.topNode.Find(moduleName, false))
2447 strcpy(extension, h2s);
2448 collision = info ? info.IsExtensionColliding(extension) : false;
2449 ChangeExtension(filePath, h2s, filePath);
2450 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2451 StripExtension(moduleName);
2455 headerAltFailed = true;
2456 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2457 StripExtension(moduleName);
2463 if(!headerAltFailed)
2465 output.concat(" \"");
2466 output.concat(objDir); //.concat(" $(OBJ)");
2471 strcat(moduleName, ".");
2472 strcat(moduleName, extension);
2474 strcat(moduleName, ".");
2475 strcat(moduleName, objectFileExt);
2476 output.concat(moduleName);
2477 output.concat("\"");
2480 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2482 Project prj = property::project;
2484 ReplaceSpaces(moduleName, prj.moduleName);
2485 strcat(moduleName, ".main.ec");
2486 output.concat(" \"");
2487 output.concat(objDir);
2489 output.concat(moduleName);
2490 output.concat("\"");
2492 ChangeExtension(moduleName, "c", moduleName);
2493 output.concat(" \"");
2494 output.concat(objDir);
2496 output.concat(moduleName);
2497 output.concat("\"");
2499 ChangeExtension(moduleName, "o", moduleName);
2500 output.concat(" \"");
2501 output.concat(objDir);
2503 output.concat(moduleName);
2504 output.concat("\"");
2510 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2511 child.GetTargets(prjConfig, namesInfo, objDir, objectFileExt, output);
2516 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2521 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
2522 char extension[MAX_EXTENSION];
2523 char fileName[MAX_FILENAME];
2524 char moduleName[MAX_FILENAME];
2525 NameCollisionInfo info;
2526 Project prj = property::project;
2527 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2529 GetExtension(name, extension);
2530 ReplaceSpaces(moduleName, name);
2531 StripExtension(moduleName);
2532 info = namesInfo[moduleName];
2533 collision = info ? info.IsExtensionColliding(extension) : false;
2535 strcpy(fileName, prj.topNode.path);
2536 PathCatSlash(fileName, objDir.dir);
2537 PathCatSlash(fileName, name);
2539 if(!onlyCObject && !strcmp(extension, "ec"))
2541 ChangeExtension(fileName, "c", fileName);
2542 if(FileExists(fileName)) DeleteFile(fileName);
2543 ChangeExtension(fileName, "sym", fileName);
2544 if(FileExists(fileName)) DeleteFile(fileName);
2545 ChangeExtension(fileName, "imp", fileName);
2546 if(FileExists(fileName)) DeleteFile(fileName);
2547 ChangeExtension(fileName, "bowl", fileName);
2548 if(FileExists(fileName)) DeleteFile(fileName);
2549 ChangeExtension(fileName, "ec", fileName);
2554 strcat(fileName, ".");
2555 strcat(fileName, objectFileExt);
2558 ChangeExtension(fileName, objectFileExt, fileName);
2559 if(FileExists(fileName)) DeleteFile(fileName);
2567 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2568 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2573 bool IsInNode(ProjectNode node)
2575 bool result = false;
2577 for(n = this; n; n = n.parent)
2589 // the code in this function is closely matched to OptionsBox::Load
2590 // and accompanying derivations of OptionBox and their use of OptionSet,
2591 // OptionCheck, LoadOption and FinalizeLoading methods.
2592 // output changing modification should be mirrored in both implementations
2593 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2595 ProjectOptions output { };
2597 // legend: e Element
2598 // o Option (of a ProjectOptions)
2599 // n Node (ProjectNode)
2601 // u Utility (GenericOptionTools)
2605 int includeDirsOption = OPTION(includeDirs);
2607 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2609 // OPTION(ProjectOptions' last member) for size
2610 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2611 Array<bool> optionDone { size = OPTION(installCommands) };
2612 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2614 GenericOptionTools<SetBool> utilSetBool {
2615 bool OptionCheck(ProjectOptions options, int option) {
2616 return *(SetBool*)((byte *)options + option) == true;
2618 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2619 if(options && (*(SetBool*)((byte *)options + option) == true))
2620 *(SetBool*)((byte *)output + option) = true;
2623 GenericOptionTools<String> utilString {
2624 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2625 String * string = (String*)((byte *)output + option);
2626 if(*string) delete *string;
2628 *string = CopyString(*(String*)((byte *)options + option));
2631 StringArrayOptionTools utilStringArrays {
2633 caseSensitive = true;
2634 bool OptionCheck(ProjectOptions options, int option) {
2635 Array<String> strings = *(Array<String>*)((byte *)options + option);
2636 return strings && strings.count;
2638 bool OptionSet(ProjectOptions options, int option) {
2639 Array<String> strings = *(Array<String>*)((byte *)options + option);
2640 if(mergeValues && !configReplaces)
2641 return strings && strings.count;
2643 return strings != null;
2645 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2648 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2652 Array<String> tempStrings = optionTempStrings[option];
2654 optionTempStrings[option] = tempStrings = { };
2658 char priorityMark[10];
2661 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2662 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2663 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2669 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2670 Array<String> * strings = (Array<String>*)((byte *)output + option);
2671 if(*strings) { strings->Free(); delete *strings; }
2672 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2675 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2678 Array<String> tempStrings = optionTempStrings[option];
2679 Array<String> * strings = (Array<String>*)((byte *)output + option);
2680 if(*strings) { strings->Free(); delete *strings; }
2681 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2686 GenericOptionTools<WarningsOption> utilWarningsOption {
2687 bool OptionCheck(ProjectOptions options, int option) {
2688 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2689 return value && value != none;
2691 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2692 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2693 *(WarningsOption*)((byte *)output + option) = value;
2696 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2697 bool OptionCheck(ProjectOptions options, int option) {
2698 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2699 return value && value != none;
2701 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2702 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2703 *(OptimizationStrategy*)((byte *)output + option) = value;
2707 Map<int, GenericOptionTools> ot { };
2709 // The following are compiler options
2711 ot[OPTION(debug)] = utilSetBool;
2712 ot[OPTION(memoryGuard)] = utilSetBool;
2713 ot[OPTION(profile)] = utilSetBool;
2714 ot[OPTION(noLineNumbers)] = utilSetBool;
2715 ot[OPTION(strictNameSpaces)] = utilSetBool;
2716 ot[OPTION(fastMath)] = utilSetBool;
2718 ot[OPTION(defaultNameSpace)] = utilString;
2720 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2721 ot[OPTION(includeDirs)] = utilStringArrays;
2723 ot[OPTION(warnings)] = utilWarningsOption;
2725 ot[OPTION(optimization)] = utilOptimizationStrategy;
2727 for(n = node; n; n = n.parent)
2729 ProjectConfig nodeConfig = null;
2731 priority = (priority / 10 + 1) * 10;
2734 if(projectConfig && n.configurations)
2736 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2738 if(platform && c.platforms)
2740 for(p : c.platforms; !strcmpi(p.name, platformName))
2744 GenericOptionTools u = uu;
2746 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2748 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2749 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2750 optionConfigXplatformSet[o] = true;
2762 GenericOptionTools u = uu;
2766 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2768 for(p : n.platforms; !strcmpi(p.name, platformName))
2770 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2772 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2773 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2778 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2779 ((u.mergeValues && !u.configReplaces) ?
2780 u.OptionCheck(nodeConfig.options, o) :
2781 u.OptionSet(nodeConfig.options, o)))
2783 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2784 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2788 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2790 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2791 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2795 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2796 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2804 GenericOptionTools u = uu;
2807 u.FinalizeLoading(o, optionTempStrings, output);
2810 delete optionConfigXplatformSet;
2812 delete optionTempStrings;
2816 delete utilStringArrays;
2817 delete utilWarningsOption;
2818 delete utilOptimizationStrategy;
2825 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2827 ProjectOptions first = null;
2828 ProjectOptions commonOptions;
2830 Map<String, int> countIncludeDirs { };
2831 Map<String, int> countPreprocessorDefinitions { };
2832 Map<String, bool> commonIncludeDirs { };
2833 Map<String, bool> commonPreprocessorDefinitions { };
2835 for(options : byPlatformOptions) { first = options; break; }
2837 *platformsCommonOptions = commonOptions = first ? first.Copy() : { };
2839 if(commonOptions.includeDirs)
2840 commonOptions.includeDirs.Free();
2841 if(commonOptions.preprocessorDefinitions)
2842 commonOptions.preprocessorDefinitions.Free();
2844 for(options : byPlatformOptions)
2846 if(options != first)
2848 if(commonOptions.debug && options.debug != commonOptions.debug)
2849 commonOptions.debug = unset;
2850 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2851 commonOptions.memoryGuard = unset;
2852 if(commonOptions.profile && options.profile != commonOptions.profile)
2853 commonOptions.profile = unset;
2854 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2855 commonOptions.noLineNumbers = unset;
2856 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2857 commonOptions.strictNameSpaces = unset;
2858 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2859 commonOptions.fastMath = unset;
2861 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2862 commonOptions.warnings = unset;
2863 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2864 commonOptions.optimization = unset;
2866 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2867 delete commonOptions.defaultNameSpace;
2870 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2871 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2874 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2875 commonIncludeDirs, commonOptions.includeDirs);
2876 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2877 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2879 for(options : byPlatformOptions)
2881 if(options.debug && options.debug == commonOptions.debug)
2882 options.debug = unset;
2883 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2884 options.memoryGuard = unset;
2885 if(options.profile && options.profile == commonOptions.profile)
2886 options.profile = unset;
2887 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2888 options.noLineNumbers = unset;
2889 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2890 options.strictNameSpaces = unset;
2891 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2892 options.fastMath = unset;
2894 if(options.warnings && options.warnings == commonOptions.warnings)
2895 options.warnings = unset;
2896 if(options.optimization && options.optimization == commonOptions.optimization)
2897 options.optimization = unset;
2899 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2900 delete options.defaultNameSpace;
2902 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2903 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2906 delete countIncludeDirs;
2907 delete countPreprocessorDefinitions;
2908 delete commonIncludeDirs;
2909 delete commonPreprocessorDefinitions;
2912 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2913 Map<Platform, ProjectOptions> parentByPlatformOptions,
2914 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2916 ComplexComparison result = equal;
2917 ComplexComparison compare;
2919 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2921 ProjectOptions additionalOptions;
2922 additionsByPlatformOptions[platform] = { };
2923 additionalOptions = additionsByPlatformOptions[platform];
2924 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2925 if(compare == greater && result == equal)
2927 else if(compare == different)
2936 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2938 ComplexComparison result = equal;
2939 if(options.debug != parentOptions.debug ||
2940 options.memoryGuard != parentOptions.memoryGuard ||
2941 options.profile != parentOptions.profile ||
2942 options.noLineNumbers != parentOptions.noLineNumbers ||
2943 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2944 options.fastMath != parentOptions.fastMath ||
2945 options.warnings != parentOptions.warnings ||
2946 options.optimization != parentOptions.optimization ||
2947 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2948 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2952 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2953 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2955 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2956 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2962 enum ComplexComparison { different/*, smaller*/, equal, greater };
2964 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2967 if((!strings || !strings.count) && originals && originals.count)
2969 else if(strings && strings.count && (!originals || !originals.count))
2974 additions->Add(CopyString(s));
2976 else if(strings && strings.count && originals && originals.count)
2978 Map<String, String> map { };
2979 MapIterator<String, bool> mit { map = map };
2982 char * s = strstr(it, "\n");
2988 char * s = strstr(it, "\n");
2990 if(!mit.Index(s, false))
3005 additions->Add(CopyString(it));
3013 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3026 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3033 const char * s = ⁢
3034 strings.Add(CopyString(s));
3040 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3044 Array<String> tmp { };
3045 MapIterator<String, bool> mit { map = common };
3049 if(!mit.Index(s, false))
3050 tmp.Add(CopyString(s));
3056 strings.Add(CopyString(s));
3063 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3066 customFlags = nodeFlagsMapping[(intptr)node];
3068 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3070 f.Printf(" $(%s)", variableName);
3073 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3076 customFlags = nodeFlagsMapping[(intptr)node];
3078 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3080 s.concatf(" $(%s)", variableName);
3083 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3089 if(options.optimization == speed || options.optimization == size ||
3090 options.fastMath == true || options.debug == true)
3092 if(options.debug != true)
3094 s.concat(" $(if $(DEBUG),");
3098 switch(options.optimization)
3100 case speed: s.concat(" -O2"); break;
3101 case size: s.concat(" -Os"); break;
3103 if(options.fastMath == true)
3104 s.concat(" -ffast-math");
3105 if(options.debug == true)
3107 if(options.debug != true)
3110 else if(commonOptions)
3111 s.concat(" $(if $(DEBUG),-g)");
3113 s.concat(" $(FPIC)");
3115 switch(options.warnings)
3117 case all: s.concat(" -Wall"); break;
3118 case none: s.concat(" -w"); break;
3123 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3126 if(options && options.preprocessorDefinitions)
3127 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3128 if(options && options.includeDirs)
3129 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3132 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3134 if(options.memoryGuard == true)
3135 s.concat(" -memguard");
3136 if(options.noLineNumbers == true)
3137 s.concat(" -nolinenumbers");
3138 if(options.strictNameSpaces == true)
3139 s.concat(" -strictns");
3140 if(options.defaultNameSpace && options.defaultNameSpace[0])
3141 s.concatf(" -defaultns %s", options.defaultNameSpace);
3144 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3145 LineOutputMethod lineMethod, const String newLineStart)
3149 if(lineMethod == newLine)
3151 output.concat(" \\\n");
3152 output.concat(newLineStart);
3156 Map<String, int> sortedList { };
3157 MapNode<String, int> mn;
3159 sortedList[item] = 1;
3160 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3162 char * start = strstr(mn.key, "\n");
3163 if(lineMethod == lineEach)
3165 output.concat(" \\\n");
3166 output.concat(newLineStart);
3169 output.concat(flagNames[flag]);
3170 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3178 if(lineMethod == lineEach)
3180 output.concat(" \\\n");
3181 output.concat(newLineStart);
3184 output.concat(flagNames[flag]);
3185 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3191 class GenericOptionTools<class X>
3193 bool mergeValues, configReplaces;
3195 virtual bool OptionSet(ProjectOptions options, int option) {
3196 if(*(X*)((byte *)options + option))
3201 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3203 virtual bool OptionCheck(ProjectOptions options, int option) {
3204 return OptionSet(options, option);
3207 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3208 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3211 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3216 class NameCollisionInfo
3229 bool IsExtensionColliding(char * extension)
3233 ((!strcmpi(extension, "c") && ec) ||
3234 (!strcmpi(extension, "rc") && (ec || c)) ||
3235 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3236 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3237 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3238 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3239 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3240 !strcmpi(extension, "mm")))