1 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
12 static define app = ((GuiApplication)__thisModule);
15 #define OPTION(x) ((uint)(uintptr)(&((ProjectOptions)0).x))
17 static void OutputLog(const char * string)
19 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
20 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, bool absolute, bool resolveVars)
527 strcpy(buffer, root.path);
532 DirExpression pathExp { };
533 Project project = property::project;
534 CompilerConfig compiler = GetCompilerConfig();
535 ProjectConfig config = project.config;
536 int bitDepth = GetBitDepth();
537 pathExp.Evaluate(path, project, compiler, config, bitDepth);
538 PathCatSlash(buffer, pathExp.dir);
542 PathCatSlash(buffer, name);
546 PathCatSlash(buffer, path);
547 PathCatSlash(buffer, name);
553 char * GetObjectFileName(char * buffer, Map<String, NameCollisionInfo> namesInfo, IntermediateFileType type, bool dotMain, const char * objectFileExt)
555 if(buffer && (this.type == file || (this.type == project && dotMain == true)))
558 char extension[MAX_EXTENSION];
559 char moduleName[MAX_FILENAME];
560 const char * objFileExt = objectFileExt ? objectFileExt : objectDefaultFileExt;
561 NameCollisionInfo info;
563 GetExtension(name, extension);
564 ReplaceSpaces(moduleName, name);
565 StripExtension(moduleName);
566 info = namesInfo[moduleName];
567 collision = info ? info.IsExtensionColliding(extension) : false;
571 Project prj = property::project;
572 ReplaceSpaces(buffer, prj.moduleName);
573 StripExtension(buffer);
574 strcat(buffer, ".main.ec");
577 strcpy(buffer, name);
578 if(!strcmp(extension, "ec") || dotMain)
581 ChangeExtension(buffer, "c", buffer);
583 ChangeExtension(buffer, "sym", buffer);
585 ChangeExtension(buffer, "imp", buffer);
586 else if(type == bowl)
587 ChangeExtension(buffer, "bowl", buffer);
594 strcat(buffer, objFileExt);
597 ChangeExtension(buffer, objFileExt, buffer);
603 char * GetFileSysMatchingPath(char * buffer)
607 ProjectNode n, root = this.root;
608 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
610 strcpy(buffer, root.path);
612 PathCatSlash(buffer, n.path);
613 if(FileExists(buffer).isDirectory)
616 if(!(n && (n.type == folder || n.type == project)))
622 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
624 ProjectNode node = null;
625 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
626 List<ProjectNode> nodeStack { };
628 for(node = this; node && node.parent; node = node.parent)
631 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
633 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
634 while((node = nodeStack.lastIterator.data))
636 ProjectOptions nodeOptions = node.property::options;
637 if(nodeOptions && nodeOptions.preprocessorDefinitions)
639 for(def : nodeOptions.preprocessorDefinitions)
640 perFilePreprocessorDefs.Add(CopyString(def));
642 if(config && config.options && config.options.preprocessorDefinitions)
644 for(def : config.options.preprocessorDefinitions)
645 perFilePreprocessorDefs.Add(CopyString(def));
647 if(nodeOptions && nodeOptions.includeDirs)
649 for(dir : nodeOptions.includeDirs)
650 perFileIncludeDirs.Add(CopySystemPath(dir));
652 if(config && config.options && config.options.includeDirs)
654 for(dir : config.options.includeDirs)
655 perFileIncludeDirs.Add(CopySystemPath(dir));
657 nodeStack.lastIterator.Remove();
663 property Project project
667 ProjectNode n = this;
668 while(n && n.type != project) n = n.parent;
669 return n ? (*&n.project) : null;
673 void RenameConfig(const char * oldName, const char * newName)
677 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
679 if(property::configurations)
681 for(c : property::configurations; !strcmp(c.name, oldName))
684 c.name = CopyString(newName);
689 void DeleteConfig(ProjectConfig configToDelete)
693 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
695 if(property::configurations)
697 Iterator<ProjectConfig> c { property::configurations };
700 ProjectConfig config = c.data;
701 if(!strcmp(configToDelete.name, config.name))
708 if(!property::configurations.count)
709 property::configurations = null;
715 ProjectNode backupNode { };
719 backupNode.files = { };
720 for(f : files) backupNode.files.Add(f.Backup());
722 if(property::options)
723 backupNode.options = property::options.Copy();
725 if(property::platforms)
727 backupNode.platforms = { };
728 for(p : property::platforms)
729 backupNode.platforms.Add(p.Copy());
732 if(property::configurations)
734 backupNode.configurations = { };
735 for(c : property::configurations)
736 backupNode.configurations.Add(c.Copy());
741 void Revert(ProjectNode backupNode)
745 Iterator<ProjectNode> it { backupNode.files };
753 property::options = backupNode.options ? backupNode.options.Copy() : null;
754 if(backupNode.platforms)
756 Array<PlatformOptions> platforms { };
757 property::platforms = platforms;
759 for(p : backupNode.platforms)
760 platforms.Add(p.Copy());
762 if(backupNode.configurations)
764 List<ProjectConfig> configurations { };
765 property::configurations = configurations;
766 for(c : backupNode.configurations)
767 configurations.Add(c.Copy());
771 void FixupNode(char * parentPath)
777 else if(nodeType == file)
782 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
785 else if(nodeType == folder)
791 char temp[MAX_LOCATION];
792 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
793 PathCatSlash(temp, name);
794 path = CopyString(temp);
798 indent = parent ? parent.indent + 1 : 0;
801 icon = NodeIcons::SelectFileIcon(name);
803 icon = NodeIcons::SelectNodeIcon(type);
812 parentPath[0] = '\0';
813 else if(type == resources || type == folder)
814 strcpy(parentPath, path);
816 f.FixupNode(parentPath);
821 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
825 // TOCHECK: Called from JSON writer
826 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
828 strcpy(tempString, "\"");
829 strcat(tempString, property::fileName);
830 strcat(tempString, "\"");
837 // TOCHECK: Called from ProjectView rendering
838 return name ? name : "";
851 if(!project && platforms)
856 if(!project && configurations)
858 configurations.Free();
859 delete configurations;
862 /////////////////////////////
868 property bool isInResources
873 for(node = this; node; node = node.parent)
875 if(node.type == resources)
882 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
884 TwoStrings result { a = CopyString(""), b = CopyString("") };
885 // note: unknown platform is for common
886 Map<Platform, SetBool> exclusionInfo { };
887 MapNode<Platform, SetBool> mn;
893 CollectExclusionInfo(exclusionInfo, prjConfig);
894 common = exclusionInfo[unknown];
896 Map<Platform, SetBool> cleaned { };
897 SetBool opposite = common == true ? false : true;
898 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
900 if(mn.key == unknown || mn.value == opposite)
901 cleaned[mn.key] = mn.value;
903 delete exclusionInfo;
904 exclusionInfo = cleaned;
907 if(exclusionInfo.count > 1)
909 if(exclusionInfo.count > 2)
912 len = strlen(exp) + strlen("$(if $(or ");
913 exp = renew exp char[len+1];
914 strcat(exp, "$(if $(or ");
917 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
919 if(mn.key != unknown)
921 const char * comma = mn.next ? "," : "";
923 var = PlatformToMakefileTargetVariable(mn.key);
926 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
927 exp = renew exp char[len+1];
937 len = strlen(exp) + strlen("),");
938 exp = renew exp char[len+1];
942 if(exclusionInfo.root.minimum.key != unknown)
943 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.key);
945 var = PlatformToMakefileTargetVariable(exclusionInfo.root.minimum.next.key);
948 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
949 exp = renew exp char[len+1];
950 strcat(exp, "$(if $(");
957 exp = common == true ? result.b : result.a;
958 len = strlen(exp) + strlen(",");
959 exp = renew exp char[len+1];
961 if(common == true) result.b = exp; else result.a = exp;
964 len = strlen(exp) + strlen(")");
965 exp = renew exp char[len+1];
969 delete exclusionInfo;
974 bool GetIsExcluded(ProjectConfig prjConfig)
977 // note: unknown platform is for common
978 Map<Platform, SetBool> exclusionInfo { };
979 CollectExclusionInfo(exclusionInfo, prjConfig);
980 if(exclusionInfo.count == 0)
982 else if(exclusionInfo.count == 1)
983 result = exclusionInfo.root.minimum.value == true;
986 SetBool check = exclusionInfo.root.minimum.value;
987 MapNode<Platform, SetBool> mn;
988 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
990 if(check != mn.value)
993 if(!mn) // all are same
994 result = check == true;
998 delete exclusionInfo;
1002 bool GetIsExcludedForCompiler(ProjectConfig prjConfig, CompilerConfig compiler)
1005 Map<Platform, SetBool> exclusionInfo { };
1006 SetBool common, platform;
1007 CollectExclusionInfo(exclusionInfo, prjConfig);
1008 common = exclusionInfo[unknown];
1009 platform = exclusionInfo[compiler.targetPlatform];
1010 result = platform == true || (common == true && platform == unset);
1011 delete exclusionInfo;
1015 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
1017 // note: unknown platform is for common
1019 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1020 ProjectOptions options = property::options;
1021 Array<PlatformOptions> platforms = property::platforms;
1024 parent.CollectExclusionInfo(output, prjConfig);
1026 output[unknown] = unset;
1028 if(options && options.excludeFromBuild)
1029 output[unknown] = options.excludeFromBuild;
1031 if(config && config.options && config.options.excludeFromBuild)
1032 output[unknown] = config.options.excludeFromBuild;
1038 if(p.options.excludeFromBuild && (platform = p.name))
1039 output[platform] = p.options.excludeFromBuild;
1042 if(config && config.platforms)
1044 for(p : config.platforms)
1046 if(p.options.excludeFromBuild && (platform = p.name))
1047 output[platform] = p.options.excludeFromBuild;
1052 void EnsureVisible()
1055 parent.EnsureVisible();
1056 row.collapsed = false;
1062 parent.files.Delete(this);
1065 ProjectNode Find(const char * name, bool includeResources)
1067 ProjectNode result = null;
1072 if(includeResources || child.type != resources)
1074 if(child.type != folder && child.name && !strcmpi(child.name, name))
1079 result = child.Find(name, includeResources);
1088 ProjectNode FindWithPath(const char * name, bool includeResources)
1090 ProjectNode result = null;
1095 if(includeResources || child.type != resources)
1097 char path[MAX_LOCATION];
1098 strcpy(path, child.path);
1099 if(child.type != folder && child.name)
1101 PathCatSlash(path, child.name);
1102 if(!strcmpi(path, name))
1108 result = child.FindWithPath(name, includeResources);
1117 ProjectNode FindByFullPath(const char * path, bool includeResources)
1121 char name[MAX_FILENAME];
1122 GetLastDirectory(path, name);
1123 return InternalFindByFullPath(path, includeResources, name);
1128 ProjectNode InternalFindByFullPath(const char * path, bool includeResources, const char * lastDirName)
1130 ProjectNode result = null;
1135 if(includeResources || child.type != resources)
1137 if(child.type != file)
1138 result = child.InternalFindByFullPath(path, includeResources, lastDirName);
1139 else if(child.name && !fstrcmp(lastDirName, child.name))
1141 char p[MAX_LOCATION];
1142 child.GetFullFilePath(p, true, true);
1143 if(!fstrcmp(p, path))
1157 ProjectNode FindByObjectFileName(const char * fileName, IntermediateFileType type, bool dotMain, Map<String, NameCollisionInfo> namesInfo, const char * objectFileExt)
1159 char p[MAX_LOCATION];
1160 ProjectNode result = null;
1161 if(dotMain == true && this.type == project)
1163 GetObjectFileName(p, namesInfo, type, dotMain, objectFileExt);
1164 if(!fstrcmp(p, fileName))
1169 for(child : files; child.type != resources)
1171 if(child.type != file && (result = child.FindByObjectFileName(fileName, type, dotMain, namesInfo, objectFileExt)))
1173 else if(child.type == file && child.name)
1175 child.GetObjectFileName(p, namesInfo, type, dotMain, objectFileExt);
1176 if(!fstrcmp(p, fileName))
1187 ProjectNode FindSpecial(const char * name, bool recursive, bool includeResources, bool includeFolders)
1189 ProjectNode result = null;
1194 if(includeResources || child.type != resources)
1196 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1202 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1211 ProjectNode FindSameNameConflict(const char * name, bool includeResources,
1212 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1214 ProjectNode result = null;
1215 Map<Platform, SetBool> compareExclusion { };
1216 SetBool common, commonComp;
1217 SetBool actual, actualComp;
1222 if(includeResources || child.type != resources)
1224 if(child.type != folder && child.name && !strcmpi(child.name, name))
1226 child.CollectExclusionInfo(compareExclusion, prjConfig);
1227 common = exclusionInfo[unknown];
1228 commonComp = compareExclusion[unknown];
1229 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1231 if(!(common == true || commonComp == true))
1240 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1243 actualComp = commonComp;
1244 if(exclusionInfo[platform] != unset)
1245 actual = exclusionInfo[platform];
1246 if(compareExclusion[platform] != unset)
1247 actualComp = compareExclusion[platform];
1248 if(!(actual == true || actualComp == true))
1256 compareExclusion.Free();
1259 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1263 compareExclusion.Free();
1265 delete compareExclusion;
1269 ProjectNode Add(Project project, const char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1271 ProjectNode node = null;
1272 if(!project.topNode.FindByFullPath(filePath, true))
1274 char temp[MAX_LOCATION];
1275 Map<Platform, SetBool> exclusionInfo { };
1277 GetLastDirectory(filePath, temp);
1278 //if(!checkIfExists || !project.topNode.Find(temp, false))
1280 // TOCHECK: Shouldn't this apply either for all configs or none?
1281 CollectExclusionInfo(exclusionInfo, project.config);
1282 if(!checkIfExists || type == folder || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1284 // Do the check for folder in the same parent or resource files only here
1285 if(type == folder || !checkIfExists)
1289 if(node.name && !strcmpi(node.name, temp))
1294 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1298 node.nodeType = folder;
1304 StripLastDirectory(filePath, temp);
1305 MakePathRelative(temp, project.topNode.path, temp);
1306 node.path = CopyUnixPath(temp);
1308 node.nodeType = file;
1312 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1313 PathCatSlash(temp, node.name);
1314 node.path = CopyString(temp);
1316 files.Insert(after, node);
1318 delete exclusionInfo;
1323 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1324 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1326 char label[MAX_FILENAME];
1331 bool showConfig = true;
1336 projectView = ide.projectView;
1339 bmp = projectView.icons[icon].bitmap;
1340 xStart = x + (bmp ? (bmp.width + 5) : 0);
1342 GetLastDirectory(name, label);
1343 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1345 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1347 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1349 const char * addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1350 if(strlen(addendum))
1352 strcat(label, " (");
1353 strcat(label, addendum);
1356 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1357 if(strlen(addendum))
1359 strcat(label, " (");
1360 strcat(label, addendum);
1366 else if(!projectView.drawingInProjectSettingsDialog)
1369 strcat(label, " *");
1370 if(type == project && info)
1372 int len = strlen(info) + 4;
1373 char * more = new char[len];
1374 sprintf(more, " (%s)", info);
1375 strcat(label, more);
1379 len = strlen(label);
1383 if(type == folder || type == folderOpen)
1384 surface.SetForeground(yellow);
1388 surface.TextOpacity(false);
1389 surface.TextExtent(label, len, &w, &h);
1392 // Draw the current row stipple
1393 if(displayFlags.selected)
1394 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1395 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1396 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1398 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1402 if(displayFlags.current)
1404 if(displayFlags.active)
1406 surface.LineStipple(0x5555);
1407 if(displayFlags.selected)
1408 surface.SetForeground(projectView.fileList.stippleColor);
1410 surface.SetForeground(projectView.fileList.foreground);
1414 surface.SetForeground(SELECTION_COLOR);
1416 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1417 surface.LineStipple(0);
1422 surface.SetForeground(white);
1423 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1429 int OnCompare(ProjectNode b)
1432 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1433 result = strcmpi(name, b.name);
1436 if(type == folder && b.type == file) result = -1;
1437 else if(type == file && b.type == folder) result = 1;
1442 bool ContainsFilesWithExtension(const char * extension, ProjectConfig prjConfig)
1444 if(type == file && name && name[0])
1446 char ext[MAX_EXTENSION];
1447 GetExtension(name, ext);
1448 if(!fstrcmp(ext, extension))
1455 if(child.type != resources && (child.type == folder || !prjConfig || !child.GetIsExcluded(prjConfig)))
1457 if(child.ContainsFilesWithExtension(extension, prjConfig))
1465 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1469 char extension[MAX_EXTENSION];
1470 GetExtension(name, extension);
1471 if(!strcmpi(extension, "ec") || !strcmpi(extension, "s") || !strcmpi(extension, "c") ||
1472 !strcmpi(extension, "rc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1473 !strcmpi(extension, "cxx") || !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1475 char moduleName[MAX_FILENAME];
1476 NameCollisionInfo info;
1477 ReplaceSpaces(moduleName, name);
1478 StripExtension(moduleName);
1479 info = namesInfo[moduleName];
1481 info = NameCollisionInfo { };
1482 info.count++; // += 1; unless this is for a bug?
1483 if(!strcmpi(extension, "ec"))
1485 else if(!strcmpi(extension, "s"))
1487 else if(!strcmpi(extension, "c"))
1489 else if(!strcmpi(extension, "rc"))
1491 else if(!strcmpi(extension, "cpp"))
1493 else if(!strcmpi(extension, "cc"))
1495 else if(!strcmpi(extension, "cxx"))
1497 else if(!strcmpi(extension, "m"))
1499 else if(!strcmpi(extension, "mm"))
1501 namesInfo[moduleName] = info;
1508 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1509 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1514 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1515 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1516 ProjectConfig prjConfig, bool * containsCXX)
1522 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1523 char moduleName[MAX_FILENAME];
1524 char extension[MAX_EXTENSION];
1525 GetExtension(name, extension);
1526 if(printType == resources)
1529 char tempPath[MAX_LOCATION];
1530 char modulePath[MAX_LOCATION];
1533 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1536 PathCatSlash(tempPath, name);
1541 strcpy(tempPath, path);
1542 PathCatSlash(tempPath, name);
1544 EscapeForMake(modulePath, tempPath, false, true, false);
1545 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1546 items.Add(CopyString(s));
1548 else if(printType == sources)
1550 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1551 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1552 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1554 char modulePath[MAX_LOCATION];
1555 EscapeForMake(modulePath, path, false, true, false);
1556 EscapeForMake(moduleName, name, false, true, false);
1557 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1558 items.Add(CopyString(s));
1561 else if(printType == eCsources)
1563 if(!strcmpi(extension, "ec"))
1565 char modulePath[MAX_LOCATION];
1566 EscapeForMake(modulePath, path, true, true, false);
1567 EscapeForMake(moduleName, name, true, true, false);
1568 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1569 items.Add(CopyString(s));
1573 else if(printType == rcSources)
1575 if(!strcmpi(extension, "rc"))
1577 char modulePath[MAX_LOCATION];
1578 EscapeForMake(modulePath, path, false, true, false);
1579 EscapeForMake(moduleName, name, false, true, false);
1580 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1581 items.Add(CopyString(s));
1585 else if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1586 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1587 !strcmpi(extension, "m") || !strcmpi(extension, "mm"))
1589 if(printType == objects)
1592 NameCollisionInfo info;
1594 EscapeForMake(moduleName, name, false, true, false);
1595 StripExtension(moduleName);
1596 info = namesInfo[moduleName];
1597 collision = info ? info.IsExtensionColliding(extension) : false;
1598 sprintf(s, "%s$(OBJ)%s%s%s$(O)%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1599 items.Add(CopyString(s));
1601 else if(printType == noPrint && containsCXX &&
1602 (!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")))
1603 *containsCXX = true;
1611 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1612 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig, containsCXX);
1618 void GenMakefilePrintSymbolRules(File f, Project project,
1619 ProjectConfig prjConfig, //Map<Platform, bool> parentExcludedPlatforms,
1620 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1623 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1624 //ProjectNode child;
1625 //char objDir[MAX_LOCATION];
1626 //ReplaceSpaces(objDir, config.objDir.dir);
1628 //eSystem_Log("Printing Symbol Rules\n");
1631 char extension[MAX_EXTENSION];
1632 char modulePath[MAX_LOCATION];
1633 char moduleName[MAX_FILENAME];
1635 GetExtension(name, extension);
1636 if(!strcmpi(extension, "ec"))
1639 //char command[2048];
1641 ReplaceSpaces(moduleName, name);
1642 StripExtension(moduleName);
1644 ReplaceSpaces(modulePath, path);
1645 if(modulePath[0]) strcat(modulePath, SEPS);
1647 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1649 // *** Dependency command ***
1650 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1651 modulePath, moduleName, extension);
1653 // System Includes (from global settings)
1654 for(item : compiler.dirs[Includes])
1656 strcat(command, " -isystem ");
1657 if(strchr(item, ' '))
1659 strcat(command, "\"");
1660 strcat(command, item);
1661 strcat(command, "\"");
1664 strcat(command, item);
1667 for(item : project.includeDirs)
1669 strcat(command, " -I");
1670 if(strchr(item, ' '))
1672 strcat(command, "\"");
1673 strcat(command, item);
1674 strcat(command, "\"");
1677 strcat(command, item);
1679 for(item : project.preprocessorDefs)
1681 strcat(command, " -D");
1682 strcat(command, item);
1686 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1689 bool firstLine = true;
1692 // To do some time: auto save external dependencies?
1695 if(dep.GetLine(line, sizeof(line)-1))
1699 char * colon = strstr(line, ":");
1700 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1714 // If we failed to generate dependencies...
1718 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1719 moduleName, modulePath, moduleName, extension);
1723 f.Puts(" $(CFLAGS)");
1724 f.Puts(" $(CECFLAGS)"); // tocheck: what of this? should this stuff be per-file customized?
1726 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1727 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1729 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
1730 modulePath, moduleName, extension);
1731 if(ifCount) f.Puts("endif\n");
1741 if(ContainsFilesWithExtension("ec", prjConfig))
1745 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1746 child.GenMakefilePrintSymbolRules(f, project, prjConfig, /*excludedPlatforms,*/
1747 nodeCFlagsMapping, nodeECFlagsMapping);
1754 void GenMakefilePrintPrepecsRules(File f, Project project,
1755 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1756 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1759 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1760 //ProjectNode child;
1761 //char objDir[MAX_LOCATION];
1762 //ReplaceSpaces(objDir, config.objDir.dir);
1764 //eSystem_Log("Printing Symbol Rules\n");
1767 char extension[MAX_EXTENSION];
1768 char modulePath[MAX_LOCATION];
1769 char moduleName[MAX_FILENAME];
1771 GetExtension(name, extension);
1772 if(!strcmpi(extension, "ec"))
1774 ReplaceSpaces(moduleName, name);
1775 StripExtension(moduleName);
1777 ReplaceSpaces(modulePath, path);
1778 if(modulePath[0]) strcat(modulePath, SEPS);
1780 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1781 f.Printf("$(OBJ)%s$(EC): %s%s.%s\n",
1782 moduleName, modulePath, moduleName, extension);
1783 /*f.Printf("\t$(CPP) %s%s.%s %s$(S)\n\n",
1784 modulePath, moduleName, extension, moduleName);*/
1788 f.Puts(" $(CFLAGS)");
1789 //f.Puts(" $(CECFLAGS)");
1790 //GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1791 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1793 f.Printf(" -x c -E %s%s.%s -o $(OBJ)%s$(EC)\n",
1794 modulePath, moduleName, extension, moduleName);
1795 if(ifCount) f.Puts("endif\n");
1801 if(ContainsFilesWithExtension("ec", prjConfig))
1805 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1806 child.GenMakefilePrintPrepecsRules(f, project, prjConfig, /*excludedPlatforms,*/
1807 nodeCFlagsMapping, nodeECFlagsMapping);
1814 void GenMakefilePrintCObjectRules(File f, Project project,
1815 ProjectConfig prjConfig, /*Map<Platform, bool> parentExcludedPlatforms,*/
1816 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1819 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1820 //ProjectNode child;
1821 //char objDir[MAX_LOCATION];
1822 //ReplaceSpaces(objDir, config.objDir.dir);
1823 //eSystem_Log("Printing C Object Rules\n");
1826 char extension[MAX_EXTENSION];
1827 char modulePath[MAX_LOCATION];
1828 char moduleName[MAX_FILENAME];
1830 GetExtension(name, extension);
1831 if(!strcmpi(extension, "ec"))
1834 //char command[2048];
1836 ReplaceSpaces(moduleName, name);
1837 StripExtension(moduleName);
1839 ReplaceSpaces(modulePath, path);
1840 if(modulePath[0]) strcat(modulePath, SEPS);
1842 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
1844 // *** Dependency command ***
1845 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1846 moduleName, modulePath, moduleName, extension);
1848 // System Includes (from global settings)
1849 for(item : compiler.dirs[Includes])
1851 strcat(command, " -isystem ");
1852 if(strchr(item, ' '))
1854 strcat(command, "\"");
1855 strcat(command, item);
1856 strcat(command, "\"");
1859 strcat(command, item);
1862 for(item : config.includeDirs)
1864 strcat(command, " -I");
1865 if(strchr(item, ' '))
1867 strcat(command, "\"");
1868 strcat(command, item);
1869 strcat(command, "\"");
1872 strcat(command, item);
1874 for(item : config.preprocessorDefs)
1876 strcat(command, " -D");
1877 strcat(command, item);
1881 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true/*, input = true*/ }, command)))
1885 bool firstLine = true;
1887 // To do some time: auto save external dependencies?
1890 if(dep.GetLine(line, sizeof(line)-1))
1894 char * colon = strstr(line, ":");
1895 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1909 // If we failed to generate dependencies...
1912 /* COMMENTED OUT FOR NOW
1913 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1914 moduleName, modulePath, moduleName, extension);
1917 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1918 moduleName, modulePath, moduleName, extension, moduleName);
1924 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1925 modulePath, moduleName, extension, moduleName);
1930 f.Puts(" $(CFLAGS)");
1931 f.Puts(" $(CECFLAGS)"); // what of this? should this stuff be per-file customized?
1932 GenMakePrintNodeFlagsVariable(this, nodeECFlagsMapping, "ECFLAGS", f);
1933 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
1934 f.Puts(" $(FVISIBILITY)");
1936 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@) -symbols $(OBJ)\n",
1937 modulePath, moduleName, extension);
1938 if(ifCount) f.Puts("endif\n");
1944 if(ContainsFilesWithExtension("ec", prjConfig))
1948 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1949 child.GenMakefilePrintCObjectRules(f, project, prjConfig, /*excludedPlatforms,*/
1950 nodeCFlagsMapping, nodeECFlagsMapping);
1957 void GenMakefilePrintObjectRules(File f, Project project,
1958 Map<String, NameCollisionInfo> namesInfo,
1959 ProjectConfig prjConfig,
1960 //Map<Platform, bool> parentExcludedPlatforms,
1961 Map<intptr, int> nodeCFlagsMapping, Map<intptr, int> nodeECFlagsMapping)
1964 Array<Platform> platforms = GetPlatformsArrayFromExclusionInfo(prjConfig);
1965 //ProjectNode child;
1966 //char objDir[MAX_LOCATION];
1967 //ReplaceSpaces(objDir, config.objDir.dir);
1968 //eSystem_Log("Printing Object Rules\n");
1972 char extension[MAX_EXTENSION];
1973 char modulePath[MAX_LOCATION];
1974 char moduleName[MAX_FILENAME];
1976 GetExtension(name, extension);
1977 if(!strcmpi(extension, "s") || !strcmpi(extension, "c") || !strcmpi(extension, "rc") ||
1978 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1979 !strcmpi(extension, "m") || !strcmpi(extension, "mm") || !strcmpi(extension, "ec"))
1982 //char command[2048];
1983 NameCollisionInfo info;
1985 ReplaceSpaces(moduleName, name);
1986 StripExtension(moduleName);
1988 info = namesInfo[moduleName];
1989 collision = info ? info.IsExtensionColliding(extension) : false;
1991 ReplaceSpaces(modulePath, path);
1992 if(modulePath[0]) strcat(modulePath, SEPS);
1996 // *** Dependency command ***
1997 if(!strcmpi(extension, "ec"))
1998 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", "$(CPP)", moduleName, moduleName);
2000 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", (!strcmpi(extension, "cc") || !strcmpi(extension, "cxx") || !strcmpi(extension, "cpp")) ? "$(CXX)" : "$(CC)",
2001 moduleName, modulePath, moduleName, extension);
2003 if(!strcmpi(extension, "ec"))
2005 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
2009 // System Includes (from global settings)
2010 for(item : compiler.dirs[includes])
2012 strcat(command, " -isystem ");
2013 if(strchr(item, ' '))
2015 strcat(command, "\"");
2016 strcat(command, item);
2017 strcat(command, "\"");
2020 strcat(command, item);
2023 for(item : config.includeDirs)
2025 strcat(command, " -I");
2026 if(strchr(item, ' '))
2028 strcat(command, "\"");
2029 strcat(command, item);
2030 strcat(command, "\"");
2033 strcat(command, item);
2035 for(item : config.preprocessorDefs)
2037 strcat(command, " -D");
2038 strcat(command, item);
2042 if((dep = DualPipeOpen(PipeOpenMode { output = true, error = true, input = false }, command)))
2045 bool firstLine = true;
2048 // To do some time: auto save external dependencies?
2052 if(dep.GetLine(line, sizeof(line)-1))
2056 char * colon = strstr(line, ":");
2057 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
2071 // If we failed to generate dependencies...
2080 if(!strcmpi(extension, "rc"))
2083 f.Puts("ifdef WINDOWS_TARGET\n\n");
2086 OpenRulesPlatformExclusionIfs(f, &ifCount, platforms);
2088 if(!strcmpi(extension, "ec"))
2089 f.Printf("$(OBJ)%s$(O): $(OBJ)%s.c\n", moduleName, moduleName);
2091 f.Printf("$(OBJ)%s%s%s$(O): %s%s.%s\n",
2092 moduleName, collision ? "." : "", collision ? extension : "",
2093 modulePath, moduleName, extension);
2094 if(!strcmpi(extension, "cc") || !strcmpi(extension, "cpp") || !strcmpi(extension, "cxx"))
2095 f.Printf("\t$(CXX) $(CXXFLAGS)");
2096 else if(!strcmpi(extension, "rc"))
2097 f.Printf("\t$(WINDRES) $(WINDRES_FLAGS) $< \"$(call escspace,$(call quote_path,$@))\"\n");
2099 f.Printf("\t$(CC) $(CFLAGS)");
2101 if(strcmpi(extension, "rc") != 0)
2103 GenMakePrintNodeFlagsVariable(this, nodeCFlagsMapping, "PRJ_CFLAGS", f);
2105 if(!strcmpi(extension, "ec"))
2106 f.Printf(" $(FVISIBILITY) -c $(call quote_path,$(OBJ)%s.c) -o $(call quote_path,$@)\n",
2109 f.Printf(" -c $(call quote_path,%s%s.%s) -o $(call quote_path,$@)\n",
2110 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension);
2112 if(ifCount) f.Puts("endif\n");
2118 bool needed = false;
2121 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2131 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2132 child.GenMakefilePrintObjectRules(f, project, namesInfo, prjConfig, /*excludedPlatforms,*/
2133 nodeCFlagsMapping, nodeECFlagsMapping);
2140 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig, const char * resourcesTarget)
2147 //Iterator<ProjectNode> i { files };
2148 //Iterator<ProjectNode> prev { files };
2149 //for(child : files)
2151 for(c = 0; c < files.count; c++)
2153 ProjectNode child = files[c];
2154 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
2157 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
2160 char tempPath[MAX_LOCATION];
2161 char resPath[MAX_LOCATION];
2163 // $(EAR) aw%s --- /*quiet ? "q" : */""
2165 f.Printf("\t%s$(EAR) aw$(EARFLAGS) $(%s)", ts.a, resourcesTarget);
2168 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
2171 PathCatSlash(tempPath, child.name);
2176 strcpy(tempPath, child.path);
2177 PathCatSlash(tempPath, child.name);
2179 EscapeForMake(resPath, tempPath, false, true, false);
2180 f.Printf(" %s%s", useRes ? "$(RES)" : "", resPath);
2183 if(count == 10 || (count > 0 && (ts || !child.next)))
2185 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
2188 for(parent = this; parent.type == folder; parent = parent.parent)
2191 strcpy(path, parent.name);
2198 f.Printf(" \"%s\"%s\n", path, ts.b);
2210 if(child.type == folder)
2211 child.GenMakefileAddResources(f, resourcesPath, prjConfig, resourcesTarget);
2216 void GenMakeCollectAssignNodeFlags(ProjectConfig prjConfig, bool prjWithEcFiles,
2217 Map<String, int> cflagsVariations, Map<intptr, int> nodeCFlagsMapping,
2218 Map<String, int> ecflagsVariations, Map<intptr, int> nodeECFlagsMapping,
2219 Map<Platform, ProjectOptions> parentByPlatformOptions)
2221 Map<Platform, ProjectOptions> byPlatformOptions = parentByPlatformOptions;
2222 if(type == file || type == folder || type == project)
2224 bool hasPerNodeOptions = type == project;
2225 if(!hasPerNodeOptions)
2227 if(options && !options.isEmpty)
2228 hasPerNodeOptions = true;
2229 else if(configurations)
2231 for(c : configurations)
2233 if(c.options && !c.options.isEmpty)
2235 hasPerNodeOptions = true;
2240 for(p : c.platforms)
2242 if(p.options && !p.options.isEmpty)
2244 hasPerNodeOptions = true;
2248 if(hasPerNodeOptions)
2253 if(!hasPerNodeOptions && platforms)
2257 if(p.options && !p.options.isEmpty)
2259 hasPerNodeOptions = true;
2266 if(hasPerNodeOptions)
2268 bool isEqual = false, isGreater = false;
2269 ComplexComparison complexCmp;
2271 Map<Platform, ProjectOptions> additionsByPlatformOptions { };
2272 ProjectOptions platformsCommonOptions;
2273 ProjectOptions byFileConfigPlatformProjectOptions;
2275 DynamicString cflags { };
2276 DynamicString ecflags { };
2280 byPlatformOptions = { };
2282 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2284 byFileConfigPlatformProjectOptions =
2285 BlendFileConfigPlatformProjectOptions(this, prjConfig, platform);
2286 byPlatformOptions[platform] = byFileConfigPlatformProjectOptions;
2289 CollectPlatformsCommonOptions(byPlatformOptions, &platformsCommonOptions);
2291 byPlatformOptions[unknown] = platformsCommonOptions;
2293 if(parentByPlatformOptions)
2295 complexCmp = PlatformsOptionsGreaterEqual(byPlatformOptions,
2296 parentByPlatformOptions, additionsByPlatformOptions);
2297 isGreater = complexCmp == greater;
2298 isEqual = complexCmp == equal;
2303 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
2305 byFileConfigPlatformProjectOptions = isGreater ? additionsByPlatformOptions[platform] : byPlatformOptions[platform];
2307 GenCFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, false, isGreater, s);
2309 cflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2312 GenECFlagsFromProjectOptions(byFileConfigPlatformProjectOptions, prjWithEcFiles, s);
2314 ecflags.concatf(" \\\n\t $(if $(%s),%s,)", PlatformToMakefileTargetVariable(platform), (String)s);
2318 platformsCommonOptions = isGreater ? additionsByPlatformOptions[unknown] : byPlatformOptions[unknown];
2320 GenCFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, true, isGreater, s);
2323 if(!isGreater) cflags.concat(" \\\n\t");
2328 GenECFlagsFromProjectOptions(platformsCommonOptions, prjWithEcFiles, s);
2331 ecflags.concat(" \\\n\t");
2338 cflags.concat(" \\\n\t");
2339 DynStringPrintNodeFlagsVariable(parent, nodeCFlagsMapping, "PRJ_CFLAGS", cflags);
2343 additionsByPlatformOptions.Free();
2344 delete additionsByPlatformOptions;
2350 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2351 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2359 if((s = cflags) && s[0] && !(variationNum = cflagsVariations[s]))
2360 cflagsVariations[s] = variationNum = cflagsVariations.count;
2361 nodeCFlagsMapping[(intptr)this] = variationNum;
2364 if((s = ecflags) && s[0] && !(variationNum = ecflagsVariations[s]))
2365 ecflagsVariations[s] = variationNum = ecflagsVariations.count;
2366 nodeECFlagsMapping[(intptr)this] = variationNum;
2377 nodeCFlagsMapping[(intptr)this] = nodeCFlagsMapping[(intptr)parent];
2378 nodeECFlagsMapping[(intptr)this] = nodeECFlagsMapping[(intptr)parent];
2386 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2387 child.GenMakeCollectAssignNodeFlags(prjConfig, prjWithEcFiles,
2388 cflagsVariations, nodeCFlagsMapping, ecflagsVariations, nodeECFlagsMapping,
2393 if(byPlatformOptions != parentByPlatformOptions)
2395 byPlatformOptions.Free();
2396 delete byPlatformOptions;
2400 Array<Platform> GetPlatformsArrayFromExclusionInfo(ProjectConfig prjConfig)
2402 Array<Platform> platforms { };
2403 Map<Platform, SetBool> exclusionInfo { };
2404 CollectExclusionInfo(exclusionInfo, prjConfig);
2406 if(exclusionInfo[unknown] == true)
2408 if(exclusionInfo.count > 1)
2409 for(p : exclusionInfo; p == false)
2414 bool onlyOnknown = true;
2415 for(p : exclusionInfo)
2416 if(&p != unknown && p == true)
2418 onlyOnknown = false;
2422 platforms.Add(unknown);
2426 for(p = unknown + 1; p < Platform::enumSize; p++)
2427 if(exclusionInfo[p] != true)
2431 delete exclusionInfo;
2435 void GetTargets(ProjectConfig prjConfig, Map<String, NameCollisionInfo> namesInfo, char * objDir, const char * objectFileExt, DynamicString output)
2437 char moduleName[MAX_FILENAME];
2440 bool headerAltFailed = false;
2442 char extension[MAX_EXTENSION];
2443 NameCollisionInfo info;
2444 Project prj = property::project;
2445 Map<String, const String> headerToSource { [ { "eh", "ec" }, { "h", "c" }, { "hh", "cc" }, { "hpp", "cpp" }, { "hxx", "cxx" } ] };
2447 GetExtension(name, extension);
2448 strcpy(moduleName, name);
2449 StripExtension(moduleName);
2450 info = namesInfo[moduleName];
2451 collision = info ? info.IsExtensionColliding(extension) : false;
2453 for(h2s : headerToSource)
2455 if(!strcmpi(extension, &h2s))
2457 char filePath[MAX_LOCATION];
2458 GetFullFilePath(filePath, true, true);
2459 OutputLog($"No compilation required for header file "); OutputLog(filePath); OutputLog("\n");
2460 ChangeExtension(moduleName, h2s, moduleName);
2461 if(prj.topNode.Find(moduleName, false))
2463 strcpy(extension, h2s);
2464 collision = info ? info.IsExtensionColliding(extension) : false;
2465 ChangeExtension(filePath, h2s, filePath);
2466 OutputLog($"Compiling source file "); OutputLog(filePath); OutputLog($" instead\n");
2467 StripExtension(moduleName);
2471 headerAltFailed = true;
2472 OutputLog($"Unable to locate source file "); OutputLog(moduleName); OutputLog($" to compile instead of "); OutputLog(filePath); OutputLog($"\n");
2473 StripExtension(moduleName);
2479 if(!headerAltFailed)
2481 output.concat(" \"");
2482 output.concat(objDir); //.concat(" $(OBJ)");
2487 strcat(moduleName, ".");
2488 strcat(moduleName, extension);
2490 strcat(moduleName, ".");
2491 strcat(moduleName, objectFileExt);
2492 output.concat(moduleName);
2493 output.concat("\"");
2496 else if(type == project && ContainsFilesWithExtension("ec", prjConfig))
2498 Project prj = property::project;
2500 ReplaceSpaces(moduleName, prj.moduleName);
2501 strcat(moduleName, ".main.ec");
2502 output.concat(" \"");
2503 output.concat(objDir);
2505 output.concat(moduleName);
2506 output.concat("\"");
2508 ChangeExtension(moduleName, "c", moduleName);
2509 output.concat(" \"");
2510 output.concat(objDir);
2512 output.concat(moduleName);
2513 output.concat("\"");
2515 ChangeExtension(moduleName, "o", moduleName);
2516 output.concat(" \"");
2517 output.concat(objDir);
2519 output.concat(moduleName);
2520 output.concat("\"");
2526 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2527 child.GetTargets(prjConfig, namesInfo, objDir, objectFileExt, output);
2532 void DeleteIntermediateFiles(CompilerConfig compiler, ProjectConfig prjConfig, int bitDepth, Map<String, NameCollisionInfo> namesInfo, bool onlyCObject)
2537 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
2538 char extension[MAX_EXTENSION];
2539 char fileName[MAX_FILENAME];
2540 char moduleName[MAX_FILENAME];
2541 NameCollisionInfo info;
2542 Project prj = property::project;
2543 DirExpression objDir = prj.GetObjDir(compiler, prjConfig, bitDepth);
2545 GetExtension(name, extension);
2546 ReplaceSpaces(moduleName, name);
2547 StripExtension(moduleName);
2548 info = namesInfo[moduleName];
2549 collision = info ? info.IsExtensionColliding(extension) : false;
2551 strcpy(fileName, prj.topNode.path);
2552 PathCatSlash(fileName, objDir.dir);
2553 PathCatSlash(fileName, name);
2555 if(!onlyCObject && !strcmp(extension, "ec"))
2557 ChangeExtension(fileName, "c", fileName);
2558 if(FileExists(fileName)) DeleteFile(fileName);
2559 ChangeExtension(fileName, "sym", fileName);
2560 if(FileExists(fileName)) DeleteFile(fileName);
2561 ChangeExtension(fileName, "imp", fileName);
2562 if(FileExists(fileName)) DeleteFile(fileName);
2563 ChangeExtension(fileName, "bowl", fileName);
2564 if(FileExists(fileName)) DeleteFile(fileName);
2565 ChangeExtension(fileName, "ec", fileName);
2570 strcat(fileName, ".");
2571 strcat(fileName, objectFileExt);
2574 ChangeExtension(fileName, objectFileExt, fileName);
2575 if(FileExists(fileName)) DeleteFile(fileName);
2583 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
2584 child.DeleteIntermediateFiles(compiler, prjConfig, bitDepth, namesInfo, onlyCObject);
2589 bool IsInNode(ProjectNode node)
2591 bool result = false;
2593 for(n = this; n; n = n.parent)
2605 // the code in this function is closely matched to OptionsBox::Load
2606 // and accompanying derivations of OptionBox and their use of OptionSet,
2607 // OptionCheck, LoadOption and FinalizeLoading methods.
2608 // output changing modification should be mirrored in both implementations
2609 static ProjectOptions BlendFileConfigPlatformProjectOptions(ProjectNode node, ProjectConfig projectConfig, Platform platform)
2611 ProjectOptions output { };
2613 // legend: e Element
2614 // o Option (of a ProjectOptions)
2615 // n Node (ProjectNode)
2617 // u Utility (GenericOptionTools)
2621 int includeDirsOption = OPTION(includeDirs);
2623 const char * platformName = platform ? platform.OnGetString(0,0,0) : null;
2625 // OPTION(ProjectOptions' last member) for size
2626 Array<bool> optionConfigXplatformSet { size = OPTION(installCommands) };
2627 Array<bool> optionDone { size = OPTION(installCommands) };
2628 Array<Array<String>> optionTempStrings { size = OPTION(installCommands) };
2630 GenericOptionTools<SetBool> utilSetBool {
2631 bool OptionCheck(ProjectOptions options, int option) {
2632 return *(SetBool*)((byte *)options + option) == true;
2634 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2635 if(options && (*(SetBool*)((byte *)options + option) == true))
2636 *(SetBool*)((byte *)output + option) = true;
2639 GenericOptionTools<String> utilString {
2640 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2641 String * string = (String*)((byte *)output + option);
2642 if(*string) delete *string;
2644 *string = CopyString(*(String*)((byte *)options + option));
2647 StringArrayOptionTools utilStringArrays {
2649 caseSensitive = true;
2650 bool OptionCheck(ProjectOptions options, int option) {
2651 Array<String> strings = *(Array<String>*)((byte *)options + option);
2652 return strings && strings.count;
2654 bool OptionSet(ProjectOptions options, int option) {
2655 Array<String> strings = *(Array<String>*)((byte *)options + option);
2656 if(mergeValues && !configReplaces)
2657 return strings && strings.count;
2659 return strings != null;
2661 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2664 Array<String> strings = options ? *(Array<String>*)((byte *)options + option) : null;
2668 Array<String> tempStrings = optionTempStrings[option];
2670 optionTempStrings[option] = tempStrings = { };
2674 char priorityMark[10];
2677 sprintf(priorityMark, "%06d\n", priority * 1000 + order);
2678 for(i : tempStrings; !(caseSensitive ? strcmp : strcmpi)(i, s)) { found = true; break; }
2679 if(!found) tempStrings.Add(priority ? PrintString(priorityMark, s) : CopyString(s));
2685 Array<String> * newStrings = (Array<String>*)((byte *)options + option);
2686 Array<String> * strings = (Array<String>*)((byte *)output + option);
2687 if(*strings) { strings->Free(); delete *strings; }
2688 if(*newStrings && newStrings->count) { *strings = { }; strings->Copy((void*)*newStrings); }
2691 void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2694 Array<String> tempStrings = optionTempStrings[option];
2695 Array<String> * strings = (Array<String>*)((byte *)output + option);
2696 if(*strings) { strings->Free(); delete *strings; }
2697 if(tempStrings && tempStrings.count) { *strings = { }; strings->Copy((void*)tempStrings); }
2702 GenericOptionTools<WarningsOption> utilWarningsOption {
2703 bool OptionCheck(ProjectOptions options, int option) {
2704 WarningsOption value = *(WarningsOption*)((byte *)options + option);
2705 return value && value != none;
2707 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2708 WarningsOption value = options ? *(WarningsOption*)((byte *)options + option) : (WarningsOption)0;
2709 *(WarningsOption*)((byte *)output + option) = value;
2712 GenericOptionTools<OptimizationStrategy> utilOptimizationStrategy {
2713 bool OptionCheck(ProjectOptions options, int option) {
2714 OptimizationStrategy value = *(OptimizationStrategy*)((byte *)options + option);
2715 return value && value != none;
2717 void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output) {
2718 OptimizationStrategy value = options ? *(OptimizationStrategy*)((byte *)options + option) : (OptimizationStrategy)0;
2719 *(OptimizationStrategy*)((byte *)output + option) = value;
2723 Map<int, GenericOptionTools> ot { };
2725 // The following are compiler options
2727 ot[OPTION(debug)] = utilSetBool;
2728 ot[OPTION(memoryGuard)] = utilSetBool;
2729 ot[OPTION(profile)] = utilSetBool;
2730 ot[OPTION(noLineNumbers)] = utilSetBool;
2731 ot[OPTION(strictNameSpaces)] = utilSetBool;
2732 ot[OPTION(fastMath)] = utilSetBool;
2734 ot[OPTION(defaultNameSpace)] = utilString;
2736 ot[OPTION(preprocessorDefinitions)] = utilStringArrays;
2737 ot[OPTION(includeDirs)] = utilStringArrays;
2739 ot[OPTION(warnings)] = utilWarningsOption;
2741 ot[OPTION(optimization)] = utilOptimizationStrategy;
2743 for(n = node; n; n = n.parent)
2745 ProjectConfig nodeConfig = null;
2747 priority = (priority / 10 + 1) * 10;
2750 if(projectConfig && n.configurations)
2752 for(c : n.configurations; !strcmpi(c.name, projectConfig.name))
2754 if(platform && c.platforms)
2756 for(p : c.platforms; !strcmpi(p.name, platformName))
2760 GenericOptionTools u = uu;
2762 if(!optionDone[o] && p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2764 u.LoadOption(p.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2765 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2766 optionConfigXplatformSet[o] = true;
2778 GenericOptionTools u = uu;
2782 if(platform && n.platforms && (!optionConfigXplatformSet[o] || !u.configReplaces))
2784 for(p : n.platforms; !strcmpi(p.name, platformName))
2786 if(p.options && (u.mergeValues ? u.OptionCheck(p.options, o) : u.OptionSet(p.options, o)))
2788 u.LoadOption(p.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2789 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2794 if(!optionDone[o] && nodeConfig && nodeConfig.options &&
2795 ((u.mergeValues && !u.configReplaces) ?
2796 u.OptionCheck(nodeConfig.options, o) :
2797 u.OptionSet(nodeConfig.options, o)))
2799 u.LoadOption(nodeConfig.options, o, o == includeDirsOption ? priority : 0, optionTempStrings, output);
2800 if(!u.mergeValues || u.configReplaces) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2804 if(n.options && (u.mergeValues ? u.OptionCheck(n.options, o) : u.OptionSet(n.options, o)))
2806 u.LoadOption(n.options, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2807 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2811 u.LoadOption(null, o, o == includeDirsOption ? priority + 1 : 0, optionTempStrings, output);
2812 if(!u.mergeValues) { u.FinalizeLoading(o, optionTempStrings, output); optionDone[o] = true; }
2820 GenericOptionTools u = uu;
2823 u.FinalizeLoading(o, optionTempStrings, output);
2826 delete optionConfigXplatformSet;
2828 delete optionTempStrings;
2832 delete utilStringArrays;
2833 delete utilWarningsOption;
2834 delete utilOptimizationStrategy;
2841 static void CollectPlatformsCommonOptions(Map<Platform, ProjectOptions> byPlatformOptions, ProjectOptions * platformsCommonOptions)
2843 ProjectOptions first = null;
2844 ProjectOptions commonOptions;
2846 Map<String, int> countIncludeDirs { };
2847 Map<String, int> countPreprocessorDefinitions { };
2848 Map<String, bool> commonIncludeDirs { };
2849 Map<String, bool> commonPreprocessorDefinitions { };
2851 for(options : byPlatformOptions) { first = options; break; }
2853 *platformsCommonOptions = commonOptions = first ? first.Copy() : { };
2855 if(commonOptions.includeDirs)
2856 commonOptions.includeDirs.Free();
2857 if(commonOptions.preprocessorDefinitions)
2858 commonOptions.preprocessorDefinitions.Free();
2860 for(options : byPlatformOptions)
2862 if(options != first)
2864 if(commonOptions.debug && options.debug != commonOptions.debug)
2865 commonOptions.debug = unset;
2866 if(commonOptions.memoryGuard && options.memoryGuard != commonOptions.memoryGuard)
2867 commonOptions.memoryGuard = unset;
2868 if(commonOptions.profile && options.profile != commonOptions.profile)
2869 commonOptions.profile = unset;
2870 if(commonOptions.noLineNumbers && options.noLineNumbers != commonOptions.noLineNumbers)
2871 commonOptions.noLineNumbers = unset;
2872 if(commonOptions.strictNameSpaces && options.strictNameSpaces != commonOptions.strictNameSpaces)
2873 commonOptions.strictNameSpaces = unset;
2874 if(commonOptions.fastMath && options.fastMath != commonOptions.fastMath)
2875 commonOptions.fastMath = unset;
2877 if(commonOptions.warnings && options.warnings != commonOptions.warnings)
2878 commonOptions.warnings = unset;
2879 if(commonOptions.optimization && options.optimization != commonOptions.optimization)
2880 commonOptions.optimization = unset;
2882 if(commonOptions.defaultNameSpace && strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2883 delete commonOptions.defaultNameSpace;
2886 CountSameNonEmptyOrNullStrings(options.includeDirs, countIncludeDirs);
2887 CountSameNonEmptyOrNullStrings(options.preprocessorDefinitions, countPreprocessorDefinitions);
2890 GetPlatformsCommonStrings(countIncludeDirs, byPlatformOptions.count,
2891 commonIncludeDirs, commonOptions.includeDirs);
2892 GetPlatformsCommonStrings(countPreprocessorDefinitions, byPlatformOptions.count,
2893 commonPreprocessorDefinitions, commonOptions.preprocessorDefinitions);
2895 for(options : byPlatformOptions)
2897 if(options.debug && options.debug == commonOptions.debug)
2898 options.debug = unset;
2899 if(options.memoryGuard && options.memoryGuard == commonOptions.memoryGuard)
2900 options.memoryGuard = unset;
2901 if(options.profile && options.profile == commonOptions.profile)
2902 options.profile = unset;
2903 if(options.noLineNumbers && options.noLineNumbers == commonOptions.noLineNumbers)
2904 options.noLineNumbers = unset;
2905 if(options.strictNameSpaces && options.strictNameSpaces == commonOptions.strictNameSpaces)
2906 options.strictNameSpaces = unset;
2907 if(options.fastMath && options.fastMath == commonOptions.fastMath)
2908 options.fastMath = unset;
2910 if(options.warnings && options.warnings == commonOptions.warnings)
2911 options.warnings = unset;
2912 if(options.optimization && options.optimization == commonOptions.optimization)
2913 options.optimization = unset;
2915 if(options.defaultNameSpace && !strcmp(options.defaultNameSpace, commonOptions.defaultNameSpace))
2916 delete options.defaultNameSpace;
2918 RemovePlatformsCommonStrings(commonIncludeDirs, options.includeDirs);
2919 RemovePlatformsCommonStrings(commonPreprocessorDefinitions, options.preprocessorDefinitions);
2922 delete countIncludeDirs;
2923 delete countPreprocessorDefinitions;
2924 delete commonIncludeDirs;
2925 delete commonPreprocessorDefinitions;
2928 static ComplexComparison PlatformsOptionsGreaterEqual(Map<Platform, ProjectOptions> byPlatformOptions,
2929 Map<Platform, ProjectOptions> parentByPlatformOptions,
2930 Map<Platform, ProjectOptions> additionsByPlatformOptions)
2932 ComplexComparison result = equal;
2933 ComplexComparison compare;
2935 for(platform = (Platform)0; platform < Platform::enumSize; platform++)
2937 ProjectOptions additionalOptions;
2938 additionsByPlatformOptions[platform] = { };
2939 additionalOptions = additionsByPlatformOptions[platform];
2940 compare = ExtractPlatformsOptionsAdditions(byPlatformOptions[platform], parentByPlatformOptions[platform], additionalOptions);
2941 if(compare == greater && result == equal)
2943 else if(compare == different)
2952 static ComplexComparison ExtractPlatformsOptionsAdditions(ProjectOptions options, ProjectOptions parentOptions, ProjectOptions additionalOptions)
2954 ComplexComparison result = equal;
2955 if(options.debug != parentOptions.debug ||
2956 options.memoryGuard != parentOptions.memoryGuard ||
2957 options.profile != parentOptions.profile ||
2958 options.noLineNumbers != parentOptions.noLineNumbers ||
2959 options.strictNameSpaces != parentOptions.strictNameSpaces ||
2960 options.fastMath != parentOptions.fastMath ||
2961 options.warnings != parentOptions.warnings ||
2962 options.optimization != parentOptions.optimization ||
2963 (options.defaultNameSpace != parentOptions.defaultNameSpace &&
2964 strcmp(options.defaultNameSpace, parentOptions.defaultNameSpace)))
2968 if(!StringsAreSameOrMore(options.includeDirs, parentOptions.includeDirs, &additionalOptions.includeDirs) ||
2969 !StringsAreSameOrMore(options.preprocessorDefinitions, parentOptions.preprocessorDefinitions, &additionalOptions.preprocessorDefinitions))
2971 if((additionalOptions.includeDirs && additionalOptions.includeDirs.count) ||
2972 (additionalOptions.preprocessorDefinitions && additionalOptions.preprocessorDefinitions.count))
2978 enum ComplexComparison { different/*, smaller*/, equal, greater };
2980 static bool StringsAreSameOrMore(Array<String> strings, Array<String> originals, Array<String> * additions)
2983 if((!strings || !strings.count) && originals && originals.count)
2985 else if(strings && strings.count && (!originals || !originals.count))
2990 additions->Add(CopyString(s));
2992 else if(strings && strings.count && originals && originals.count)
2994 Map<String, String> map { };
2995 MapIterator<String, bool> mit { map = map };
2998 char * s = strstr(it, "\n");
3004 char * s = strstr(it, "\n");
3006 if(!mit.Index(s, false))
3013 // TOFIX: Templates map[s] = null;
3022 additions->Add(CopyString(it));
3030 static void CountSameNonEmptyOrNullStrings(Array<String> strings, Map<String, int> counts)
3043 static void GetPlatformsCommonStrings(Map<String, int> counts, int goodCount, Map<String, bool> common, Array<String> strings)
3050 const char * s = ⁢
3051 strings.Add(CopyString(s));
3057 static void RemovePlatformsCommonStrings(Map<String, bool> common, Array<String> strings)
3061 Array<String> tmp { };
3062 MapIterator<String, bool> mit { map = common };
3066 if(!mit.Index(s, false))
3067 tmp.Add(CopyString(s));
3073 strings.Add(CopyString(s));
3080 static void GenMakePrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, File f)
3083 customFlags = nodeFlagsMapping[(intptr)node];
3085 f.Printf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3087 f.Printf(" $(%s)", variableName);
3090 static void DynStringPrintNodeFlagsVariable(ProjectNode node, Map<intptr, int> nodeFlagsMapping, const String variableName, DynamicString s)
3093 customFlags = nodeFlagsMapping[(intptr)node];
3095 s.concatf(" $(CUSTOM%d_%s)", customFlags-1, variableName);
3097 s.concatf(" $(%s)", variableName);
3100 static void GenCFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, bool commonOptions, bool isGreater, DynamicString s)
3106 if(options.optimization == speed || options.optimization == size ||
3107 options.fastMath == true || options.debug == true)
3109 if(options.debug != true)
3111 s.concat(" $(if $(DEBUG),");
3115 switch(options.optimization)
3117 case speed: s.concat(" -O2"); break;
3118 case size: s.concat(" -Os"); break;
3120 if(options.fastMath == true)
3121 s.concat(" -ffast-math");
3122 if(options.debug == true)
3124 if(options.debug != true)
3127 else if(commonOptions)
3128 s.concat(" $(if $(DEBUG),-g)");
3130 s.concat(" $(FPIC)");
3132 switch(options.warnings)
3134 case all: s.concat(" -Wall"); break;
3135 case none: s.concat(" -w"); break;
3140 s.concat(" -DREPOSITORY_VERSION=\"\\\"$(REPOSITORY_VER)\\\"\"");
3143 if(options && options.preprocessorDefinitions)
3144 ListOptionToDynamicString(s, _D, options.preprocessorDefinitions, false, lineEach, "\t\t\t");
3145 if(options && options.includeDirs)
3146 ListOptionToDynamicString(s, _I, options.includeDirs, true, lineEach, "\t\t\t");
3149 static void GenECFlagsFromProjectOptions(ProjectOptions options, bool prjWithEcFiles, DynamicString s)
3151 if(options.memoryGuard == true)
3152 s.concat(" -memguard");
3153 if(options.noLineNumbers == true)
3154 s.concat(" -nolinenumbers");
3155 if(options.strictNameSpaces == true)
3156 s.concat(" -strictns");
3157 if(options.defaultNameSpace && options.defaultNameSpace[0])
3158 s.concatf(" -defaultns %s", options.defaultNameSpace);
3161 static void ListOptionToDynamicString(DynamicString output, ToolchainFlag flag, Array<String> list, bool prioritize,
3162 LineOutputMethod lineMethod, const String newLineStart)
3166 if(lineMethod == newLine)
3168 output.concat(" \\\n");
3169 output.concat(newLineStart);
3173 Map<String, int> sortedList { };
3174 MapNode<String, int> mn;
3176 sortedList[item] = 1;
3177 for(mn = sortedList.root.minimum; mn; mn = mn.next)
3179 char * start = strstr(mn.key, "\n");
3180 if(lineMethod == lineEach)
3182 output.concat(" \\\n");
3183 output.concat(newLineStart);
3186 output.concat(flagNames[flag]);
3187 EscapeForMakeToDynString(output, start ? start+1 : mn.key, false, true, flag == _D);
3195 if(lineMethod == lineEach)
3197 output.concat(" \\\n");
3198 output.concat(newLineStart);
3201 output.concat(flagNames[flag]);
3202 EscapeForMakeToDynString(output, item, false, true, flag == _D);
3208 class GenericOptionTools<class X>
3210 bool mergeValues, configReplaces;
3212 virtual bool OptionSet(ProjectOptions options, int option) {
3213 if(*(X*)((byte *)options + option))
3218 // BUG: OptionCheck = OptionSet; // Overrides derived classes OptionCheck ?
3220 virtual bool OptionCheck(ProjectOptions options, int option) {
3221 return OptionSet(options, option);
3224 virtual void LoadOption(ProjectOptions options, int option, int priority, Array<Array<String>> optionTempStrings, ProjectOptions output);
3225 virtual void FinalizeLoading(int option, Array<Array<String>> optionTempStrings, ProjectOptions output);
3228 class StringArrayOptionTools : GenericOptionTools<Array<String>>
3233 class NameCollisionInfo
3246 bool IsExtensionColliding(char * extension)
3250 ((!strcmpi(extension, "c") && ec) ||
3251 (!strcmpi(extension, "rc") && (ec || c)) ||
3252 (!strcmpi(extension, "s") && (ec || c || rc)) ||
3253 (!strcmpi(extension, "cpp") && (ec || c || rc || s)) ||
3254 (!strcmpi(extension, "cc") && (ec || c || rc || s || cpp)) ||
3255 (!strcmpi(extension, "cxx") && (ec || c || rc || s || cpp || cc)) ||
3256 (!strcmpi(extension, "m") && (ec || c || rc || s || cpp || cc || m)) ||
3257 !strcmpi(extension, "mm")))