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)
534 if(buffer && (this.type == file || (this.type == project && dotMain == true)))
537 char extension[MAX_EXTENSION];
538 char moduleName[MAX_FILENAME];
539 NameCollisionInfo info;
541 GetExtension(name, extension);
542 ReplaceSpaces(moduleName, name);
543 StripExtension(moduleName);
544 info = namesInfo[moduleName];
545 collision = info ? info.IsExtensionColliding(extension) : false;
549 Project prj = property::project;
550 ReplaceSpaces(buffer, prj.moduleName);
551 StripExtension(buffer);
552 strcat(buffer, ".main.ec");
555 strcpy(buffer, name);
556 if(!strcmp(extension, "ec") || dotMain)
559 ChangeExtension(buffer, "c", buffer);
561 ChangeExtension(buffer, "sym", buffer);
563 ChangeExtension(buffer, "imp", buffer);
564 else if(type == bowl)
565 ChangeExtension(buffer, "bowl", buffer);
570 strcat(buffer, ".o");
572 ChangeExtension(buffer, "o", buffer);
578 char * GetFileSysMatchingPath(char * buffer)
582 ProjectNode n, root = this.root;
583 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
585 strcpy(buffer, root.path);
587 PathCatSlash(buffer, n.path);
588 if(FileExists(buffer).isDirectory)
591 if(!(n && (n.type == folder || n.type == project)))
597 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
599 ProjectNode node = null;
600 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
601 List<ProjectNode> nodeStack { };
603 for(node = this; node && node.parent; node = node.parent)
606 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
608 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
609 while((node = nodeStack.lastIterator.data))
611 ProjectOptions nodeOptions = node.property::options;
612 if(nodeOptions && nodeOptions.preprocessorDefinitions)
614 for(def : nodeOptions.preprocessorDefinitions)
615 perFilePreprocessorDefs.Add(CopyString(def));
617 if(config && config.options && config.options.preprocessorDefinitions)
619 for(def : config.options.preprocessorDefinitions)
620 perFilePreprocessorDefs.Add(CopyString(def));
622 if(nodeOptions && nodeOptions.includeDirs)
624 for(dir : nodeOptions.includeDirs)
625 perFileIncludeDirs.Add(CopySystemPath(dir));
627 if(config && config.options && config.options.includeDirs)
629 for(dir : config.options.includeDirs)
630 perFileIncludeDirs.Add(CopySystemPath(dir));
632 nodeStack.lastIterator.Remove();
638 property Project project
642 ProjectNode n = this;
643 while(n && n.type != project) n = n.parent;
644 return n ? (*&n.project) : null;
648 void RenameConfig(const char * oldName, const char * newName)
652 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
654 if(property::configurations)
656 for(c : property::configurations; !strcmp(c.name, oldName))
659 c.name = CopyString(newName);
664 void DeleteConfig(ProjectConfig configToDelete)
668 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
670 if(property::configurations)
672 Iterator<ProjectConfig> c { property::configurations };
675 ProjectConfig config = c.data;
676 if(!strcmp(configToDelete.name, config.name))
683 if(!property::configurations.count)
684 property::configurations = null;
690 ProjectNode backupNode { };
694 backupNode.files = { };
695 for(f : files) backupNode.files.Add(f.Backup());
697 if(property::options)
698 backupNode.options = property::options.Copy();
700 if(property::platforms)
702 backupNode.platforms = { };
703 for(p : property::platforms)
704 backupNode.platforms.Add(p.Copy());
707 if(property::configurations)
709 backupNode.configurations = { };
710 for(c : property::configurations)
711 backupNode.configurations.Add(c.Copy());
716 void Revert(ProjectNode backupNode)
720 Iterator<ProjectNode> it { backupNode.files };
728 property::options = backupNode.options ? backupNode.options.Copy() : null;
729 if(backupNode.platforms)
731 Array<PlatformOptions> platforms { };
732 property::platforms = platforms;
734 for(p : backupNode.platforms)
735 platforms.Add(p.Copy());
737 if(backupNode.configurations)
739 List<ProjectConfig> configurations { };
740 property::configurations = configurations;
741 for(c : backupNode.configurations)
742 configurations.Add(c.Copy());
746 void FixupNode(char * parentPath)
752 else if(nodeType == file)
757 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
760 else if(nodeType == folder)
766 char temp[MAX_LOCATION];
767 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
768 PathCatSlash(temp, name);
769 path = CopyString(temp);
773 indent = parent ? parent.indent + 1 : 0;
776 icon = NodeIcons::SelectFileIcon(name);
778 icon = NodeIcons::SelectNodeIcon(type);
787 parentPath[0] = '\0';
788 else if(type == resources || type == folder)
789 strcpy(parentPath, path);
791 f.FixupNode(parentPath);
796 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
800 // TOCHECK: Called from JSON writer
801 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
803 strcpy(tempString, "\"");
804 strcat(tempString, property::fileName);
805 strcat(tempString, "\"");
812 // TOCHECK: Called from ProjectView rendering
813 return name ? name : "";
826 if(!project && platforms)
831 if(!project && configurations)
833 configurations.Free();
834 delete configurations;
837 /////////////////////////////
843 property bool isInResources
848 for(node = this; node; node = node.parent)
850 if(node.type == resources)
857 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
859 TwoStrings result { a = CopyString(""), b = CopyString("") };
860 // note: unknown platform is for common
861 Map<Platform, SetBool> exclusionInfo { };
862 MapNode<Platform, SetBool> mn;
868 CollectExclusionInfo(exclusionInfo, prjConfig);
869 common = exclusionInfo[unknown];
871 Map<Platform, SetBool> cleaned { };
872 SetBool opposite = common == true ? false : true;
873 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
875 if(mn.key == unknown || mn.value == opposite)
876 cleaned[mn.key] = mn.value;
878 delete exclusionInfo;
879 exclusionInfo = cleaned;
882 if(exclusionInfo.count > 1)
884 if(exclusionInfo.count > 2)
887 len = strlen(exp) + strlen("$(if $(or ");
888 exp = renew exp char[len+1];
889 strcat(exp, "$(if $(or ");
892 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
894 if(mn.key != unknown)
896 const char * comma = mn.next ? "," : "";
898 var = PlatformToMakefileTargetVariable(mn.key);
901 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
902 exp = renew exp char[len+1];
912 len = strlen(exp) + strlen("),");
913 exp = renew exp char[len+1];
917 if(exclusionInfo.root.minimum.key != unknown)
918 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
920 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
923 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
924 exp = renew exp char[len+1];
925 strcat(exp, "$(if $(");
932 exp = common == true ? result.b : result.a;
933 len = strlen(exp) + strlen(",");
934 exp = renew exp char[len+1];
936 if(common == true) result.b = exp; else result.a = exp;
939 len = strlen(exp) + strlen(")");
940 exp = renew exp char[len+1];
944 delete exclusionInfo;
949 bool GetIsExcluded(ProjectConfig prjConfig)
952 // note: unknown platform is for common
953 Map<Platform, SetBool> exclusionInfo { };
954 CollectExclusionInfo(exclusionInfo, prjConfig);
955 if(exclusionInfo.count == 0)
957 else if(exclusionInfo.count == 1)
958 result = exclusionInfo.root.minimum.value == true;
961 SetBool check = exclusionInfo.root.minimum.value;
962 MapNode<Platform, SetBool> mn;
963 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
965 if(check != mn.value)
968 if(!mn) // all are same
969 result = check == true;
973 delete exclusionInfo;
977 bool GetIsExcludedForCompiler(ProjectConfig prjConfig, CompilerConfig compiler)
980 Map<Platform, SetBool> exclusionInfo { };
981 SetBool common, platform;
982 CollectExclusionInfo(exclusionInfo, prjConfig);
983 common = exclusionInfo[unknown];
984 platform = exclusionInfo[compiler.targetPlatform];
985 result = platform == true || (common == true && platform == unset);
986 delete exclusionInfo;
990 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
992 // note: unknown platform is for common
994 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
995 ProjectOptions options = property::options;
996 Array<PlatformOptions> platforms = property::platforms;
999 parent.CollectExclusionInfo(output, prjConfig);
1001 output[unknown] = unset;
1003 if(options && options.excludeFromBuild)
1004 output[unknown] = options.excludeFromBuild;
1006 if(config && config.options && config.options.excludeFromBuild)
1007 output[unknown] = config.options.excludeFromBuild;
1013 if(p.options.excludeFromBuild && (platform = p.name))
1014 output[platform] = p.options.excludeFromBuild;
1017 if(config && config.platforms)
1019 for(p : config.platforms)
1021 if(p.options.excludeFromBuild && (platform = p.name))
1022 output[platform] = p.options.excludeFromBuild;
1027 void EnsureVisible()
1030 parent.EnsureVisible();
1031 row.collapsed = false;
1037 parent.files.Delete(this);
1040 ProjectNode Find(const char * name, bool includeResources)
1042 ProjectNode result = null;
1047 if(includeResources || child.type != resources)
1049 if(child.type != folder && child.name && !strcmpi(child.name, name))
1054 result = child.Find(name, includeResources);
1063 ProjectNode FindWithPath(const char * name, bool includeResources)
1065 ProjectNode result = null;
1070 if(includeResources || child.type != resources)
1072 char path[MAX_LOCATION];
1073 strcpy(path, child.path);
1074 if(child.type != folder && child.name)
1076 PathCatSlash(path, child.name);
1077 if(!strcmpi(path, name))
1083 result = child.FindWithPath(name, includeResources);
1092 ProjectNode FindByFullPath(const char * path, bool includeResources)
1096 char name[MAX_FILENAME];
1097 GetLastDirectory(path, name);
1098 return InternalFindByFullPath(path, includeResources, name);
1103 ProjectNode InternalFindByFullPath(const char * path, bool includeResources, const char * lastDirName)
1105 ProjectNode result = null;
1110 if(includeResources || child.type != resources)
1112 if(child.type != file)
1113 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1114 else if(child.name && !fstrcmp(lastDirName, child.name))
1116 char p[MAX_LOCATION];
1117 child.GetFullFilePath(p);
1118 if(!fstrcmp(p, path))
1132 ProjectNode FindByObjectFileName(const char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo)
1134 char p[MAX_LOCATION];
1135 ProjectNode result = null;
1136 if(dotMain == true && this.type == project)
1138 GetObjectFileName(p, namesInfo, type, dotMain);
1139 if(!fstrcmp(p, fileName))
1144 for(child : files; child.type != resources)
1146 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo)))
1148 else if(child.type == file && child.name)
1150 child.GetObjectFileName(p, namesInfo, type, dotMain);
1151 if(!fstrcmp(p, fileName))
1162 ProjectNode FindSpecial(const char * name, bool recursive, bool includeResources, bool includeFolders)
1164 ProjectNode result = null;
1169 if(includeResources || child.type != resources)
1171 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1177 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1186 ProjectNode FindSameNameConflict(const char * name, bool includeResources,
1187 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1189 ProjectNode result = null;
1190 Map<Platform, SetBool> compareExclusion { };
1191 SetBool common, commonComp;
1192 SetBool actual, actualComp;
1197 if(includeResources || child.type != resources)
1199 if(child.type != folder && child.name && !strcmpi(child.name, name))
1201 child.CollectExclusionInfo(compareExclusion, prjConfig);
1202 common = exclusionInfo[unknown];
1203 commonComp = compareExclusion[unknown];
1204 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1206 if(!(common == true || commonComp == true))
1215 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1218 actualComp = commonComp;
1219 if(exclusionInfo[platform] != unset)
1220 actual = exclusionInfo[platform];
1221 if(compareExclusion[platform] != unset)
1222 actualComp = compareExclusion[platform];
1223 if(!(actual == true || actualComp == true))
1231 compareExclusion.Free();
1234 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1238 compareExclusion.Free();
1240 delete compareExclusion;
1244 ProjectNode Add(Project project, const char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1246 ProjectNode node = null;
1247 if(!project.topNode.FindByFullPath(filePath, true))
1249 char temp[MAX_LOCATION];
1250 Map<Platform, SetBool> exclusionInfo { };
1252 GetLastDirectory(filePath, temp);
1253 //if(!checkIfExists || !project.topNode.Find(temp, false))
1255 // TOCHECK: Shouldn't this apply either for all configs or none?
1256 CollectExclusionInfo(exclusionInfo, project.config);
1257 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1259 // Do the check for folder in the same parent or resource files only here
1260 if(type == folder || !checkIfExists)
1264 if(node.name && !strcmpi(node.name, temp))
1269 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1273 node.nodeType = folder;
1279 StripLastDirectory(filePath, temp);
1280 MakePathRelative(temp, project.topNode.path, temp);
1281 node.path = CopyUnixPath(temp);
1283 node.nodeType = file;
1287 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1288 PathCatSlash(temp, node.name);
1289 node.path = CopyString(temp);
1291 files.Insert(after, node);
1293 delete exclusionInfo;
1298 #ifndef MAKEFILE_GENERATOR
1299 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1301 char label[MAX_FILENAME];
1306 bool showConfig = true;
1311 projectView = ide.projectView;
1314 bmp = projectView.icons[icon].bitmap;
1315 xStart = x + (bmp ? (bmp.width + 5) : 0);
1317 GetLastDirectory(name, label);
1318 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1320 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1322 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1324 const char * addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1325 if(strlen(addendum))
1327 strcat(label, " (");
1328 strcat(label, addendum);
1331 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1332 if(strlen(addendum))
1334 strcat(label, " (");
1335 strcat(label, addendum);
1341 else if(!projectView.drawingInProjectSettingsDialog)
1344 strcat(label, " *");
1345 if(type == project && info)
1347 int len = strlen(info) + 4;
1348 char * more = new char[len];
1349 sprintf(more, " (%s)", info);
1350 strcat(label, more);
1354 len = strlen(label);
1358 if(type == folder || type == folderOpen)
1359 surface.SetForeground(yellow);
1363 surface.TextOpacity(false);
1364 surface.TextExtent(label, len, &w, &h);
1367 // Draw the current row stipple
1368 if(displayFlags.selected)
1369 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1370 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1371 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1373 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1377 if(displayFlags.current)
1379 if(displayFlags.active)
1381 surface.LineStipple(0x5555);
1382 if(displayFlags.selected)
1383 surface.SetForeground(projectView.fileList.stippleColor);
1385 surface.SetForeground(projectView.fileList.foreground);
1389 surface.SetForeground(SELECTION_COLOR);
1391 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1392 surface.LineStipple(0);
1397 surface.SetForeground(white);
1398 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1404 int OnCompare(ProjectNode b)
1407 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1408 result = strcmpi(name, b.name);
1411 if(type == folder && b.type == file) result = -1;
1412 else if(type == file && b.type == folder) result = 1;
1417 bool ContainsFilesWithExtension(const char * extension, ProjectConfig prjConfig)
1421 char ext[MAX_EXTENSION];
1422 GetExtension(name, ext);
1423 if(!fstrcmp(ext, extension))
1430 if(child.type != resources && (child.type == folder || !prjConfig || !child.GetIsExcluded(prjConfig)))
1432 if(child.ContainsFilesWithExtension(extension, prjConfig))
1440 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1444 char extension[MAX_EXTENSION];
1445 GetExtension(name, extension);
1446 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1447 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1448 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1450 char moduleName[MAX_FILENAME];
1451 NameCollisionInfo info;
1452 ReplaceSpaces(moduleName, name);
1453 StripExtension(moduleName);
1454 info = namesInfo[moduleName];
1456 info = NameCollisionInfo { };
1457 info.count++; // += 1; unless this is for a bug?
1458 if(!strcmpi(extension, "ec"))
1460 else if(!strcmpi(extension, "s"))
1462 else if(!strcmpi(extension, "c"))
1464 else if(!strcmpi(extension, "rc"))
1466 else if(!strcmpi(extension, "cpp"))
1468 else if(!strcmpi(extension, "cc"))
1470 else if(!strcmpi(extension, "cxx"))
1472 else if(!strcmpi(extension, "m"))
1474 else if(!strcmpi(extension, "mm"))
1476 namesInfo[moduleName] = info;
1483 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1484 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1489 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1490 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1491 ProjectConfig prjConfig, bool * containsCXX)
1497 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1498 char moduleName[MAX_FILENAME];
1499 char extension[MAX_EXTENSION];
1500 GetExtension(name, extension);
1501 if(printType == resources)
1504 char tempPath[MAX_LOCATION];
1505 char modulePath[MAX_LOCATION];
1508 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1511 PathCatSlash(tempPath, name);
1516 strcpy(tempPath, path);
1517 PathCatSlash(tempPath, name);
1519 EscapeForMake(modulePath, tempPath, false, true, false);
1520 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1521 items.Add(CopyString(s));
1523 else if(printType == sources)
1525 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1526 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1527 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1529 char modulePath[MAX_LOCATION];
1530 EscapeForMake(modulePath, path, false, true, false);
1531 EscapeForMake(moduleName, name, false, true, false);
1532 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1533 items.Add(CopyString(s));
1536 else if(printType == eCsources)
1538 if(!strcmpi(extension, "ec"))
1540 char modulePath[MAX_LOCATION];
1541 EscapeForMake(modulePath, path, true, true, false);
1542 EscapeForMake(moduleName, name, true, true, false);
1543 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1544 items.Add(CopyString(s));
1548 else if(printType == rcSources)
1550 if(!strcmpi(extension, "rc"))
1552 char modulePath[MAX_LOCATION];
1553 EscapeForMake(modulePath, path, false, true, false);
1554 EscapeForMake(moduleName, name, false, true, false);
1555 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1556 items.Add(CopyString(s));
1560 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1561 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1562 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1564 if(printType == objects)
1567 NameCollisionInfo info;
1569 EscapeForMake(moduleName, name, false, true, false);
1570 StripExtension(moduleName);
1571 info = namesInfo[moduleName];
1572 collision = info ? info.IsExtensionColliding(extension) : false;
1573 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1574 items.Add(CopyString(s));
1575 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1576 *containsCXX = true;
1585 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1586 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1592 void GenMakefilePrintSymbolRules(File f, Project project,
1593 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1594 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1597 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1598 //ProjectNode child;
1599 //char objDir[MAX_LOCATION];
1600 //ReplaceSpaces(objDir, config.objDir.dir);
1602 //eSystem_Log("Printing Symbol Rules\n");
1605 char extension[MAX_EXTENSION];
1606 char modulePath[MAX_LOCATION];
1607 char moduleName[MAX_FILENAME];
1609 GetExtension(name, extension);
1610 if(!strcmpi(extension, "ec"))
1613 //char command[2048];
1615 ReplaceSpaces(moduleName, name);
1616 StripExtension(moduleName);
1618 ReplaceSpaces(modulePath, path);
1619 if(modulePath[0]) strcat(modulePath, SEPS);
1621 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1623 // *** Dependency command ***
1624 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1625 modulePath, moduleName, extension);
1627 // System Includes (from global settings)
1628 for(item : compiler.dirs[Includes])
1630 strcat(command, " -isystem ");
1631 if(strchr(item, ' '))
1633 strcat(command, "\"");
1634 strcat(command, item);
1635 strcat(command, "\"");
1638 strcat(command, item);
1641 for(item : project.includeDirs)
1643 strcat(command, " -I");
1644 if(strchr(item, ' '))
1646 strcat(command, "\"");
1647 strcat(command, item);
1648 strcat(command, "\"");
1651 strcat(command, item);
1653 for(item : project.preprocessorDefs)
1655 strcat(command, " -D");
1656 strcat(command, item);
1660 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1663 bool firstLine = true;
1666 // To do some time: auto save external dependencies?
1669 if(dep.GetLine(line, sizeof(line)-1))
1673 char * colon = strstr(line, ":");
1674 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1688 // If we failed to generate dependencies...
1692 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1693 moduleName, modulePath, moduleName, extension);
1697 f.Puts(" $(CFLAGS)");
1698 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1700 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1701 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1703 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1704 modulePath, moduleName, extension);
1705 if(ifCount) f.Puts("endif\n");
1715 if(ContainsFilesWithExtension("ec", prjConfig))
1719 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1720 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1721 nodeCFlagsMapping, nodeECFlagsMapping);
1728 void GenMakefilePrintPrepecsRules(File f, Project project,
1729 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1730 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1733 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1734 //ProjectNode child;
1735 //char objDir[MAX_LOCATION];
1736 //ReplaceSpaces(objDir, config.objDir.dir);
1738 //eSystem_Log("Printing Symbol Rules\n");
1741 char extension[MAX_EXTENSION];
1742 char modulePath[MAX_LOCATION];
1743 char moduleName[MAX_FILENAME];
1745 GetExtension(name, extension);
1746 if(!strcmpi(extension, "ec"))
1748 ReplaceSpaces(moduleName, name);
1749 StripExtension(moduleName);
1751 ReplaceSpaces(modulePath, path);
1752 if(modulePath[0]) strcat(modulePath, SEPS);
1754 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1755 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1756 moduleName, modulePath, moduleName, extension);
1757 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1758 modulePath, moduleName, extension, moduleName);*/
1762 f.Puts(" $(CFLAGS)");
1763 //f.Puts(" $(CECFLAGS)");
1764 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1765 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1767 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1768 modulePath, moduleName, extension, moduleName);
1769 if(ifCount) f.Puts("endif\n");
1775 if(ContainsFilesWithExtension("ec", prjConfig))
1779 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1780 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1781 nodeCFlagsMapping, nodeECFlagsMapping);
1788 void GenMakefilePrintCObjectRules(File f, Project project,
1789 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1790 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1793 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1794 //ProjectNode child;
1795 //char objDir[MAX_LOCATION];
1796 //ReplaceSpaces(objDir, config.objDir.dir);
1797 //eSystem_Log("Printing C Object Rules\n");
1800 char extension[MAX_EXTENSION];
1801 char modulePath[MAX_LOCATION];
1802 char moduleName[MAX_FILENAME];
1804 GetExtension(name, extension);
1805 if(!strcmpi(extension, "ec"))
1808 //char command[2048];
1810 ReplaceSpaces(moduleName, name);
1811 StripExtension(moduleName);
1813 ReplaceSpaces(modulePath, path);
1814 if(modulePath[0]) strcat(modulePath, SEPS);
1816 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1818 // *** Dependency command ***
1819 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1820 moduleName, modulePath, moduleName, extension);
1822 // System Includes (from global settings)
1823 for(item : compiler.dirs[Includes])
1825 strcat(command, " -isystem ");
1826 if(strchr(item, ' '))
1828 strcat(command, "\"");
1829 strcat(command, item);
1830 strcat(command, "\"");
1833 strcat(command, item);
1836 for(item : config.includeDirs)
1838 strcat(command, " -I");
1839 if(strchr(item, ' '))
1841 strcat(command, "\"");
1842 strcat(command, item);
1843 strcat(command, "\"");
1846 strcat(command, item);
1848 for(item : config.preprocessorDefs)
1850 strcat(command, " -D");
1851 strcat(command, item);
1855 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1859 bool firstLine = true;
1861 // To do some time: auto save external dependencies?
1864 if(dep.GetLine(line, sizeof(line)-1))
1868 char * colon = strstr(line, ":");
1869 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1883 // If we failed to generate dependencies...
1886 /* COMMENTED OUT FOR NOW
1887 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1888 moduleName, modulePath, moduleName, extension);
1891 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1892 moduleName, modulePath, moduleName, extension, moduleName);
1898 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1899 modulePath, moduleName, extension, moduleName);
1904 f.Puts(" $(CFLAGS)");
1905 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1906 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1907 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1908 f.Puts(" $(FVISIBILITY)");
1910 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1911 modulePath, moduleName, extension);
1912 if(ifCount) f.Puts("endif\n");
1918 if(ContainsFilesWithExtension("ec", prjConfig))
1922 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1923 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1924 nodeCFlagsMapping, nodeECFlagsMapping);
1931 void GenMakefilePrintObjectRules(File f, Project project,
1932 Map<String, NameCollisionInfo> namesInfo,
1933 ProjectConfig prjConfig,
1934 //Map<Platform, bool> parentExcludedPlatforms,
1935 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1938 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1939 //ProjectNode child;
1940 //char objDir[MAX_LOCATION];
1941 //ReplaceSpaces(objDir, config.objDir.dir);
1942 //eSystem_Log("Printing Object Rules\n");
1946 char extension[MAX_EXTENSION];
1947 char modulePath[MAX_LOCATION];
1948 char moduleName[MAX_FILENAME];
1950 GetExtension(name, extension);
1951 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1952 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1953 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1956 //char command[2048];
1957 NameCollisionInfo info;
1959 ReplaceSpaces(moduleName, name);
1960 StripExtension(moduleName);
1962 info = namesInfo[moduleName];
1963 collision = info ? info.IsExtensionColliding(extension) : false;
1965 ReplaceSpaces(modulePath, path);
1966 if(modulePath[0]) strcat(modulePath, SEPS);
1970 // *** Dependency command ***
1971 if(!strcmpi(extension, "ec"))
1972 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1974 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1975 moduleName, modulePath, moduleName, extension);
1977 if(!strcmpi(extension, "ec"))
1979 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1983 // System Includes (from global settings)
1984 for(item : compiler.dirs[includes])
1986 strcat(command, " -isystem ");
1987 if(strchr(item, ' '))
1989 strcat(command, "\"");
1990 strcat(command, item);
1991 strcat(command, "\"");
1994 strcat(command, item);
1997 for(item : config.includeDirs)
1999 strcat(command, " -I");
2000 if(strchr(item, ' '))
2002 strcat(command, "\"");
2003 strcat(command, item);
2004 strcat(command, "\"");
2007 strcat(command, item);
2009 for(item : config.preprocessorDefs)
2011 strcat(command, " -D");
2012 strcat(command, item);
2016 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2019 bool firstLine = true;
2022 // To do some time: auto save external dependencies?
2026 if(dep.GetLine(line, sizeof(line)-1))
2030 char * colon = strstr(line, ":");
2031 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2045 // If we failed to generate dependencies...
2054 if(!strcmpi(extension, "rc"))
2057 f.Puts("ifdef WINDOWS_TARGET\n\n");
2060 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2062 if(!strcmpi(extension, "ec"))
2063 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2065 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
2066 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
2067 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2068 f.Printf("\t$(CXX)");
2069 else if(!strcmpi(extension, "rc"))
2070 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2072 f.Printf("\t$(CC)");
2074 if(strcmpi(extension, "rc") != 0)
2076 f.Puts(" $(CFLAGS)");
2077 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2079 if(!strcmpi(extension, "ec"))
2080 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n", moduleName);
2082 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2083 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2085 if(ifCount) f.Puts("endif\n");
2091 bool needed = false;
2094 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2104 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2105 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2106 nodeCFlagsMapping, nodeECFlagsMapping);
2113 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2120 //Iterator<ProjectNode> i { files };
2121 //Iterator<ProjectNode> prev { files };
2122 //for(child : files)
2124 for(c = 0; c < files.count; c++)
2126 ProjectNode child = files[c];
2127 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2130 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2133 char tempPath[MAX_LOCATION];
2134 char resPath[MAX_LOCATION];
2136 // $(EAR) aw%s --- /*quiet ? "q" : */""
2138 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2141 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2144 PathCatSlash(tempPath, child.name);
2149 strcpy(tempPath, child.path);
2150 PathCatSlash(tempPath, child.name);
2152 EscapeForMake(resPath, tempPath, false, true, false);
2153 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2156 if(count == 10 || (count > 0 && (ts || !child.next)))
2158 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2161 for(parent = this; parent.type == folder; parent = parent.parent)
2164 strcpy(path, parent.name);
2171 f.Printf(" \"%s\"%s\n", path, ts.b);
2183 if(child.type == folder)
2184 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2189 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2190 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2191 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2192 Map<Platform, ProjectOptions> parentByPlatformOptions)
2194 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2195 if(type == file || type == folder || type == project)
2197 bool hasPerNodeOptions = type == project;
2198 if(!hasPerNodeOptions)
2200 if(options && !options.isEmpty)
2201 hasPerNodeOptions = true;
2202 else if(configurations)
2204 for(c : configurations)
2206 if(c.options && !c.options.isEmpty)
2208 hasPerNodeOptions = true;
2213 for(p : c.platforms)
2215 if(p.options && !p.options.isEmpty)
2217 hasPerNodeOptions = true;
2221 if(hasPerNodeOptions)
2226 if(!hasPerNodeOptions && platforms)
2230 if(p.options && !p.options.isEmpty)
2232 hasPerNodeOptions = true;
2239 if(hasPerNodeOptions)
2241 bool isEqual = false, isGreater = false;
2242 ComplexComparison complexCmp;
2244 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2245 ProjectOptions platformsCommonOptions;
2246 ProjectOptions byFileConfigPlatformProjectOptions;
2248 DynamicString cflags { };
2249 DynamicString ecflags { };
2253 byPlatformOptions = { };
2255 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2257 byFileConfigPlatformProjectOptions =
2258 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2259 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2262 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2264 byPlatformOptions[unknown] = platformsCommonOptions;
2266 if(parentByPlatformOptions)
2268 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2269 parentByPlatformOptions, additionsByPlatformOptions);
2270 isGreater = complexCmp == greater;
2271 isEqual = complexCmp == equal;
2276 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2278 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2280 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2282 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2285 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2287 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2291 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2293 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2296 if(!isGreater) cflags.concat(" \\\n\t");
2301 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2304 ecflags.concat(" \\\n\t");
2311 cflags.concat(" \\\n\t");
2312 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2316 additionsByPlatformOptions.Free();
2317 delete additionsByPlatformOptions;
2323 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2324 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2332 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2333 cflagsVariations[s] = variationNum = cflagsVariations.count;
2334 nodeCFlagsMapping[(intptr)this] = variationNum;
2337 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2338 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2339 nodeECFlagsMapping[(intptr)this] = variationNum;
2350 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2351 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2360 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2361 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2362 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2367 if(byPlatformOptions != parentByPlatformOptions)
2369 byPlatformOptions.Free();
2370 delete byPlatformOptions;
2374 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2376 Array<Platform> platforms { };
2377 Map<Platform, SetBool> exclusionInfo { };
2378 CollectExclusionInfo(exclusionInfo, prjConfig);
2380 if(exclusionInfo[unknown] == true)
2382 if(exclusionInfo.count > 1)
2383 for(p : exclusionInfo; p == false)
2388 bool onlyOnknown = true;
2389 for(p : exclusionInfo)
2390 if(&p != unknown && p == true)
2392 onlyOnknown = false;
2396 platforms.Add(unknown);
2400 for(p = unknown + 1; p < Platform::enumSize; p++)
2401 if(exclusionInfo[p] != true)
2405 delete exclusionInfo;
2409 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2411 char moduleName[MAX_FILENAME];
2414 bool headerAltFailed = false;
2416 char extension[MAX_EXTENSION];
2417 NameCollisionInfo info;
2418 Project prj = property::project;
2419 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2421 GetExtension(name, extension);
2422 strcpy(moduleName, name);
2423 StripExtension(moduleName);
2424 info = namesInfo[moduleName];
2425 collision = info ? info.IsExtensionColliding(extension) : false;
2427 for(h2s : headerToSource)
2429 if(!strcmpi(extension, &h2s))
2431 char filePath[MAX_LOCATION];
2432 GetFullFilePath(filePath);
2433 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2434 ChangeExtension(moduleName, h2s, moduleName);
2435 if(prj.topNode.Find(moduleName, false))
2437 strcpy(extension, h2s);
2438 collision = info ? info.IsExtensionColliding(extension) : false;
2439 ChangeExtension(filePath, h2s, filePath);
2440 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2441 StripExtension(moduleName);
2445 headerAltFailed = true;
2446 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2447 StripExtension(moduleName);
2453 if(!headerAltFailed)
2455 output.concat(" \"");
2456 output.concat(objDir); //.concat(" $(OBJ)");
2461 strcat(moduleName, ".");
2462 strcat(moduleName, extension);
2464 strcat(moduleName, ".o");
2465 output.concat(moduleName);
2466 output.concat("\"");
2469 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2471 Project prj = property::project;
2473 ReplaceSpaces(moduleName, prj.moduleName);
2474 strcat(moduleName, ".main.ec");
2475 output.concat(" \"");
2476 output.concat(objDir);
2478 output.concat(moduleName);
2479 output.concat("\"");
2481 ChangeExtension(moduleName, "c", moduleName);
2482 output.concat(" \"");
2483 output.concat(objDir);
2485 output.concat(moduleName);
2486 output.concat("\"");
2488 ChangeExtension(moduleName, "o", moduleName);
2489 output.concat(" \"");
2490 output.concat(objDir);
2492 output.concat(moduleName);
2493 output.concat("\"");
2499 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2500 child.GetTargets(prjConfig, namesInfo, objDir, output);
2505 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2510 char extension[MAX_EXTENSION];
2511 char fileName[MAX_FILENAME];
2512 char moduleName[MAX_FILENAME];
2513 NameCollisionInfo info;
2514 Project prj = property::project;
2515 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2517 GetExtension(name, extension);
2518 ReplaceSpaces(moduleName, name);
2519 StripExtension(moduleName);
2520 info = namesInfo[moduleName];
2521 collision = info ? info.IsExtensionColliding(extension) : false;
2523 strcpy(fileName, prj.topNode.path);
2524 PathCatSlash(fileName, objDir.dir);
2525 PathCatSlash(fileName, name);
2527 if(!onlyCObject && !strcmp(extension, "ec"))
2529 ChangeExtension(fileName, "c", fileName);
2530 if(FileExists(fileName)) DeleteFile(fileName);
2531 ChangeExtension(fileName, "sym", fileName);
2532 if(FileExists(fileName)) DeleteFile(fileName);
2533 ChangeExtension(fileName, "imp", fileName);
2534 if(FileExists(fileName)) DeleteFile(fileName);
2535 ChangeExtension(fileName, "bowl", fileName);
2536 if(FileExists(fileName)) DeleteFile(fileName);
2537 ChangeExtension(fileName, "ec", fileName);
2541 strcat(fileName, ".o");
2543 ChangeExtension(fileName, "o", fileName);
2544 if(FileExists(fileName)) DeleteFile(fileName);
2552 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2553 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2558 bool IsInNode(ProjectNode node)
2560 bool result = false;
2562 for(n = this; n; n = n.parent)
2574 // the code in this function is closely matched to OptionsBox::Load
2575 // and accompanying derivations of OptionBox and their use of OptionSet,
2576 // OptionCheck, LoadOption and FinalizeLoading methods.
2577 // output changing modification should be mirrored in both implementations
2578 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2580 ProjectOptions output { };
2582 // legend: e Element
2583 // o Option (of a ProjectOptions)
2584 // n Node (ProjectNode)
2586 // u Utility (GenericOptionTools)
2590 int includeDirsOption = OPTION(includeDirs);
2592 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2594 // OPTION(ProjectOptions' last member) for size
2595 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2596 Array<bool> optionDone { size = OPTION(installCommands) };
2597 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2599 GenericOptionTools<SetBool> utilSetBool {
2600 bool OptionCheck(ProjectOptions options, int option) {
2601 return *(SetBool*)((byte *)options + option) == true;
2603 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2604 if(options && (*(SetBool*)((byte *)options + option) == true))
2605 *(SetBool*)((byte *)output + option) = true;
2608 GenericOptionTools<String> utilString {
2609 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2610 String * string = (String*)((byte *)output + option);
2611 if(*string) delete *string;
2613 *string = CopyString(*(String*)((byte *)options + option));
2616 StringArrayOptionTools utilStringArrays {
2618 caseSensitive = true;
2619 bool OptionCheck(ProjectOptions options, int option) {
2620 Array<String> strings = *(Array<String>*)((byte *)options + option);
2621 return strings && strings.count;
2623 bool OptionSet(ProjectOptions options, int option) {
2624 Array<String> strings = *(Array<String>*)((byte *)options + option);
2625 if(mergeValues && !configReplaces)
2626 return strings && strings.count;
2628 return strings != null;
2630 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2633 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2637 Array<String> tempStrings = optionTempStrings[option];
2639 optionTempStrings[option] = tempStrings = { };
2643 char priorityMark[10];
2646 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2647 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2648 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2654 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2655 Array<String> * strings = (Array<String>*)((byte *)output + option);
2656 if(*strings) { strings->Free(); delete *strings; }
2657 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2660 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2663 Array<String> tempStrings = optionTempStrings[option];
2664 Array<String> * strings = (Array<String>*)((byte *)output + option);
2665 if(*strings) { strings->Free(); delete *strings; }
2666 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2671 GenericOptionTools<WarningsOption> utilWarningsOption {
2672 bool OptionCheck(ProjectOptions options, int option) {
2673 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2674 return value && value != none;
2676 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2677 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2678 *(WarningsOption*)((byte *)output + option) = value;
2681 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2682 bool OptionCheck(ProjectOptions options, int option) {
2683 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2684 return value && value != none;
2686 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2687 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2688 *(OptimizationStrategy*)((byte *)output + option) = value;
2692 Map<int, GenericOptionTools> ot { };
2694 // The following are compiler options
2696 ot[OPTION(debug)] = utilSetBool;
2697 ot[OPTION(memoryGuard)] = utilSetBool;
2698 ot[OPTION(profile)] = utilSetBool;
2699 ot[OPTION(noLineNumbers)] = utilSetBool;
2700 ot[OPTION(strictNameSpaces)] = utilSetBool;
2701 ot[OPTION(fastMath)] = utilSetBool;
2703 ot[OPTION(defaultNameSpace)] = utilString;
2705 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2706 ot[OPTION(includeDirs)] = utilStringArrays;
2708 ot[OPTION(warnings)] = utilWarningsOption;
2710 ot[OPTION(optimization)] = utilOptimizationStrategy;
2712 for(n = node; n; n = n.parent)
2714 ProjectConfig nodeConfig = null;
2716 priority = (priority / 10 + 1) * 10;
2719 if(projectConfig && n.configurations)
2721 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2723 if(platform && c.platforms)
2725 for(p : c.platforms; !strcmpi(p.name, platformName))
2729 GenericOptionTools u = uu;
2731 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2733 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2734 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2735 optionConfigXplatformSet[o] = true;
2747 GenericOptionTools u = uu;
2751 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2753 for(p : n.platforms; !strcmpi(p.name, platformName))
2755 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2757 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2758 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2763 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2764 ((u.mergeValues && !u.configReplaces) ?
2765 u.OptionCheck(nodeConfig.options, o) :
2766 u.OptionSet(nodeConfig.options, o)))
2768 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2769 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2773 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2775 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2776 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2780 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2781 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2789 GenericOptionTools u = uu;
2792 u.FinalizeLoading(o, optionTempStrings, output);
2795 delete optionConfigXplatformSet;
2797 delete optionTempStrings;
2801 delete utilStringArrays;
2802 delete utilWarningsOption;
2803 delete utilOptimizationStrategy;
2810 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2812 ProjectOptions first = null;
2813 ProjectOptions commonOptions;
2815 Map<String, int> countIncludeDirs { };
2816 Map<String, int> countPreprocessorDefinitions { };
2817 Map<String, bool> commonIncludeDirs { };
2818 Map<String, bool> commonPreprocessorDefinitions { };
2820 for(options : byPlatformOptions) { first = options; break; }
2822 *platformsCommonOptions = commonOptions = first ? first.Copy() : { };
2824 if(commonOptions.includeDirs)
2825 commonOptions.includeDirs.Free();
2826 if(commonOptions.preprocessorDefinitions)
2827 commonOptions.preprocessorDefinitions.Free();
2829 for(options : byPlatformOptions)
2831 if(options != first)
2833 if(commonOptions.debug && options.debug != commonOptions.debug)
2834 commonOptions.debug = unset;
2835 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2836 commonOptions.memoryGuard = unset;
2837 if(commonOptions.profile && options.profile != commonOptions.profile)
2838 commonOptions.profile = unset;
2839 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2840 commonOptions.noLineNumbers = unset;
2841 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2842 commonOptions.strictNameSpaces = unset;
2843 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2844 commonOptions.fastMath = unset;
2846 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2847 commonOptions.warnings = unset;
2848 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2849 commonOptions.optimization = unset;
2851 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2852 delete commonOptions.defaultNameSpace;
2855 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2856 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2859 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2860 commonIncludeDirs, commonOptions.includeDirs);
2861 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2862 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2864 for(options : byPlatformOptions)
2866 if(options.debug && options.debug == commonOptions.debug)
2867 options.debug = unset;
2868 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2869 options.memoryGuard = unset;
2870 if(options.profile && options.profile == commonOptions.profile)
2871 options.profile = unset;
2872 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2873 options.noLineNumbers = unset;
2874 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2875 options.strictNameSpaces = unset;
2876 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2877 options.fastMath = unset;
2879 if(options.warnings && options.warnings == commonOptions.warnings)
2880 options.warnings = unset;
2881 if(options.optimization && options.optimization == commonOptions.optimization)
2882 options.optimization = unset;
2884 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2885 delete options.defaultNameSpace;
2887 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2888 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2891 delete countIncludeDirs;
2892 delete countPreprocessorDefinitions;
2893 delete commonIncludeDirs;
2894 delete commonPreprocessorDefinitions;
2897 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2898 Map<Platform, ProjectOptions> parentByPlatformOptions,
2899 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2901 ComplexComparison result = equal;
2902 ComplexComparison compare;
2904 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2906 ProjectOptions additionalOptions;
2907 additionsByPlatformOptions[platform] = { };
2908 additionalOptions = additionsByPlatformOptions[platform];
2909 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2910 if(compare == greater && result == equal)
2912 else if(compare == different)
2921 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2923 ComplexComparison result = equal;
2924 if(options.debug != parentOptions.debug ||
2925 options.memoryGuard != parentOptions.memoryGuard ||
2926 options.profile != parentOptions.profile ||
2927 options.noLineNumbers != parentOptions.noLineNumbers ||
2928 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2929 options.fastMath != parentOptions.fastMath ||
2930 options.warnings != parentOptions.warnings ||
2931 options.optimization != parentOptions.optimization ||
2932 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2933 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2937 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2938 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2940 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2941 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2947 enum ComplexComparison { different/*, smaller*/, equal, greater };
2949 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2952 if((!strings || !strings.count) && originals && originals.count)
2954 else if(strings && strings.count && (!originals || !originals.count))
2959 additions->Add(CopyString(s));
2961 else if(strings && strings.count && originals && originals.count)
2963 Map<String, String> map { };
2964 MapIterator<String, bool> mit { map = map };
2967 char * s = strstr(it, "\n");
2973 char * s = strstr(it, "\n");
2975 if(!mit.Index(s, false))
2990 additions->Add(CopyString(it));
2998 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3011 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3018 const char * s = ⁢
3019 strings.Add(CopyString(s));
3025 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3029 Array<String> tmp { };
3030 MapIterator<String, bool> mit { map = common };
3034 if(!mit.Index(s, false))
3035 tmp.Add(CopyString(s));
3041 strings.Add(CopyString(s));
3048 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3051 customFlags = nodeFlagsMapping[(intptr)node];
3053 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3055 f.Printf(" $(%s)", variableName);
3058 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3061 customFlags = nodeFlagsMapping[(intptr)node];
3063 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3065 s.concatf(" $(%s)", variableName);
3068 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3074 if(options.optimization == speed || options.optimization == size ||
3075 options.fastMath == true || options.debug == true)
3077 if(options.debug != true)
3079 s.concat(" $(if $(DEBUG),");
3083 switch(options.optimization)
3085 case speed: s.concat(" -O2"); break;
3086 case size: s.concat(" -Os"); break;
3088 if(options.fastMath == true)
3089 s.concat(" -ffast-math");
3090 if(options.debug == true)
3092 if(options.debug != true)
3095 else if(commonOptions)
3096 s.concat(" $(if $(DEBUG),-g)");
3098 s.concat(" $(FPIC)");
3100 switch(options.warnings)
3102 case all: s.concat(" -Wall"); break;
3103 case none: s.concat(" -w"); break;
3108 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3111 if(options && options.preprocessorDefinitions)
3112 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3113 if(options && options.includeDirs)
3114 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3117 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3119 if(options.memoryGuard == true)
3120 s.concat(" -memguard");
3121 if(options.noLineNumbers == true)
3122 s.concat(" -nolinenumbers");
3123 if(options.strictNameSpaces == true)
3124 s.concat(" -strictns");
3125 if(options.defaultNameSpace && options.defaultNameSpace[0])
3126 s.concatf(" -defaultns %s", options.defaultNameSpace);
3129 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3130 LineOutputMethod lineMethod, const String newLineStart)
3134 if(lineMethod == newLine)
3136 output.concat(" \\\n");
3137 output.concat(newLineStart);
3141 Map<String, int> sortedList { };
3142 MapNode<String, int> mn;
3144 sortedList[item] = 1;
3145 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3147 char * start = strstr(mn.key, "\n");
3148 if(lineMethod == lineEach)
3150 output.concat(" \\\n");
3151 output.concat(newLineStart);
3154 output.concat(flagNames[flag]);
3155 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3163 if(lineMethod == lineEach)
3165 output.concat(" \\\n");
3166 output.concat(newLineStart);
3169 output.concat(flagNames[flag]);
3170 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3176 class GenericOptionTools<class X>
3178 bool mergeValues, configReplaces;
3180 virtual bool OptionSet(ProjectOptions options, int option) {
3181 if(*(X*)((byte *)options + option))
3186 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3188 virtual bool OptionCheck(ProjectOptions options, int option) {
3189 return OptionSet(options, option);
3192 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3193 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3196 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3201 class NameCollisionInfo
3214 bool IsExtensionColliding(char * extension)
3218 ((!strcmpi(extension, "c") && ec) ||
3219 (!strcmpi(extension, "rc") && (ec || c)) ||
3220 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3221 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3222 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3223 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3224 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3225 !strcmpi(extension, "mm")))