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(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1708 modulePath, moduleName, extension);
1709 if(ifCount) f.Puts("endif\n");
1719 if(ContainsFilesWithExtension("ec", prjConfig))
1723 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1724 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1725 nodeCFlagsMapping, nodeECFlagsMapping);
1732 void GenMakefilePrintPrepecsRules(File f, Project project,
1733 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1734 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1737 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1738 //ProjectNode child;
1739 //char objDir[MAX_LOCATION];
1740 //ReplaceSpaces(objDir, config.objDir.dir);
1742 //eSystem_Log("Printing Symbol Rules\n");
1745 char extension[MAX_EXTENSION];
1746 char modulePath[MAX_LOCATION];
1747 char moduleName[MAX_FILENAME];
1749 GetExtension(name, extension);
1750 if(!strcmpi(extension, "ec"))
1752 ReplaceSpaces(moduleName, name);
1753 StripExtension(moduleName);
1755 ReplaceSpaces(modulePath, path);
1756 if(modulePath[0]) strcat(modulePath, SEPS);
1758 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1759 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1760 moduleName, modulePath, moduleName, extension);
1761 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1762 modulePath, moduleName, extension, moduleName);*/
1766 f.Puts(" $(CFLAGS)");
1767 //f.Puts(" $(CECFLAGS)");
1768 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1769 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1771 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1772 modulePath, moduleName, extension, moduleName);
1773 if(ifCount) f.Puts("endif\n");
1779 if(ContainsFilesWithExtension("ec", prjConfig))
1783 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1784 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1785 nodeCFlagsMapping, nodeECFlagsMapping);
1792 void GenMakefilePrintCObjectRules(File f, Project project,
1793 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1794 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1797 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1798 //ProjectNode child;
1799 //char objDir[MAX_LOCATION];
1800 //ReplaceSpaces(objDir, config.objDir.dir);
1801 //eSystem_Log("Printing C Object Rules\n");
1804 char extension[MAX_EXTENSION];
1805 char modulePath[MAX_LOCATION];
1806 char moduleName[MAX_FILENAME];
1808 GetExtension(name, extension);
1809 if(!strcmpi(extension, "ec"))
1812 //char command[2048];
1814 ReplaceSpaces(moduleName, name);
1815 StripExtension(moduleName);
1817 ReplaceSpaces(modulePath, path);
1818 if(modulePath[0]) strcat(modulePath, SEPS);
1820 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1822 // *** Dependency command ***
1823 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1824 moduleName, modulePath, moduleName, extension);
1826 // System Includes (from global settings)
1827 for(item : compiler.dirs[Includes])
1829 strcat(command, " -isystem ");
1830 if(strchr(item, ' '))
1832 strcat(command, "\"");
1833 strcat(command, item);
1834 strcat(command, "\"");
1837 strcat(command, item);
1840 for(item : config.includeDirs)
1842 strcat(command, " -I");
1843 if(strchr(item, ' '))
1845 strcat(command, "\"");
1846 strcat(command, item);
1847 strcat(command, "\"");
1850 strcat(command, item);
1852 for(item : config.preprocessorDefs)
1854 strcat(command, " -D");
1855 strcat(command, item);
1859 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1863 bool firstLine = true;
1865 // To do some time: auto save external dependencies?
1868 if(dep.GetLine(line, sizeof(line)-1))
1872 char * colon = strstr(line, ":");
1873 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1887 // If we failed to generate dependencies...
1890 /* COMMENTED OUT FOR NOW
1891 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1892 moduleName, modulePath, moduleName, extension);
1895 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1896 moduleName, modulePath, moduleName, extension, moduleName);
1902 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1903 modulePath, moduleName, extension, moduleName);
1908 f.Puts(" $(CFLAGS)");
1909 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1910 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1911 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1912 f.Puts(" $(FVISIBILITY)");
1914 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1915 modulePath, moduleName, extension);
1916 if(ifCount) f.Puts("endif\n");
1922 if(ContainsFilesWithExtension("ec", prjConfig))
1926 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1927 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1928 nodeCFlagsMapping, nodeECFlagsMapping);
1935 void GenMakefilePrintObjectRules(File f, Project project,
1936 Map<String, NameCollisionInfo> namesInfo,
1937 ProjectConfig prjConfig,
1938 //Map<Platform, bool> parentExcludedPlatforms,
1939 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1942 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1943 //ProjectNode child;
1944 //char objDir[MAX_LOCATION];
1945 //ReplaceSpaces(objDir, config.objDir.dir);
1946 //eSystem_Log("Printing Object Rules\n");
1950 char extension[MAX_EXTENSION];
1951 char modulePath[MAX_LOCATION];
1952 char moduleName[MAX_FILENAME];
1954 GetExtension(name, extension);
1955 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1956 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1957 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1960 //char command[2048];
1961 NameCollisionInfo info;
1963 ReplaceSpaces(moduleName, name);
1964 StripExtension(moduleName);
1966 info = namesInfo[moduleName];
1967 collision = info ? info.IsExtensionColliding(extension) : false;
1969 ReplaceSpaces(modulePath, path);
1970 if(modulePath[0]) strcat(modulePath, SEPS);
1974 // *** Dependency command ***
1975 if(!strcmpi(extension, "ec"))
1976 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1978 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1979 moduleName, modulePath, moduleName, extension);
1981 if(!strcmpi(extension, "ec"))
1983 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1987 // System Includes (from global settings)
1988 for(item : compiler.dirs[includes])
1990 strcat(command, " -isystem ");
1991 if(strchr(item, ' '))
1993 strcat(command, "\"");
1994 strcat(command, item);
1995 strcat(command, "\"");
1998 strcat(command, item);
2001 for(item : config.includeDirs)
2003 strcat(command, " -I");
2004 if(strchr(item, ' '))
2006 strcat(command, "\"");
2007 strcat(command, item);
2008 strcat(command, "\"");
2011 strcat(command, item);
2013 for(item : config.preprocessorDefs)
2015 strcat(command, " -D");
2016 strcat(command, item);
2020 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2023 bool firstLine = true;
2026 // To do some time: auto save external dependencies?
2030 if(dep.GetLine(line, sizeof(line)-1))
2034 char * colon = strstr(line, ":");
2035 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2049 // If we failed to generate dependencies...
2058 if(!strcmpi(extension, "rc"))
2061 f.Puts("ifdef WINDOWS_TARGET\n\n");
2064 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2066 if(!strcmpi(extension, "ec"))
2067 f.Printf("$(OBJ)%s$(O): $(OBJ)%s.c\n", moduleName, moduleName);
2069 f.Printf("$(OBJ)%s%s%s$(O): %s%s.%s\n",
2070 moduleName, collision ? "." : "", collision ? extension : "",
2071 modulePath, moduleName, extension);
2072 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2073 f.Printf("\t$(CXX)");
2074 else if(!strcmpi(extension, "rc"))
2075 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2077 f.Printf("\t$(CC)");
2079 if(strcmpi(extension, "rc") != 0)
2081 f.Puts(" $(CFLAGS)");
2082 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2084 if(!strcmpi(extension, "ec"))
2085 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n",
2088 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2089 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2091 if(ifCount) f.Puts("endif\n");
2097 bool needed = false;
2100 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2110 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2111 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2112 nodeCFlagsMapping, nodeECFlagsMapping);
2119 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2126 //Iterator<ProjectNode> i { files };
2127 //Iterator<ProjectNode> prev { files };
2128 //for(child : files)
2130 for(c = 0; c < files.count; c++)
2132 ProjectNode child = files[c];
2133 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2136 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2139 char tempPath[MAX_LOCATION];
2140 char resPath[MAX_LOCATION];
2142 // $(EAR) aw%s --- /*quiet ? "q" : */""
2144 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2147 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2150 PathCatSlash(tempPath, child.name);
2155 strcpy(tempPath, child.path);
2156 PathCatSlash(tempPath, child.name);
2158 EscapeForMake(resPath, tempPath, false, true, false);
2159 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2162 if(count == 10 || (count > 0 && (ts || !child.next)))
2164 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2167 for(parent = this; parent.type == folder; parent = parent.parent)
2170 strcpy(path, parent.name);
2177 f.Printf(" \"%s\"%s\n", path, ts.b);
2189 if(child.type == folder)
2190 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2195 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2196 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2197 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2198 Map<Platform, ProjectOptions> parentByPlatformOptions)
2200 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2201 if(type == file || type == folder || type == project)
2203 bool hasPerNodeOptions = type == project;
2204 if(!hasPerNodeOptions)
2206 if(options && !options.isEmpty)
2207 hasPerNodeOptions = true;
2208 else if(configurations)
2210 for(c : configurations)
2212 if(c.options && !c.options.isEmpty)
2214 hasPerNodeOptions = true;
2219 for(p : c.platforms)
2221 if(p.options && !p.options.isEmpty)
2223 hasPerNodeOptions = true;
2227 if(hasPerNodeOptions)
2232 if(!hasPerNodeOptions && platforms)
2236 if(p.options && !p.options.isEmpty)
2238 hasPerNodeOptions = true;
2245 if(hasPerNodeOptions)
2247 bool isEqual = false, isGreater = false;
2248 ComplexComparison complexCmp;
2250 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2251 ProjectOptions platformsCommonOptions;
2252 ProjectOptions byFileConfigPlatformProjectOptions;
2254 DynamicString cflags { };
2255 DynamicString ecflags { };
2259 byPlatformOptions = { };
2261 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2263 byFileConfigPlatformProjectOptions =
2264 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2265 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2268 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2270 byPlatformOptions[unknown] = platformsCommonOptions;
2272 if(parentByPlatformOptions)
2274 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2275 parentByPlatformOptions, additionsByPlatformOptions);
2276 isGreater = complexCmp == greater;
2277 isEqual = complexCmp == equal;
2282 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2284 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2286 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2288 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2291 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2293 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2297 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2299 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2302 if(!isGreater) cflags.concat(" \\\n\t");
2307 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2310 ecflags.concat(" \\\n\t");
2317 cflags.concat(" \\\n\t");
2318 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2322 additionsByPlatformOptions.Free();
2323 delete additionsByPlatformOptions;
2329 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2330 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2338 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2339 cflagsVariations[s] = variationNum = cflagsVariations.count;
2340 nodeCFlagsMapping[(intptr)this] = variationNum;
2343 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2344 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2345 nodeECFlagsMapping[(intptr)this] = variationNum;
2356 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2357 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2365 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2366 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2367 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2372 if(byPlatformOptions != parentByPlatformOptions)
2374 byPlatformOptions.Free();
2375 delete byPlatformOptions;
2379 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2381 Array<Platform> platforms { };
2382 Map<Platform, SetBool> exclusionInfo { };
2383 CollectExclusionInfo(exclusionInfo, prjConfig);
2385 if(exclusionInfo[unknown] == true)
2387 if(exclusionInfo.count > 1)
2388 for(p : exclusionInfo; p == false)
2393 bool onlyOnknown = true;
2394 for(p : exclusionInfo)
2395 if(&p != unknown && p == true)
2397 onlyOnknown = false;
2401 platforms.Add(unknown);
2405 for(p = unknown + 1; p < Platform::enumSize; p++)
2406 if(exclusionInfo[p] != true)
2410 delete exclusionInfo;
2414 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, const char * objectFileExt, DynamicString output)
2416 char moduleName[MAX_FILENAME];
2419 bool headerAltFailed = false;
2421 char extension[MAX_EXTENSION];
2422 NameCollisionInfo info;
2423 Project prj = property::project;
2424 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2426 GetExtension(name, extension);
2427 strcpy(moduleName, name);
2428 StripExtension(moduleName);
2429 info = namesInfo[moduleName];
2430 collision = info ? info.IsExtensionColliding(extension) : false;
2432 for(h2s : headerToSource)
2434 if(!strcmpi(extension, &h2s))
2436 char filePath[MAX_LOCATION];
2437 GetFullFilePath(filePath);
2438 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2439 ChangeExtension(moduleName, h2s, moduleName);
2440 if(prj.topNode.Find(moduleName, false))
2442 strcpy(extension, h2s);
2443 collision = info ? info.IsExtensionColliding(extension) : false;
2444 ChangeExtension(filePath, h2s, filePath);
2445 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2446 StripExtension(moduleName);
2450 headerAltFailed = true;
2451 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2452 StripExtension(moduleName);
2458 if(!headerAltFailed)
2460 output.concat(" \"");
2461 output.concat(objDir); //.concat(" $(OBJ)");
2466 strcat(moduleName, ".");
2467 strcat(moduleName, extension);
2469 strcat(moduleName, ".");
2470 strcat(moduleName, objectFileExt);
2471 output.concat(moduleName);
2472 output.concat("\"");
2475 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2477 Project prj = property::project;
2479 ReplaceSpaces(moduleName, prj.moduleName);
2480 strcat(moduleName, ".main.ec");
2481 output.concat(" \"");
2482 output.concat(objDir);
2484 output.concat(moduleName);
2485 output.concat("\"");
2487 ChangeExtension(moduleName, "c", moduleName);
2488 output.concat(" \"");
2489 output.concat(objDir);
2491 output.concat(moduleName);
2492 output.concat("\"");
2494 ChangeExtension(moduleName, "o", moduleName);
2495 output.concat(" \"");
2496 output.concat(objDir);
2498 output.concat(moduleName);
2499 output.concat("\"");
2505 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2506 child.GetTargets(prjConfig, namesInfo, objDir, objectFileExt, output);
2511 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2516 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
2517 char extension[MAX_EXTENSION];
2518 char fileName[MAX_FILENAME];
2519 char moduleName[MAX_FILENAME];
2520 NameCollisionInfo info;
2521 Project prj = property::project;
2522 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2524 GetExtension(name, extension);
2525 ReplaceSpaces(moduleName, name);
2526 StripExtension(moduleName);
2527 info = namesInfo[moduleName];
2528 collision = info ? info.IsExtensionColliding(extension) : false;
2530 strcpy(fileName, prj.topNode.path);
2531 PathCatSlash(fileName, objDir.dir);
2532 PathCatSlash(fileName, name);
2534 if(!onlyCObject && !strcmp(extension, "ec"))
2536 ChangeExtension(fileName, "c", fileName);
2537 if(FileExists(fileName)) DeleteFile(fileName);
2538 ChangeExtension(fileName, "sym", fileName);
2539 if(FileExists(fileName)) DeleteFile(fileName);
2540 ChangeExtension(fileName, "imp", fileName);
2541 if(FileExists(fileName)) DeleteFile(fileName);
2542 ChangeExtension(fileName, "bowl", fileName);
2543 if(FileExists(fileName)) DeleteFile(fileName);
2544 ChangeExtension(fileName, "ec", fileName);
2549 strcat(fileName, ".");
2550 strcat(fileName, objectFileExt);
2553 ChangeExtension(fileName, objectFileExt, fileName);
2554 if(FileExists(fileName)) DeleteFile(fileName);
2562 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2563 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2568 bool IsInNode(ProjectNode node)
2570 bool result = false;
2572 for(n = this; n; n = n.parent)
2584 // the code in this function is closely matched to OptionsBox::Load
2585 // and accompanying derivations of OptionBox and their use of OptionSet,
2586 // OptionCheck, LoadOption and FinalizeLoading methods.
2587 // output changing modification should be mirrored in both implementations
2588 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2590 ProjectOptions output { };
2592 // legend: e Element
2593 // o Option (of a ProjectOptions)
2594 // n Node (ProjectNode)
2596 // u Utility (GenericOptionTools)
2600 int includeDirsOption = OPTION(includeDirs);
2602 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2604 // OPTION(ProjectOptions' last member) for size
2605 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2606 Array<bool> optionDone { size = OPTION(installCommands) };
2607 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2609 GenericOptionTools<SetBool> utilSetBool {
2610 bool OptionCheck(ProjectOptions options, int option) {
2611 return *(SetBool*)((byte *)options + option) == true;
2613 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2614 if(options && (*(SetBool*)((byte *)options + option) == true))
2615 *(SetBool*)((byte *)output + option) = true;
2618 GenericOptionTools<String> utilString {
2619 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2620 String * string = (String*)((byte *)output + option);
2621 if(*string) delete *string;
2623 *string = CopyString(*(String*)((byte *)options + option));
2626 StringArrayOptionTools utilStringArrays {
2628 caseSensitive = true;
2629 bool OptionCheck(ProjectOptions options, int option) {
2630 Array<String> strings = *(Array<String>*)((byte *)options + option);
2631 return strings && strings.count;
2633 bool OptionSet(ProjectOptions options, int option) {
2634 Array<String> strings = *(Array<String>*)((byte *)options + option);
2635 if(mergeValues && !configReplaces)
2636 return strings && strings.count;
2638 return strings != null;
2640 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2643 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2647 Array<String> tempStrings = optionTempStrings[option];
2649 optionTempStrings[option] = tempStrings = { };
2653 char priorityMark[10];
2656 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2657 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2658 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2664 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2665 Array<String> * strings = (Array<String>*)((byte *)output + option);
2666 if(*strings) { strings->Free(); delete *strings; }
2667 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2670 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2673 Array<String> tempStrings = optionTempStrings[option];
2674 Array<String> * strings = (Array<String>*)((byte *)output + option);
2675 if(*strings) { strings->Free(); delete *strings; }
2676 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2681 GenericOptionTools<WarningsOption> utilWarningsOption {
2682 bool OptionCheck(ProjectOptions options, int option) {
2683 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2684 return value && value != none;
2686 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2687 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2688 *(WarningsOption*)((byte *)output + option) = value;
2691 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2692 bool OptionCheck(ProjectOptions options, int option) {
2693 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2694 return value && value != none;
2696 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2697 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2698 *(OptimizationStrategy*)((byte *)output + option) = value;
2702 Map<int, GenericOptionTools> ot { };
2704 // The following are compiler options
2706 ot[OPTION(debug)] = utilSetBool;
2707 ot[OPTION(memoryGuard)] = utilSetBool;
2708 ot[OPTION(profile)] = utilSetBool;
2709 ot[OPTION(noLineNumbers)] = utilSetBool;
2710 ot[OPTION(strictNameSpaces)] = utilSetBool;
2711 ot[OPTION(fastMath)] = utilSetBool;
2713 ot[OPTION(defaultNameSpace)] = utilString;
2715 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2716 ot[OPTION(includeDirs)] = utilStringArrays;
2718 ot[OPTION(warnings)] = utilWarningsOption;
2720 ot[OPTION(optimization)] = utilOptimizationStrategy;
2722 for(n = node; n; n = n.parent)
2724 ProjectConfig nodeConfig = null;
2726 priority = (priority / 10 + 1) * 10;
2729 if(projectConfig && n.configurations)
2731 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2733 if(platform && c.platforms)
2735 for(p : c.platforms; !strcmpi(p.name, platformName))
2739 GenericOptionTools u = uu;
2741 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2743 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2744 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2745 optionConfigXplatformSet[o] = true;
2757 GenericOptionTools u = uu;
2761 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2763 for(p : n.platforms; !strcmpi(p.name, platformName))
2765 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2767 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2768 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2773 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2774 ((u.mergeValues && !u.configReplaces) ?
2775 u.OptionCheck(nodeConfig.options, o) :
2776 u.OptionSet(nodeConfig.options, o)))
2778 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2779 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2783 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2785 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2786 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2790 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2791 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2799 GenericOptionTools u = uu;
2802 u.FinalizeLoading(o, optionTempStrings, output);
2805 delete optionConfigXplatformSet;
2807 delete optionTempStrings;
2811 delete utilStringArrays;
2812 delete utilWarningsOption;
2813 delete utilOptimizationStrategy;
2820 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2822 ProjectOptions first = null;
2823 ProjectOptions commonOptions;
2825 Map<String, int> countIncludeDirs { };
2826 Map<String, int> countPreprocessorDefinitions { };
2827 Map<String, bool> commonIncludeDirs { };
2828 Map<String, bool> commonPreprocessorDefinitions { };
2830 for(options : byPlatformOptions) { first = options; break; }
2832 *platformsCommonOptions = commonOptions = first ? first.Copy() : { };
2834 if(commonOptions.includeDirs)
2835 commonOptions.includeDirs.Free();
2836 if(commonOptions.preprocessorDefinitions)
2837 commonOptions.preprocessorDefinitions.Free();
2839 for(options : byPlatformOptions)
2841 if(options != first)
2843 if(commonOptions.debug && options.debug != commonOptions.debug)
2844 commonOptions.debug = unset;
2845 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2846 commonOptions.memoryGuard = unset;
2847 if(commonOptions.profile && options.profile != commonOptions.profile)
2848 commonOptions.profile = unset;
2849 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2850 commonOptions.noLineNumbers = unset;
2851 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2852 commonOptions.strictNameSpaces = unset;
2853 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2854 commonOptions.fastMath = unset;
2856 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2857 commonOptions.warnings = unset;
2858 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2859 commonOptions.optimization = unset;
2861 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2862 delete commonOptions.defaultNameSpace;
2865 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2866 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2869 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2870 commonIncludeDirs, commonOptions.includeDirs);
2871 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2872 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2874 for(options : byPlatformOptions)
2876 if(options.debug && options.debug == commonOptions.debug)
2877 options.debug = unset;
2878 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2879 options.memoryGuard = unset;
2880 if(options.profile && options.profile == commonOptions.profile)
2881 options.profile = unset;
2882 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2883 options.noLineNumbers = unset;
2884 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2885 options.strictNameSpaces = unset;
2886 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2887 options.fastMath = unset;
2889 if(options.warnings && options.warnings == commonOptions.warnings)
2890 options.warnings = unset;
2891 if(options.optimization && options.optimization == commonOptions.optimization)
2892 options.optimization = unset;
2894 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2895 delete options.defaultNameSpace;
2897 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2898 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2901 delete countIncludeDirs;
2902 delete countPreprocessorDefinitions;
2903 delete commonIncludeDirs;
2904 delete commonPreprocessorDefinitions;
2907 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2908 Map<Platform, ProjectOptions> parentByPlatformOptions,
2909 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2911 ComplexComparison result = equal;
2912 ComplexComparison compare;
2914 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2916 ProjectOptions additionalOptions;
2917 additionsByPlatformOptions[platform] = { };
2918 additionalOptions = additionsByPlatformOptions[platform];
2919 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2920 if(compare == greater && result == equal)
2922 else if(compare == different)
2931 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2933 ComplexComparison result = equal;
2934 if(options.debug != parentOptions.debug ||
2935 options.memoryGuard != parentOptions.memoryGuard ||
2936 options.profile != parentOptions.profile ||
2937 options.noLineNumbers != parentOptions.noLineNumbers ||
2938 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2939 options.fastMath != parentOptions.fastMath ||
2940 options.warnings != parentOptions.warnings ||
2941 options.optimization != parentOptions.optimization ||
2942 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2943 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2947 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2948 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2950 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2951 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2957 enum ComplexComparison { different/*, smaller*/, equal, greater };
2959 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2962 if((!strings || !strings.count) && originals && originals.count)
2964 else if(strings && strings.count && (!originals || !originals.count))
2969 additions->Add(CopyString(s));
2971 else if(strings && strings.count && originals && originals.count)
2973 Map<String, String> map { };
2974 MapIterator<String, bool> mit { map = map };
2977 char * s = strstr(it, "\n");
2983 char * s = strstr(it, "\n");
2985 if(!mit.Index(s, false))
3000 additions->Add(CopyString(it));
3008 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3021 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3028 const char * s = ⁢
3029 strings.Add(CopyString(s));
3035 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3039 Array<String> tmp { };
3040 MapIterator<String, bool> mit { map = common };
3044 if(!mit.Index(s, false))
3045 tmp.Add(CopyString(s));
3051 strings.Add(CopyString(s));
3058 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3061 customFlags = nodeFlagsMapping[(intptr)node];
3063 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3065 f.Printf(" $(%s)", variableName);
3068 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3071 customFlags = nodeFlagsMapping[(intptr)node];
3073 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3075 s.concatf(" $(%s)", variableName);
3078 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3084 if(options.optimization == speed || options.optimization == size ||
3085 options.fastMath == true || options.debug == true)
3087 if(options.debug != true)
3089 s.concat(" $(if $(DEBUG),");
3093 switch(options.optimization)
3095 case speed: s.concat(" -O2"); break;
3096 case size: s.concat(" -Os"); break;
3098 if(options.fastMath == true)
3099 s.concat(" -ffast-math");
3100 if(options.debug == true)
3102 if(options.debug != true)
3105 else if(commonOptions)
3106 s.concat(" $(if $(DEBUG),-g)");
3108 s.concat(" $(FPIC)");
3110 switch(options.warnings)
3112 case all: s.concat(" -Wall"); break;
3113 case none: s.concat(" -w"); break;
3118 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3121 if(options && options.preprocessorDefinitions)
3122 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3123 if(options && options.includeDirs)
3124 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3127 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3129 if(options.memoryGuard == true)
3130 s.concat(" -memguard");
3131 if(options.noLineNumbers == true)
3132 s.concat(" -nolinenumbers");
3133 if(options.strictNameSpaces == true)
3134 s.concat(" -strictns");
3135 if(options.defaultNameSpace && options.defaultNameSpace[0])
3136 s.concatf(" -defaultns %s", options.defaultNameSpace);
3139 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3140 LineOutputMethod lineMethod, const String newLineStart)
3144 if(lineMethod == newLine)
3146 output.concat(" \\\n");
3147 output.concat(newLineStart);
3151 Map<String, int> sortedList { };
3152 MapNode<String, int> mn;
3154 sortedList[item] = 1;
3155 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3157 char * start = strstr(mn.key, "\n");
3158 if(lineMethod == lineEach)
3160 output.concat(" \\\n");
3161 output.concat(newLineStart);
3164 output.concat(flagNames[flag]);
3165 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3173 if(lineMethod == lineEach)
3175 output.concat(" \\\n");
3176 output.concat(newLineStart);
3179 output.concat(flagNames[flag]);
3180 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3186 class GenericOptionTools<class X>
3188 bool mergeValues, configReplaces;
3190 virtual bool OptionSet(ProjectOptions options, int option) {
3191 if(*(X*)((byte *)options + option))
3196 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3198 virtual bool OptionCheck(ProjectOptions options, int option) {
3199 return OptionSet(options, option);
3202 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3203 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3206 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3211 class NameCollisionInfo
3224 bool IsExtensionColliding(char * extension)
3228 ((!strcmpi(extension, "c") && ec) ||
3229 (!strcmpi(extension, "rc") && (ec || c)) ||
3230 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3231 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3232 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3233 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3234 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3235 !strcmpi(extension, "mm")))