ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
tool.cpp File Reference

Go to the source code of this file.

Functions

std::mutex & outputRegistryMutex ()
 
std::unordered_set< std::string > & outputRegistry ()
 
bool registerOutputPath (const std::string &path)
 
void unregisterOutputPath (const std::string &path)
 
int main (int argc, const char **argv)
 

Variables

constexpr unsigned kMacroFlagNone = 0U
 
constexpr unsigned kMacroFlagExpansion = 1U
 
constexpr unsigned kMacroFlagInvocation = 2U
 

Function Documentation

◆ main()

int main ( int  argc,
const char **  argv 
)

Definition at line 676 of file panic/tool.cpp.

676 {
677 // Initialize LLVM infrastructure (this triggers command-line option registration!)
678 llvm::InitLLVM InitLLVM(argc, argv);
679
680 // Parse command-line options
681 cl::ParseCommandLineOptions(argc, argv, "ascii-chat instrumentation tool\n");
682
683 const fs::path outputDir = fs::path(OutputDirectoryOption.getValue());
684 fs::path inputRoot;
685 if (!InputRootOption.getValue().empty()) {
686 inputRoot = fs::path(InputRootOption.getValue());
687 } else {
688 inputRoot = fs::current_path();
689 }
690
691 std::vector<std::string> rawSourceArgs;
692 rawSourceArgs.reserve(SourcePaths.size());
693 for (const auto &path : SourcePaths) {
694 rawSourceArgs.push_back(path);
695 }
696 std::vector<std::string> sourcePaths;
697 std::vector<std::string> extraCompilerArgs;
698 for (std::size_t i = 0; i < rawSourceArgs.size(); ++i) {
699 const std::string &entry = rawSourceArgs[i];
700 if (entry.empty()) {
701 continue;
702 }
703 if (entry == "--") {
704 continue;
705 }
706 if (entry[0] == '-') {
707 extraCompilerArgs.push_back(entry);
708 const bool consumesNext = (entry == "-I" || entry == "-isystem" || entry == "-include" ||
709 entry == "-include-pch" || entry == "-imacros" || entry == "-idirafter" ||
710 entry == "-iprefix" || entry == "-iwithprefix" || entry == "-iwithprefixbefore" ||
711 entry == "-resource-dir" || entry == "-Xclang" || entry == "-Xpreprocessor");
712 if (consumesNext && (i + 1) < rawSourceArgs.size()) {
713 extraCompilerArgs.push_back(rawSourceArgs[i + 1]);
714 ++i;
715 }
716 continue;
717 }
718 sourcePaths.push_back(entry);
719 }
720 if (!FileListOption.getValue().empty()) {
721 std::ifstream listStream(FileListOption.getValue());
722 if (!listStream.is_open()) {
723 llvm::errs() << "Failed to open file list: " << FileListOption.getValue() << "\n";
724 return 1;
725 }
726
727 std::string line;
728 while (std::getline(listStream, line)) {
729 llvm::StringRef trimmed(line);
730 trimmed = trimmed.trim();
731 if (trimmed.empty()) {
732 continue;
733 }
734 sourcePaths.emplace_back(trimmed.str());
735 }
736 }
737
738 if (sourcePaths.empty()) {
739 llvm::errs()
740 << "No translation units specified for instrumentation. Provide positional source paths or --file-list."
741 << "\n";
742 return 1;
743 }
744
745 if (fs::exists(outputDir)) {
746 if (!fs::is_directory(outputDir)) {
747 llvm::errs() << "Output path exists and is not a directory: " << outputDir.c_str() << "\n";
748 return 1;
749 }
750 } else {
751 std::error_code errorCode;
752 fs::create_directories(outputDir, errorCode);
753 if (errorCode) {
754 llvm::errs() << "Failed to create output directory: " << outputDir.c_str() << " - " << errorCode.message()
755 << "\n";
756 return 1;
757 }
758 }
759
760 const bool logMacroExpansions = LogMacroExpansionsOption.getValue() || LegacyIncludeMacroExpansionsOption.getValue();
761 const bool logMacroInvocations = LogMacroInvocationsOption.getValue();
762
763 if (!LogMacroExpansionsOption.getValue() && LegacyIncludeMacroExpansionsOption.getValue()) {
764 llvm::errs() << "warning: --include-macro-expansions is deprecated; use --log-macro-expansions instead\n";
765 }
766
767 // Load compilation database
768 std::string buildPath = BuildPath.getValue();
769 if (buildPath.empty()) {
770 buildPath = ".";
771 }
772 std::string errorMessage;
773 std::unique_ptr<tooling::CompilationDatabase> compilations =
774 tooling::CompilationDatabase::loadFromDirectory(buildPath, errorMessage);
775 if (!compilations) {
776 llvm::errs() << "Error loading compilation database from '" << buildPath << "': " << errorMessage << "\n";
777 return 1;
778 }
779
780 clang::tooling::ClangTool tool(*compilations, sourcePaths);
781
782 if (!extraCompilerArgs.empty()) {
783 const std::vector<std::string> extraArgsCopy(extraCompilerArgs.begin(), extraCompilerArgs.end());
784 tool.appendArgumentsAdjuster([extraArgsCopy](const clang::tooling::CommandLineArguments &args, llvm::StringRef) {
785 clang::tooling::CommandLineArguments adjusted = args;
786 adjusted.insert(adjusted.end(), extraArgsCopy.begin(), extraArgsCopy.end());
787 return adjusted;
788 });
789 }
790
791 auto stripPchAdjuster = [](const clang::tooling::CommandLineArguments &args, llvm::StringRef) {
792 clang::tooling::CommandLineArguments result;
793 const auto containsCMakePch = [](llvm::StringRef value) { return value.contains("cmake_pch"); };
794
795 for (std::size_t i = 0; i < args.size(); ++i) {
796 const std::string &arg = args[i];
797 llvm::StringRef argRef(arg);
798
799 if ((argRef == "-include" || argRef == "--include" || argRef == "-include-pch" || argRef == "--include-pch") &&
800 (i + 1) < args.size()) {
801 if (containsCMakePch(args[i + 1])) {
802 ++i;
803 continue;
804 }
805 }
806
807 if ((argRef.starts_with("-include=") || argRef.starts_with("--include=") || argRef.starts_with("-include-pch=") ||
808 argRef.starts_with("--include-pch=")) &&
809 containsCMakePch(argRef)) {
810 continue;
811 }
812
813 result.push_back(arg);
814 }
815
816 return result;
817 };
818 tool.appendArgumentsAdjuster(stripPchAdjuster);
819
820 auto ensureSourceIncludeAdjuster = [&inputRoot](const clang::tooling::CommandLineArguments &args, llvm::StringRef) {
821 clang::tooling::CommandLineArguments result = args;
822
823 const auto hasInclude = [&result](const std::string &dir) {
824 const std::string combined = "-I" + dir;
825 if (std::find(result.begin(), result.end(), combined) != result.end()) {
826 return true;
827 }
828 for (std::size_t i = 0; i + 1 < result.size(); ++i) {
829 if (result[i] == "-I" && result[i + 1] == dir) {
830 return true;
831 }
832 }
833 return false;
834 };
835
836 const auto appendInclude = [&result](const std::string &dir) {
837 result.push_back("-I");
838 result.push_back(dir);
839 };
840
841 const std::string libDir = (inputRoot / "lib").generic_string();
842 const std::string srcDir = (inputRoot / "src").generic_string();
843
844 if (!hasInclude(libDir)) {
845 appendInclude(libDir);
846 }
847 if (!hasInclude(srcDir)) {
848 appendInclude(srcDir);
849 }
850
851 return result;
852 };
853 tool.appendArgumentsAdjuster(ensureSourceIncludeAdjuster);
854
855 // Instrumented headers are now hard-linked into the output tree, so we can
856 // rely on the original include paths without further adjustment.
857
858 // NOTE: -skip-function-bodies optimization removed - it was causing errors with LibTooling
859 // LibTooling handles arguments differently than the clang driver, so -Xclang flags don't work
860 // The optimization wasn't providing significant benefit anyway
861
862 // Optimization: strip unnecessary compilation flags
863 auto stripUnnecessaryFlags = [](const clang::tooling::CommandLineArguments &args, llvm::StringRef) {
864 clang::tooling::CommandLineArguments result;
865
866 for (size_t i = 0; i < args.size(); ++i) {
867 const std::string &arg = args[i];
868
869 // Skip sanitizer flags (not needed for instrumentation, slow down parsing)
870 if (arg.find("-fsanitize") != std::string::npos)
871 continue;
872 if (arg.find("-fno-sanitize") != std::string::npos)
873 continue;
874 if (arg.find("sanitize") != std::string::npos)
875 continue;
876
877 // Skip debug info generation flags (not needed, slow down codegen)
878 if (arg == "-g" || arg == "-g2" || arg == "-g3")
879 continue;
880 if (arg == "-gcolumn-info")
881 continue;
882 if (arg == "-fstandalone-debug")
883 continue;
884 if (arg.find("-gcodeview") != std::string::npos)
885 continue;
886 if (arg.find("-gdwarf") != std::string::npos)
887 continue;
888
889 // Skip stack protector (not needed for instrumentation)
890 if (arg.find("-fstack-protector") != std::string::npos)
891 continue;
892
893 // Skip frame pointer flags
894 if (arg.find("-fno-omit-frame-pointer") != std::string::npos)
895 continue;
896 if (arg.find("-fomit-frame-pointer") != std::string::npos)
897 continue;
898
899 // Skip optimization-related debug flags
900 if (arg == "-fno-inline")
901 continue;
902 if (arg == "-fno-eliminate-unused-debug-types")
903 continue;
904
905 result.push_back(arg);
906 }
907
908 // NOTE: -w flag removed - it was causing "no such file or directory" errors with LibTooling
909 // Warnings are already suppressed by the stripped flags above
910
911 return result;
912 };
913 tool.appendArgumentsAdjuster(stripUnnecessaryFlags);
914
915 InstrumentationActionFactory actionFactory(outputDir, inputRoot, !FileIncludeFilters.empty(),
916 !FunctionIncludeFilters.empty(), logMacroInvocations, logMacroExpansions);
917 const int executionResult = tool.run(&actionFactory);
918 if (executionResult != 0) {
919 llvm::errs() << "Instrumenter failed with code " << executionResult << "\n";
920 }
921 return executionResult;
922}
action_args_t args

