25#include "clang/Tooling/AllTUsExecution.h"
26#include "clang/Tooling/CommonOptionsParser.h"
27#include "clang/Tooling/Execution.h"
28#include "llvm/ADT/APFloat.h"
29#include "llvm/Support/CommandLine.h"
30#include "llvm/Support/Error.h"
31#include "llvm/Support/FileSystem.h"
32#include "llvm/Support/Mutex.h"
33#include "llvm/Support/Path.h"
34#include "llvm/Support/Process.h"
35#include "llvm/Support/Signals.h"
36#include "llvm/Support/ThreadPool.h"
37#include "llvm/Support/TimeProfiler.h"
38#include "llvm/Support/raw_ostream.h"
46static llvm::cl::extrahelp
CommonHelp(CommonOptionsParser::HelpMessage);
49static llvm::cl::opt<std::string>
50 ProjectName(
"project-name", llvm::cl::desc(
"Name of project."),
55 llvm::cl::desc(
"Continue if files are not mapped correctly."),
58static llvm::cl::opt<std::string>
60 llvm::cl::desc(
"Directory for outputting generated files."),
63static llvm::cl::opt<std::string>
65 llvm::cl::desc(R
"(Base Directory for generated documentation.
66URLs will be rooted at this directory for HTML links.)"),
69static llvm::cl::opt<bool>
70 PublicOnly(
"public", llvm::cl::desc(
"Document only public declarations."),
75 llvm::cl::desc(
"Use only doxygen-style comments to generate docs."),
79 "stylesheets", llvm::cl::CommaSeparated,
80 llvm::cl::desc(
"CSS stylesheets to extend the default styles."),
85 llvm::cl::desc(
"User supplied asset path to "
86 "override the default css and js files for html output"),
89static llvm::cl::opt<std::string>
SourceRoot(
"source-root", llvm::cl::desc(R
"(
90Directory where processed files are stored.
91Links to definition locations will only be
92generated if the file is in this dir.)"),
95static llvm::cl::opt<std::string>
97URL of repository that hosts code.
98Used for links to definition locations.)"),
102 "repository-line-prefix",
103 llvm::cl::desc(
"Prefix of line code for repository."),
106static llvm::cl::opt<bool>
FTimeTrace(
"ftime-trace", llvm::cl::desc(R
"(
107Turn on time profiler. Generates clang-doc-tracing.json)"),
108 llvm::cl::init(false),
113static llvm::cl::opt<OutputFormatTy>
FormatEnum(
114 "format", llvm::cl::desc(
"Format for outputted docs."),
116 "Documentation in YAML format."),
118 "Documentation in MD format."),
120 "Documentation in HTML format."),
122 "Documentation in mustache HTML format"),
124 "Documentation in JSON format")),
142 llvm_unreachable(
"Unknown OutputFormatTy");
151 return llvm::sys::fs::getMainExecutable(
Argv0, MainAddr);
155 using DirIt = llvm::sys::fs::directory_iterator;
156 std::error_code FileErr;
159 !FileErr && DirStart != DirEnd; DirStart.increment(FileErr)) {
160 FilePath = DirStart->path();
161 if (llvm::sys::fs::is_regular_file(FilePath)) {
162 if (llvm::sys::path::extension(FilePath) ==
".css")
164 std::string(FilePath));
165 else if (llvm::sys::path::extension(FilePath) ==
".js")
166 CDCtx.
JsScripts.emplace_back(FilePath.str());
170 return llvm::createFileError(FilePath, FileErr);
171 return llvm::Error::success();
178 llvm::SmallString<128> NativeClangDocPath;
179 llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
181 llvm::SmallString<128> AssetsPath;
182 AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
183 llvm::sys::path::append(AssetsPath,
"..",
"share",
"clang-doc");
184 llvm::SmallString<128> DefaultStylesheet =
188 if (!llvm::sys::fs::is_regular_file(IndexJS))
189 return llvm::createStringError(llvm::inconvertibleErrorCode(),
190 "default index.js file missing at " +
193 if (!llvm::sys::fs::is_regular_file(DefaultStylesheet))
194 return llvm::createStringError(
195 llvm::inconvertibleErrorCode(),
196 "default clang-doc-default-stylesheet.css file missing at " +
197 DefaultStylesheet +
"\n");
200 std::string(DefaultStylesheet));
201 CDCtx.
JsScripts.emplace_back(IndexJS.str());
203 return llvm::Error::success();
211 <<
" falling back to default\n";
221 llvm::outs() <<
"Asset path supply is not a directory: " <<
UserAssetPath
222 <<
" falling back to default\n";
225 return llvm::Error::success();
229 llvm::SmallString<128> NativeClangDocPath;
230 llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
232 llvm::SmallString<128> AssetsPath;
233 AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
234 llvm::sys::path::append(AssetsPath,
"..",
"share",
"clang-doc");
238 return llvm::Error::success();
244sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> &USRToInfo) {
245 for (
auto &I : USRToInfo) {
246 auto &
Info = I.second;
253 Record->Children.sort();
260 return llvm::Error::success();
262 llvm::errs() <<
"Error mapping decls in files. Clang-doc will ignore these "
263 "files and continue:\n"
264 << toString(std::move(Err)) <<
"\n";
265 return llvm::Error::success();
271 if (std::error_code Err = llvm::sys::fs::create_directories(
OutDirectory))
273 "failed to create directory.");
274 return llvm::Error::success();
277int main(
int argc,
const char **argv) {
278 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
281 ExitOnErr.setBanner(
"clang-doc error: ");
283 const char *Overview =
284 R
"(Generates documentation from source code and comments.
286Example usage for files without flags (default):
288 $ clang-doc File1.cpp File2.cpp ... FileN.cpp
290Example usage for a project using a compile commands database:
292 $ clang-doc --executor=all-TUs compile_commands.json
295 auto Executor =
ExitOnErr(clang::tooling::createExecutorFromCommandLineArgs(
300 llvm::timeTraceProfilerInitialize(200,
"clang-doc");
302 llvm::TimeTraceScope(
"main");
306 llvm::outs() <<
"Emiting docs in " << Format <<
" format.\n";
309 ArgumentsAdjuster ArgAdjuster;
311 ArgAdjuster = combineAdjusters(
312 getInsertArgumentAdjuster(
"-fparse-all-comments",
313 tooling::ArgumentInsertPosition::END),
317 Executor->getExecutionContext(),
328 if (Format ==
"html") {
330 }
else if (Format ==
"mustache") {
334 llvm::timeTraceProfilerBegin(
"Executor Launch",
"total runtime");
336 llvm::outs() <<
"Mapping decls...\n";
339 llvm::timeTraceProfilerEnd();
344 llvm::timeTraceProfilerBegin(
"Collect Info",
"total runtime");
345 llvm::outs() <<
"Collecting infos...\n";
346 llvm::StringMap<std::vector<StringRef>> USRToBitcode;
347 Executor->getToolResults()->forEachResult(
348 [&](StringRef Key, StringRef Value) {
349 USRToBitcode[
Key].emplace_back(Value);
351 llvm::timeTraceProfilerEnd();
355 llvm::sys::Mutex USRToInfoMutex;
356 llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo;
359 llvm::outs() <<
"Reducing " << USRToBitcode.size() <<
" infos...\n";
360 std::atomic<bool>
Error;
362 llvm::sys::Mutex IndexMutex;
364 llvm::DefaultThreadPool Pool(
365 llvm::hardware_concurrency(ExecutorConcurrency));
367 llvm::TimeTraceScope TS(
"Reduce");
368 for (
auto &Group : USRToBitcode) {
371 llvm::timeTraceProfilerInitialize(200,
"clang-doc");
373 std::vector<std::unique_ptr<doc::Info>> Infos;
375 llvm::TimeTraceScope Red(
"decoding bitcode");
376 for (
auto &Bitcode : Group.getValue()) {
377 llvm::BitstreamCursor Stream(Bitcode);
379 auto ReadInfos = Reader.readBitcode();
381 llvm::errs() << toString(ReadInfos.takeError()) <<
"\n";
385 std::move(ReadInfos->begin(), ReadInfos->end(),
386 std::back_inserter(Infos));
390 std::unique_ptr<doc::Info> Reduced;
393 llvm::TimeTraceScope
Merge(
"merging bitcode");
397 llvm::errs() << llvm::toString(ExpReduced.takeError());
400 Reduced = std::move(*ExpReduced);
405 llvm::TimeTraceScope
Merge(
"addInfoToIndex");
406 std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex);
411 llvm::TimeTraceScope
Merge(
"USRToInfo");
412 std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex);
413 USRToInfo[Group.getKey()] = std::move(Reduced);
417 llvm::timeTraceProfilerFinishThread();
428 llvm::TimeTraceScope Sort(
"Sort USRToInfo");
432 llvm::timeTraceProfilerBegin(
"Writing output",
"total runtime");
437 llvm::outs() <<
"Generating docs...\n";
440 G->generateDocumentation(
OutDirectory, std::move(USRToInfo), CDCtx));
441 llvm::outs() <<
"Generating assets for docs...\n";
443 llvm::timeTraceProfilerEnd();
448 llvm::raw_fd_ostream OS(
"clang-doc-tracing.json", EC,
449 llvm::sys::fs::OF_Text);
451 llvm::timeTraceProfilerWrite(OS);
452 llvm::timeTraceProfilerCleanup();
static llvm::cl::opt< std::string > UserAssetPath("asset", llvm::cl::desc("User supplied asset path to " "override the default css and js files for html output"), llvm::cl::cat(ClangDocCategory))
static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage)
static std::string getExecutablePath(const char *Argv0, void *MainAddr)
static llvm::cl::opt< bool > PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
static llvm::cl::opt< std::string > RepositoryCodeLinePrefix("repository-line-prefix", llvm::cl::desc("Prefix of line code for repository."), llvm::cl::cat(ClangDocCategory))
int main(int argc, const char **argv)
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."), clEnumValN(OutputFormatTy::mustache, "mustache", "Documentation in mustache HTML format"), clEnumValN(OutputFormatTy::json, "json", "Documentation in JSON format")), llvm::cl::init(OutputFormatTy::yaml), llvm::cl::cat(ClangDocCategory))
static void sortUsrToInfo(llvm::StringMap< std::unique_ptr< doc::Info > > &USRToInfo)
Make the output of clang-doc deterministic by sorting the children of namespaces and records.
static llvm::cl::opt< std::string > ProjectName("project-name", llvm::cl::desc("Name of project."), llvm::cl::cat(ClangDocCategory))
static llvm::Error handleMappingFailures(llvm::Error Err)
static llvm::Error getHtmlAssetFiles(const char *Argv0, clang::doc::ClangDocContext &CDCtx)
static llvm::Error createDirectories(llvm::StringRef OutDirectory)
static llvm::cl::opt< bool > FTimeTrace("ftime-trace", llvm::cl::desc(R"(
Turn on time profiler. Generates clang-doc-tracing.json)"), 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))
static llvm::ExitOnError ExitOnErr
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
generated if the file is in this dir.)"), llvm::cl::cat(ClangDocCategory))
static std::string getFormatString()
static llvm::cl::opt< std::string > BaseDirectory("base", llvm::cl::desc(R"(Base Directory for generated documentation.
URLs will be rooted at this directory for HTML links.)"), llvm::cl::init(""), 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))
static llvm::cl::opt< std::string > OutDirectory("output", llvm::cl::desc("Directory for outputting generated files."), llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory))
static llvm::Error getMustacheHtmlFiles(const char *Argv0, clang::doc::ClangDocContext &CDCtx)
static llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx)
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))
static llvm::Error getDefaultAssetFiles(const char *Argv0, clang::doc::ClangDocContext &CDCtx)
static llvm::cl::OptionCategory ClangDocCategory("clang-doc options")
static llvm::cl::opt< std::string > RepositoryUrl("repository", llvm::cl::desc(R"(
URL of repository that hosts code.
Used for links to definition locations.)"), llvm::cl::cat(ClangDocCategory))
SmallString< 128 > appendPathNative(StringRef Base, StringRef Path)
static void addInfoToIndex(Index &Idx, const doc::Info *Info)
@ Info
An information message.
llvm::Expected< std::unique_ptr< Info > > mergeInfos(std::vector< std::unique_ptr< Info > > &Values)
std::unique_ptr< tooling::FrontendActionFactory > newMapperActionFactory(ClangDocContext CDCtx)
llvm::Expected< std::unique_ptr< Generator > > findGeneratorByName(llvm::StringRef Format)
bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< std::string > UserStylesheets
std::vector< std::string > JsScripts