1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(uintptr)(&((ProjectOptions)0).x))
17 static void OutputLog(const char * string)
19 #ifdef MAKEFILE_GENERATOR
22 ide.outputView.buildBox.Log(string);
26 bool eString_PathInsideOfMore(const char * path, const char * of, char * pathRest)
28 if(!path[0] || !of[0])
29 return false; // What to do here? Ever used?
32 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
33 char pathPart[MAX_FILENAME]; //, pathRest[MAX_LOCATION];
35 strcpy(pathRest, path);
36 for(; ofRest[0] && pathRest[0];)
38 SplitDirectory(ofRest, ofPart, ofRest);
39 SplitDirectory(pathRest, pathPart, pathRest);
40 if(fstrcmp(pathPart, ofPart))
43 if(!ofRest[0] && !pathRest[0])
45 else if(!pathRest[0]) // not inside of, it's the other way around
51 enum NodeTypes { project, file, folder, resources, folderOpen };
54 genFile, ewsFile, epjFile, folder, openFolder, ecFile, ehFile,
55 sFile, cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile,
56 archiveFile, packageFile, opticalMediaImageFile, mFile, mmFile;
58 NodeIcons ::SelectFileIcon(const char * filePath)
61 if(filePath && filePath[0])
63 char extension[MAX_EXTENSION];
64 GetExtension(filePath, extension);
67 if(!strcmpi(extension, WorkspaceExtension))
69 else if(!strcmpi(extension, ProjectExtension))
71 else if(!strcmpi(extension, "ec"))
73 else if(!strcmpi(extension, "eh"))
75 else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
76 !strcmpi(extension, "cxx"))
78 else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
79 !strcmpi(extension, "hxx"))
81 else if(!strcmpi(extension, "s"))
83 else if(!strcmpi(extension, "c"))
85 else if(!strcmpi(extension, "h"))
87 else if(!strcmpi(extension, "m"))
89 else if(!strcmpi(extension, "mm"))
91 else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
92 !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
94 else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
95 !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
96 !strcmpi(extension, "js"))
98 else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
99 !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
100 !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
101 !strcmpi(extension, "ico"))
103 else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
104 !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
106 else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
107 !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
108 !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
109 !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
110 !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
111 !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
113 else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
114 !strcmpi(extension, "rpm"))
116 else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
117 !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
118 !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
119 !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
120 icon = opticalMediaImageFile;
128 icon = genFile; // tocheck: error icon?
132 NodeIcons ::SelectNodeIcon(NodeTypes type)
151 #define SELECTION_COLOR Color { 10, 36, 106 }
157 // this is so not working, why!
159 // return result was not even executed (did not step on while debugging)
160 class TwoStrings : struct
182 //property char * { set { } }
183 DotMain ::FromFileName(const char * fileName)
185 DotMain dotMain = false;
186 if(fileName && fileName[0])
188 char ext[MAX_EXTENSION];
189 GetExtension(fileName, ext);
190 if(!strcmp(ext, "c") || !strcmp(ext, "ec"))
192 char stripExt[MAX_LOCATION];
193 strcpy(stripExt, fileName);
194 StripExtension(stripExt);
195 GetExtension(stripExt, ext);
196 if(!strcmp(ext, "main"))
204 enum IntermediateFileType
206 none, ec, c, sym, imp, bowl, o;
208 //property char * { set { } }
209 IntermediateFileType ::FromExtension(char * extension)
211 IntermediateFileType type = none;
212 if(extension && extension[0])
214 if(!fstrcmp(extension, "ec"))
216 else if(!fstrcmp(extension, "c"))
218 else if(!fstrcmp(extension, "sym"))
220 else if(!fstrcmp(extension, "imp"))
222 else if(!fstrcmp(extension, "bowl"))
224 else if(!fstrcmp(extension, "o"))
231 class ProjectNode : ListItem
236 set { return { fileName = value }; }
237 // TOCHECK: Is this isset necessary at all?
238 isset { return nodeType == file && !options && !configurations && !platforms && !files; }
240 property String folder
245 if(strchr(value, '/'))
247 char p[MAX_LOCATION];
248 char n[MAX_FILENAME];
249 GetLastDirectory(value, n);
250 StripLastDirectory(value, p);
251 name = CopyString(n);
252 path = CopyString(p);
255 name = CopyString(value);
259 // TOCHECK: Non Reentrant
260 static char insidePath[MAX_LOCATION];
262 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
263 PathCatSlash(insidePath, name);
265 if(!fstrcmp(path, insidePath))
269 strcpy(insidePath, path);
270 if(!insidePath[0]) strcpy(insidePath, ".");
271 PathCatSlash(insidePath, name);
275 isset { return nodeType == folder; }
277 property const String fileName
282 if(strchr(value, '/'))
284 char p[MAX_LOCATION];
285 char n[MAX_FILENAME];
286 GetLastDirectory(value, n);
287 StripLastDirectory(value, p);
288 name = CopyValidateMakefilePath(n);
289 path = CopyValidateMakefilePath(p);
292 name = CopyValidateMakefilePath(value);
296 // TOCHECK: Non Reentrant
297 static char insidePath[MAX_LOCATION];
299 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
300 if(!fstrcmp(path, insidePath))
304 strcpy(insidePath, path);
305 if(!insidePath[0]) strcpy(insidePath, ".");
306 PathCatSlash(insidePath, name);
310 isset { return nodeType == file && (options || configurations || platforms); }
313 LinkList<ProjectNode> files;
314 property ProjectOptions options
316 get { return project ? project.options : options; }
317 set { if(project) { delete project.options; project.options = value; } else { delete options; options = value; } }
318 isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
320 property Array<PlatformOptions> platforms
322 get { return project ? project.platforms : platforms; }
325 if(project) { project.platforms = value; }
328 if(platforms) { platforms.Free(); delete platforms; }
331 List<PlatformOptions> empty { };
332 Iterator<PlatformOptions> it { value };
334 for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
335 for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
342 Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
347 if(p.options && !p.options.isEmpty)
354 property List<ProjectConfig> configurations
356 get { return project ? project.configurations : configurations; }
361 if(project.configurations)
363 project.configurations.Free();
364 delete project.configurations;
366 project.configurations = value;
370 if(configurations) { configurations.Free(); delete configurations; }
373 List<ProjectConfig> empty { };
374 Iterator<ProjectConfig> it { value };
375 configurations = value;
376 for(c : configurations)
378 bool somethingSet = c.options && !c.options.isEmpty;
379 // TODO: Implement isset keyword
380 if(!somethingSet && c.platforms && c.platforms.count)
384 if(p.options && !p.options.isEmpty)
394 for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
401 if(!parent) return true;
404 for(c : configurations)
406 bool somethingSet = c.options && !c.options.isEmpty;
407 if(!somethingSet && c.platforms && c.platforms.count)
411 if(p.options && !p.options.isEmpty)
426 ProjectOptions options;
427 Array<PlatformOptions> platforms;
428 List<ProjectConfig> configurations;
429 ProjectNodeType nodeType;
434 // This holds the absolute path of the .epj for the project topnode (without the filename)
435 // It holds a relative path to the topNode (project) for other nodes (folders and files)
436 // For folders, it includes the folder it refers to. If there is a name difference between the
437 // file system folder and the grouping folder of the project view, it maps to that folder.
447 // This is only set for Top Nodes
450 void OpenRulesPlatformExclusionIfs(File f, int * ifCount, Array<Platform> platforms)
452 if(!platforms.Find(unknown)) // unknown is "Common"
454 // e.g. ifneq "$(or $(or $(OSX_TARGET),$(LINUX_TARGET)),$(WINDOWS_TARGET))"
457 for(i = 0; platforms.count && i < platforms.count - 1; i++)
465 f.Puts(PlatformToMakefileTargetVariable(p));
478 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
480 ProjectConfig nodeConfig = null;
481 if(property::configurations && prjConfig)
483 const char * configName = prjConfig.name;
484 for(cfg : property::configurations)
486 if(!strcmpi(cfg.name, configName))
496 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
498 property bool containsFile
507 if(child.type == file ||
508 ((child.type == folder || child.type == folderOpen) && child.containsFile))
521 char * GetFullFilePath(char * buffer)
525 strcpy(buffer, root.path);
526 PathCatSlash(buffer, path);
527 PathCatSlash(buffer, name);
532 char * GetObjectFileName(char * buffer, Map<String, NameCollisionInfo> namesInfo, IntermediateFileType type, bool dotMain)
534 if(buffer && (this.type == file || (this.type == project && dotMain == true)))
537 char extension[MAX_EXTENSION];
538 char moduleName[MAX_FILENAME];
539 NameCollisionInfo info;
541 GetExtension(name, extension);
542 ReplaceSpaces(moduleName, name);
543 StripExtension(moduleName);
544 info = namesInfo[moduleName];
545 collision = info ? info.IsExtensionColliding(extension) : false;
549 Project prj = property::project;
550 ReplaceSpaces(buffer, prj.moduleName);
551 StripExtension(buffer);
552 strcat(buffer, ".main.ec");
555 strcpy(buffer, name);
556 if(!strcmp(extension, "ec") || dotMain)
559 ChangeExtension(buffer, "c", buffer);
561 ChangeExtension(buffer, "sym", buffer);
563 ChangeExtension(buffer, "imp", buffer);
564 else if(type == bowl)
565 ChangeExtension(buffer, "bowl", buffer);
570 strcat(buffer, ".o");
572 ChangeExtension(buffer, "o", buffer);
578 char * GetFileSysMatchingPath(char * buffer)
582 ProjectNode n, root = this.root;
583 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
585 strcpy(buffer, root.path);
587 PathCatSlash(buffer, n.path);
588 if(FileExists(buffer).isDirectory)
591 if(!(n && (n.type == folder || n.type == project)))
597 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
599 ProjectNode node = null;
600 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
601 List<ProjectNode> nodeStack { };
603 for(node = this; node && node.parent; node = node.parent)
606 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
608 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
609 while((node = nodeStack.lastIterator.data))
611 ProjectOptions nodeOptions = node.property::options;
612 if(nodeOptions && nodeOptions.preprocessorDefinitions)
614 for(def : nodeOptions.preprocessorDefinitions)
615 perFilePreprocessorDefs.Add(CopyString(def));
617 if(config && config.options && config.options.preprocessorDefinitions)
619 for(def : config.options.preprocessorDefinitions)
620 perFilePreprocessorDefs.Add(CopyString(def));
622 if(nodeOptions && nodeOptions.includeDirs)
624 for(dir : nodeOptions.includeDirs)
625 perFileIncludeDirs.Add(CopySystemPath(dir));
627 if(config && config.options && config.options.includeDirs)
629 for(dir : config.options.includeDirs)
630 perFileIncludeDirs.Add(CopySystemPath(dir));
632 nodeStack.lastIterator.Remove();
638 property Project project
642 ProjectNode n = this;
643 while(n && n.type != project) n = n.parent;
644 return n ? (*&n.project) : null;
648 void RenameConfig(const char * oldName, const char * newName)
652 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
654 if(property::configurations)
656 for(c : property::configurations; !strcmp(c.name, oldName))
659 c.name = CopyString(newName);
664 void DeleteConfig(ProjectConfig configToDelete)
668 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
670 if(property::configurations)
672 Iterator<ProjectConfig> c { property::configurations };
675 ProjectConfig config = c.data;
676 if(!strcmp(configToDelete.name, config.name))
683 if(!property::configurations.count)
684 property::configurations = null;
690 ProjectNode backupNode { };
694 backupNode.files = { };
695 for(f : files) backupNode.files.Add(f.Backup());
697 if(property::options)
698 backupNode.options = property::options.Copy();
700 if(property::platforms)
702 backupNode.platforms = { };
703 for(p : property::platforms)
704 backupNode.platforms.Add(p.Copy());
707 if(property::configurations)
709 backupNode.configurations = { };
710 for(c : property::configurations)
711 backupNode.configurations.Add(c.Copy());
716 void Revert(ProjectNode backupNode)
720 Iterator<ProjectNode> it { backupNode.files };
728 property::options = backupNode.options ? backupNode.options.Copy() : null;
729 if(backupNode.platforms)
731 Array<PlatformOptions> platforms { };
732 property::platforms = platforms;
734 for(p : backupNode.platforms)
735 platforms.Add(p.Copy());
737 if(backupNode.configurations)
739 List<ProjectConfig> configurations { };
740 property::configurations = configurations;
741 for(c : backupNode.configurations)
742 configurations.Add(c.Copy());
746 void FixupNode(char * parentPath)
752 else if(nodeType == file)
757 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
760 else if(nodeType == folder)
766 char temp[MAX_LOCATION];
767 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
768 PathCatSlash(temp, name);
769 path = CopyString(temp);
773 indent = parent ? parent.indent + 1 : 0;
776 icon = NodeIcons::SelectFileIcon(name);
778 icon = NodeIcons::SelectNodeIcon(type);
787 parentPath[0] = '\0';
788 else if(type == resources || type == folder)
789 strcpy(parentPath, path);
791 f.FixupNode(parentPath);
796 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
800 // TOCHECK: Called from JSON writer
801 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
803 strcpy(tempString, "\"");
804 strcat(tempString, property::fileName);
805 strcat(tempString, "\"");
812 // TOCHECK: Called from ProjectView rendering
813 return name ? name : "";
826 if(!project && platforms)
831 if(!project && configurations)
833 configurations.Free();
834 delete configurations;
837 /////////////////////////////
843 property bool isInResources
848 for(node = this; node; node = node.parent)
850 if(node.type == resources)
857 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
859 TwoStrings result { a = CopyString(""), b = CopyString("") };
860 // note: unknown platform is for common
861 Map<Platform, SetBool> exclusionInfo { };
862 MapNode<Platform, SetBool> mn;
868 CollectExclusionInfo(exclusionInfo, prjConfig);
869 common = exclusionInfo[unknown];
871 Map<Platform, SetBool> cleaned { };
872 SetBool opposite = common == true ? false : true;
873 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
875 if(mn.key == unknown || mn.value == opposite)
876 cleaned[mn.key] = mn.value;
878 delete exclusionInfo;
879 exclusionInfo = cleaned;
882 if(exclusionInfo.count > 1)
884 if(exclusionInfo.count > 2)
887 len = strlen(exp) + strlen("$(if $(or ");
888 exp = renew exp char[len+1];
889 strcat(exp, "$(if $(or ");
892 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
894 if(mn.key != unknown)
896 const char * comma = mn.next ? "," : "";
898 var = PlatformToMakefileTargetVariable(mn.key);
901 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
902 exp = renew exp char[len+1];
912 len = strlen(exp) + strlen("),");
913 exp = renew exp char[len+1];
917 if(exclusionInfo.root.minimum.key != unknown)
918 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
920 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
923 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
924 exp = renew exp char[len+1];
925 strcat(exp, "$(if $(");
932 exp = common == true ? result.b : result.a;
933 len = strlen(exp) + strlen(",");
934 exp = renew exp char[len+1];
936 if(common == true) result.b = exp; else result.a = exp;
939 len = strlen(exp) + strlen(")");
940 exp = renew exp char[len+1];
944 delete exclusionInfo;
949 bool GetIsExcluded(ProjectConfig prjConfig)
952 // note: unknown platform is for common
953 Map<Platform, SetBool> exclusionInfo { };
954 CollectExclusionInfo(exclusionInfo, prjConfig);
955 if(exclusionInfo.count == 0)
957 else if(exclusionInfo.count == 1)
958 result = exclusionInfo.root.minimum.value == true;
961 SetBool check = exclusionInfo.root.minimum.value;
962 MapNode<Platform, SetBool> mn;
963 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
965 if(check != mn.value)
968 if(!mn) // all are same
969 result = check == true;
973 delete exclusionInfo;
977 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
979 // note: unknown platform is for common
981 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
982 ProjectOptions options = property::options;
983 Array<PlatformOptions> platforms = property::platforms;
986 parent.CollectExclusionInfo(output, prjConfig);
988 output[unknown] = unset;
990 if(options && options.excludeFromBuild)
991 output[unknown] = options.excludeFromBuild;
993 if(config && config.options && config.options.excludeFromBuild)
994 output[unknown] = config.options.excludeFromBuild;
1000 if(p.options.excludeFromBuild && (platform = p.name))
1001 output[platform] = p.options.excludeFromBuild;
1004 if(config && config.platforms)
1006 for(p : config.platforms)
1008 if(p.options.excludeFromBuild && (platform = p.name))
1009 output[platform] = p.options.excludeFromBuild;
1014 void EnsureVisible()
1017 parent.EnsureVisible();
1018 row.collapsed = false;
1024 parent.files.Delete(this);
1027 ProjectNode Find(const char * name, bool includeResources)
1029 ProjectNode result = null;
1034 if(includeResources || child.type != resources)
1036 if(child.type != folder && child.name && !strcmpi(child.name, name))
1041 result = child.Find(name, includeResources);
1050 ProjectNode FindWithPath(const char * name, bool includeResources)
1052 ProjectNode result = null;
1057 if(includeResources || child.type != resources)
1059 char path[MAX_LOCATION];
1060 strcpy(path, child.path);
1061 if(child.type != folder && child.name)
1063 PathCatSlash(path, child.name);
1064 if(!strcmpi(path, name))
1070 result = child.FindWithPath(name, includeResources);
1079 ProjectNode FindByFullPath(const char * path, bool includeResources)
1083 char name[MAX_FILENAME];
1084 GetLastDirectory(path, name);
1085 return InternalFindByFullPath(path, includeResources, name);
1090 ProjectNode InternalFindByFullPath(const char * path, bool includeResources, const char * lastDirName)
1092 ProjectNode result = null;
1097 if(includeResources || child.type != resources)
1099 if(child.type != file)
1100 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1101 else if(child.name && !fstrcmp(lastDirName, child.name))
1103 char p[MAX_LOCATION];
1104 child.GetFullFilePath(p);
1105 if(!fstrcmp(p, path))
1119 ProjectNode FindByObjectFileName(const char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo)
1121 char p[MAX_LOCATION];
1122 ProjectNode result = null;
1123 if(dotMain == true && this.type == project)
1125 GetObjectFileName(p, namesInfo, type, dotMain);
1126 if(!fstrcmp(p, fileName))
1131 for(child : files; child.type != resources)
1133 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo)))
1135 else if(child.type == file && child.name)
1137 child.GetObjectFileName(p, namesInfo, type, dotMain);
1138 if(!fstrcmp(p, fileName))
1149 ProjectNode FindSpecial(const char * name, bool recursive, bool includeResources, bool includeFolders)
1151 ProjectNode result = null;
1156 if(includeResources || child.type != resources)
1158 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1164 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1173 ProjectNode FindSameNameConflict(const char * name, bool includeResources,
1174 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1176 ProjectNode result = null;
1177 Map<Platform, SetBool> compareExclusion { };
1178 SetBool common, commonComp;
1179 SetBool actual, actualComp;
1184 if(includeResources || child.type != resources)
1186 if(child.type != folder && child.name && !strcmpi(child.name, name))
1188 child.CollectExclusionInfo(compareExclusion, prjConfig);
1189 common = exclusionInfo[unknown];
1190 commonComp = compareExclusion[unknown];
1191 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1193 if(!(common == true || commonComp == true))
1202 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1205 actualComp = commonComp;
1206 if(exclusionInfo[platform] != unset)
1207 actual = exclusionInfo[platform];
1208 if(compareExclusion[platform] != unset)
1209 actualComp = compareExclusion[platform];
1210 if(!(actual == true || actualComp == true))
1218 compareExclusion.Free();
1221 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1225 compareExclusion.Free();
1227 delete compareExclusion;
1231 ProjectNode Add(Project project, const char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1233 ProjectNode node = null;
1234 if(!project.topNode.FindByFullPath(filePath, true))
1236 char temp[MAX_LOCATION];
1237 Map<Platform, SetBool> exclusionInfo { };
1239 GetLastDirectory(filePath, temp);
1240 //if(!checkIfExists || !project.topNode.Find(temp, false))
1242 // TOCHECK: Shouldn't this apply either for all configs or none?
1243 CollectExclusionInfo(exclusionInfo, project.config);
1244 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1246 // Do the check for folder in the same parent or resource files only here
1247 if(type == folder || !checkIfExists)
1251 if(node.name && !strcmpi(node.name, temp))
1256 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1260 node.nodeType = folder;
1266 StripLastDirectory(filePath, temp);
1267 MakePathRelative(temp, project.topNode.path, temp);
1268 node.path = CopyUnixPath(temp);
1270 node.nodeType = file;
1274 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1275 PathCatSlash(temp, node.name);
1276 node.path = CopyString(temp);
1278 files.Insert(after, node);
1280 delete exclusionInfo;
1285 #ifndef MAKEFILE_GENERATOR
1286 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1288 char label[MAX_FILENAME];
1293 bool showConfig = true;
1298 projectView = ide.projectView;
1301 bmp = projectView.icons[icon].bitmap;
1302 xStart = x + (bmp ? (bmp.width + 5) : 0);
1304 GetLastDirectory(name, label);
1305 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1307 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1309 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1311 const char * addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1312 if(strlen(addendum))
1314 strcat(label, " (");
1315 strcat(label, addendum);
1318 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1319 if(strlen(addendum))
1321 strcat(label, " (");
1322 strcat(label, addendum);
1328 else if(!projectView.drawingInProjectSettingsDialog)
1331 strcat(label, " *");
1332 if(type == project && info)
1334 int len = strlen(info) + 4;
1335 char * more = new char[len];
1336 sprintf(more, " (%s)", info);
1337 strcat(label, more);
1341 len = strlen(label);
1345 if(type == folder || type == folderOpen)
1346 surface.SetForeground(yellow);
1350 surface.TextOpacity(false);
1351 surface.TextExtent(label, len, &w, &h);
1354 // Draw the current row stipple
1355 if(displayFlags.selected)
1356 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1357 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1358 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1360 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1364 if(displayFlags.current)
1366 if(displayFlags.active)
1368 surface.LineStipple(0x5555);
1369 if(displayFlags.selected)
1370 surface.SetForeground(projectView.fileList.stippleColor);
1372 surface.SetForeground(projectView.fileList.foreground);
1376 surface.SetForeground(SELECTION_COLOR);
1378 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1379 surface.LineStipple(0);
1384 surface.SetForeground(white);
1385 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1391 int OnCompare(ProjectNode b)
1394 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1395 result = strcmpi(name, b.name);
1398 if(type == folder && b.type == file) result = -1;
1399 else if(type == file && b.type == folder) result = 1;
1404 bool ContainsFilesWithExtension(const char * extension, ProjectConfig prjConfig)
1408 char ext[MAX_EXTENSION];
1409 GetExtension(name, ext);
1410 if(!fstrcmp(ext, extension))
1417 if(child.type != resources && (child.type == folder || !prjConfig || !child.GetIsExcluded(prjConfig)))
1419 if(child.ContainsFilesWithExtension(extension, prjConfig))
1427 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1431 char extension[MAX_EXTENSION];
1432 GetExtension(name, extension);
1433 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1434 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1435 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1437 char moduleName[MAX_FILENAME];
1438 NameCollisionInfo info;
1439 ReplaceSpaces(moduleName, name);
1440 StripExtension(moduleName);
1441 info = namesInfo[moduleName];
1443 info = NameCollisionInfo { };
1444 info.count++; // += 1; unless this is for a bug?
1445 if(!strcmpi(extension, "ec"))
1447 else if(!strcmpi(extension, "s"))
1449 else if(!strcmpi(extension, "c"))
1451 else if(!strcmpi(extension, "rc"))
1453 else if(!strcmpi(extension, "cpp"))
1455 else if(!strcmpi(extension, "cc"))
1457 else if(!strcmpi(extension, "cxx"))
1459 else if(!strcmpi(extension, "m"))
1461 else if(!strcmpi(extension, "mm"))
1463 namesInfo[moduleName] = info;
1470 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1471 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1476 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1477 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1478 ProjectConfig prjConfig, bool * containsCXX)
1484 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1485 char moduleName[MAX_FILENAME];
1486 char extension[MAX_EXTENSION];
1487 GetExtension(name, extension);
1488 if(printType == resources)
1491 char tempPath[MAX_LOCATION];
1492 char modulePath[MAX_LOCATION];
1495 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1498 PathCatSlash(tempPath, name);
1503 strcpy(tempPath, path);
1504 PathCatSlash(tempPath, name);
1506 EscapeForMake(modulePath, tempPath, false, true, false);
1507 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1508 items.Add(CopyString(s));
1510 else if(printType == sources)
1512 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1513 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1514 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1516 char modulePath[MAX_LOCATION];
1517 EscapeForMake(modulePath, path, false, true, false);
1518 EscapeForMake(moduleName, name, false, true, false);
1519 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1520 items.Add(CopyString(s));
1523 else if(printType == eCsources)
1525 if(!strcmpi(extension, "ec"))
1527 char modulePath[MAX_LOCATION];
1528 EscapeForMake(modulePath, path, true, true, false);
1529 EscapeForMake(moduleName, name, true, true, false);
1530 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1531 items.Add(CopyString(s));
1535 else if(printType == rcSources)
1537 if(!strcmpi(extension, "rc"))
1539 char modulePath[MAX_LOCATION];
1540 EscapeForMake(modulePath, path, false, true, false);
1541 EscapeForMake(moduleName, name, false, true, false);
1542 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1543 items.Add(CopyString(s));
1547 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1548 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1549 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1551 if(printType == objects)
1554 NameCollisionInfo info;
1556 EscapeForMake(moduleName, name, false, true, false);
1557 StripExtension(moduleName);
1558 info = namesInfo[moduleName];
1559 collision = info ? info.IsExtensionColliding(extension) : false;
1560 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1561 items.Add(CopyString(s));
1562 if(containsCXX && (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1563 *containsCXX = true;
1572 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1573 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1579 void GenMakefilePrintSymbolRules(File f, Project project,
1580 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1581 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1584 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1585 //ProjectNode child;
1586 //char objDir[MAX_LOCATION];
1587 //ReplaceSpaces(objDir, config.objDir.dir);
1589 //eSystem_Log("Printing Symbol Rules\n");
1592 char extension[MAX_EXTENSION];
1593 char modulePath[MAX_LOCATION];
1594 char moduleName[MAX_FILENAME];
1596 GetExtension(name, extension);
1597 if(!strcmpi(extension, "ec"))
1600 //char command[2048];
1602 ReplaceSpaces(moduleName, name);
1603 StripExtension(moduleName);
1605 ReplaceSpaces(modulePath, path);
1606 if(modulePath[0]) strcat(modulePath, SEPS);
1608 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1610 // *** Dependency command ***
1611 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1612 modulePath, moduleName, extension);
1614 // System Includes (from global settings)
1615 for(item : compiler.dirs[Includes])
1617 strcat(command, " -isystem ");
1618 if(strchr(item, ' '))
1620 strcat(command, "\"");
1621 strcat(command, item);
1622 strcat(command, "\"");
1625 strcat(command, item);
1628 for(item : project.includeDirs)
1630 strcat(command, " -I");
1631 if(strchr(item, ' '))
1633 strcat(command, "\"");
1634 strcat(command, item);
1635 strcat(command, "\"");
1638 strcat(command, item);
1640 for(item : project.preprocessorDefs)
1642 strcat(command, " -D");
1643 strcat(command, item);
1647 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1650 bool firstLine = true;
1653 // To do some time: auto save external dependencies?
1656 if(dep.GetLine(line, sizeof(line)-1))
1660 char * colon = strstr(line, ":");
1661 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1675 // If we failed to generate dependencies...
1679 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1680 moduleName, modulePath, moduleName, extension);
1684 f.Puts(" $(CFLAGS)");
1685 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1687 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1688 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1690 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1691 modulePath, moduleName, extension);
1692 if(ifCount) f.Puts("endif\n");
1702 if(ContainsFilesWithExtension("ec", prjConfig))
1706 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1707 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1708 nodeCFlagsMapping, nodeECFlagsMapping);
1715 void GenMakefilePrintPrepecsRules(File f, Project project,
1716 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1717 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1720 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1721 //ProjectNode child;
1722 //char objDir[MAX_LOCATION];
1723 //ReplaceSpaces(objDir, config.objDir.dir);
1725 //eSystem_Log("Printing Symbol Rules\n");
1728 char extension[MAX_EXTENSION];
1729 char modulePath[MAX_LOCATION];
1730 char moduleName[MAX_FILENAME];
1732 GetExtension(name, extension);
1733 if(!strcmpi(extension, "ec"))
1735 ReplaceSpaces(moduleName, name);
1736 StripExtension(moduleName);
1738 ReplaceSpaces(modulePath, path);
1739 if(modulePath[0]) strcat(modulePath, SEPS);
1741 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1742 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1743 moduleName, modulePath, moduleName, extension);
1744 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1745 modulePath, moduleName, extension, moduleName);*/
1749 f.Puts(" $(CFLAGS)");
1750 //f.Puts(" $(CECFLAGS)");
1751 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1752 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1754 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1755 modulePath, moduleName, extension, moduleName);
1756 if(ifCount) f.Puts("endif\n");
1762 if(ContainsFilesWithExtension("ec", prjConfig))
1766 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1767 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1768 nodeCFlagsMapping, nodeECFlagsMapping);
1775 void GenMakefilePrintCObjectRules(File f, Project project,
1776 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1777 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1780 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1781 //ProjectNode child;
1782 //char objDir[MAX_LOCATION];
1783 //ReplaceSpaces(objDir, config.objDir.dir);
1784 //eSystem_Log("Printing C Object Rules\n");
1787 char extension[MAX_EXTENSION];
1788 char modulePath[MAX_LOCATION];
1789 char moduleName[MAX_FILENAME];
1791 GetExtension(name, extension);
1792 if(!strcmpi(extension, "ec"))
1795 //char command[2048];
1797 ReplaceSpaces(moduleName, name);
1798 StripExtension(moduleName);
1800 ReplaceSpaces(modulePath, path);
1801 if(modulePath[0]) strcat(modulePath, SEPS);
1803 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1805 // *** Dependency command ***
1806 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1807 moduleName, modulePath, moduleName, extension);
1809 // System Includes (from global settings)
1810 for(item : compiler.dirs[Includes])
1812 strcat(command, " -isystem ");
1813 if(strchr(item, ' '))
1815 strcat(command, "\"");
1816 strcat(command, item);
1817 strcat(command, "\"");
1820 strcat(command, item);
1823 for(item : config.includeDirs)
1825 strcat(command, " -I");
1826 if(strchr(item, ' '))
1828 strcat(command, "\"");
1829 strcat(command, item);
1830 strcat(command, "\"");
1833 strcat(command, item);
1835 for(item : config.preprocessorDefs)
1837 strcat(command, " -D");
1838 strcat(command, item);
1842 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1846 bool firstLine = true;
1848 // To do some time: auto save external dependencies?
1851 if(dep.GetLine(line, sizeof(line)-1))
1855 char * colon = strstr(line, ":");
1856 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1870 // If we failed to generate dependencies...
1873 /* COMMENTED OUT FOR NOW
1874 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1875 moduleName, modulePath, moduleName, extension);
1878 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1879 moduleName, modulePath, moduleName, extension, moduleName);
1885 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1886 modulePath, moduleName, extension, moduleName);
1891 f.Puts(" $(CFLAGS)");
1892 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1893 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1894 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1895 f.Puts(" $(FVISIBILITY)");
1897 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1898 modulePath, moduleName, extension);
1899 if(ifCount) f.Puts("endif\n");
1905 if(ContainsFilesWithExtension("ec", prjConfig))
1909 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1910 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1911 nodeCFlagsMapping, nodeECFlagsMapping);
1918 void GenMakefilePrintObjectRules(File f, Project project,
1919 Map<String, NameCollisionInfo> namesInfo,
1920 ProjectConfig prjConfig,
1921 //Map<Platform, bool> parentExcludedPlatforms,
1922 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1925 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1926 //ProjectNode child;
1927 //char objDir[MAX_LOCATION];
1928 //ReplaceSpaces(objDir, config.objDir.dir);
1929 //eSystem_Log("Printing Object Rules\n");
1933 char extension[MAX_EXTENSION];
1934 char modulePath[MAX_LOCATION];
1935 char moduleName[MAX_FILENAME];
1937 GetExtension(name, extension);
1938 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1939 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1940 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1943 //char command[2048];
1944 NameCollisionInfo info;
1946 ReplaceSpaces(moduleName, name);
1947 StripExtension(moduleName);
1949 info = namesInfo[moduleName];
1950 collision = info ? info.IsExtensionColliding(extension) : false;
1952 ReplaceSpaces(modulePath, path);
1953 if(modulePath[0]) strcat(modulePath, SEPS);
1957 // *** Dependency command ***
1958 if(!strcmpi(extension, "ec"))
1959 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
1961 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
1962 moduleName, modulePath, moduleName, extension);
1964 if(!strcmpi(extension, "ec"))
1966 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1970 // System Includes (from global settings)
1971 for(item : compiler.dirs[includes])
1973 strcat(command, " -isystem ");
1974 if(strchr(item, ' '))
1976 strcat(command, "\"");
1977 strcat(command, item);
1978 strcat(command, "\"");
1981 strcat(command, item);
1984 for(item : config.includeDirs)
1986 strcat(command, " -I");
1987 if(strchr(item, ' '))
1989 strcat(command, "\"");
1990 strcat(command, item);
1991 strcat(command, "\"");
1994 strcat(command, item);
1996 for(item : config.preprocessorDefs)
1998 strcat(command, " -D");
1999 strcat(command, item);
2003 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2006 bool firstLine = true;
2009 // To do some time: auto save external dependencies?
2013 if(dep.GetLine(line, sizeof(line)-1))
2017 char * colon = strstr(line, ":");
2018 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2032 // If we failed to generate dependencies...
2041 if(!strcmpi(extension, "rc"))
2044 f.Puts("ifdef WINDOWS_TARGET\n\n");
2047 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2049 if(!strcmpi(extension, "ec"))
2050 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2052 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
2053 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
2054 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2055 f.Printf("\t$(CXX)");
2056 else if(!strcmpi(extension, "rc"))
2057 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2059 f.Printf("\t$(CC)");
2061 if(strcmpi(extension, "rc") != 0)
2063 f.Puts(" $(CFLAGS)");
2064 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2066 if(!strcmpi(extension, "ec"))
2067 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n", moduleName);
2069 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2070 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2072 if(ifCount) f.Puts("endif\n");
2078 bool needed = false;
2081 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2091 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2092 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2093 nodeCFlagsMapping, nodeECFlagsMapping);
2100 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
2107 //Iterator<ProjectNode> i { files };
2108 //Iterator<ProjectNode> prev { files };
2109 //for(child : files)
2111 for(c = 0; c < files.count; c++)
2113 ProjectNode child = files[c];
2114 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2117 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2120 char tempPath[MAX_LOCATION];
2121 char resPath[MAX_LOCATION];
2123 // $(EAR) aw%s --- /*quiet ? "q" : */""
2125 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(TARGET)", ts.a);
2128 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2131 PathCatSlash(tempPath, child.name);
2136 strcpy(tempPath, child.path);
2137 PathCatSlash(tempPath, child.name);
2139 EscapeForMake(resPath, tempPath, false, true, false);
2140 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2143 if(count == 10 || (count > 0 && (ts || !child.next)))
2145 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2148 for(parent = this; parent.type == folder; parent = parent.parent)
2151 strcpy(path, parent.name);
2158 f.Printf(" \"%s\"%s\n", path, ts.b);
2170 if(child.type == folder)
2171 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
2176 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2177 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2178 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2179 Map<Platform, ProjectOptions> parentByPlatformOptions)
2181 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2182 if(type == file || type == folder || type == project)
2184 bool hasPerNodeOptions = type == project;
2185 if(!hasPerNodeOptions)
2187 if(options && !options.isEmpty)
2188 hasPerNodeOptions = true;
2189 else if(configurations)
2191 for(c : configurations)
2193 if(c.options && !c.options.isEmpty)
2195 hasPerNodeOptions = true;
2200 for(p : c.platforms)
2202 if(p.options && !p.options.isEmpty)
2204 hasPerNodeOptions = true;
2208 if(hasPerNodeOptions)
2213 if(!hasPerNodeOptions && platforms)
2217 if(p.options && !p.options.isEmpty)
2219 hasPerNodeOptions = true;
2226 if(hasPerNodeOptions)
2228 bool isEqual = false, isGreater = false;
2229 ComplexComparison complexCmp;
2231 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2232 ProjectOptions platformsCommonOptions;
2233 ProjectOptions byFileConfigPlatformProjectOptions;
2235 DynamicString cflags { };
2236 DynamicString ecflags { };
2240 byPlatformOptions = { };
2242 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2244 byFileConfigPlatformProjectOptions =
2245 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2246 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2249 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2251 byPlatformOptions[unknown] = platformsCommonOptions;
2253 if(parentByPlatformOptions)
2255 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2256 parentByPlatformOptions, additionsByPlatformOptions);
2257 isGreater = complexCmp == greater;
2258 isEqual = complexCmp == equal;
2263 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2265 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2267 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2269 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2272 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2274 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2278 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2280 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2283 if(!isGreater) cflags.concat(" \\\n\t");
2288 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2291 ecflags.concat(" \\\n\t");
2298 cflags.concat(" \\\n\t");
2299 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2303 additionsByPlatformOptions.Free();
2304 delete additionsByPlatformOptions;
2310 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2311 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2319 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2320 cflagsVariations[s] = variationNum = cflagsVariations.count;
2321 nodeCFlagsMapping[(intptr)this] = variationNum;
2324 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2325 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2326 nodeECFlagsMapping[(intptr)this] = variationNum;
2337 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2338 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2347 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2348 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2349 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2354 if(byPlatformOptions != parentByPlatformOptions)
2356 byPlatformOptions.Free();
2357 delete byPlatformOptions;
2361 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2363 Array<Platform> platforms { };
2364 Map<Platform, SetBool> exclusionInfo { };
2365 CollectExclusionInfo(exclusionInfo, prjConfig);
2367 if(exclusionInfo[unknown] == true)
2369 if(exclusionInfo.count > 1)
2370 for(p : exclusionInfo; p == false)
2375 bool onlyOnknown = true;
2376 for(p : exclusionInfo)
2377 if(&p != unknown && p == true)
2379 onlyOnknown = false;
2383 platforms.Add(unknown);
2387 for(p = unknown + 1; p < Platform::enumSize; p++)
2388 if(exclusionInfo[p] != true)
2392 delete exclusionInfo;
2396 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, DynamicString output)
2398 char moduleName[MAX_FILENAME];
2401 bool headerAltFailed = false;
2403 char extension[MAX_EXTENSION];
2404 NameCollisionInfo info;
2405 Project prj = property::project;
2406 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2408 GetExtension(name, extension);
2409 strcpy(moduleName, name);
2410 StripExtension(moduleName);
2411 info = namesInfo[moduleName];
2412 collision = info ? info.IsExtensionColliding(extension) : false;
2414 for(h2s : headerToSource)
2416 if(!strcmpi(extension, &h2s))
2418 char filePath[MAX_LOCATION];
2419 GetFullFilePath(filePath);
2420 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2421 ChangeExtension(moduleName, h2s, moduleName);
2422 if(prj.topNode.Find(moduleName, false))
2424 strcpy(extension, h2s);
2425 collision = info ? info.IsExtensionColliding(extension) : false;
2426 ChangeExtension(filePath, h2s, filePath);
2427 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2428 StripExtension(moduleName);
2432 headerAltFailed = true;
2433 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2434 StripExtension(moduleName);
2440 if(!headerAltFailed)
2442 output.concat(" \"");
2443 output.concat(objDir); //.concat(" $(OBJ)");
2448 strcat(moduleName, ".");
2449 strcat(moduleName, extension);
2451 strcat(moduleName, ".o");
2452 output.concat(moduleName);
2453 output.concat("\"");
2456 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2458 Project prj = property::project;
2460 ReplaceSpaces(moduleName, prj.moduleName);
2461 strcat(moduleName, ".main.ec");
2462 output.concat(" \"");
2463 output.concat(objDir);
2465 output.concat(moduleName);
2466 output.concat("\"");
2468 ChangeExtension(moduleName, "c", moduleName);
2469 output.concat(" \"");
2470 output.concat(objDir);
2472 output.concat(moduleName);
2473 output.concat("\"");
2475 ChangeExtension(moduleName, "o", moduleName);
2476 output.concat(" \"");
2477 output.concat(objDir);
2479 output.concat(moduleName);
2480 output.concat("\"");
2486 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2487 child.GetTargets(prjConfig, namesInfo, objDir, output);
2492 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2497 char extension[MAX_EXTENSION];
2498 char fileName[MAX_FILENAME];
2499 char moduleName[MAX_FILENAME];
2500 NameCollisionInfo info;
2501 Project prj = property::project;
2502 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2504 GetExtension(name, extension);
2505 ReplaceSpaces(moduleName, name);
2506 StripExtension(moduleName);
2507 info = namesInfo[moduleName];
2508 collision = info ? info.IsExtensionColliding(extension) : false;
2510 strcpy(fileName, prj.topNode.path);
2511 PathCatSlash(fileName, objDir.dir);
2512 PathCatSlash(fileName, name);
2514 if(!onlyCObject && !strcmp(extension, "ec"))
2516 ChangeExtension(fileName, "c", fileName);
2517 if(FileExists(fileName)) DeleteFile(fileName);
2518 ChangeExtension(fileName, "sym", fileName);
2519 if(FileExists(fileName)) DeleteFile(fileName);
2520 ChangeExtension(fileName, "imp", fileName);
2521 if(FileExists(fileName)) DeleteFile(fileName);
2522 ChangeExtension(fileName, "bowl", fileName);
2523 if(FileExists(fileName)) DeleteFile(fileName);
2524 ChangeExtension(fileName, "ec", fileName);
2528 strcat(fileName, ".o");
2530 ChangeExtension(fileName, "o", fileName);
2531 if(FileExists(fileName)) DeleteFile(fileName);
2539 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2540 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2545 bool IsInNode(ProjectNode node)
2547 bool result = false;
2549 for(n = this; n; n = n.parent)
2561 // the code in this function is closely matched to OptionsBox::Load
2562 // and accompanying derivations of OptionBox and their use of OptionSet,
2563 // OptionCheck, LoadOption and FinalizeLoading methods.
2564 // output changing modification should be mirrored in both implementations
2565 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2567 ProjectOptions output { };
2569 // legend: e Element
2570 // o Option (of a ProjectOptions)
2571 // n Node (ProjectNode)
2573 // u Utility (GenericOptionTools)
2577 int includeDirsOption = OPTION(includeDirs);
2579 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2581 // OPTION(ProjectOptions' last member) for size
2582 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2583 Array<bool> optionDone { size = OPTION(installCommands) };
2584 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2586 GenericOptionTools<SetBool> utilSetBool {
2587 bool OptionCheck(ProjectOptions options, int option) {
2588 return *(SetBool*)((byte *)options + option) == true;
2590 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2591 if(options && (*(SetBool*)((byte *)options + option) == true))
2592 *(SetBool*)((byte *)output + option) = true;
2595 GenericOptionTools<String> utilString {
2596 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2597 String * string = (String*)((byte *)output + option);
2598 if(*string) delete *string;
2600 *string = CopyString(*(String*)((byte *)options + option));
2603 StringArrayOptionTools utilStringArrays {
2605 caseSensitive = true;
2606 bool OptionCheck(ProjectOptions options, int option) {
2607 Array<String> strings = *(Array<String>*)((byte *)options + option);
2608 return strings && strings.count;
2610 bool OptionSet(ProjectOptions options, int option) {
2611 Array<String> strings = *(Array<String>*)((byte *)options + option);
2612 if(mergeValues && !configReplaces)
2613 return strings && strings.count;
2615 return strings != null;
2617 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2620 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2624 Array<String> tempStrings = optionTempStrings[option];
2626 optionTempStrings[option] = tempStrings = { };
2630 char priorityMark[10];
2633 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2634 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2635 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2641 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2642 Array<String> * strings = (Array<String>*)((byte *)output + option);
2643 if(*strings) { strings->Free(); delete *strings; }
2644 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2647 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2650 Array<String> tempStrings = optionTempStrings[option];
2651 Array<String> * strings = (Array<String>*)((byte *)output + option);
2652 if(*strings) { strings->Free(); delete *strings; }
2653 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2658 GenericOptionTools<WarningsOption> utilWarningsOption {
2659 bool OptionCheck(ProjectOptions options, int option) {
2660 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2661 return value && value != none;
2663 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2664 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2665 *(WarningsOption*)((byte *)output + option) = value;
2668 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2669 bool OptionCheck(ProjectOptions options, int option) {
2670 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2671 return value && value != none;
2673 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2674 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2675 *(OptimizationStrategy*)((byte *)output + option) = value;
2679 Map<int, GenericOptionTools> ot { };
2681 // The following are compiler options
2683 ot[OPTION(debug)] = utilSetBool;
2684 ot[OPTION(memoryGuard)] = utilSetBool;
2685 ot[OPTION(profile)] = utilSetBool;
2686 ot[OPTION(noLineNumbers)] = utilSetBool;
2687 ot[OPTION(strictNameSpaces)] = utilSetBool;
2688 ot[OPTION(fastMath)] = utilSetBool;
2690 ot[OPTION(defaultNameSpace)] = utilString;
2692 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2693 ot[OPTION(includeDirs)] = utilStringArrays;
2695 ot[OPTION(warnings)] = utilWarningsOption;
2697 ot[OPTION(optimization)] = utilOptimizationStrategy;
2699 for(n = node; n; n = n.parent)
2701 ProjectConfig nodeConfig = null;
2703 priority = (priority / 10 + 1) * 10;
2706 if(projectConfig && n.configurations)
2708 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2710 if(platform && c.platforms)
2712 for(p : c.platforms; !strcmpi(p.name, platformName))
2716 GenericOptionTools u = uu;
2718 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2720 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2721 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2722 optionConfigXplatformSet[o] = true;
2734 GenericOptionTools u = uu;
2738 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2740 for(p : n.platforms; !strcmpi(p.name, platformName))
2742 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2744 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2745 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2750 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2751 ((u.mergeValues && !u.configReplaces) ?
2752 u.OptionCheck(nodeConfig.options, o) :
2753 u.OptionSet(nodeConfig.options, o)))
2755 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2756 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2760 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2762 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2763 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2767 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2768 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2776 GenericOptionTools u = uu;
2779 u.FinalizeLoading(o, optionTempStrings, output);
2782 delete optionConfigXplatformSet;
2784 delete optionTempStrings;
2788 delete utilStringArrays;
2789 delete utilWarningsOption;
2790 delete utilOptimizationStrategy;
2797 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2799 ProjectOptions first = null;
2800 ProjectOptions commonOptions;
2802 Map<String, int> countIncludeDirs { };
2803 Map<String, int> countPreprocessorDefinitions { };
2804 Map<String, bool> commonIncludeDirs { };
2805 Map<String, bool> commonPreprocessorDefinitions { };
2807 for(options : byPlatformOptions) { first = options; break; }
2809 *platformsCommonOptions = commonOptions = first ? first.Copy() : { };
2811 if(commonOptions.includeDirs)
2812 commonOptions.includeDirs.Free();
2813 if(commonOptions.preprocessorDefinitions)
2814 commonOptions.preprocessorDefinitions.Free();
2816 for(options : byPlatformOptions)
2818 if(options != first)
2820 if(commonOptions.debug && options.debug != commonOptions.debug)
2821 commonOptions.debug = unset;
2822 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2823 commonOptions.memoryGuard = unset;
2824 if(commonOptions.profile && options.profile != commonOptions.profile)
2825 commonOptions.profile = unset;
2826 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2827 commonOptions.noLineNumbers = unset;
2828 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2829 commonOptions.strictNameSpaces = unset;
2830 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2831 commonOptions.fastMath = unset;
2833 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2834 commonOptions.warnings = unset;
2835 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2836 commonOptions.optimization = unset;
2838 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2839 delete commonOptions.defaultNameSpace;
2842 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2843 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2846 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2847 commonIncludeDirs, commonOptions.includeDirs);
2848 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2849 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2851 for(options : byPlatformOptions)
2853 if(options.debug && options.debug == commonOptions.debug)
2854 options.debug = unset;
2855 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2856 options.memoryGuard = unset;
2857 if(options.profile && options.profile == commonOptions.profile)
2858 options.profile = unset;
2859 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2860 options.noLineNumbers = unset;
2861 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2862 options.strictNameSpaces = unset;
2863 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2864 options.fastMath = unset;
2866 if(options.warnings && options.warnings == commonOptions.warnings)
2867 options.warnings = unset;
2868 if(options.optimization && options.optimization == commonOptions.optimization)
2869 options.optimization = unset;
2871 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2872 delete options.defaultNameSpace;
2874 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2875 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2878 delete countIncludeDirs;
2879 delete countPreprocessorDefinitions;
2880 delete commonIncludeDirs;
2881 delete commonPreprocessorDefinitions;
2884 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2885 Map<Platform, ProjectOptions> parentByPlatformOptions,
2886 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2888 ComplexComparison result = equal;
2889 ComplexComparison compare;
2891 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2893 ProjectOptions additionalOptions;
2894 additionsByPlatformOptions[platform] = { };
2895 additionalOptions = additionsByPlatformOptions[platform];
2896 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2897 if(compare == greater && result == equal)
2899 else if(compare == different)
2908 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2910 ComplexComparison result = equal;
2911 if(options.debug != parentOptions.debug ||
2912 options.memoryGuard != parentOptions.memoryGuard ||
2913 options.profile != parentOptions.profile ||
2914 options.noLineNumbers != parentOptions.noLineNumbers ||
2915 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2916 options.fastMath != parentOptions.fastMath ||
2917 options.warnings != parentOptions.warnings ||
2918 options.optimization != parentOptions.optimization ||
2919 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2920 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2924 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2925 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2927 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2928 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2934 enum ComplexComparison { different/*, smaller*/, equal, greater };
2936 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2939 if((!strings || !strings.count) && originals && originals.count)
2941 else if(strings && strings.count && (!originals || !originals.count))
2946 additions->Add(CopyString(s));
2948 else if(strings && strings.count && originals && originals.count)
2950 Map<String, String> map { };
2951 MapIterator<String, bool> mit { map = map };
2954 char * s = strstr(it, "\n");
2960 char * s = strstr(it, "\n");
2962 if(!mit.Index(s, false))
2977 additions->Add(CopyString(it));
2985 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
2998 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3005 const char * s = ⁢
3006 strings.Add(CopyString(s));
3012 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3016 Array<String> tmp { };
3017 MapIterator<String, bool> mit { map = common };
3021 if(!mit.Index(s, false))
3022 tmp.Add(CopyString(s));
3028 strings.Add(CopyString(s));
3035 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3038 customFlags = nodeFlagsMapping[(intptr)node];
3040 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3042 f.Printf(" $(%s)", variableName);
3045 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3048 customFlags = nodeFlagsMapping[(intptr)node];
3050 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3052 s.concatf(" $(%s)", variableName);
3055 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3061 if(options.optimization == speed || options.optimization == size ||
3062 options.fastMath == true || options.debug == true)
3064 if(options.debug != true)
3066 s.concat(" $(if $(DEBUG),");
3070 switch(options.optimization)
3072 case speed: s.concat(" -O2"); break;
3073 case size: s.concat(" -Os"); break;
3075 if(options.fastMath == true)
3076 s.concat(" -ffast-math");
3077 if(options.debug == true)
3079 if(options.debug != true)
3082 else if(commonOptions)
3083 s.concat(" $(if $(DEBUG),-g)");
3085 s.concat(" $(FPIC)");
3087 switch(options.warnings)
3089 case all: s.concat(" -Wall"); break;
3090 case none: s.concat(" -w"); break;
3095 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3098 if(options && options.preprocessorDefinitions)
3099 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3100 if(options && options.includeDirs)
3101 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3104 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3106 if(options.memoryGuard == true)
3107 s.concat(" -memguard");
3108 if(options.noLineNumbers == true)
3109 s.concat(" -nolinenumbers");
3110 if(options.strictNameSpaces == true)
3111 s.concat(" -strictns");
3112 if(options.defaultNameSpace && options.defaultNameSpace[0])
3113 s.concatf(" -defaultns %s", options.defaultNameSpace);
3116 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3117 LineOutputMethod lineMethod, const String newLineStart)
3121 if(lineMethod == newLine)
3123 output.concat(" \\\n");
3124 output.concat(newLineStart);
3128 Map<String, int> sortedList { };
3129 MapNode<String, int> mn;
3131 sortedList[item] = 1;
3132 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3134 char * start = strstr(mn.key, "\n");
3135 if(lineMethod == lineEach)
3137 output.concat(" \\\n");
3138 output.concat(newLineStart);
3141 output.concat(flagNames[flag]);
3142 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3150 if(lineMethod == lineEach)
3152 output.concat(" \\\n");
3153 output.concat(newLineStart);
3156 output.concat(flagNames[flag]);
3157 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3163 class GenericOptionTools<class X>
3165 bool mergeValues, configReplaces;
3167 virtual bool OptionSet(ProjectOptions options, int option) {
3168 if(*(X*)((byte *)options + option))
3173 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3175 virtual bool OptionCheck(ProjectOptions options, int option) {
3176 return OptionSet(options, option);
3179 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3180 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3183 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3188 class NameCollisionInfo
3201 bool IsExtensionColliding(char * extension)
3205 ((!strcmpi(extension, "c") && ec) ||
3206 (!strcmpi(extension, "rc") && (ec || c)) ||
3207 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3208 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3209 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3210 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3211 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3212 !strcmpi(extension, "mm")))