#include "Codepack.h" int main(int argc, char* argv[]) { Console::SetTitle(L"Vczh CodePack for C++"); if (argc != 2) { Console::SetColor(true, false, false, true); Console::WriteLine(L"CodePack.exe "); Console::SetColor(true, true, true, false); return 0; } // load configuration auto workingDir = FilePath(atow(argv[1])).GetFolder(); Ptr config; { Parser parser; List errors; InstallDefaultErrorMessageGenerator(parser, errors); auto text = ReadFile(atow(argv[1])); config = XmlParseDocument(text, parser); if (errors.Count() > 0) { Console::SetColor(true, false, false, true); Console::WriteLine(L"Failed to read the input XML file."); for (auto error : errors) { Console::WriteLine(L"[row:" + itow(error.codeRange.start.row + 1) + L"][column:" + itow(error.codeRange.start.column + 1) + L"]: " + error.message); } Console::SetColor(true, true, true, false); return 1; } } Dictionary> categorizedOutput; // category -> {output file, generate?} { // get configuration for all categories CopyFrom( categorizedOutput, XmlGetElements(XmlGetElement(config->rootElement, L"output"), L"codepair") .Select([&](Ptr e)->Pair> { return { XmlGetAttribute(e, L"category")->value.value, { XmlGetAttribute(e, L"filename")->value.value, XmlGetAttribute(e, L"generate")->value.value == L"true" } }; }) ); } // collect code files List unprocessedCppFiles; // all cpp files need to combine List unprocessedHeaderFiles; // all header files need to combine Dictionary> cachedFileToIncludes; // file -> directly/indirectly included files Group> conditionOns; // #ifdef -> files to include Group> conditionOffs; // #ifndef -> files to include { // get included folders List folders; CopyFrom( folders, XmlGetElements(XmlGetElement(config->rootElement,L"folders"), L"folder") .Select([&](Ptr e) { return workingDir / XmlGetAttribute(e, L"path")->value.value; }) ); // get excluded folders List exceptions; CopyFrom( exceptions, XmlGetElements(XmlGetElement(config->rootElement,L"folders"), L"except") .Select([&](Ptr e) { return XmlGetAttribute(e, L"pattern")->value.value; }) ); // enumerate all *.cpp files in specified folders CopyFrom( unprocessedCppFiles, From(folders) .SelectMany([&](const FilePath& folder) { return GetCppFiles(folder, exceptions); }) .Distinct() ); // enumerate all *.h files in specified folders CopyFrom( unprocessedHeaderFiles, From(folders) .SelectMany([&](const FilePath& folder) { return GetHeaderFiles(folder, exceptions); }) .Distinct() ); } // categorize code files Group categorizedCppFiles; // category -> cpp files Group categorizedHeaderFiles; // category -> header files Dictionary inputFileToCategories; // input file -> category { // categorize all *.cpp and *.h files CategorizeCodeFiles(config, unprocessedCppFiles, categorizedCppFiles, inputFileToCategories); CategorizeCodeFiles(config, unprocessedHeaderFiles, categorizedHeaderFiles, inputFileToCategories); } // collect import files as system include Dictionary skippedImportFiles; // file name -> file path for (vint i = 0; i < categorizedOutput.Count(); i++) { if (!categorizedOutput.Values()[i].f1) { auto category = categorizedOutput.Keys()[i]; for (auto skippedImportFile : categorizedHeaderFiles[category]) { skippedImportFiles.Add(skippedImportFile.GetName(), skippedImportFile); } } } // check if there any *.h file is included without assigning a category { List headerFiles; CopyFrom( headerFiles, From(unprocessedHeaderFiles) .Concat(unprocessedCppFiles) .SelectMany([&](const FilePath& includedFile) { return GetIncludedFiles(includedFile, skippedImportFiles, cachedFileToIncludes, conditionOns, conditionOffs); }) .Concat(unprocessedHeaderFiles) .Distinct() .Except(unprocessedHeaderFiles) ); if (headerFiles.Count() > 0) { Console::SetColor(true, false, false, true); Console::WriteLine(L"Error: The following files are not categorized."); for (auto headerFile : headerFiles) { Console::WriteLine(headerFile.GetFullPath()); } Console::SetColor(true, true, true, false); CHECK_ERROR(true, L"All included files should be categorized"); } } // calculate category dependencies PartialOrderingProcessor popCategories; // POP for category ordering Group componentToCategoryNames; // component index to category names { SortedList items; Group depGroup; CopyFrom(items, From(unprocessedCppFiles).Concat(unprocessedHeaderFiles)); for (auto filePath : items) { for (auto includedFile : GetIncludedFiles(filePath, skippedImportFiles, cachedFileToIncludes, conditionOns, conditionOffs)) { depGroup.Add(filePath, includedFile); } } popCategories.InitWithSubClass(items, depGroup, inputFileToCategories); popCategories.Sort(); for (vint i = 0; i < popCategories.components.Count(); i++) { auto& component = popCategories.components[i]; for (vint j = 0; j < component.nodeCount; j++) { auto& firstNode = popCategories.nodes[component.firstNode[j]]; auto firstFile = items[firstNode.firstSubClassItem[0]]; componentToCategoryNames.Add(i, inputFileToCategories[firstFile]); } } bool needExit = false; for (vint i = 0; i < componentToCategoryNames.Count(); i++) { const auto& cycleCategories = componentToCategoryNames.GetByIndex(i); if (cycleCategories.Count() > 1) { Console::SetColor(true, false, false, true); Console::WriteLine( L"Error: Cycle dependency found in categories: " + From(cycleCategories).Aggregate([](const WString& a, const WString& b) {return a + L", " + b; }) + L"."); Console::SetColor(true, true, true, false); needExit = true; } } CHECK_ERROR(!needExit, L"Cycle dependency is not allowed"); } Dictionary inputFileToOutputFiles; // input file -> output file { for (vint i = 0; i < inputFileToCategories.Count(); i++) { auto key = inputFileToCategories.Keys()[i]; auto value = inputFileToCategories.Values()[i]; inputFileToOutputFiles.Add(key, categorizedOutput[value].f0); } } // prepare output folder auto outputFolder = workingDir / (XmlGetAttribute(XmlGetElement(config->rootElement, L"output"), L"path")->value.value); auto outputIncludeOnlyFolder = outputFolder / L"IncludeOnly"; if (!Folder(outputIncludeOnlyFolder).Exists()) { Folder(outputIncludeOnlyFolder).Create(true); } // generate categorized header dependencies Dictionary> categorizedHeaderIncludes; for (vint i = 0; i < popCategories.components.Count(); i++) { auto& component = popCategories.components[i]; auto categoryName = componentToCategoryNames[i][0]; categorizedHeaderIncludes.Add( categoryName, From(*popCategories.nodes[component.firstNode[0]].ins) .Where([&](vint nodeIndex) { return nodeIndex != component.firstNode[0]; }) .Select([&](vint nodeIndex) { return categorizedOutput[componentToCategoryNames[popCategories.nodes[nodeIndex].component][0]].f0 + L".h"; }) ); } // generate code pair header files Dictionary>> categorizedSystemIncludes; for (vint i = 0; i < popCategories.components.Count(); i++) { auto categoryName = componentToCategoryNames[i][0]; auto outputPath = outputFolder / (categorizedOutput[categoryName].f0 + L".h"); auto outputIncludeOnlyPath = outputIncludeOnlyFolder / (categorizedOutput[categoryName].f0 + L".h"); auto systemIncludes = Ptr(new SortedList); categorizedSystemIncludes.Add(categoryName, systemIncludes); if (categorizedOutput[categoryName].f1) { vint headerIndex = categorizedHeaderFiles.Keys().IndexOf(categoryName); if (headerIndex == -1) continue; Combine( inputFileToOutputFiles, skippedImportFiles, cachedFileToIncludes, conditionOns, conditionOffs, categorizedHeaderFiles.GetByIndex(headerIndex), outputPath, outputIncludeOnlyPath, *systemIncludes.Obj(), categorizedHeaderIncludes[categoryName] ); } } // generate code pair cpp files for (vint i = 0; i < popCategories.components.Count(); i++) { auto categoryName = componentToCategoryNames[i][0]; if (categorizedOutput[categoryName].f1) { WString outputHeader[] = { categorizedOutput[categoryName].f0 + L".h" }; vint headerIndex = categorizedHeaderFiles.Keys().IndexOf(categoryName); auto outputPath = outputFolder / (categorizedOutput[categoryName].f0 + L".cpp"); auto outputIncludeOnlyPath = outputIncludeOnlyFolder / (categorizedOutput[categoryName].f0 + L".cpp"); Combine( inputFileToOutputFiles, skippedImportFiles, cachedFileToIncludes, conditionOns, conditionOffs, categorizedCppFiles[categoryName], outputPath, outputIncludeOnlyPath, *categorizedSystemIncludes[categoryName].Obj(), (headerIndex == -1 ? categorizedHeaderIncludes[categoryName] : From(outputHeader)) ); } } return 0; }