llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Aviral Goel (aviralg) <details> <summary>Changes</summary> This patch factors the duplicated code from `clang-ssaf-linker` and `clang-ssaf-format` into a new static library `clangSSAFToolCommon` at `clang/tools/clang-ssaf-tool-common/`. This includes identical `fail()` overloads, a format registry cache (getFormatForExtension), the `SummaryFile` abstraction, shared error message strings, `printVersion`, and near-identical `main()` initialization sequences. --- Patch is 25.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/187439.diff 8 Files Affected: - (modified) clang/tools/CMakeLists.txt (+1) - (modified) clang/tools/clang-ssaf-format/CMakeLists.txt (+1) - (modified) clang/tools/clang-ssaf-format/SSAFFormat.cpp (+10-120) - (modified) clang/tools/clang-ssaf-linker/CMakeLists.txt (+1) - (modified) clang/tools/clang-ssaf-linker/SSAFLinker.cpp (+17-109) - (added) clang/tools/clang-ssaf-tool-common/CMakeLists.txt (+17) - (added) clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp (+127) - (added) clang/tools/clang-ssaf-tool-common/SSAFToolUtils.h (+115) ``````````diff diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt index 891043ec31f77..b63778991e99f 100644 --- a/clang/tools/CMakeLists.txt +++ b/clang/tools/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_subdirectory(clang-offload-bundler) add_clang_subdirectory(clang-scan-deps) add_clang_subdirectory(clang-ssaf-format) add_clang_subdirectory(clang-ssaf-linker) +add_clang_subdirectory(clang-ssaf-tool-common) add_clang_subdirectory(clang-sycl-linker) add_clang_subdirectory(clang-installapi) if(HAVE_CLANG_REPL_SUPPORT) diff --git a/clang/tools/clang-ssaf-format/CMakeLists.txt b/clang/tools/clang-ssaf-format/CMakeLists.txt index f64d12eb3fac0..0eba14190e4ba 100644 --- a/clang/tools/clang-ssaf-format/CMakeLists.txt +++ b/clang/tools/clang-ssaf-format/CMakeLists.txt @@ -11,4 +11,5 @@ clang_target_link_libraries(clang-ssaf-format PRIVATE clangBasic clangScalableStaticAnalysisFrameworkCore + clangSSAFToolCommon ) diff --git a/clang/tools/clang-ssaf-format/SSAFFormat.cpp b/clang/tools/clang-ssaf-format/SSAFFormat.cpp index d91ff9402f7ec..e1267c93d4768 100644 --- a/clang/tools/clang-ssaf-format/SSAFFormat.cpp +++ b/clang/tools/clang-ssaf-format/SSAFFormat.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "SSAFToolUtils.h" #include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummaryEncoding.h" #include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/TUSummaryEncoding.h" #include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h" @@ -19,15 +20,12 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include <memory> #include <optional> @@ -36,6 +34,7 @@ using namespace llvm; using namespace clang::ssaf; +using namespace clang::ssaf::tool; namespace { @@ -84,87 +83,18 @@ cl::opt<bool> ListFormats("list", "analyses, then exit"), cl::init(false), cl::cat(SsafFormatCategory)); -llvm::StringRef ToolName; - -void printVersion(llvm::raw_ostream &OS) { OS << ToolName << " 0.1\n"; } - //===----------------------------------------------------------------------===// // Error Messages //===----------------------------------------------------------------------===// -namespace ErrorMessages { - -constexpr const char *FailedToLoadPlugin = "failed to load plugin '{0}': {1}"; - -constexpr const char *CannotValidateSummary = - "failed to validate summary '{0}': {1}"; - -constexpr const char *ExtensionNotSupplied = "Extension not supplied"; - -constexpr const char *NoFormatForExtension = - "Format not registered for extension '{0}'"; - -constexpr const char *OutputDirectoryMissing = - "Parent directory does not exist"; +namespace LocalErrorMessages { constexpr const char *OutputFileAlreadyExists = "Output file already exists"; constexpr const char *InputOutputSamePath = "Input and Output resolve to the same path"; -} // namespace ErrorMessages - -//===----------------------------------------------------------------------===// -// Diagnostic Utilities -//===----------------------------------------------------------------------===// - -[[noreturn]] void fail(const char *Msg) { - llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n"; - llvm::sys::Process::Exit(1); -} - -template <typename... Ts> -[[noreturn]] void fail(const char *Fmt, Ts &&...Args) { - std::string Message = llvm::formatv(Fmt, std::forward<Ts>(Args)...); - fail(Message.data()); -} - -[[noreturn]] void fail(llvm::Error Err) { - fail(toString(std::move(Err)).data()); -} - -//===----------------------------------------------------------------------===// -// Format Registry -//===----------------------------------------------------------------------===// - -// FIXME: This will be revisited after we add support for registering formats -// with extensions. -SerializationFormat *getFormatForExtension(llvm::StringRef Extension) { - static llvm::SmallVector< - std::pair<std::string, std::unique_ptr<SerializationFormat>>, 4> - ExtensionFormatList; - - // Most recently used format is most likely to be reused again. - auto ReversedList = llvm::reverse(ExtensionFormatList); - auto It = llvm::find_if(ReversedList, [&](const auto &Entry) { - return Entry.first == Extension; - }); - if (It != ReversedList.end()) { - return It->second.get(); - } - - if (!isFormatRegistered(Extension)) { - return nullptr; - } - - auto Format = makeFormat(Extension); - SerializationFormat *Result = Format.get(); - assert(Result); - - ExtensionFormatList.emplace_back(Extension, std::move(Format)); - - return Result; -} +} // namespace LocalErrorMessages //===----------------------------------------------------------------------===// // Format Listing @@ -295,47 +225,10 @@ void listFormats() { printFormats(Formats, computePrintLayout(Formats)); } -//===----------------------------------------------------------------------===// -// Plugin Loading -//===----------------------------------------------------------------------===// - -void loadPlugins() { - for (const auto &PluginPath : LoadPlugins) { - std::string ErrMsg; - if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(PluginPath.c_str(), - &ErrMsg)) { - fail(ErrorMessages::FailedToLoadPlugin, PluginPath, ErrMsg); - } - } -} - //===----------------------------------------------------------------------===// // Input Validation //===----------------------------------------------------------------------===// -struct SummaryFile { - std::string Path; - SerializationFormat *Format = nullptr; - - static SummaryFile fromPath(llvm::StringRef Path) { - llvm::StringRef Extension = path::extension(Path); - if (Extension.empty()) { - fail(ErrorMessages::CannotValidateSummary, Path, - ErrorMessages::ExtensionNotSupplied); - } - - Extension = Extension.drop_front(); - SerializationFormat *Format = getFormatForExtension(Extension); - if (!Format) { - std::string Msg = - llvm::formatv(ErrorMessages::NoFormatForExtension, Extension); - fail(ErrorMessages::CannotValidateSummary, Path, Msg); - } - - return {Path.str(), Format}; - } -}; - struct FormatInput { SummaryFile InputFile; std::optional<SummaryFile> OutputFile; @@ -391,12 +284,12 @@ FormatInput validateInput() { if (RealOutputPath == FI.InputFile.Path) { fail(ErrorMessages::CannotValidateSummary, OutputPath, - ErrorMessages::InputOutputSamePath); + LocalErrorMessages::InputOutputSamePath); } if (fs::exists(RealOutputPath)) { fail(ErrorMessages::CannotValidateSummary, OutputPath, - ErrorMessages::OutputFileAlreadyExists); + LocalErrorMessages::OutputFileAlreadyExists); } FI.OutputFile = SummaryFile::fromPath(RealOutputPath); @@ -458,15 +351,12 @@ void convert(const FormatInput &FI) { //===----------------------------------------------------------------------===// int main(int argc, const char **argv) { - InitLLVM X(argc, argv); - // path::stem strips the .exe extension on Windows so ToolName is consistent. - ToolName = path::stem(argv[0]); + llvm::StringRef ToolHeading = "SSAF Format"; - cl::HideUnrelatedOptions(SsafFormatCategory); - cl::SetVersionPrinter(printVersion); - cl::ParseCommandLineOptions(argc, argv, "SSAF Format\n"); + InitLLVM X(argc, argv); + initTool(argc, argv, "0.1", SsafFormatCategory, ToolHeading); - loadPlugins(); + loadPlugins(LoadPlugins); if (ListFormats) { listFormats(); diff --git a/clang/tools/clang-ssaf-linker/CMakeLists.txt b/clang/tools/clang-ssaf-linker/CMakeLists.txt index 0f6041fb109c9..ed317cb0fb182 100644 --- a/clang/tools/clang-ssaf-linker/CMakeLists.txt +++ b/clang/tools/clang-ssaf-linker/CMakeLists.txt @@ -11,4 +11,5 @@ clang_target_link_libraries(clang-ssaf-linker PRIVATE clangBasic clangScalableStaticAnalysisFrameworkCore + clangSSAFToolCommon ) diff --git a/clang/tools/clang-ssaf-linker/SSAFLinker.cpp b/clang/tools/clang-ssaf-linker/SSAFLinker.cpp index 3c57a2fe2cf98..1b48060cf9795 100644 --- a/clang/tools/clang-ssaf-linker/SSAFLinker.cpp +++ b/clang/tools/clang-ssaf-linker/SSAFLinker.cpp @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// +#include "SSAFToolUtils.h" #include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/EntityLinker.h" #include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/TUSummaryEncoding.h" #include "clang/ScalableStaticAnalysisFramework/Core/Model/BuildNamespace.h" -#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormatRegistry.h" #include "clang/ScalableStaticAnalysisFramework/Core/Support/ErrorBuilder.h" #include "clang/ScalableStaticAnalysisFramework/SSAFForceLinker.h" // IWYU pragma: keep #include "llvm/ADT/STLExtras.h" @@ -24,7 +24,6 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" #include "llvm/Support/Timer.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" @@ -34,6 +33,7 @@ using namespace llvm; using namespace clang::ssaf; +using namespace clang::ssaf::tool; namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; @@ -59,53 +59,12 @@ cl::opt<bool> Verbose("verbose", cl::desc("Enable verbose output"), cl::opt<bool> Time("time", cl::desc("Enable timing"), cl::init(false), cl::cat(SsafLinkerCategory)); -//===----------------------------------------------------------------------===// -// Error Messages -//===----------------------------------------------------------------------===// - -namespace ErrorMessages { - -constexpr const char *CannotValidateSummary = - "failed to validate summary '{0}': {1}"; - -constexpr const char *OutputDirectoryMissing = - "Parent directory does not exist"; - -constexpr const char *OutputDirectoryNotWritable = - "Parent directory is not writable"; - -constexpr const char *ExtensionNotSupplied = "Extension not supplied"; - -constexpr const char *NoFormatForExtension = - "Format not registered for extension '{0}'"; - -constexpr const char *LinkingSummary = "Linking summary '{0}'"; - -} // namespace ErrorMessages - //===----------------------------------------------------------------------===// // Diagnostic Utilities //===----------------------------------------------------------------------===// constexpr unsigned IndentationWidth = 2; -llvm::StringRef ToolName; - -template <typename... Ts> [[noreturn]] void fail(const char *Msg) { - llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n"; - llvm::sys::Process::Exit(1); -} - -template <typename... Ts> -[[noreturn]] void fail(const char *Fmt, Ts &&...Args) { - std::string Message = llvm::formatv(Fmt, std::forward<Ts>(Args)...); - fail(Message.data()); -} - -template <typename... Ts> [[noreturn]] void fail(llvm::Error Err) { - fail(toString(std::move(Err)).data()); -} - template <typename... Ts> void info(unsigned IndentationLevel, const char *Fmt, Ts &&...Args) { if (Verbose) { @@ -115,74 +74,29 @@ void info(unsigned IndentationLevel, const char *Fmt, Ts &&...Args) { } } -//===----------------------------------------------------------------------===// -// Format Registry -//===----------------------------------------------------------------------===// - -SerializationFormat *getFormatForExtension(llvm::StringRef Extension) { - static llvm::SmallVector< - std::pair<std::string, std::unique_ptr<SerializationFormat>>, 4> - ExtensionFormatList; - - // Most recently used format is most likely to be reused again. - auto ReversedList = llvm::reverse(ExtensionFormatList); - auto It = llvm::find_if(ReversedList, [&](const auto &Entry) { - return Entry.first == Extension; - }); - if (It != ReversedList.end()) { - return It->second.get(); - } - - if (!isFormatRegistered(Extension)) { - return nullptr; - } - - auto Format = makeFormat(Extension); - SerializationFormat *Result = Format.get(); - assert(Result); - - ExtensionFormatList.emplace_back(Extension, std::move(Format)); - - return Result; -} - //===----------------------------------------------------------------------===// // Data Structures //===----------------------------------------------------------------------===// -struct SummaryFile { - std::string Path; - SerializationFormat *Format = nullptr; - - static SummaryFile fromPath(llvm::StringRef Path) { - llvm::StringRef Extension = path::extension(Path); - if (Extension.empty()) { - fail(ErrorMessages::CannotValidateSummary, Path, - ErrorMessages::ExtensionNotSupplied); - } - Extension = Extension.drop_front(); - SerializationFormat *Format = getFormatForExtension(Extension); - if (!Format) { - std::string BadExtension = - llvm::formatv(ErrorMessages::NoFormatForExtension, Extension); - fail(ErrorMessages::CannotValidateSummary, Path, BadExtension); - } - return {Path.str(), Format}; - } -}; - struct LinkerInput { std::vector<SummaryFile> InputFiles; SummaryFile OutputFile; std::string LinkUnitName; }; -static void printVersion(llvm::raw_ostream &OS) { OS << ToolName << " 0.1\n"; } - //===----------------------------------------------------------------------===// // Pipeline //===----------------------------------------------------------------------===// +namespace LocalErrorMessages { + +constexpr const char *OutputDirectoryNotWritable = + "Parent directory is not writable"; + +constexpr const char *LinkingSummary = "Linking summary '{0}'"; + +} // namespace LocalErrorMessages + LinkerInput validate(llvm::TimerGroup &TG) { llvm::Timer TValidate("validate", "Validate Input", TG); LinkerInput LI; @@ -199,7 +113,7 @@ LinkerInput validate(llvm::TimerGroup &TG) { if (fs::access(DirToCheck, fs::AccessMode::Write)) { fail(ErrorMessages::CannotValidateSummary, OutputPath, - ErrorMessages::OutputDirectoryNotWritable); + LocalErrorMessages::OutputDirectoryNotWritable); } LI.OutputFile = SummaryFile::fromPath(OutputPath); @@ -264,7 +178,7 @@ void link(const LinkerInput &LI, llvm::TimerGroup &TG) { if (auto Err = EL.link(std::move(Summary))) { fail(ErrorBuilder::wrap(std::move(Err)) - .context(ErrorMessages::LinkingSummary, InputFile.Path) + .context(LocalErrorMessages::LinkingSummary, InputFile.Path) .build()); } } @@ -290,18 +204,12 @@ void link(const LinkerInput &LI, llvm::TimerGroup &TG) { //===----------------------------------------------------------------------===// int main(int argc, const char **argv) { - InitLLVM X(argc, argv); - // path::stem strips the .exe extension on Windows so ToolName is consistent. - ToolName = llvm::sys::path::stem(argv[0]); + llvm::StringRef ToolHeading = "SSAF Linker"; - // Hide options unrelated to clang-ssaf-linker from --help output. - cl::HideUnrelatedOptions(SsafLinkerCategory); - // Register a custom version printer for the --version flag. - cl::SetVersionPrinter(printVersion); - // Parse command-line arguments and exit with an error if they are invalid. - cl::ParseCommandLineOptions(argc, argv, "SSAF Linker\n"); + InitLLVM X(argc, argv); + initTool(argc, argv, "0.1", SsafLinkerCategory, ToolHeading); - llvm::TimerGroup LinkerTimers(ToolName, "SSAF Linker"); + llvm::TimerGroup LinkerTimers(ToolName, ToolHeading); LinkerInput LI; { diff --git a/clang/tools/clang-ssaf-tool-common/CMakeLists.txt b/clang/tools/clang-ssaf-tool-common/CMakeLists.txt new file mode 100644 index 0000000000000..67715b7aa7e19 --- /dev/null +++ b/clang/tools/clang-ssaf-tool-common/CMakeLists.txt @@ -0,0 +1,17 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(clangSSAFToolCommon + SSAFToolUtils.cpp + ) + +clang_target_link_libraries(clangSSAFToolCommon + PUBLIC + clangBasic + clangScalableStaticAnalysisFrameworkCore + ) + +target_include_directories(clangSSAFToolCommon + PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + ) diff --git a/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp b/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp new file mode 100644 index 0000000000000..fe86b5d484a97 --- /dev/null +++ b/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp @@ -0,0 +1,127 @@ +//===- SSAFToolUtils.cpp - Shared utilities for SSAF tools ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SSAFToolUtils.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <memory> +#include <string> + +namespace clang::ssaf::tool { + +namespace path = llvm::sys::path; + +llvm::StringRef ToolName; +static llvm::StringRef ToolVersion; + +void printVersion(llvm::raw_ostream &OS) { + OS << ToolName << " " << ToolVersion << "\n"; +} + +[[noreturn]] void fail(const char *Msg) { + llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n"; + llvm::sys::Process::Exit(1); +} + +[[noreturn]] void fail(llvm::Error Err) { + std::string Message = llvm::toString(std::move(Err)); + fail(Message.data()); +} + +void loadPlugins(llvm::ArrayRef<std::string> Paths) { + for (const std::string &PluginPath : Paths) { + std::string ErrMsg; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(PluginPath.c_str(), + &ErrMsg)) { + fail(ErrorMessages::FailedToLoadPlugin, PluginPath, ErrMsg); + } + } +} + +void initTool(int argc, const char **argv, llvm::StringRef Version, + llvm::cl::OptionCategory &Category, llvm::StringRef ToolHeading) { + // path::stem strips the .exe extension on Windows so ToolName is consistent. + ToolName = path::stem(argv[0]); + + // Set tool version for the version printer. + ToolVersion = Version; + + // Hide options unrelated to the tool from --help output. + llvm::cl::HideUnrelatedOptions(Category); + + // Register a custom version printer for the --version flag. + llvm::cl::SetVersionPrinter(printVersion); + + // Parse command-line arguments and exit with an error if they are invalid. + std::string Overview = (ToolHeading + "\n").str(); + llvm::cl::ParseCommandLineOptions(argc, argv, Overview); +} + +// FIXME: This will be revisited after we add support for registering formats +// with extensions. +SerializationFormat *getFormatForExtension(llvm::StringRef Extension) { + // This cache is not thread-safe. SSAF tools are single-threaded CLIs, so + // concurrent calls to this function are not expected. + + // Realistically, we don't expect to encounter more than four registered + // formats. + static llvm::SmallVector< + std::pair<std::string, std::unique_ptr<SerializationFormat>>, 4> + ExtensionFormatList; + + // Most recently used format is most likely to be reused again. + auto ReversedList = llvm::reverse(ExtensionFormatList); + auto It = llvm::find_if(ReversedList, [&](const auto &Entry) { + return Entry.first == Extension; + }); + if (It != ReversedList.end()) { + return It->second.get(); + } + + if (!isFormatRegistered(Extension)) { + return nullptr; + } + + auto Format = makeFormat(Extension); +... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/187439 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
