1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
13 #endif // #ifndef MAKEFILE_GENERATOR
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);
23 #endif // #ifdef MAKEFILE_GENERATOR
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, bool resolveVars)
525 strcpy(buffer, root.path);
530 DirExpression pathExp { };
531 Project project = property::project;
532 CompilerConfig compiler = GetCompilerConfig();
533 ProjectConfig config = project.config;
534 int bitDepth = GetBitDepth();
535 pathExp.Evaluate(path, project, compiler, config, bitDepth);
536 PathCatSlash(buffer, pathExp.dir);
540 PathCatSlash(buffer, name);
544 PathCatSlash(buffer, path);
545 PathCatSlash(buffer, name);
551 char * GetObjectFileName(char * buffer, Map<String, NameCollisionInfo> namesInfo, IntermediateFileType type, bool dotMain, const char * objectFileExt)
553 if(buffer && (this.type == file || (this.type == project && dotMain == true)))
556 char extension[MAX_EXTENSION];
557 char moduleName[MAX_FILENAME];
558 const char * objFileExt = objectFileExt ? objectFileExt : objectDefaultFileExt;
559 NameCollisionInfo info;
561 GetExtension(name, extension);
562 ReplaceSpaces(moduleName, name);
563 StripExtension(moduleName);
564 info = namesInfo[moduleName];
565 collision = info ? info.IsExtensionColliding(extension) : false;
569 Project prj = property::project;
570 ReplaceSpaces(buffer, prj.moduleName);
571 StripExtension(buffer);
572 strcat(buffer, ".main.ec");
575 strcpy(buffer, name);
576 if(!strcmp(extension, "ec") || dotMain)
579 ChangeExtension(buffer, "c", buffer);
581 ChangeExtension(buffer, "sym", buffer);
583 ChangeExtension(buffer, "imp", buffer);
584 else if(type == bowl)
585 ChangeExtension(buffer, "bowl", buffer);
592 strcat(buffer, objFileExt);
595 ChangeExtension(buffer, objFileExt, buffer);
601 char * GetFileSysMatchingPath(char * buffer)
605 ProjectNode n, root = this.root;
606 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
608 strcpy(buffer, root.path);
610 PathCatSlash(buffer, n.path);
611 if(FileExists(buffer).isDirectory)
614 if(!(n && (n.type == folder || n.type == project)))
620 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
622 ProjectNode node = null;
623 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
624 List<ProjectNode> nodeStack { };
626 for(node = this; node && node.parent; node = node.parent)
629 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
631 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
632 while((node = nodeStack.lastIterator.data))
634 ProjectOptions nodeOptions = node.property::options;
635 if(nodeOptions && nodeOptions.preprocessorDefinitions)
637 for(def : nodeOptions.preprocessorDefinitions)
638 perFilePreprocessorDefs.Add(CopyString(def));
640 if(config && config.options && config.options.preprocessorDefinitions)
642 for(def : config.options.preprocessorDefinitions)
643 perFilePreprocessorDefs.Add(CopyString(def));
645 if(nodeOptions && nodeOptions.includeDirs)
647 for(dir : nodeOptions.includeDirs)
648 perFileIncludeDirs.Add(CopySystemPath(dir));
650 if(config && config.options && config.options.includeDirs)
652 for(dir : config.options.includeDirs)
653 perFileIncludeDirs.Add(CopySystemPath(dir));
655 nodeStack.lastIterator.Remove();
661 property Project project
665 ProjectNode n = this;
666 while(n && n.type != project) n = n.parent;
667 return n ? (*&n.project) : null;
671 void RenameConfig(const char * oldName, const char * newName)
675 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
677 if(property::configurations)
679 for(c : property::configurations; !strcmp(c.name, oldName))
682 c.name = CopyString(newName);
687 void DeleteConfig(ProjectConfig configToDelete)
691 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
693 if(property::configurations)
695 Iterator<ProjectConfig> c { property::configurations };
698 ProjectConfig config = c.data;
699 if(!strcmp(configToDelete.name, config.name))
706 if(!property::configurations.count)
707 property::configurations = null;
713 ProjectNode backupNode { };
717 backupNode.files = { };
718 for(f : files) backupNode.files.Add(f.Backup());
720 if(property::options)
721 backupNode.options = property::options.Copy();
723 if(property::platforms)
725 backupNode.platforms = { };
726 for(p : property::platforms)
727 backupNode.platforms.Add(p.Copy());
730 if(property::configurations)
732 backupNode.configurations = { };
733 for(c : property::configurations)
734 backupNode.configurations.Add(c.Copy());
739 void Revert(ProjectNode backupNode)
743 Iterator<ProjectNode> it { backupNode.files };
751 property::options = backupNode.options ? backupNode.options.Copy() : null;
752 if(backupNode.platforms)
754 Array<PlatformOptions> platforms { };
755 property::platforms = platforms;
757 for(p : backupNode.platforms)
758 platforms.Add(p.Copy());
760 if(backupNode.configurations)
762 List<ProjectConfig> configurations { };
763 property::configurations = configurations;
764 for(c : backupNode.configurations)
765 configurations.Add(c.Copy());
769 void FixupNode(char * parentPath)
775 else if(nodeType == file)
780 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
783 else if(nodeType == folder)
789 char temp[MAX_LOCATION];
790 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
791 PathCatSlash(temp, name);
792 path = CopyString(temp);
796 indent = parent ? parent.indent + 1 : 0;
799 icon = NodeIcons::SelectFileIcon(name);
801 icon = NodeIcons::SelectNodeIcon(type);
810 parentPath[0] = '\0';
811 else if(type == resources || type == folder)
812 strcpy(parentPath, path);
814 f.FixupNode(parentPath);
819 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
823 // TOCHECK: Called from JSON writer
824 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
826 strcpy(tempString, "\"");
827 strcat(tempString, property::fileName);
828 strcat(tempString, "\"");
835 // TOCHECK: Called from ProjectView rendering
836 return name ? name : "";
849 if(!project && platforms)
854 if(!project && configurations)
856 configurations.Free();
857 delete configurations;
860 /////////////////////////////
866 property bool isInResources
871 for(node = this; node; node = node.parent)
873 if(node.type == resources)
880 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
882 TwoStrings result { a = CopyString(""), b = CopyString("") };
883 // note: unknown platform is for common
884 Map<Platform, SetBool> exclusionInfo { };
885 MapNode<Platform, SetBool> mn;
891 CollectExclusionInfo(exclusionInfo, prjConfig);
892 common = exclusionInfo[unknown];
894 Map<Platform, SetBool> cleaned { };
895 SetBool opposite = common == true ? false : true;
896 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
898 if(mn.key == unknown || mn.value == opposite)
899 cleaned[mn.key] = mn.value;
901 delete exclusionInfo;
902 exclusionInfo = cleaned;
905 if(exclusionInfo.count > 1)
907 if(exclusionInfo.count > 2)
910 len = strlen(exp) + strlen("$(if $(or ");
911 exp = renew exp char[len+1];
912 strcat(exp, "$(if $(or ");
915 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
917 if(mn.key != unknown)
919 const char * comma = mn.next ? "," : "";
921 var = PlatformToMakefileTargetVariable(mn.key);
924 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
925 exp = renew exp char[len+1];
935 len = strlen(exp) + strlen("),");
936 exp = renew exp char[len+1];
940 if(exclusionInfo.root.minimum.key != unknown)
941 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
943 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
946 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
947 exp = renew exp char[len+1];
948 strcat(exp, "$(if $(");
955 exp = common == true ? result.b : result.a;
956 len = strlen(exp) + strlen(",");
957 exp = renew exp char[len+1];
959 if(common == true) result.b = exp; else result.a = exp;
962 len = strlen(exp) + strlen(")");
963 exp = renew exp char[len+1];
967 delete exclusionInfo;
972 bool GetIsExcluded(ProjectConfig prjConfig)
975 // note: unknown platform is for common
976 Map<Platform, SetBool> exclusionInfo { };
977 CollectExclusionInfo(exclusionInfo, prjConfig);
978 if(exclusionInfo.count == 0)
980 else if(exclusionInfo.count == 1)
981 result = exclusionInfo.root.minimum.value == true;
984 SetBool check = exclusionInfo.root.minimum.value;
985 MapNode<Platform, SetBool> mn;
986 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
988 if(check != mn.value)
991 if(!mn) // all are same
992 result = check == true;
996 delete exclusionInfo;
1000 bool GetIsExcludedForCompiler(ProjectConfig prjConfig, CompilerConfig compiler)
1003 Map<Platform, SetBool> exclusionInfo { };
1004 SetBool common, platform;
1005 CollectExclusionInfo(exclusionInfo, prjConfig);
1006 common = exclusionInfo[unknown];
1007 platform = exclusionInfo[compiler.targetPlatform];
1008 result = platform == true || (common == true && platform == unset);
1009 delete exclusionInfo;
1013 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
1015 // note: unknown platform is for common
1017 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1018 ProjectOptions options = property::options;
1019 Array<PlatformOptions> platforms = property::platforms;
1022 parent.CollectExclusionInfo(output, prjConfig);
1024 output[unknown] = unset;
1026 if(options && options.excludeFromBuild)
1027 output[unknown] = options.excludeFromBuild;
1029 if(config && config.options && config.options.excludeFromBuild)
1030 output[unknown] = config.options.excludeFromBuild;
1036 if(p.options.excludeFromBuild && (platform = p.name))
1037 output[platform] = p.options.excludeFromBuild;
1040 if(config && config.platforms)
1042 for(p : config.platforms)
1044 if(p.options.excludeFromBuild && (platform = p.name))
1045 output[platform] = p.options.excludeFromBuild;
1050 void EnsureVisible()
1053 parent.EnsureVisible();
1054 row.collapsed = false;
1060 parent.files.Delete(this);
1063 ProjectNode Find(const char * name, bool includeResources)
1065 ProjectNode result = null;
1070 if(includeResources || child.type != resources)
1072 if(child.type != folder && child.name && !strcmpi(child.name, name))
1077 result = child.Find(name, includeResources);
1086 ProjectNode FindWithPath(const char * name, bool includeResources)
1088 ProjectNode result = null;
1093 if(includeResources || child.type != resources)
1095 char path[MAX_LOCATION];
1096 strcpy(path, child.path);
1097 if(child.type != folder && child.name)
1099 PathCatSlash(path, child.name);
1100 if(!strcmpi(path, name))
1106 result = child.FindWithPath(name, includeResources);
1115 ProjectNode FindByFullPath(const char * path, bool includeResources)
1119 char name[MAX_FILENAME];
1120 GetLastDirectory(path, name);
1121 return InternalFindByFullPath(path, includeResources, name);
1126 ProjectNode InternalFindByFullPath(const char * path, bool includeResources, const char * lastDirName)
1128 ProjectNode result = null;
1133 if(includeResources || child.type != resources)
1135 if(child.type != file)
1136 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1137 else if(child.name && !fstrcmp(lastDirName, child.name))
1139 char p[MAX_LOCATION];
1140 child.GetFullFilePath(p, true);
1141 if(!fstrcmp(p, path))
1155 ProjectNode FindByObjectFileName(const char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo, const char * objectFileExt)
1157 char p[MAX_LOCATION];
1158 ProjectNode result = null;
1159 if(dotMain == true && this.type == project)
1161 GetObjectFileName(p, namesInfo, type, dotMain, objectFileExt);
1162 if(!fstrcmp(p, fileName))
1167 for(child : files; child.type != resources)
1169 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo, objectFileExt)))
1171 else if(child.type == file && child.name)
1173 child.GetObjectFileName(p, namesInfo, type, dotMain, objectFileExt);
1174 if(!fstrcmp(p, fileName))
1185 ProjectNode FindSpecial(const char * name, bool recursive, bool includeResources, bool includeFolders)
1187 ProjectNode result = null;
1192 if(includeResources || child.type != resources)
1194 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1200 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1209 ProjectNode FindSameNameConflict(const char * name, bool includeResources,
1210 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1212 ProjectNode result = null;
1213 Map<Platform, SetBool> compareExclusion { };
1214 SetBool common, commonComp;
1215 SetBool actual, actualComp;
1220 if(includeResources || child.type != resources)
1222 if(child.type != folder && child.name && !strcmpi(child.name, name))
1224 child.CollectExclusionInfo(compareExclusion, prjConfig);
1225 common = exclusionInfo[unknown];
1226 commonComp = compareExclusion[unknown];
1227 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1229 if(!(common == true || commonComp == true))
1238 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1241 actualComp = commonComp;
1242 if(exclusionInfo[platform] != unset)
1243 actual = exclusionInfo[platform];
1244 if(compareExclusion[platform] != unset)
1245 actualComp = compareExclusion[platform];
1246 if(!(actual == true || actualComp == true))
1254 compareExclusion.Free();
1257 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1261 compareExclusion.Free();
1263 delete compareExclusion;
1267 ProjectNode Add(Project project, const char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1269 ProjectNode node = null;
1270 if(!project.topNode.FindByFullPath(filePath, true))
1272 char temp[MAX_LOCATION];
1273 Map<Platform, SetBool> exclusionInfo { };
1275 GetLastDirectory(filePath, temp);
1276 //if(!checkIfExists || !project.topNode.Find(temp, false))
1278 // TOCHECK: Shouldn't this apply either for all configs or none?
1279 CollectExclusionInfo(exclusionInfo, project.config);
1280 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1282 // Do the check for folder in the same parent or resource files only here
1283 if(type == folder || !checkIfExists)
1287 if(node.name && !strcmpi(node.name, temp))
1292 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1296 node.nodeType = folder;
1302 StripLastDirectory(filePath, temp);
1303 MakePathRelative(temp, project.topNode.path, temp);
1304 node.path = CopyUnixPath(temp);
1306 node.nodeType = file;
1310 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1311 PathCatSlash(temp, node.name);
1312 node.path = CopyString(temp);
1314 files.Insert(after, node);
1316 delete exclusionInfo;
1321 #ifndef MAKEFILE_GENERATOR
1322 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1324 char label[MAX_FILENAME];
1329 bool showConfig = true;
1334 projectView = ide.projectView;
1337 bmp = projectView.icons[icon].bitmap;
1338 xStart = x + (bmp ? (bmp.width + 5) : 0);
1340 GetLastDirectory(name, label);
1341 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1343 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1345 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1347 const char * addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1348 if(strlen(addendum))
1350 strcat(label, " (");
1351 strcat(label, addendum);
1354 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1355 if(strlen(addendum))
1357 strcat(label, " (");
1358 strcat(label, addendum);
1364 else if(!projectView.drawingInProjectSettingsDialog)
1367 strcat(label, " *");
1368 if(type == project && info)
1370 int len = strlen(info) + 4;
1371 char * more = new char[len];
1372 sprintf(more, " (%s)", info);
1373 strcat(label, more);
1377 len = strlen(label);
1381 if(type == folder || type == folderOpen)
1382 surface.SetForeground(yellow);
1386 surface.TextOpacity(false);
1387 surface.TextExtent(label, len, &w, &h);
1390 // Draw the current row stipple
1391 if(displayFlags.selected)
1392 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1393 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1394 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1396 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1400 if(displayFlags.current)
1402 if(displayFlags.active)
1404 surface.LineStipple(0x5555);
1405 if(displayFlags.selected)
1406 surface.SetForeground(projectView.fileList.stippleColor);
1408 surface.SetForeground(projectView.fileList.foreground);
1412 surface.SetForeground(SELECTION_COLOR);
1414 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1415 surface.LineStipple(0);
1420 surface.SetForeground(white);
1421 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1425 #endif // #ifndef MAKEFILE_GENERATOR
1427 int OnCompare(ProjectNode b)
1430 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1431 result = strcmpi(name, b.name);
1434 if(type == folder && b.type == file) result = -1;
1435 else if(type == file && b.type == folder) result = 1;
1440 bool ContainsFilesWithExtension(const char * extension, ProjectConfig prjConfig)
1442 if(type == file && name && name[0])
1444 char ext[MAX_EXTENSION];
1445 GetExtension(name, ext);
1446 if(!fstrcmp(ext, extension))
1453 if(child.type != resources && (child.type == folder || !prjConfig || !child.GetIsExcluded(prjConfig)))
1455 if(child.ContainsFilesWithExtension(extension, prjConfig))
1463 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1467 char extension[MAX_EXTENSION];
1468 GetExtension(name, extension);
1469 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1470 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1471 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1473 char moduleName[MAX_FILENAME];
1474 NameCollisionInfo info;
1475 ReplaceSpaces(moduleName, name);
1476 StripExtension(moduleName);
1477 info = namesInfo[moduleName];
1479 info = NameCollisionInfo { };
1480 info.count++; // += 1; unless this is for a bug?
1481 if(!strcmpi(extension, "ec"))
1483 else if(!strcmpi(extension, "s"))
1485 else if(!strcmpi(extension, "c"))
1487 else if(!strcmpi(extension, "rc"))
1489 else if(!strcmpi(extension, "cpp"))
1491 else if(!strcmpi(extension, "cc"))
1493 else if(!strcmpi(extension, "cxx"))
1495 else if(!strcmpi(extension, "m"))
1497 else if(!strcmpi(extension, "mm"))
1499 namesInfo[moduleName] = info;
1506 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1507 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1512 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1513 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1514 ProjectConfig prjConfig, bool * containsCXX)
1520 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1521 char moduleName[MAX_FILENAME];
1522 char extension[MAX_EXTENSION];
1523 GetExtension(name, extension);
1524 if(printType == resources)
1527 char tempPath[MAX_LOCATION];
1528 char modulePath[MAX_LOCATION];
1531 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1534 PathCatSlash(tempPath, name);
1539 strcpy(tempPath, path);
1540 PathCatSlash(tempPath, name);
1542 EscapeForMake(modulePath, tempPath, false, true, false);
1543 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1544 items.Add(CopyString(s));
1546 else if(printType == sources)
1548 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1549 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1550 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
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));
1559 else if(printType == eCsources)
1561 if(!strcmpi(extension, "ec"))
1563 char modulePath[MAX_LOCATION];
1564 EscapeForMake(modulePath, path, true, true, false);
1565 EscapeForMake(moduleName, name, true, true, false);
1566 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1567 items.Add(CopyString(s));
1571 else if(printType == rcSources)
1573 if(!strcmpi(extension, "rc"))
1575 char modulePath[MAX_LOCATION];
1576 EscapeForMake(modulePath, path, false, true, false);
1577 EscapeForMake(moduleName, name, false, true, false);
1578 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1579 items.Add(CopyString(s));
1583 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1584 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1585 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1587 if(printType == objects)
1590 NameCollisionInfo info;
1592 EscapeForMake(moduleName, name, false, true, false);
1593 StripExtension(moduleName);
1594 info = namesInfo[moduleName];
1595 collision = info ? info.IsExtensionColliding(extension) : false;
1596 sprintf(s, "%s$(OBJ)%s%s%s$(O)%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1597 items.Add(CopyString(s));
1598 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1599 *containsCXX = true;
1608 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1609 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1615 void GenMakefilePrintSymbolRules(File f, Project project,
1616 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1617 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1620 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1621 //ProjectNode child;
1622 //char objDir[MAX_LOCATION];
1623 //ReplaceSpaces(objDir, config.objDir.dir);
1625 //eSystem_Log("Printing Symbol Rules\n");
1628 char extension[MAX_EXTENSION];
1629 char modulePath[MAX_LOCATION];
1630 char moduleName[MAX_FILENAME];
1632 GetExtension(name, extension);
1633 if(!strcmpi(extension, "ec"))
1636 //char command[2048];
1638 ReplaceSpaces(moduleName, name);
1639 StripExtension(moduleName);
1641 ReplaceSpaces(modulePath, path);
1642 if(modulePath[0]) strcat(modulePath, SEPS);
1644 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1646 // *** Dependency command ***
1647 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1648 modulePath, moduleName, extension);
1650 // System Includes (from global settings)
1651 for(item : compiler.dirs[Includes])
1653 strcat(command, " -isystem ");
1654 if(strchr(item, ' '))
1656 strcat(command, "\"");
1657 strcat(command, item);
1658 strcat(command, "\"");
1661 strcat(command, item);
1664 for(item : project.includeDirs)
1666 strcat(command, " -I");
1667 if(strchr(item, ' '))
1669 strcat(command, "\"");
1670 strcat(command, item);
1671 strcat(command, "\"");
1674 strcat(command, item);
1676 for(item : project.preprocessorDefs)
1678 strcat(command, " -D");
1679 strcat(command, item);
1683 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1686 bool firstLine = true;
1689 // To do some time: auto save external dependencies?
1692 if(dep.GetLine(line, sizeof(line)-1))
1696 char * colon = strstr(line, ":");
1697 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1711 // If we failed to generate dependencies...
1715 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1716 moduleName, modulePath, moduleName, extension);
1720 f.Puts(" $(CFLAGS)");
1721 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1723 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1724 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1726 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1727 modulePath, moduleName, extension);
1728 if(ifCount) f.Puts("endif\n");
1738 if(ContainsFilesWithExtension("ec", prjConfig))
1742 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1743 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1744 nodeCFlagsMapping, nodeECFlagsMapping);
1751 void GenMakefilePrintPrepecsRules(File f, Project project,
1752 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1753 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1756 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1757 //ProjectNode child;
1758 //char objDir[MAX_LOCATION];
1759 //ReplaceSpaces(objDir, config.objDir.dir);
1761 //eSystem_Log("Printing Symbol Rules\n");
1764 char extension[MAX_EXTENSION];
1765 char modulePath[MAX_LOCATION];
1766 char moduleName[MAX_FILENAME];
1768 GetExtension(name, extension);
1769 if(!strcmpi(extension, "ec"))
1771 ReplaceSpaces(moduleName, name);
1772 StripExtension(moduleName);
1774 ReplaceSpaces(modulePath, path);
1775 if(modulePath[0]) strcat(modulePath, SEPS);
1777 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1778 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1779 moduleName, modulePath, moduleName, extension);
1780 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1781 modulePath, moduleName, extension, moduleName);*/
1785 f.Puts(" $(CFLAGS)");
1786 //f.Puts(" $(CECFLAGS)");
1787 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1788 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1790 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1791 modulePath, moduleName, extension, moduleName);
1792 if(ifCount) f.Puts("endif\n");
1798 if(ContainsFilesWithExtension("ec", prjConfig))
1802 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1803 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1804 nodeCFlagsMapping, nodeECFlagsMapping);
1811 void GenMakefilePrintCObjectRules(File f, Project project,
1812 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1813 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1816 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1817 //ProjectNode child;
1818 //char objDir[MAX_LOCATION];
1819 //ReplaceSpaces(objDir, config.objDir.dir);
1820 //eSystem_Log("Printing C Object Rules\n");
1823 char extension[MAX_EXTENSION];
1824 char modulePath[MAX_LOCATION];
1825 char moduleName[MAX_FILENAME];
1827 GetExtension(name, extension);
1828 if(!strcmpi(extension, "ec"))
1831 //char command[2048];
1833 ReplaceSpaces(moduleName, name);
1834 StripExtension(moduleName);
1836 ReplaceSpaces(modulePath, path);
1837 if(modulePath[0]) strcat(modulePath, SEPS);
1839 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1841 // *** Dependency command ***
1842 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1843 moduleName, modulePath, moduleName, extension);
1845 // System Includes (from global settings)
1846 for(item : compiler.dirs[Includes])
1848 strcat(command, " -isystem ");
1849 if(strchr(item, ' '))
1851 strcat(command, "\"");
1852 strcat(command, item);
1853 strcat(command, "\"");
1856 strcat(command, item);
1859 for(item : config.includeDirs)
1861 strcat(command, " -I");
1862 if(strchr(item, ' '))
1864 strcat(command, "\"");
1865 strcat(command, item);
1866 strcat(command, "\"");
1869 strcat(command, item);
1871 for(item : config.preprocessorDefs)
1873 strcat(command, " -D");
1874 strcat(command, item);
1878 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1882 bool firstLine = true;
1884 // To do some time: auto save external dependencies?
1887 if(dep.GetLine(line, sizeof(line)-1))
1891 char * colon = strstr(line, ":");
1892 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1906 // If we failed to generate dependencies...
1909 /* COMMENTED OUT FOR NOW
1910 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1911 moduleName, modulePath, moduleName, extension);
1914 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1915 moduleName, modulePath, moduleName, extension, moduleName);
1921 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1922 modulePath, moduleName, extension, moduleName);
1927 f.Puts(" $(CFLAGS)");
1928 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1929 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1930 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1931 f.Puts(" $(FVISIBILITY)");
1933 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1934 modulePath, moduleName, extension);
1935 if(ifCount) f.Puts("endif\n");
1941 if(ContainsFilesWithExtension("ec", prjConfig))
1945 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1946 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1947 nodeCFlagsMapping, nodeECFlagsMapping);
1954 void GenMakefilePrintObjectRules(File f, Project project,
1955 Map<String, NameCollisionInfo> namesInfo,
1956 ProjectConfig prjConfig,
1957 //Map<Platform, bool> parentExcludedPlatforms,
1958 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1961 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1962 //ProjectNode child;
1963 //char objDir[MAX_LOCATION];
1964 //ReplaceSpaces(objDir, config.objDir.dir);
1965 //eSystem_Log("Printing Object Rules\n");
1969 char extension[MAX_EXTENSION];
1970 char modulePath[MAX_LOCATION];
1971 char moduleName[MAX_FILENAME];
1973 GetExtension(name, extension);
1974 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1975 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1976 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1979 //char command[2048];
1980 NameCollisionInfo info;
1982 ReplaceSpaces(moduleName, name);
1983 StripExtension(moduleName);
1985 info = namesInfo[moduleName];
1986 collision = info ? info.IsExtensionColliding(extension) : false;
1988 ReplaceSpaces(modulePath, path);
1989 if(modulePath[0]) strcat(modulePath, SEPS);
1993 // *** Dependency command ***
1994 if(!strcmpi(extension, "ec"))
1995 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1997 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1998 moduleName, modulePath, moduleName, extension);
2000 if(!strcmpi(extension, "ec"))
2002 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2006 // System Includes (from global settings)
2007 for(item : compiler.dirs[includes])
2009 strcat(command, " -isystem ");
2010 if(strchr(item, ' '))
2012 strcat(command, "\"");
2013 strcat(command, item);
2014 strcat(command, "\"");
2017 strcat(command, item);
2020 for(item : config.includeDirs)
2022 strcat(command, " -I");
2023 if(strchr(item, ' '))
2025 strcat(command, "\"");
2026 strcat(command, item);
2027 strcat(command, "\"");
2030 strcat(command, item);
2032 for(item : config.preprocessorDefs)
2034 strcat(command, " -D");
2035 strcat(command, item);
2039 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2042 bool firstLine = true;
2045 // To do some time: auto save external dependencies?
2049 if(dep.GetLine(line, sizeof(line)-1))
2053 char * colon = strstr(line, ":");
2054 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2068 // If we failed to generate dependencies...
2077 if(!strcmpi(extension, "rc"))
2080 f.Puts("ifdef WINDOWS_TARGET\n\n");
2083 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2085 if(!strcmpi(extension, "ec"))
2086 f.Printf("$(OBJ)%s$(O): $(OBJ)%s.c\n", moduleName, moduleName);
2088 f.Printf("$(OBJ)%s%s%s$(O): %s%s.%s\n",
2089 moduleName, collision ? "." : "", collision ? extension : "",
2090 modulePath, moduleName, extension);
2091 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2092 f.Printf("\t$(CXX)");
2093 else if(!strcmpi(extension, "rc"))
2094 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2096 f.Printf("\t$(CC)");
2098 if(strcmpi(extension, "rc") != 0)
2100 f.Puts(" $(CFLAGS)");
2101 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2103 if(!strcmpi(extension, "ec"))
2104 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n",
2107 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2108 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2110 if(ifCount) f.Puts("endif\n");
2116 bool needed = false;
2119 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2129 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2130 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2131 nodeCFlagsMapping, nodeECFlagsMapping);
2138 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2145 //Iterator<ProjectNode> i { files };
2146 //Iterator<ProjectNode> prev { files };
2147 //for(child : files)
2149 for(c = 0; c < files.count; c++)
2151 ProjectNode child = files[c];
2152 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2155 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2158 char tempPath[MAX_LOCATION];
2159 char resPath[MAX_LOCATION];
2161 // $(EAR) aw%s --- /*quiet ? "q" : */""
2163 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2166 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2169 PathCatSlash(tempPath, child.name);
2174 strcpy(tempPath, child.path);
2175 PathCatSlash(tempPath, child.name);
2177 EscapeForMake(resPath, tempPath, false, true, false);
2178 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2181 if(count == 10 || (count > 0 && (ts || !child.next)))
2183 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2186 for(parent = this; parent.type == folder; parent = parent.parent)
2189 strcpy(path, parent.name);
2196 f.Printf(" \"%s\"%s\n", path, ts.b);
2208 if(child.type == folder)
2209 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2214 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2215 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2216 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2217 Map<Platform, ProjectOptions> parentByPlatformOptions)
2219 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2220 if(type == file || type == folder || type == project)
2222 bool hasPerNodeOptions = type == project;
2223 if(!hasPerNodeOptions)
2225 if(options && !options.isEmpty)
2226 hasPerNodeOptions = true;
2227 else if(configurations)
2229 for(c : configurations)
2231 if(c.options && !c.options.isEmpty)
2233 hasPerNodeOptions = true;
2238 for(p : c.platforms)
2240 if(p.options && !p.options.isEmpty)
2242 hasPerNodeOptions = true;
2246 if(hasPerNodeOptions)
2251 if(!hasPerNodeOptions && platforms)
2255 if(p.options && !p.options.isEmpty)
2257 hasPerNodeOptions = true;
2264 if(hasPerNodeOptions)
2266 bool isEqual = false, isGreater = false;
2267 ComplexComparison complexCmp;
2269 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2270 ProjectOptions platformsCommonOptions;
2271 ProjectOptions byFileConfigPlatformProjectOptions;
2273 DynamicString cflags { };
2274 DynamicString ecflags { };
2278 byPlatformOptions = { };
2280 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2282 byFileConfigPlatformProjectOptions =
2283 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2284 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2287 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2289 byPlatformOptions[unknown] = platformsCommonOptions;
2291 if(parentByPlatformOptions)
2293 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2294 parentByPlatformOptions, additionsByPlatformOptions);
2295 isGreater = complexCmp == greater;
2296 isEqual = complexCmp == equal;
2301 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2303 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2305 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2307 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2310 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2312 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2316 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2318 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2321 if(!isGreater) cflags.concat(" \\\n\t");
2326 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2329 ecflags.concat(" \\\n\t");
2336 cflags.concat(" \\\n\t");
2337 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2341 additionsByPlatformOptions.Free();
2342 delete additionsByPlatformOptions;
2348 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2349 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2357 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2358 cflagsVariations[s] = variationNum = cflagsVariations.count;
2359 nodeCFlagsMapping[(intptr)this] = variationNum;
2362 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2363 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2364 nodeECFlagsMapping[(intptr)this] = variationNum;
2375 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2376 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2384 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2385 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2386 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2391 if(byPlatformOptions != parentByPlatformOptions)
2393 byPlatformOptions.Free();
2394 delete byPlatformOptions;
2398 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2400 Array<Platform> platforms { };
2401 Map<Platform, SetBool> exclusionInfo { };
2402 CollectExclusionInfo(exclusionInfo, prjConfig);
2404 if(exclusionInfo[unknown] == true)
2406 if(exclusionInfo.count > 1)
2407 for(p : exclusionInfo; p == false)
2412 bool onlyOnknown = true;
2413 for(p : exclusionInfo)
2414 if(&p != unknown && p == true)
2416 onlyOnknown = false;
2420 platforms.Add(unknown);
2424 for(p = unknown + 1; p < Platform::enumSize; p++)
2425 if(exclusionInfo[p] != true)
2429 delete exclusionInfo;
2433 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, const char * objectFileExt, DynamicString output)
2435 char moduleName[MAX_FILENAME];
2438 bool headerAltFailed = false;
2440 char extension[MAX_EXTENSION];
2441 NameCollisionInfo info;
2442 Project prj = property::project;
2443 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2445 GetExtension(name, extension);
2446 strcpy(moduleName, name);
2447 StripExtension(moduleName);
2448 info = namesInfo[moduleName];
2449 collision = info ? info.IsExtensionColliding(extension) : false;
2451 for(h2s : headerToSource)
2453 if(!strcmpi(extension, &h2s))
2455 char filePath[MAX_LOCATION];
2456 GetFullFilePath(filePath, false);
2457 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2458 ChangeExtension(moduleName, h2s, moduleName);
2459 if(prj.topNode.Find(moduleName, false))
2461 strcpy(extension, h2s);
2462 collision = info ? info.IsExtensionColliding(extension) : false;
2463 ChangeExtension(filePath, h2s, filePath);
2464 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2465 StripExtension(moduleName);
2469 headerAltFailed = true;
2470 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2471 StripExtension(moduleName);
2477 if(!headerAltFailed)
2479 output.concat(" \"");
2480 output.concat(objDir); //.concat(" $(OBJ)");
2485 strcat(moduleName, ".");
2486 strcat(moduleName, extension);
2488 strcat(moduleName, ".");
2489 strcat(moduleName, objectFileExt);
2490 output.concat(moduleName);
2491 output.concat("\"");
2494 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2496 Project prj = property::project;
2498 ReplaceSpaces(moduleName, prj.moduleName);
2499 strcat(moduleName, ".main.ec");
2500 output.concat(" \"");
2501 output.concat(objDir);
2503 output.concat(moduleName);
2504 output.concat("\"");
2506 ChangeExtension(moduleName, "c", moduleName);
2507 output.concat(" \"");
2508 output.concat(objDir);
2510 output.concat(moduleName);
2511 output.concat("\"");
2513 ChangeExtension(moduleName, "o", moduleName);
2514 output.concat(" \"");
2515 output.concat(objDir);
2517 output.concat(moduleName);
2518 output.concat("\"");
2524 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2525 child.GetTargets(prjConfig, namesInfo, objDir, objectFileExt, output);
2530 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2535 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
2536 char extension[MAX_EXTENSION];
2537 char fileName[MAX_FILENAME];
2538 char moduleName[MAX_FILENAME];
2539 NameCollisionInfo info;
2540 Project prj = property::project;
2541 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2543 GetExtension(name, extension);
2544 ReplaceSpaces(moduleName, name);
2545 StripExtension(moduleName);
2546 info = namesInfo[moduleName];
2547 collision = info ? info.IsExtensionColliding(extension) : false;
2549 strcpy(fileName, prj.topNode.path);
2550 PathCatSlash(fileName, objDir.dir);
2551 PathCatSlash(fileName, name);
2553 if(!onlyCObject && !strcmp(extension, "ec"))
2555 ChangeExtension(fileName, "c", fileName);
2556 if(FileExists(fileName)) DeleteFile(fileName);
2557 ChangeExtension(fileName, "sym", fileName);
2558 if(FileExists(fileName)) DeleteFile(fileName);
2559 ChangeExtension(fileName, "imp", fileName);
2560 if(FileExists(fileName)) DeleteFile(fileName);
2561 ChangeExtension(fileName, "bowl", fileName);
2562 if(FileExists(fileName)) DeleteFile(fileName);
2563 ChangeExtension(fileName, "ec", fileName);
2568 strcat(fileName, ".");
2569 strcat(fileName, objectFileExt);
2572 ChangeExtension(fileName, objectFileExt, fileName);
2573 if(FileExists(fileName)) DeleteFile(fileName);
2581 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2582 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2587 bool IsInNode(ProjectNode node)
2589 bool result = false;
2591 for(n = this; n; n = n.parent)
2603 // the code in this function is closely matched to OptionsBox::Load
2604 // and accompanying derivations of OptionBox and their use of OptionSet,
2605 // OptionCheck, LoadOption and FinalizeLoading methods.
2606 // output changing modification should be mirrored in both implementations
2607 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2609 ProjectOptions output { };
2611 // legend: e Element
2612 // o Option (of a ProjectOptions)
2613 // n Node (ProjectNode)
2615 // u Utility (GenericOptionTools)
2619 int includeDirsOption = OPTION(includeDirs);
2621 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2623 // OPTION(ProjectOptions' last member) for size
2624 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2625 Array<bool> optionDone { size = OPTION(installCommands) };
2626 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2628 GenericOptionTools<SetBool> utilSetBool {
2629 bool OptionCheck(ProjectOptions options, int option) {
2630 return *(SetBool*)((byte *)options + option) == true;
2632 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2633 if(options && (*(SetBool*)((byte *)options + option) == true))
2634 *(SetBool*)((byte *)output + option) = true;
2637 GenericOptionTools<String> utilString {
2638 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2639 String * string = (String*)((byte *)output + option);
2640 if(*string) delete *string;
2642 *string = CopyString(*(String*)((byte *)options + option));
2645 StringArrayOptionTools utilStringArrays {
2647 caseSensitive = true;
2648 bool OptionCheck(ProjectOptions options, int option) {
2649 Array<String> strings = *(Array<String>*)((byte *)options + option);
2650 return strings && strings.count;
2652 bool OptionSet(ProjectOptions options, int option) {
2653 Array<String> strings = *(Array<String>*)((byte *)options + option);
2654 if(mergeValues && !configReplaces)
2655 return strings && strings.count;
2657 return strings != null;
2659 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2662 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2666 Array<String> tempStrings = optionTempStrings[option];
2668 optionTempStrings[option] = tempStrings = { };
2672 char priorityMark[10];
2675 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2676 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2677 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2683 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2684 Array<String> * strings = (Array<String>*)((byte *)output + option);
2685 if(*strings) { strings->Free(); delete *strings; }
2686 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2689 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2692 Array<String> tempStrings = optionTempStrings[option];
2693 Array<String> * strings = (Array<String>*)((byte *)output + option);
2694 if(*strings) { strings->Free(); delete *strings; }
2695 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2700 GenericOptionTools<WarningsOption> utilWarningsOption {
2701 bool OptionCheck(ProjectOptions options, int option) {
2702 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2703 return value && value != none;
2705 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2706 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2707 *(WarningsOption*)((byte *)output + option) = value;
2710 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2711 bool OptionCheck(ProjectOptions options, int option) {
2712 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2713 return value && value != none;
2715 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2716 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2717 *(OptimizationStrategy*)((byte *)output + option) = value;
2721 Map<int, GenericOptionTools> ot { };
2723 // The following are compiler options
2725 ot[OPTION(debug)] = utilSetBool;
2726 ot[OPTION(memoryGuard)] = utilSetBool;
2727 ot[OPTION(profile)] = utilSetBool;
2728 ot[OPTION(noLineNumbers)] = utilSetBool;
2729 ot[OPTION(strictNameSpaces)] = utilSetBool;
2730 ot[OPTION(fastMath)] = utilSetBool;
2732 ot[OPTION(defaultNameSpace)] = utilString;
2734 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2735 ot[OPTION(includeDirs)] = utilStringArrays;
2737 ot[OPTION(warnings)] = utilWarningsOption;
2739 ot[OPTION(optimization)] = utilOptimizationStrategy;
2741 for(n = node; n; n = n.parent)
2743 ProjectConfig nodeConfig = null;
2745 priority = (priority / 10 + 1) * 10;
2748 if(projectConfig && n.configurations)
2750 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2752 if(platform && c.platforms)
2754 for(p : c.platforms; !strcmpi(p.name, platformName))
2758 GenericOptionTools u = uu;
2760 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2762 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2763 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2764 optionConfigXplatformSet[o] = true;
2776 GenericOptionTools u = uu;
2780 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2782 for(p : n.platforms; !strcmpi(p.name, platformName))
2784 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2786 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2787 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2792 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2793 ((u.mergeValues && !u.configReplaces) ?
2794 u.OptionCheck(nodeConfig.options, o) :
2795 u.OptionSet(nodeConfig.options, o)))
2797 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2798 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2802 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2804 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2805 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2809 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2810 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2818 GenericOptionTools u = uu;
2821 u.FinalizeLoading(o, optionTempStrings, output);
2824 delete optionConfigXplatformSet;
2826 delete optionTempStrings;
2830 delete utilStringArrays;
2831 delete utilWarningsOption;
2832 delete utilOptimizationStrategy;
2839 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2841 ProjectOptions first = null;
2842 ProjectOptions commonOptions;
2844 Map<String, int> countIncludeDirs { };
2845 Map<String, int> countPreprocessorDefinitions { };
2846 Map<String, bool> commonIncludeDirs { };
2847 Map<String, bool> commonPreprocessorDefinitions { };
2849 for(options : byPlatformOptions) { first = options; break; }
2851 *platformsCommonOptions = commonOptions = first ? first.Copy() : { };
2853 if(commonOptions.includeDirs)
2854 commonOptions.includeDirs.Free();
2855 if(commonOptions.preprocessorDefinitions)
2856 commonOptions.preprocessorDefinitions.Free();
2858 for(options : byPlatformOptions)
2860 if(options != first)
2862 if(commonOptions.debug && options.debug != commonOptions.debug)
2863 commonOptions.debug = unset;
2864 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2865 commonOptions.memoryGuard = unset;
2866 if(commonOptions.profile && options.profile != commonOptions.profile)
2867 commonOptions.profile = unset;
2868 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2869 commonOptions.noLineNumbers = unset;
2870 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2871 commonOptions.strictNameSpaces = unset;
2872 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2873 commonOptions.fastMath = unset;
2875 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2876 commonOptions.warnings = unset;
2877 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2878 commonOptions.optimization = unset;
2880 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2881 delete commonOptions.defaultNameSpace;
2884 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2885 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2888 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2889 commonIncludeDirs, commonOptions.includeDirs);
2890 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2891 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2893 for(options : byPlatformOptions)
2895 if(options.debug && options.debug == commonOptions.debug)
2896 options.debug = unset;
2897 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2898 options.memoryGuard = unset;
2899 if(options.profile && options.profile == commonOptions.profile)
2900 options.profile = unset;
2901 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2902 options.noLineNumbers = unset;
2903 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2904 options.strictNameSpaces = unset;
2905 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2906 options.fastMath = unset;
2908 if(options.warnings && options.warnings == commonOptions.warnings)
2909 options.warnings = unset;
2910 if(options.optimization && options.optimization == commonOptions.optimization)
2911 options.optimization = unset;
2913 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2914 delete options.defaultNameSpace;
2916 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2917 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2920 delete countIncludeDirs;
2921 delete countPreprocessorDefinitions;
2922 delete commonIncludeDirs;
2923 delete commonPreprocessorDefinitions;
2926 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2927 Map<Platform, ProjectOptions> parentByPlatformOptions,
2928 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2930 ComplexComparison result = equal;
2931 ComplexComparison compare;
2933 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2935 ProjectOptions additionalOptions;
2936 additionsByPlatformOptions[platform] = { };
2937 additionalOptions = additionsByPlatformOptions[platform];
2938 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2939 if(compare == greater && result == equal)
2941 else if(compare == different)
2950 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2952 ComplexComparison result = equal;
2953 if(options.debug != parentOptions.debug ||
2954 options.memoryGuard != parentOptions.memoryGuard ||
2955 options.profile != parentOptions.profile ||
2956 options.noLineNumbers != parentOptions.noLineNumbers ||
2957 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2958 options.fastMath != parentOptions.fastMath ||
2959 options.warnings != parentOptions.warnings ||
2960 options.optimization != parentOptions.optimization ||
2961 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2962 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2966 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2967 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2969 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2970 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2976 enum ComplexComparison { different/*, smaller*/, equal, greater };
2978 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2981 if((!strings || !strings.count) && originals && originals.count)
2983 else if(strings && strings.count && (!originals || !originals.count))
2988 additions->Add(CopyString(s));
2990 else if(strings && strings.count && originals && originals.count)
2992 Map<String, String> map { };
2993 MapIterator<String, bool> mit { map = map };
2996 char * s = strstr(it, "\n");
3002 char * s = strstr(it, "\n");
3004 if(!mit.Index(s, false))
3019 additions->Add(CopyString(it));
3027 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3040 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3047 const char * s = ⁢
3048 strings.Add(CopyString(s));
3054 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3058 Array<String> tmp { };
3059 MapIterator<String, bool> mit { map = common };
3063 if(!mit.Index(s, false))
3064 tmp.Add(CopyString(s));
3070 strings.Add(CopyString(s));
3077 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3080 customFlags = nodeFlagsMapping[(intptr)node];
3082 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3084 f.Printf(" $(%s)", variableName);
3087 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3090 customFlags = nodeFlagsMapping[(intptr)node];
3092 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3094 s.concatf(" $(%s)", variableName);
3097 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3103 if(options.optimization == speed || options.optimization == size ||
3104 options.fastMath == true || options.debug == true)
3106 if(options.debug != true)
3108 s.concat(" $(if $(DEBUG),");
3112 switch(options.optimization)
3114 case speed: s.concat(" -O2"); break;
3115 case size: s.concat(" -Os"); break;
3117 if(options.fastMath == true)
3118 s.concat(" -ffast-math");
3119 if(options.debug == true)
3121 if(options.debug != true)
3124 else if(commonOptions)
3125 s.concat(" $(if $(DEBUG),-g)");
3127 s.concat(" $(FPIC)");
3129 switch(options.warnings)
3131 case all: s.concat(" -Wall"); break;
3132 case none: s.concat(" -w"); break;
3137 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3140 if(options && options.preprocessorDefinitions)
3141 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3142 if(options && options.includeDirs)
3143 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3146 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3148 if(options.memoryGuard == true)
3149 s.concat(" -memguard");
3150 if(options.noLineNumbers == true)
3151 s.concat(" -nolinenumbers");
3152 if(options.strictNameSpaces == true)
3153 s.concat(" -strictns");
3154 if(options.defaultNameSpace && options.defaultNameSpace[0])
3155 s.concatf(" -defaultns %s", options.defaultNameSpace);
3158 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3159 LineOutputMethod lineMethod, const String newLineStart)
3163 if(lineMethod == newLine)
3165 output.concat(" \\\n");
3166 output.concat(newLineStart);
3170 Map<String, int> sortedList { };
3171 MapNode<String, int> mn;
3173 sortedList[item] = 1;
3174 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3176 char * start = strstr(mn.key, "\n");
3177 if(lineMethod == lineEach)
3179 output.concat(" \\\n");
3180 output.concat(newLineStart);
3183 output.concat(flagNames[flag]);
3184 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3192 if(lineMethod == lineEach)
3194 output.concat(" \\\n");
3195 output.concat(newLineStart);
3198 output.concat(flagNames[flag]);
3199 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3205 class GenericOptionTools<class X>
3207 bool mergeValues, configReplaces;
3209 virtual bool OptionSet(ProjectOptions options, int option) {
3210 if(*(X*)((byte *)options + option))
3215 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3217 virtual bool OptionCheck(ProjectOptions options, int option) {
3218 return OptionSet(options, option);
3221 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3222 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3225 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3230 class NameCollisionInfo
3243 bool IsExtensionColliding(char * extension)
3247 ((!strcmpi(extension, "c") && ec) ||
3248 (!strcmpi(extension, "rc") && (ec || c)) ||
3249 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3250 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3251 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3252 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3253 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3254 !strcmpi(extension, "mm")))