References args.

◆ outputRegistry()

std::unordered_set< std::string > & outputRegistry ( )

Definition at line 40 of file panic/tool.cpp.

40 {
41 static std::unordered_set<std::string> registry;
42 return registry;
43}

Referenced by registerOutputPath(), and unregisterOutputPath().

◆ outputRegistryMutex()

std::mutex & outputRegistryMutex ( )

Definition at line 35 of file panic/tool.cpp.

35 {
36 static std::mutex mutex;
37 return mutex;
38}

Referenced by registerOutputPath(), and unregisterOutputPath().

◆ registerOutputPath()

bool registerOutputPath ( const std::string &  path)

Definition at line 45 of file panic/tool.cpp.

45 {
46 std::lock_guard<std::mutex> guard(outputRegistryMutex());
47 auto &registry = outputRegistry();
48 auto [_, inserted] = registry.insert(path);
49 return inserted;
50}
std::mutex & outputRegistryMutex()
std::unordered_set< std::string > & outputRegistry()

References outputRegistry(), and outputRegistryMutex().

◆ unregisterOutputPath()

void unregisterOutputPath ( const std::string &  path)

Definition at line 52 of file panic/tool.cpp.

52 {
53 std::lock_guard<std::mutex> guard(outputRegistryMutex());
54 outputRegistry().erase(path);
55}

References outputRegistry(), and outputRegistryMutex().

Variable Documentation

◆ kMacroFlagExpansion

constexpr unsigned kMacroFlagExpansion = 1U
constexpr

Definition at line 112 of file panic/tool.cpp.

◆ kMacroFlagInvocation

constexpr unsigned kMacroFlagInvocation = 2U
constexpr

Definition at line 113 of file panic/tool.cpp.

◆ kMacroFlagNone

constexpr unsigned kMacroFlagNone = 0U
constexpr

Definition at line 111 of file panic/tool.cpp.