https://github.com/PeterChou1 updated https://github.com/llvm/llvm-project/pull/94717
>From eeb334620df72c395a5ad27f44a864a6a0c194a5 Mon Sep 17 00:00:00 2001 From: PeterChou1 <peter.c...@mail.utoronto.ca> Date: Thu, 6 Jun 2024 23:18:12 -0400 Subject: [PATCH 1/2] [clang][clang-doc] add asset path --- .../clang-doc/tool/ClangDocMain.cpp | 73 ++++++++++++++----- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp index 21b581fa6df2e..df53c46b4a76e 100644 --- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -81,6 +81,12 @@ static llvm::cl::list<std::string> UserStylesheets( llvm::cl::desc("CSS stylesheets to extend the default styles."), llvm::cl::cat(ClangDocCategory)); +static llvm::cl::opt<std::string> + UserAssetPath("asset", + llvm::cl::desc("User supplied asset path for html output to " + "override the default css and js files"), + llvm::cl::cat(ClangDocCategory)); + static llvm::cl::opt<std::string> SourceRoot("source-root", llvm::cl::desc(R"( Directory where processed files are stored. Links to definition locations will only be @@ -131,12 +137,54 @@ std::string GetExecutablePath(const char *Argv0, void *MainAddr) { return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); } +void GetAssetFiles(clang::doc::ClangDocContext CDCtx) { + std::error_code Code; + for (auto DirIt = llvm::sys::fs::directory_iterator( + std::string(UserAssetPath), Code), + dir_end = llvm::sys::fs::directory_iterator(); + !Code && DirIt != dir_end; DirIt.increment(Code)) { + llvm::SmallString<128> filePath = llvm::SmallString<128>(DirIt->path()); + if (llvm::sys::fs::is_regular_file(filePath)) { + if (filePath.ends_with(".css")) { + CDCtx.UserStylesheets.push_back(std::string(filePath)); + } else if (filePath.ends_with(".js")) { + CDCtx.FilesToCopy.push_back(std::string(filePath)); + } + } + } +} + +void GetDefaultAssetFiles(const char *Argv0, + clang::doc::ClangDocContext CDCtx) { + void *MainAddr = (void *)(intptr_t)GetExecutablePath; + std::string ClangDocPath = GetExecutablePath(Argv0, MainAddr); + llvm::SmallString<128> NativeClangDocPath; + llvm::sys::path::native(ClangDocPath, NativeClangDocPath); + + llvm::SmallString<128> AssetsPath; + AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath); + llvm::sys::path::append(AssetsPath, "..", "share", "clang"); + llvm::SmallString<128> DefaultStylesheet; + llvm::sys::path::native(AssetsPath, DefaultStylesheet); + llvm::sys::path::append(DefaultStylesheet, + "clang-doc-default-stylesheet.css"); + llvm::SmallString<128> IndexJS; + llvm::sys::path::native(AssetsPath, IndexJS); + llvm::sys::path::append(IndexJS, "index.js"); + CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), + std::string(DefaultStylesheet)); + CDCtx.FilesToCopy.emplace_back(IndexJS.str()); + + llvm::outs() << "No default asset path found using default asset path: " + << AssetsPath << "\n"; +} + int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); std::error_code OK; const char *Overview = - R"(Generates documentation from source code and comments. + R"(Generates documentation from source code and comments. Example usage for files without flags (default): @@ -182,23 +230,12 @@ Example usage for a project using a compile commands database: {"index.js", "index_json.js"}}; if (Format == "html") { - void *MainAddr = (void *)(intptr_t)GetExecutablePath; - std::string ClangDocPath = GetExecutablePath(argv[0], MainAddr); - llvm::SmallString<128> NativeClangDocPath; - llvm::sys::path::native(ClangDocPath, NativeClangDocPath); - llvm::SmallString<128> AssetsPath; - AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath); - llvm::sys::path::append(AssetsPath, "..", "share", "clang"); - llvm::SmallString<128> DefaultStylesheet; - llvm::sys::path::native(AssetsPath, DefaultStylesheet); - llvm::sys::path::append(DefaultStylesheet, - "clang-doc-default-stylesheet.css"); - llvm::SmallString<128> IndexJS; - llvm::sys::path::native(AssetsPath, IndexJS); - llvm::sys::path::append(IndexJS, "index.js"); - CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), - std::string(DefaultStylesheet)); - CDCtx.FilesToCopy.emplace_back(IndexJS.str()); + if (!UserAssetPath.empty() && + llvm::sys::fs::is_directory(std::string(UserAssetPath))) { + GetAssetFiles(CDCtx); + } else { + GetDefaultAssetFiles(argv[0], CDCtx); + } } // Mapping phase >From d535cb7b7c92a22931b276a8c9fe97a2f04c2258 Mon Sep 17 00:00:00 2001 From: PeterChou1 <peter.c...@mail.utoronto.ca> Date: Fri, 7 Jun 2024 01:40:29 -0400 Subject: [PATCH 2/2] [clang][clang-doc] fixes bug caused by not passing by reference --- .../clang-doc/tool/ClangDocMain.cpp | 455 +++++++++--------- 1 file changed, 228 insertions(+), 227 deletions(-) diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp index df53c46b4a76e..ab6f6198aae32 100644 --- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -54,38 +54,38 @@ static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); static llvm::cl::OptionCategory ClangDocCategory("clang-doc options"); static llvm::cl::opt<std::string> - ProjectName("project-name", llvm::cl::desc("Name of project."), - llvm::cl::cat(ClangDocCategory)); + ProjectName("project-name", llvm::cl::desc("Name of project."), + llvm::cl::cat(ClangDocCategory)); static llvm::cl::opt<bool> IgnoreMappingFailures( - "ignore-map-errors", - llvm::cl::desc("Continue if files are not mapped correctly."), - llvm::cl::init(true), llvm::cl::cat(ClangDocCategory)); + "ignore-map-errors", + llvm::cl::desc("Continue if files are not mapped correctly."), + llvm::cl::init(true), llvm::cl::cat(ClangDocCategory)); static llvm::cl::opt<std::string> - OutDirectory("output", - llvm::cl::desc("Directory for outputting generated files."), - llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory)); + OutDirectory("output", + llvm::cl::desc("Directory for outputting generated files."), + llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory)); static llvm::cl::opt<bool> - PublicOnly("public", llvm::cl::desc("Document only public declarations."), - llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); + PublicOnly("public", llvm::cl::desc("Document only public declarations."), + llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); static llvm::cl::opt<bool> DoxygenOnly( - "doxygen", - llvm::cl::desc("Use only doxygen-style comments to generate docs."), - llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); + "doxygen", + llvm::cl::desc("Use only doxygen-style comments to generate docs."), + llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); static llvm::cl::list<std::string> UserStylesheets( - "stylesheets", llvm::cl::CommaSeparated, - llvm::cl::desc("CSS stylesheets to extend the default styles."), - llvm::cl::cat(ClangDocCategory)); + "stylesheets", llvm::cl::CommaSeparated, + llvm::cl::desc("CSS stylesheets to extend the default styles."), + llvm::cl::cat(ClangDocCategory)); static llvm::cl::opt<std::string> - UserAssetPath("asset", - llvm::cl::desc("User supplied asset path for html output to " - "override the default css and js files"), - llvm::cl::cat(ClangDocCategory)); + UserAssetPath("asset", + llvm::cl::desc("User supplied asset path for html output to " + "override the default css and js files"), + llvm::cl::cat(ClangDocCategory)); static llvm::cl::opt<std::string> SourceRoot("source-root", llvm::cl::desc(R"( Directory where processed files are stored. @@ -94,38 +94,38 @@ generated if the file is in this dir.)"), llvm::cl::cat(ClangDocCategory)); static llvm::cl::opt<std::string> - RepositoryUrl("repository", llvm::cl::desc(R"( + RepositoryUrl("repository", llvm::cl::desc(R"( URL of repository that hosts code. Used for links to definition locations.)"), - llvm::cl::cat(ClangDocCategory)); + llvm::cl::cat(ClangDocCategory)); enum OutputFormatTy { - md, - yaml, - html, + md, + yaml, + html, }; static llvm::cl::opt<OutputFormatTy> - FormatEnum("format", llvm::cl::desc("Format for outputted docs."), - llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml", - "Documentation in YAML format."), - clEnumValN(OutputFormatTy::md, "md", - "Documentation in MD format."), - clEnumValN(OutputFormatTy::html, "html", - "Documentation in HTML format.")), - llvm::cl::init(OutputFormatTy::yaml), - llvm::cl::cat(ClangDocCategory)); + FormatEnum("format", llvm::cl::desc("Format for outputted docs."), + llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml", + "Documentation in YAML format."), + clEnumValN(OutputFormatTy::md, "md", + "Documentation in MD format."), + clEnumValN(OutputFormatTy::html, "html", + "Documentation in HTML format.")), + llvm::cl::init(OutputFormatTy::yaml), + llvm::cl::cat(ClangDocCategory)); std::string getFormatString() { - switch (FormatEnum) { - case OutputFormatTy::yaml: - return "yaml"; - case OutputFormatTy::md: - return "md"; - case OutputFormatTy::html: - return "html"; - } - llvm_unreachable("Unknown OutputFormatTy"); + switch (FormatEnum) { + case OutputFormatTy::yaml: + return "yaml"; + case OutputFormatTy::md: + return "md"; + case OutputFormatTy::html: + return "html"; + } + llvm_unreachable("Unknown OutputFormatTy"); } // This function isn't referenced outside its translation unit, but it @@ -134,57 +134,58 @@ std::string getFormatString() { // address of main, and some platforms can't implement GetMainExecutable // without being given the address of a function in the main executable). std::string GetExecutablePath(const char *Argv0, void *MainAddr) { - return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); + return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); } -void GetAssetFiles(clang::doc::ClangDocContext CDCtx) { - std::error_code Code; - for (auto DirIt = llvm::sys::fs::directory_iterator( - std::string(UserAssetPath), Code), - dir_end = llvm::sys::fs::directory_iterator(); - !Code && DirIt != dir_end; DirIt.increment(Code)) { - llvm::SmallString<128> filePath = llvm::SmallString<128>(DirIt->path()); - if (llvm::sys::fs::is_regular_file(filePath)) { - if (filePath.ends_with(".css")) { - CDCtx.UserStylesheets.push_back(std::string(filePath)); - } else if (filePath.ends_with(".js")) { - CDCtx.FilesToCopy.push_back(std::string(filePath)); - } +void GetAssetFiles(clang::doc::ClangDocContext &CDCtx) { + std::error_code Code; + for (auto DirIt = llvm::sys::fs::directory_iterator( + std::string(UserAssetPath), Code), + dir_end = llvm::sys::fs::directory_iterator(); + !Code && DirIt != dir_end; DirIt.increment(Code)) { + llvm::SmallString<128> filePath = llvm::SmallString<128>(DirIt->path()); + if (llvm::sys::fs::is_regular_file(filePath)) { + if (filePath.ends_with(".css")) { + CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), + std::string(filePath)); + } else if (filePath.ends_with(".js")) { + CDCtx.FilesToCopy.emplace_back(filePath.str()); + } + } } - } } void GetDefaultAssetFiles(const char *Argv0, - clang::doc::ClangDocContext CDCtx) { - void *MainAddr = (void *)(intptr_t)GetExecutablePath; - std::string ClangDocPath = GetExecutablePath(Argv0, MainAddr); - llvm::SmallString<128> NativeClangDocPath; - llvm::sys::path::native(ClangDocPath, NativeClangDocPath); - - llvm::SmallString<128> AssetsPath; - AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath); - llvm::sys::path::append(AssetsPath, "..", "share", "clang"); - llvm::SmallString<128> DefaultStylesheet; - llvm::sys::path::native(AssetsPath, DefaultStylesheet); - llvm::sys::path::append(DefaultStylesheet, - "clang-doc-default-stylesheet.css"); - llvm::SmallString<128> IndexJS; - llvm::sys::path::native(AssetsPath, IndexJS); - llvm::sys::path::append(IndexJS, "index.js"); - CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), - std::string(DefaultStylesheet)); - CDCtx.FilesToCopy.emplace_back(IndexJS.str()); - - llvm::outs() << "No default asset path found using default asset path: " - << AssetsPath << "\n"; + clang::doc::ClangDocContext &CDCtx) { + void *MainAddr = (void *)(intptr_t)GetExecutablePath; + std::string ClangDocPath = GetExecutablePath(Argv0, MainAddr); + llvm::SmallString<128> NativeClangDocPath; + llvm::sys::path::native(ClangDocPath, NativeClangDocPath); + + llvm::SmallString<128> AssetsPath; + AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath); + llvm::sys::path::append(AssetsPath, "..", "share", "clang"); + llvm::SmallString<128> DefaultStylesheet; + llvm::sys::path::native(AssetsPath, DefaultStylesheet); + llvm::sys::path::append(DefaultStylesheet, + "clang-doc-default-stylesheet.css"); + llvm::SmallString<128> IndexJS; + llvm::sys::path::native(AssetsPath, IndexJS); + llvm::sys::path::append(IndexJS, "index.js"); + CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), + std::string(DefaultStylesheet)); + CDCtx.FilesToCopy.emplace_back(IndexJS.str()); + + llvm::outs() << "No default asset path found using default asset path: " + << AssetsPath << "\n"; } int main(int argc, const char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); - std::error_code OK; + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + std::error_code OK; - const char *Overview = - R"(Generates documentation from source code and comments. + const char *Overview = + R"(Generates documentation from source code and comments. Example usage for files without flags (default): @@ -195,150 +196,150 @@ Example usage for a project using a compile commands database: $ clang-doc --executor=all-TUs compile_commands.json )"; - auto Executor = clang::tooling::createExecutorFromCommandLineArgs( - argc, argv, ClangDocCategory, Overview); - - if (!Executor) { - llvm::errs() << toString(Executor.takeError()) << "\n"; - return 1; - } - - // Fail early if an invalid format was provided. - std::string Format = getFormatString(); - llvm::outs() << "Emiting docs in " << Format << " format.\n"; - auto G = doc::findGeneratorByName(Format); - if (!G) { - llvm::errs() << toString(G.takeError()) << "\n"; - return 1; - } - - ArgumentsAdjuster ArgAdjuster; - if (!DoxygenOnly) - ArgAdjuster = combineAdjusters( - getInsertArgumentAdjuster("-fparse-all-comments", - tooling::ArgumentInsertPosition::END), - ArgAdjuster); - - clang::doc::ClangDocContext CDCtx = { - Executor->get()->getExecutionContext(), - ProjectName, - PublicOnly, - OutDirectory, - SourceRoot, - RepositoryUrl, - {UserStylesheets.begin(), UserStylesheets.end()}, - {"index.js", "index_json.js"}}; - - if (Format == "html") { - if (!UserAssetPath.empty() && - llvm::sys::fs::is_directory(std::string(UserAssetPath))) { - GetAssetFiles(CDCtx); - } else { - GetDefaultAssetFiles(argv[0], CDCtx); + auto Executor = clang::tooling::createExecutorFromCommandLineArgs( + argc, argv, ClangDocCategory, Overview); + + if (!Executor) { + llvm::errs() << toString(Executor.takeError()) << "\n"; + return 1; + } + + // Fail early if an invalid format was provided. + std::string Format = getFormatString(); + llvm::outs() << "Emiting docs in " << Format << " format.\n"; + auto G = doc::findGeneratorByName(Format); + if (!G) { + llvm::errs() << toString(G.takeError()) << "\n"; + return 1; } - } - - // Mapping phase - llvm::outs() << "Mapping decls...\n"; - auto Err = - Executor->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster); - if (Err) { - if (IgnoreMappingFailures) - llvm::errs() << "Error mapping decls in files. Clang-doc will ignore " - "these files and continue:\n" - << toString(std::move(Err)) << "\n"; - else { - llvm::errs() << toString(std::move(Err)) << "\n"; - return 1; + + ArgumentsAdjuster ArgAdjuster; + if (!DoxygenOnly) + ArgAdjuster = combineAdjusters( + getInsertArgumentAdjuster("-fparse-all-comments", + tooling::ArgumentInsertPosition::END), + ArgAdjuster); + + clang::doc::ClangDocContext CDCtx = { + Executor->get()->getExecutionContext(), + ProjectName, + PublicOnly, + OutDirectory, + SourceRoot, + RepositoryUrl, + {UserStylesheets.begin(), UserStylesheets.end()}, + {"index.js", "index_json.js"}}; + + if (Format == "html") { + if (!UserAssetPath.empty() && + llvm::sys::fs::is_directory(std::string(UserAssetPath))) { + GetAssetFiles(CDCtx); + } else { + GetDefaultAssetFiles(argv[0], CDCtx); + } } - } - - // Collect values into output by key. - // In ToolResults, the Key is the hashed USR and the value is the - // bitcode-encoded representation of the Info object. - llvm::outs() << "Collecting infos...\n"; - llvm::StringMap<std::vector<StringRef>> USRToBitcode; - Executor->get()->getToolResults()->forEachResult( - [&](StringRef Key, StringRef Value) { - auto R = USRToBitcode.try_emplace(Key, std::vector<StringRef>()); - R.first->second.emplace_back(Value); - }); - - // Collects all Infos according to their unique USR value. This map is added - // to from the thread pool below and is protected by the USRToInfoMutex. - llvm::sys::Mutex USRToInfoMutex; - llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo; - - // First reducing phase (reduce all decls into one info per decl). - llvm::outs() << "Reducing " << USRToBitcode.size() << " infos...\n"; - std::atomic<bool> Error; - Error = false; - llvm::sys::Mutex IndexMutex; - // ExecutorConcurrency is a flag exposed by AllTUsExecution.h - llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(ExecutorConcurrency)); - for (auto &Group : USRToBitcode) { - Pool.async([&]() { - std::vector<std::unique_ptr<doc::Info>> Infos; - - for (auto &Bitcode : Group.getValue()) { - llvm::BitstreamCursor Stream(Bitcode); - doc::ClangDocBitcodeReader Reader(Stream); - auto ReadInfos = Reader.readBitcode(); - if (!ReadInfos) { - llvm::errs() << toString(ReadInfos.takeError()) << "\n"; - Error = true; - return; + + // Mapping phase + llvm::outs() << "Mapping decls...\n"; + auto Err = + Executor->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster); + if (Err) { + if (IgnoreMappingFailures) + llvm::errs() << "Error mapping decls in files. Clang-doc will ignore " + "these files and continue:\n" + << toString(std::move(Err)) << "\n"; + else { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; } - std::move(ReadInfos->begin(), ReadInfos->end(), - std::back_inserter(Infos)); - } - - auto Reduced = doc::mergeInfos(Infos); - if (!Reduced) { - llvm::errs() << llvm::toString(Reduced.takeError()); - return; - } - - // Add a reference to this Info in the Index - { - std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex); - clang::doc::Generator::addInfoToIndex(CDCtx.Idx, Reduced.get().get()); - } - - // Save in the result map (needs a lock due to threaded access). - { - std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex); - USRToInfo[Group.getKey()] = std::move(Reduced.get()); - } - }); - } - - Pool.wait(); - - if (Error) - return 1; - - // Ensure the root output directory exists. - if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory); - Err != std::error_code()) { - llvm::errs() << "Failed to create directory '" << OutDirectory << "'\n"; - return 1; - } - - // Run the generator. - llvm::outs() << "Generating docs...\n"; - if (auto Err = - G->get()->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx)) { - llvm::errs() << toString(std::move(Err)) << "\n"; - return 1; - } - - llvm::outs() << "Generating assets for docs...\n"; - Err = G->get()->createResources(CDCtx); - if (Err) { - llvm::errs() << toString(std::move(Err)) << "\n"; - return 1; - } - - return 0; + } + + // Collect values into output by key. + // In ToolResults, the Key is the hashed USR and the value is the + // bitcode-encoded representation of the Info object. + llvm::outs() << "Collecting infos...\n"; + llvm::StringMap<std::vector<StringRef>> USRToBitcode; + Executor->get()->getToolResults()->forEachResult( + [&](StringRef Key, StringRef Value) { + auto R = USRToBitcode.try_emplace(Key, std::vector<StringRef>()); + R.first->second.emplace_back(Value); + }); + + // Collects all Infos according to their unique USR value. This map is added + // to from the thread pool below and is protected by the USRToInfoMutex. + llvm::sys::Mutex USRToInfoMutex; + llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo; + + // First reducing phase (reduce all decls into one info per decl). + llvm::outs() << "Reducing " << USRToBitcode.size() << " infos...\n"; + std::atomic<bool> Error; + Error = false; + llvm::sys::Mutex IndexMutex; + // ExecutorConcurrency is a flag exposed by AllTUsExecution.h + llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(ExecutorConcurrency)); + for (auto &Group : USRToBitcode) { + Pool.async([&]() { + std::vector<std::unique_ptr<doc::Info>> Infos; + + for (auto &Bitcode : Group.getValue()) { + llvm::BitstreamCursor Stream(Bitcode); + doc::ClangDocBitcodeReader Reader(Stream); + auto ReadInfos = Reader.readBitcode(); + if (!ReadInfos) { + llvm::errs() << toString(ReadInfos.takeError()) << "\n"; + Error = true; + return; + } + std::move(ReadInfos->begin(), ReadInfos->end(), + std::back_inserter(Infos)); + } + + auto Reduced = doc::mergeInfos(Infos); + if (!Reduced) { + llvm::errs() << llvm::toString(Reduced.takeError()); + return; + } + + // Add a reference to this Info in the Index + { + std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex); + clang::doc::Generator::addInfoToIndex(CDCtx.Idx, Reduced.get().get()); + } + + // Save in the result map (needs a lock due to threaded access). + { + std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex); + USRToInfo[Group.getKey()] = std::move(Reduced.get()); + } + }); + } + + Pool.wait(); + + if (Error) + return 1; + + // Ensure the root output directory exists. + if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory); + Err != std::error_code()) { + llvm::errs() << "Failed to create directory '" << OutDirectory << "'\n"; + return 1; + } + + // Run the generator. + llvm::outs() << "Generating docs...\n"; + if (auto Err = + G->get()->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx)) { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; + } + + llvm::outs() << "Generating assets for docs...\n"; + Err = G->get()->createResources(CDCtx); + if (Err) { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; + } + + return 0; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits