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));
1599 else if(printType == noPrint && containsCXX &&
1600 (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1601 *containsCXX = true;
1609 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1610 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1616 void GenMakefilePrintSymbolRules(File f, Project project,
1617 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1618 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1621 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1622 //ProjectNode child;
1623 //char objDir[MAX_LOCATION];
1624 //ReplaceSpaces(objDir, config.objDir.dir);
1626 //eSystem_Log("Printing Symbol Rules\n");
1629 char extension[MAX_EXTENSION];
1630 char modulePath[MAX_LOCATION];
1631 char moduleName[MAX_FILENAME];
1633 GetExtension(name, extension);
1634 if(!strcmpi(extension, "ec"))
1637 //char command[2048];
1639 ReplaceSpaces(moduleName, name);
1640 StripExtension(moduleName);
1642 ReplaceSpaces(modulePath, path);
1643 if(modulePath[0]) strcat(modulePath, SEPS);
1645 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1647 // *** Dependency command ***
1648 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1649 modulePath, moduleName, extension);
1651 // System Includes (from global settings)
1652 for(item : compiler.dirs[Includes])
1654 strcat(command, " -isystem ");
1655 if(strchr(item, ' '))
1657 strcat(command, "\"");
1658 strcat(command, item);
1659 strcat(command, "\"");
1662 strcat(command, item);
1665 for(item : project.includeDirs)
1667 strcat(command, " -I");
1668 if(strchr(item, ' '))
1670 strcat(command, "\"");
1671 strcat(command, item);
1672 strcat(command, "\"");
1675 strcat(command, item);
1677 for(item : project.preprocessorDefs)
1679 strcat(command, " -D");
1680 strcat(command, item);
1684 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1687 bool firstLine = true;
1690 // To do some time: auto save external dependencies?
1693 if(dep.GetLine(line, sizeof(line)-1))
1697 char * colon = strstr(line, ":");
1698 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1712 // If we failed to generate dependencies...
1716 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1717 moduleName, modulePath, moduleName, extension);
1721 f.Puts(" $(CFLAGS)");
1722 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1724 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1725 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1727 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1728 modulePath, moduleName, extension);
1729 if(ifCount) f.Puts("endif\n");
1739 if(ContainsFilesWithExtension("ec", prjConfig))
1743 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1744 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1745 nodeCFlagsMapping, nodeECFlagsMapping);
1752 void GenMakefilePrintPrepecsRules(File f, Project project,
1753 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1754 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1757 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1758 //ProjectNode child;
1759 //char objDir[MAX_LOCATION];
1760 //ReplaceSpaces(objDir, config.objDir.dir);
1762 //eSystem_Log("Printing Symbol Rules\n");
1765 char extension[MAX_EXTENSION];
1766 char modulePath[MAX_LOCATION];
1767 char moduleName[MAX_FILENAME];
1769 GetExtension(name, extension);
1770 if(!strcmpi(extension, "ec"))
1772 ReplaceSpaces(moduleName, name);
1773 StripExtension(moduleName);
1775 ReplaceSpaces(modulePath, path);
1776 if(modulePath[0]) strcat(modulePath, SEPS);
1778 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1779 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1780 moduleName, modulePath, moduleName, extension);
1781 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1782 modulePath, moduleName, extension, moduleName);*/
1786 f.Puts(" $(CFLAGS)");
1787 //f.Puts(" $(CECFLAGS)");
1788 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1789 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1791 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1792 modulePath, moduleName, extension, moduleName);
1793 if(ifCount) f.Puts("endif\n");
1799 if(ContainsFilesWithExtension("ec", prjConfig))
1803 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1804 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1805 nodeCFlagsMapping, nodeECFlagsMapping);
1812 void GenMakefilePrintCObjectRules(File f, Project project,
1813 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1814 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1817 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1818 //ProjectNode child;
1819 //char objDir[MAX_LOCATION];
1820 //ReplaceSpaces(objDir, config.objDir.dir);
1821 //eSystem_Log("Printing C Object Rules\n");
1824 char extension[MAX_EXTENSION];
1825 char modulePath[MAX_LOCATION];
1826 char moduleName[MAX_FILENAME];
1828 GetExtension(name, extension);
1829 if(!strcmpi(extension, "ec"))
1832 //char command[2048];
1834 ReplaceSpaces(moduleName, name);
1835 StripExtension(moduleName);
1837 ReplaceSpaces(modulePath, path);
1838 if(modulePath[0]) strcat(modulePath, SEPS);
1840 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1842 // *** Dependency command ***
1843 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1844 moduleName, modulePath, moduleName, extension);
1846 // System Includes (from global settings)
1847 for(item : compiler.dirs[Includes])
1849 strcat(command, " -isystem ");
1850 if(strchr(item, ' '))
1852 strcat(command, "\"");
1853 strcat(command, item);
1854 strcat(command, "\"");
1857 strcat(command, item);
1860 for(item : config.includeDirs)
1862 strcat(command, " -I");
1863 if(strchr(item, ' '))
1865 strcat(command, "\"");
1866 strcat(command, item);
1867 strcat(command, "\"");
1870 strcat(command, item);
1872 for(item : config.preprocessorDefs)
1874 strcat(command, " -D");
1875 strcat(command, item);
1879 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1883 bool firstLine = true;
1885 // To do some time: auto save external dependencies?
1888 if(dep.GetLine(line, sizeof(line)-1))
1892 char * colon = strstr(line, ":");
1893 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1907 // If we failed to generate dependencies...
1910 /* COMMENTED OUT FOR NOW
1911 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1912 moduleName, modulePath, moduleName, extension);
1915 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1916 moduleName, modulePath, moduleName, extension, moduleName);
1922 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1923 modulePath, moduleName, extension, moduleName);
1928 f.Puts(" $(CFLAGS)");
1929 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1930 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1931 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1932 f.Puts(" $(FVISIBILITY)");
1934 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1935 modulePath, moduleName, extension);
1936 if(ifCount) f.Puts("endif\n");
1942 if(ContainsFilesWithExtension("ec", prjConfig))
1946 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1947 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1948 nodeCFlagsMapping, nodeECFlagsMapping);
1955 void GenMakefilePrintObjectRules(File f, Project project,
1956 Map<String, NameCollisionInfo> namesInfo,
1957 ProjectConfig prjConfig,
1958 //Map<Platform, bool> parentExcludedPlatforms,
1959 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1962 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1963 //ProjectNode child;
1964 //char objDir[MAX_LOCATION];
1965 //ReplaceSpaces(objDir, config.objDir.dir);
1966 //eSystem_Log("Printing Object Rules\n");
1970 char extension[MAX_EXTENSION];
1971 char modulePath[MAX_LOCATION];
1972 char moduleName[MAX_FILENAME];
1974 GetExtension(name, extension);
1975 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1976 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1977 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1980 //char command[2048];
1981 NameCollisionInfo info;
1983 ReplaceSpaces(moduleName, name);
1984 StripExtension(moduleName);
1986 info = namesInfo[moduleName];
1987 collision = info ? info.IsExtensionColliding(extension) : false;
1989 ReplaceSpaces(modulePath, path);
1990 if(modulePath[0]) strcat(modulePath, SEPS);
1994 // *** Dependency command ***
1995 if(!strcmpi(extension, "ec"))
1996 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1998 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1999 moduleName, modulePath, moduleName, extension);
2001 if(!strcmpi(extension, "ec"))
2003 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2007 // System Includes (from global settings)
2008 for(item : compiler.dirs[includes])
2010 strcat(command, " -isystem ");
2011 if(strchr(item, ' '))
2013 strcat(command, "\"");
2014 strcat(command, item);
2015 strcat(command, "\"");
2018 strcat(command, item);
2021 for(item : config.includeDirs)
2023 strcat(command, " -I");
2024 if(strchr(item, ' '))
2026 strcat(command, "\"");
2027 strcat(command, item);
2028 strcat(command, "\"");
2031 strcat(command, item);
2033 for(item : config.preprocessorDefs)
2035 strcat(command, " -D");
2036 strcat(command, item);
2040 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2043 bool firstLine = true;
2046 // To do some time: auto save external dependencies?
2050 if(dep.GetLine(line, sizeof(line)-1))
2054 char * colon = strstr(line, ":");
2055 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2069 // If we failed to generate dependencies...
2078 if(!strcmpi(extension, "rc"))
2081 f.Puts("ifdef WINDOWS_TARGET\n\n");
2084 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2086 if(!strcmpi(extension, "ec"))
2087 f.Printf("$(OBJ)%s$(O): $(OBJ)%s.c\n", moduleName, moduleName);
2089 f.Printf("$(OBJ)%s%s%s$(O): %s%s.%s\n",
2090 moduleName, collision ? "." : "", collision ? extension : "",
2091 modulePath, moduleName, extension);
2092 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2093 f.Printf("\t$(CXX)");
2094 else if(!strcmpi(extension, "rc"))
2095 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2097 f.Printf("\t$(CC)");
2099 if(strcmpi(extension, "rc") != 0)
2101 f.Puts(" $(CFLAGS)");
2102 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2104 if(!strcmpi(extension, "ec"))
2105 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n",
2108 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2109 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2111 if(ifCount) f.Puts("endif\n");
2117 bool needed = false;
2120 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2130 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2131 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2132 nodeCFlagsMapping, nodeECFlagsMapping);
2139 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig, const char * resourcesTarget)
2146 //Iterator<ProjectNode> i { files };
2147 //Iterator<ProjectNode> prev { files };
2148 //for(child : files)
2150 for(c = 0; c < files.count; c++)
2152 ProjectNode child = files[c];
2153 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2156 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2159 char tempPath[MAX_LOCATION];
2160 char resPath[MAX_LOCATION];
2162 // $(EAR) aw%s --- /*quiet ? "q" : */""
2164 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(%s)", ts.a, resourcesTarget);
2167 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2170 PathCatSlash(tempPath, child.name);
2175 strcpy(tempPath, child.path);
2176 PathCatSlash(tempPath, child.name);
2178 EscapeForMake(resPath, tempPath, false, true, false);
2179 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2182 if(count == 10 || (count > 0 && (ts || !child.next)))
2184 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2187 for(parent = this; parent.type == folder; parent = parent.parent)
2190 strcpy(path, parent.name);
2197 f.Printf(" \"%s\"%s\n", path, ts.b);
2209 if(child.type == folder)
2210 child.GenMakefileAddResources(f, resourcesPath, prjConfig, resourcesTarget);
2215 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2216 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2217 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2218 Map<Platform, ProjectOptions> parentByPlatformOptions)
2220 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2221 if(type == file || type == folder || type == project)
2223 bool hasPerNodeOptions = type == project;
2224 if(!hasPerNodeOptions)
2226 if(options && !options.isEmpty)
2227 hasPerNodeOptions = true;
2228 else if(configurations)
2230 for(c : configurations)
2232 if(c.options && !c.options.isEmpty)
2234 hasPerNodeOptions = true;
2239 for(p : c.platforms)
2241 if(p.options && !p.options.isEmpty)
2243 hasPerNodeOptions = true;
2247 if(hasPerNodeOptions)
2252 if(!hasPerNodeOptions && platforms)
2256 if(p.options && !p.options.isEmpty)
2258 hasPerNodeOptions = true;
2265 if(hasPerNodeOptions)
2267 bool isEqual = false, isGreater = false;
2268 ComplexComparison complexCmp;
2270 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2271 ProjectOptions platformsCommonOptions;
2272 ProjectOptions byFileConfigPlatformProjectOptions;
2274 DynamicString cflags { };
2275 DynamicString ecflags { };
2279 byPlatformOptions = { };
2281 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2283 byFileConfigPlatformProjectOptions =
2284 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2285 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2288 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2290 byPlatformOptions[unknown] = platformsCommonOptions;
2292 if(parentByPlatformOptions)
2294 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2295 parentByPlatformOptions, additionsByPlatformOptions);
2296 isGreater = complexCmp == greater;
2297 isEqual = complexCmp == equal;
2302 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2304 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2306 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2308 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2311 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2313 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2317 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2319 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2322 if(!isGreater) cflags.concat(" \\\n\t");
2327 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2330 ecflags.concat(" \\\n\t");
2337 cflags.concat(" \\\n\t");
2338 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2342 additionsByPlatformOptions.Free();
2343 delete additionsByPlatformOptions;
2349 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2350 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2358 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2359 cflagsVariations[s] = variationNum = cflagsVariations.count;
2360 nodeCFlagsMapping[(intptr)this] = variationNum;
2363 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2364 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2365 nodeECFlagsMapping[(intptr)this] = variationNum;
2376 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2377 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2385 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2386 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2387 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2392 if(byPlatformOptions != parentByPlatformOptions)
2394 byPlatformOptions.Free();
2395 delete byPlatformOptions;
2399 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2401 Array<Platform> platforms { };
2402 Map<Platform, SetBool> exclusionInfo { };
2403 CollectExclusionInfo(exclusionInfo, prjConfig);
2405 if(exclusionInfo[unknown] == true)
2407 if(exclusionInfo.count > 1)
2408 for(p : exclusionInfo; p == false)
2413 bool onlyOnknown = true;
2414 for(p : exclusionInfo)
2415 if(&p != unknown && p == true)
2417 onlyOnknown = false;
2421 platforms.Add(unknown);
2425 for(p = unknown + 1; p < Platform::enumSize; p++)
2426 if(exclusionInfo[p] != true)
2430 delete exclusionInfo;
2434 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, const char * objectFileExt, DynamicString output)
2436 char moduleName[MAX_FILENAME];
2439 bool headerAltFailed = false;
2441 char extension[MAX_EXTENSION];
2442 NameCollisionInfo info;
2443 Project prj = property::project;
2444 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2446 GetExtension(name, extension);
2447 strcpy(moduleName, name);
2448 StripExtension(moduleName);
2449 info = namesInfo[moduleName];
2450 collision = info ? info.IsExtensionColliding(extension) : false;
2452 for(h2s : headerToSource)
2454 if(!strcmpi(extension, &h2s))
2456 char filePath[MAX_LOCATION];
2457 GetFullFilePath(filePath, true);
2458 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2459 ChangeExtension(moduleName, h2s, moduleName);
2460 if(prj.topNode.Find(moduleName, false))
2462 strcpy(extension, h2s);
2463 collision = info ? info.IsExtensionColliding(extension) : false;
2464 ChangeExtension(filePath, h2s, filePath);
2465 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2466 StripExtension(moduleName);
2470 headerAltFailed = true;
2471 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2472 StripExtension(moduleName);
2478 if(!headerAltFailed)
2480 output.concat(" \"");
2481 output.concat(objDir); //.concat(" $(OBJ)");
2486 strcat(moduleName, ".");
2487 strcat(moduleName, extension);
2489 strcat(moduleName, ".");
2490 strcat(moduleName, objectFileExt);
2491 output.concat(moduleName);
2492 output.concat("\"");
2495 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2497 Project prj = property::project;
2499 ReplaceSpaces(moduleName, prj.moduleName);
2500 strcat(moduleName, ".main.ec");
2501 output.concat(" \"");
2502 output.concat(objDir);
2504 output.concat(moduleName);
2505 output.concat("\"");
2507 ChangeExtension(moduleName, "c", moduleName);
2508 output.concat(" \"");
2509 output.concat(objDir);
2511 output.concat(moduleName);
2512 output.concat("\"");
2514 ChangeExtension(moduleName, "o", moduleName);
2515 output.concat(" \"");
2516 output.concat(objDir);
2518 output.concat(moduleName);
2519 output.concat("\"");
2525 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2526 child.GetTargets(prjConfig, namesInfo, objDir, objectFileExt, output);
2531 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2536 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
2537 char extension[MAX_EXTENSION];
2538 char fileName[MAX_FILENAME];
2539 char moduleName[MAX_FILENAME];
2540 NameCollisionInfo info;
2541 Project prj = property::project;
2542 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2544 GetExtension(name, extension);
2545 ReplaceSpaces(moduleName, name);
2546 StripExtension(moduleName);
2547 info = namesInfo[moduleName];
2548 collision = info ? info.IsExtensionColliding(extension) : false;
2550 strcpy(fileName, prj.topNode.path);
2551 PathCatSlash(fileName, objDir.dir);
2552 PathCatSlash(fileName, name);
2554 if(!onlyCObject && !strcmp(extension, "ec"))
2556 ChangeExtension(fileName, "c", fileName);
2557 if(FileExists(fileName)) DeleteFile(fileName);
2558 ChangeExtension(fileName, "sym", fileName);
2559 if(FileExists(fileName)) DeleteFile(fileName);
2560 ChangeExtension(fileName, "imp", fileName);
2561 if(FileExists(fileName)) DeleteFile(fileName);
2562 ChangeExtension(fileName, "bowl", fileName);
2563 if(FileExists(fileName)) DeleteFile(fileName);
2564 ChangeExtension(fileName, "ec", fileName);
2569 strcat(fileName, ".");
2570 strcat(fileName, objectFileExt);
2573 ChangeExtension(fileName, objectFileExt, fileName);
2574 if(FileExists(fileName)) DeleteFile(fileName);
2582 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2583 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2588 bool IsInNode(ProjectNode node)
2590 bool result = false;
2592 for(n = this; n; n = n.parent)
2604 // the code in this function is closely matched to OptionsBox::Load
2605 // and accompanying derivations of OptionBox and their use of OptionSet,
2606 // OptionCheck, LoadOption and FinalizeLoading methods.
2607 // output changing modification should be mirrored in both implementations
2608 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2610 ProjectOptions output { };
2612 // legend: e Element
2613 // o Option (of a ProjectOptions)
2614 // n Node (ProjectNode)
2616 // u Utility (GenericOptionTools)
2620 int includeDirsOption = OPTION(includeDirs);
2622 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2624 // OPTION(ProjectOptions' last member) for size
2625 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2626 Array<bool> optionDone { size = OPTION(installCommands) };
2627 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2629 GenericOptionTools<SetBool> utilSetBool {
2630 bool OptionCheck(ProjectOptions options, int option) {
2631 return *(SetBool*)((byte *)options + option) == true;
2633 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2634 if(options && (*(SetBool*)((byte *)options + option) == true))
2635 *(SetBool*)((byte *)output + option) = true;
2638 GenericOptionTools<String> utilString {
2639 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2640 String * string = (String*)((byte *)output + option);
2641 if(*string) delete *string;
2643 *string = CopyString(*(String*)((byte *)options + option));
2646 StringArrayOptionTools utilStringArrays {
2648 caseSensitive = true;
2649 bool OptionCheck(ProjectOptions options, int option) {
2650 Array<String> strings = *(Array<String>*)((byte *)options + option);
2651 return strings && strings.count;
2653 bool OptionSet(ProjectOptions options, int option) {
2654 Array<String> strings = *(Array<String>*)((byte *)options + option);
2655 if(mergeValues && !configReplaces)
2656 return strings && strings.count;
2658 return strings != null;
2660 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2663 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2667 Array<String> tempStrings = optionTempStrings[option];
2669 optionTempStrings[option] = tempStrings = { };
2673 char priorityMark[10];
2676 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2677 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2678 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2684 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2685 Array<String> * strings = (Array<String>*)((byte *)output + option);
2686 if(*strings) { strings->Free(); delete *strings; }
2687 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2690 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2693 Array<String> tempStrings = optionTempStrings[option];
2694 Array<String> * strings = (Array<String>*)((byte *)output + option);
2695 if(*strings) { strings->Free(); delete *strings; }
2696 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2701 GenericOptionTools<WarningsOption> utilWarningsOption {
2702 bool OptionCheck(ProjectOptions options, int option) {
2703 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2704 return value && value != none;
2706 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2707 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2708 *(WarningsOption*)((byte *)output + option) = value;
2711 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2712 bool OptionCheck(ProjectOptions options, int option) {
2713 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2714 return value && value != none;
2716 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2717 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2718 *(OptimizationStrategy*)((byte *)output + option) = value;
2722 Map<int, GenericOptionTools> ot { };
2724 // The following are compiler options
2726 ot[OPTION(debug)] = utilSetBool;
2727 ot[OPTION(memoryGuard)] = utilSetBool;
2728 ot[OPTION(profile)] = utilSetBool;
2729 ot[OPTION(noLineNumbers)] = utilSetBool;
2730 ot[OPTION(strictNameSpaces)] = utilSetBool;
2731 ot[OPTION(fastMath)] = utilSetBool;
2733 ot[OPTION(defaultNameSpace)] = utilString;
2735 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2736 ot[OPTION(includeDirs)] = utilStringArrays;
2738 ot[OPTION(warnings)] = utilWarningsOption;
2740 ot[OPTION(optimization)] = utilOptimizationStrategy;
2742 for(n = node; n; n = n.parent)
2744 ProjectConfig nodeConfig = null;
2746 priority = (priority / 10 + 1) * 10;
2749 if(projectConfig && n.configurations)
2751 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2753 if(platform && c.platforms)
2755 for(p : c.platforms; !strcmpi(p.name, platformName))
2759 GenericOptionTools u = uu;
2761 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2763 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2764 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2765 optionConfigXplatformSet[o] = true;
2777 GenericOptionTools u = uu;
2781 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2783 for(p : n.platforms; !strcmpi(p.name, platformName))
2785 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2787 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2788 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2793 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2794 ((u.mergeValues && !u.configReplaces) ?
2795 u.OptionCheck(nodeConfig.options, o) :
2796 u.OptionSet(nodeConfig.options, o)))
2798 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2799 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2803 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2805 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2806 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2810 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2811 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2819 GenericOptionTools u = uu;
2822 u.FinalizeLoading(o, optionTempStrings, output);
2825 delete optionConfigXplatformSet;
2827 delete optionTempStrings;
2831 delete utilStringArrays;
2832 delete utilWarningsOption;
2833 delete utilOptimizationStrategy;
2840 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2842 ProjectOptions first = null;
2843 ProjectOptions commonOptions;
2845 Map<String, int> countIncludeDirs { };
2846 Map<String, int> countPreprocessorDefinitions { };
2847 Map<String, bool> commonIncludeDirs { };
2848 Map<String, bool> commonPreprocessorDefinitions { };
2850 for(options : byPlatformOptions) { first = options; break; }
2852 *platformsCommonOptions = commonOptions = first ? first.Copy() : { };
2854 if(commonOptions.includeDirs)
2855 commonOptions.includeDirs.Free();
2856 if(commonOptions.preprocessorDefinitions)
2857 commonOptions.preprocessorDefinitions.Free();
2859 for(options : byPlatformOptions)
2861 if(options != first)
2863 if(commonOptions.debug && options.debug != commonOptions.debug)
2864 commonOptions.debug = unset;
2865 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2866 commonOptions.memoryGuard = unset;
2867 if(commonOptions.profile && options.profile != commonOptions.profile)
2868 commonOptions.profile = unset;
2869 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2870 commonOptions.noLineNumbers = unset;
2871 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2872 commonOptions.strictNameSpaces = unset;
2873 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2874 commonOptions.fastMath = unset;
2876 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2877 commonOptions.warnings = unset;
2878 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2879 commonOptions.optimization = unset;
2881 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2882 delete commonOptions.defaultNameSpace;
2885 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2886 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2889 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2890 commonIncludeDirs, commonOptions.includeDirs);
2891 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2892 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2894 for(options : byPlatformOptions)
2896 if(options.debug && options.debug == commonOptions.debug)
2897 options.debug = unset;
2898 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2899 options.memoryGuard = unset;
2900 if(options.profile && options.profile == commonOptions.profile)
2901 options.profile = unset;
2902 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2903 options.noLineNumbers = unset;
2904 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2905 options.strictNameSpaces = unset;
2906 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2907 options.fastMath = unset;
2909 if(options.warnings && options.warnings == commonOptions.warnings)
2910 options.warnings = unset;
2911 if(options.optimization && options.optimization == commonOptions.optimization)
2912 options.optimization = unset;
2914 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2915 delete options.defaultNameSpace;
2917 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2918 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2921 delete countIncludeDirs;
2922 delete countPreprocessorDefinitions;
2923 delete commonIncludeDirs;
2924 delete commonPreprocessorDefinitions;
2927 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2928 Map<Platform, ProjectOptions> parentByPlatformOptions,
2929 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2931 ComplexComparison result = equal;
2932 ComplexComparison compare;
2934 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2936 ProjectOptions additionalOptions;
2937 additionsByPlatformOptions[platform] = { };
2938 additionalOptions = additionsByPlatformOptions[platform];
2939 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2940 if(compare == greater && result == equal)
2942 else if(compare == different)
2951 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2953 ComplexComparison result = equal;
2954 if(options.debug != parentOptions.debug ||
2955 options.memoryGuard != parentOptions.memoryGuard ||
2956 options.profile != parentOptions.profile ||
2957 options.noLineNumbers != parentOptions.noLineNumbers ||
2958 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2959 options.fastMath != parentOptions.fastMath ||
2960 options.warnings != parentOptions.warnings ||
2961 options.optimization != parentOptions.optimization ||
2962 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2963 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2967 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2968 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2970 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2971 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2977 enum ComplexComparison { different/*, smaller*/, equal, greater };
2979 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2982 if((!strings || !strings.count) && originals && originals.count)
2984 else if(strings && strings.count && (!originals || !originals.count))
2989 additions->Add(CopyString(s));
2991 else if(strings && strings.count && originals && originals.count)
2993 Map<String, String> map { };
2994 MapIterator<String, bool> mit { map = map };
2997 char * s = strstr(it, "\n");
3003 char * s = strstr(it, "\n");
3005 if(!mit.Index(s, false))
3020 additions->Add(CopyString(it));
3028 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3041 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3048 const char * s = ⁢
3049 strings.Add(CopyString(s));
3055 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3059 Array<String> tmp { };
3060 MapIterator<String, bool> mit { map = common };
3064 if(!mit.Index(s, false))
3065 tmp.Add(CopyString(s));
3071 strings.Add(CopyString(s));
3078 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3081 customFlags = nodeFlagsMapping[(intptr)node];
3083 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3085 f.Printf(" $(%s)", variableName);
3088 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3091 customFlags = nodeFlagsMapping[(intptr)node];
3093 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3095 s.concatf(" $(%s)", variableName);
3098 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3104 if(options.optimization == speed || options.optimization == size ||
3105 options.fastMath == true || options.debug == true)
3107 if(options.debug != true)
3109 s.concat(" $(if $(DEBUG),");
3113 switch(options.optimization)
3115 case speed: s.concat(" -O2"); break;
3116 case size: s.concat(" -Os"); break;
3118 if(options.fastMath == true)
3119 s.concat(" -ffast-math");
3120 if(options.debug == true)
3122 if(options.debug != true)
3125 else if(commonOptions)
3126 s.concat(" $(if $(DEBUG),-g)");
3128 s.concat(" $(FPIC)");
3130 switch(options.warnings)
3132 case all: s.concat(" -Wall"); break;
3133 case none: s.concat(" -w"); break;
3138 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3141 if(options && options.preprocessorDefinitions)
3142 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3143 if(options && options.includeDirs)
3144 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3147 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3149 if(options.memoryGuard == true)
3150 s.concat(" -memguard");
3151 if(options.noLineNumbers == true)
3152 s.concat(" -nolinenumbers");
3153 if(options.strictNameSpaces == true)
3154 s.concat(" -strictns");
3155 if(options.defaultNameSpace && options.defaultNameSpace[0])
3156 s.concatf(" -defaultns %s", options.defaultNameSpace);
3159 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3160 LineOutputMethod lineMethod, const String newLineStart)
3164 if(lineMethod == newLine)
3166 output.concat(" \\\n");
3167 output.concat(newLineStart);
3171 Map<String, int> sortedList { };
3172 MapNode<String, int> mn;
3174 sortedList[item] = 1;
3175 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3177 char * start = strstr(mn.key, "\n");
3178 if(lineMethod == lineEach)
3180 output.concat(" \\\n");
3181 output.concat(newLineStart);
3184 output.concat(flagNames[flag]);
3185 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3193 if(lineMethod == lineEach)
3195 output.concat(" \\\n");
3196 output.concat(newLineStart);
3199 output.concat(flagNames[flag]);
3200 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3206 class GenericOptionTools<class X>
3208 bool mergeValues, configReplaces;
3210 virtual bool OptionSet(ProjectOptions options, int option) {
3211 if(*(X*)((byte *)options + option))
3216 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3218 virtual bool OptionCheck(ProjectOptions options, int option) {
3219 return OptionSet(options, option);
3222 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3223 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3226 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3231 class NameCollisionInfo
3244 bool IsExtensionColliding(char * extension)
3248 ((!strcmpi(extension, "c") && ec) ||
3249 (!strcmpi(extension, "rc") && (ec || c)) ||
3250 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3251 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3252 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3253 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3254 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3255 !strcmpi(extension, "mm")))