void ClangCodeCompletion::OnBuildStarting(clBuildEvent& e) { e.Skip(); CHECK_CLANG_ENABLED_RET(); // Determine the compilation database CompilationDatabase cdb; cdb.Open(); cdb.Close(); // Set the compilation database environment variable ::wxSetEnv(wxT("CL_COMPILATION_DB"), cdb.GetFileName().GetFullPath()); // If this is NOT a custom project, set the CXX and CC environment wxString project = e.GetProjectName(); wxString config = e.GetConfigurationName(); BuildConfigPtr bldConf = WorkspaceST::Get()->GetProjBuildConf(project, config); if( bldConf && !bldConf->IsCustomBuild()) { wxString cxx = bldConf->GetCompiler()->GetTool(wxT("CXX")); wxString cc = bldConf->GetCompiler()->GetTool(wxT("CC")); cxx.Prepend(wxT("codelitegcc ")); cc.Prepend(wxT("codelitegcc ")); ::wxSetEnv("CXX", cxx); ::wxSetEnv("CC" , cc); } }
chimera::cd_utils::CompileCommandVector chimera::cd_utils::getCompileCommandsByFilePath( const CompilationDatabase &database, StringRef filename) { // First search for the correct "file" Twine targetFilePath = Twine(filename); std::string foundFilePath; ChimeraLogger::verboseAndIncr("Retrieving compileCommands for " + targetFilePath.str()); // Find the foundFilename to access specific compileCommands // Get all "file" field of the compilation database auto compileFile = database.getAllFiles(); // Check if it's empty if (!compileFile.empty()) { // This isn't a FixedCompilationDatabase for (auto file = compileFile.begin(); file != compileFile.end(); ++file) { // Compare with targetFilename Twine filePathToCompare(*file); ChimeraLogger::verbose("Comparing with File: " + *file); // llvm::sys::fs::equivalent to test the really equivalence if (llvm::sys::fs::equivalent(targetFilePath, filePathToCompare)) { ChimeraLogger::verbose("Successful. Match found!"); foundFilePath = *file; break; } } } else { // This is a FixedCompilationDatabase ChimeraLogger::verbose( "CompilationDatabase with an empty filelist. Maybe provided by hand"); foundFilePath = targetFilePath.str(); } ChimeraLogger::decrActualVLevel(); // Return compileCommands return database.getCompileCommands(foundFilePath); }
void CodeCompletionManager::DoUpdateCompilationDatabase() { // Create a worker thread (detached thread) that // will initialize the database now that the compilation has ended CompilationDatabase db; ClangCompilationDbThreadST::Get()->AddFile( db.GetFileName().GetFullPath() ); }
TranslationUnit::TranslationUnit(Index& index, const std::string& source, CompilationDatabase& comp_db) { auto commands = comp_db.getCompileCommands(source); unsigned cmd_args = commands.getSize(); if (cmd_args == 0) { throw std::runtime_error("No compilation info for file `" + source + "`"); } auto command = commands.getCommand(0); auto arguments = command.GetArguments(1); arguments.push_back("-I" + comp_db.GetClangHeadersLocation()); std::vector<const char*> c_arguments; c_arguments.reserve(arguments.size()); bool skip = false; for (auto& arg : arguments) { if (skip) { skip = false; continue; } if (arg == "-c") { skip = true; continue; } c_arguments.push_back(arg.c_str()); } CXErrorCode code = clang_parseTranslationUnit2( index.index_, source.c_str(), c_arguments.data(), c_arguments.size(), nullptr, 0, CXTranslationUnit_DetailedPreprocessingRecord, &unit_); if (code != CXError_Success) { throw std::runtime_error("Error while parsing file `" + source + "`: " + ErrorCodeToString(code)); } }
void CodeCompletionManager::OnCompileCommandsFileGenerated(clCommandEvent& event) { event.Skip(); CL_DEBUG("-- Code Completion Manager: process file 'compile_commands.json' file"); CompilationDatabase db; ClangCompilationDbThreadST::Get()->AddFile(db.GetFileName().GetFullPath()); clMainFrame::Get()->SetStatusText("Ready"); }
ClangTool::ClangTool(const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths) : Files(new FileManager(FileSystemOptions())), DiagConsumer(NULL) { ArgsAdjusters.push_back(new ClangStripOutputAdjuster()); ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster()); for (const auto &SourcePath : SourcePaths) { std::string File(getAbsolutePath(SourcePath)); std::vector<CompileCommand> CompileCommandsForFile = Compilations.getCompileCommands(File); if (!CompileCommandsForFile.empty()) { for (CompileCommand &CompileCommand : CompileCommandsForFile) { CompileCommands.push_back( std::make_pair(File, std::move(CompileCommand))); } } else { // FIXME: There are two use cases here: doing a fuzzy // "find . -name '*.cc' |xargs tool" match, where as a user I don't care // about the .cc files that were not found, and the use case where I // specify all files I want to run over explicitly, where this should // be an error. We'll want to add an option for this. llvm::errs() << "Skipping " << File << ". Compile command not found.\n"; } } }
ClangTool::ClangTool(const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths) : Files((FileSystemOptions())), ArgsAdjuster(new ClangSyntaxOnlyAdjuster()) { llvm::SmallString<1024> BaseDirectory; if (const char *PWD = ::getenv("PWD")) BaseDirectory = PWD; else llvm::sys::fs::current_path(BaseDirectory); for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) { llvm::SmallString<1024> File(getAbsolutePath( SourcePaths[I], BaseDirectory)); std::vector<CompileCommand> CompileCommandsForFile = Compilations.getCompileCommands(File.str()); if (!CompileCommandsForFile.empty()) { for (int I = 0, E = CompileCommandsForFile.size(); I != E; ++I) { CompileCommands.push_back(std::make_pair(File.str(), CompileCommandsForFile[I])); } } else { // FIXME: There are two use cases here: doing a fuzzy // "find . -name '*.cc' |xargs tool" match, where as a user I don't care // about the .cc files that were not found, and the use case where I // specify all files I want to run over explicitly, where this should // be an error. We'll want to add an option for this. llvm::outs() << "Skipping " << File << ". Command line not found.\n"; } } }
void ClangCodeCompletion::OnBuildEnded(clBuildEvent& e) { e.Skip(); CHECK_CLANG_ENABLED_RET(); // Clear environment variables previously set by this class ::wxUnsetEnv(wxT("CL_COMPILATION_DB")); ::wxUnsetEnv(wxT("CXX")); ::wxUnsetEnv(wxT("CC")); // Create a worker thread (detached thread) that // will initialize the database now that the compilation is ended CompilationDatabase db; ClangCompilationDbThread* thr = new ClangCompilationDbThread( db.GetFileName().GetFullPath() ); thr->Start(); // Clear the TU cache ClearCache(); }
bool CodeCompletionManager::GetDefinitionsAndSearchPaths(LEditor* editor, wxArrayString& searchPaths, wxArrayString& definitions) { // Sanity CHECK_PTR_RET_FALSE(editor); if(editor->GetProjectName().IsEmpty()) return false; if(!WorkspaceST::Get()->IsOpen()) return false; // Support only C/C++ files if(!FileExtManager::IsCxxFile(editor->GetFileName().GetFullName())) return false; // Get the file's project and get the build configuration settings // for it ProjectPtr proj = WorkspaceST::Get()->GetProject(editor->GetProjectName()); CHECK_PTR_RET_FALSE(proj); BuildConfigPtr buildConf = proj->GetBuildConfiguration(); CHECK_PTR_RET_FALSE(buildConf); CompilerPtr compiler = buildConf->GetCompiler(); CHECK_PTR_RET_FALSE(compiler); if(buildConf->IsCustomBuild()) { // Custom builds are handled differently CompilationDatabase compileDb; compileDb.Open(); if(compileDb.IsOpened()) { // we have compilation database for this workspace wxString compileLine, cwd; compileDb.CompilationLine(editor->GetFileName().GetFullPath(), compileLine, cwd); CL_DEBUG("Pre Processor dimming: %s\n", compileLine); CompilerCommandLineParser cclp(compileLine, cwd); searchPaths = cclp.GetIncludes(); // get the mcros definitions = cclp.GetMacros(); } else { // we will probably will fail... return false; } } else { // get the include paths based on the project settings (this is per build configuration) searchPaths = proj->GetIncludePaths(); CL_DEBUG("CxxPreProcessor will use the following include paths:"); CL_DEBUG_ARR(searchPaths); // get the compiler include paths // wxArrayString compileIncludePaths = compiler->GetDefaultIncludePaths(); // includePaths.insert(includePaths.end(), compileIncludePaths.begin(), compileIncludePaths.end()); definitions = proj->GetPreProcessors(); CL_DEBUG("CxxPreProcessor will use the following macros:"); CL_DEBUG_ARR(definitions); } // Append the compiler builtin macros wxArrayString builtinMacros = compiler->GetBuiltinMacros(); definitions.insert(definitions.end(), builtinMacros.begin(), builtinMacros.end()); return true; }
bool CodeCompletionManager::GetDefinitionsAndSearchPaths(clEditor* editor, wxArrayString& searchPaths, wxArrayString& definitions) { // Sanity CHECK_PTR_RET_FALSE(editor); if(editor->GetProjectName().IsEmpty()) return false; if(!clCxxWorkspaceST::Get()->IsOpen()) return false; // Support only C/C++ files if(!FileExtManager::IsCxxFile(editor->GetFileName().GetFullName())) return false; // Get the file's project and get the build configuration settings // for it ProjectPtr proj = clCxxWorkspaceST::Get()->GetProject(editor->GetProjectName()); CHECK_PTR_RET_FALSE(proj); BuildConfigPtr buildConf = proj->GetBuildConfiguration(); CHECK_PTR_RET_FALSE(buildConf); CompilerPtr compiler = buildConf->GetCompiler(); CHECK_PTR_RET_FALSE(compiler); #if 0 if(buildConf->IsCustomBuild()) { definitions = proj->GetPreProcessors(); CL_DEBUG("CxxPreProcessor will use the following macros:"); CL_DEBUG_ARR(definitions); // Custom builds are handled differently CompilationDatabase compileDb; compileDb.Open(); if(compileDb.IsOpened()) { // we have compilation database for this workspace wxString compileLine, cwd; compileDb.CompilationLine(editor->GetFileName().GetFullPath(), compileLine, cwd); CL_DEBUG("Pre Processor dimming: %s\n", compileLine); CompilerCommandLineParser cclp(compileLine, cwd); searchPaths = cclp.GetIncludes(); // get the mcros definitions << cclp.GetMacros(); } } #endif // get the include paths based on the project settings (this is per build configuration) searchPaths = proj->GetIncludePaths(); CL_DEBUG("CxxPreProcessor will use the following include paths:"); CL_DEBUG_ARR(searchPaths); // get the compiler include paths // wxArrayString compileIncludePaths = compiler->GetDefaultIncludePaths(); // includePaths.insert(includePaths.end(), compileIncludePaths.begin(), compileIncludePaths.end()); definitions = proj->GetPreProcessors(); // get macros out of workspace wxString strWorkspaceMacros = clCxxWorkspaceST::Get()->GetParserMacros(); wxArrayString workspaceMacros = wxStringTokenize(strWorkspaceMacros, wxT("\n\r"), wxTOKEN_STRTOK); for(size_t i = 0; i < workspaceMacros.GetCount(); i++) definitions.Add(workspaceMacros.Item(i).Trim().Trim(false).c_str()); CL_DEBUG("CxxPreProcessor will use the following macros:"); CL_DEBUG_ARR(definitions); // Append the compiler builtin macros wxArrayString builtinMacros = compiler->GetBuiltinMacros(); definitions.insert(definitions.end(), builtinMacros.begin(), builtinMacros.end()); return true; }
FileTypeCmpArgs_t ClangDriver::DoPrepareCompilationArgs(const wxString& projectName, const wxString& sourceFile, wxString& projectPath, wxString& pchfile) { FileTypeCmpArgs_t cmpArgs; cmpArgs.insert(std::make_pair(FileExtManager::TypeSourceC, wxArrayString())); cmpArgs.insert(std::make_pair(FileExtManager::TypeSourceCpp, wxArrayString())); wxArrayString args; wxString errMsg; wxArrayString& cppCompileArgs = cmpArgs[FileExtManager::TypeSourceCpp]; wxArrayString& cCompileArgs = cmpArgs[FileExtManager::TypeSourceC]; // Build the TU file name wxFileName fnSourceFile(sourceFile); pchfile << WorkspaceST::Get()->GetWorkspaceFileName().GetPath() << wxFileName::GetPathSeparator() << wxT(".clang"); { wxLogNull nl; wxMkdir(pchfile); } pchfile << wxFileName::GetPathSeparator() << fnSourceFile.GetFullName() << wxT(".TU"); CompilationDatabase cdb; static bool once = false; if(!cdb.IsOk() && !once) { once = true; wxString msg; msg << _("Could not locate compilation database or database version is not up-to-date: ") << cdb.GetFileName().GetFullPath() << wxT("\n\n") << _("This file should be created automatically for you.\nIf you don't have it, please run a full rebuild " "of your workspace\n\n") << _("If this is a custom build project (i.e. project that uses a custom makefile),\nplease set the CXX " "and CC environment variables like this:\n") << _("CXX=codelite-cc g++\n") << _("CC=codelite-cc gcc\n\n"); clMainFrame::Get()->GetMainBook()->ShowMessage( msg, true, PluginManager::Get()->GetStdIcons()->LoadBitmap(wxT("messages/48/tip")), ButtonDetails(), ButtonDetails(), ButtonDetails(), CheckboxDetails(wxT("CodeCompletionMissingCompilationDB"))); } else { cdb.Open(); if(cdb.IsOpened()) { CL_DEBUG(wxT("Loading compilation flags for file: %s"), fnSourceFile.GetFullPath().c_str()); wxString compilationLine, cwd; cdb.CompilationLine(fnSourceFile.GetFullPath(), compilationLine, cwd); cdb.Close(); CompilerCommandLineParser cclp(compilationLine, cwd); cclp.MakeAbsolute(cwd); CL_DEBUG(wxT("Loaded compilation flags: %s"), compilationLine.c_str()); args.insert(args.end(), cclp.GetIncludesWithPrefix().begin(), cclp.GetIncludesWithPrefix().end()); args.insert(args.end(), cclp.GetMacrosWithPrefix().begin(), cclp.GetMacrosWithPrefix().end()); args.Add(cclp.GetStandardWithPrefix()); } } const TagsOptionsData& options = TagsManagerST::Get()->GetCtagsOptions(); /////////////////////////////////////////////////////////////////////// // add global clang include paths wxString strGlobalIncludes = options.GetClangSearchPaths(); // expand any macros from the include paths strGlobalIncludes = MacroManager::Instance()->Expand(strGlobalIncludes, PluginManager::Get(), projectName); wxArrayString globalIncludes = wxStringTokenize(strGlobalIncludes, wxT("\n\r"), wxTOKEN_STRTOK); for(size_t i = 0; i < globalIncludes.GetCount(); i++) { wxFileName fn(globalIncludes.Item(i).Trim().Trim(false), wxT("")); fn.MakeAbsolute(projectPath); cppCompileArgs.Add(wxString::Format(wxT("-I%s"), fn.GetPath().c_str())); cCompileArgs.Add(wxString::Format(wxT("-I%s"), fn.GetPath().c_str())); } /////////////////////////////////////////////////////////////////////// // Workspace setting additional flags /////////////////////////////////////////////////////////////////////// // Include paths wxArrayString workspaceIncls, dummy; LocalWorkspaceST::Get()->GetParserPaths(workspaceIncls, dummy); for(size_t i = 0; i < workspaceIncls.GetCount(); i++) { wxFileName fn(workspaceIncls.Item(i).Trim().Trim(false), wxT("")); fn.MakeAbsolute(WorkspaceST::Get()->GetWorkspaceFileName().GetPath()); cppCompileArgs.Add(wxString::Format(wxT("-I%s"), fn.GetPath().c_str())); cCompileArgs.Add(wxString::Format(wxT("-I%s"), fn.GetPath().c_str())); } // Macros wxString strWorkspaceMacros; LocalWorkspaceST::Get()->GetParserMacros(strWorkspaceMacros); wxArrayString workspaceMacros = wxStringTokenize(strWorkspaceMacros, wxT("\n\r"), wxTOKEN_STRTOK); for(size_t i = 0; i < workspaceMacros.GetCount(); i++) { cppCompileArgs.Add(wxString::Format(wxT("-D%s"), workspaceMacros.Item(i).Trim().Trim(false).c_str())); cCompileArgs.Add(wxString::Format(wxT("-D%s"), workspaceMacros.Item(i).Trim().Trim(false).c_str())); } // C++ 11 / 14 size_t workspaceFlags = LocalWorkspaceST::Get()->GetParserFlags(); if(workspaceFlags & LocalWorkspace::EnableCpp11) { cppCompileArgs.Add(wxT("-std=c++11")); cCompileArgs.Add(wxT("-std=c++11")); } if(workspaceFlags & LocalWorkspace::EnableCpp14) { cppCompileArgs.Add(wxT("-std=c++14")); cCompileArgs.Add(wxT("-std=c++14")); } /////////////////////////////////////////////////////////////////////// // Project setting additional flags /////////////////////////////////////////////////////////////////////// BuildConfigPtr buildConf = ManagerST::Get()->GetCurrentBuildConf(); if(buildConf) { wxString projSearchPaths = buildConf->GetCcSearchPaths(); wxArrayString projectIncludePaths = wxStringTokenize(projSearchPaths, wxT("\r\n"), wxTOKEN_STRTOK); for(size_t i = 0; i < projectIncludePaths.GetCount(); i++) { wxFileName fn(MacroManager::Instance() ->Expand(projectIncludePaths.Item(i), PluginManager::Get(), ManagerST::Get()->GetActiveProjectName()), wxT("")); fn.MakeAbsolute(WorkspaceST::Get()->GetWorkspaceFileName().GetPath()); cppCompileArgs.Add(wxString::Format(wxT("-I%s"), fn.GetPath().c_str())); cCompileArgs.Add(wxString::Format(wxT("-I%s"), fn.GetPath().c_str())); } wxString strProjectMacros = buildConf->GetClangPPFlags(); wxArrayString projectMacros = wxStringTokenize(strProjectMacros, wxT("\n\r"), wxTOKEN_STRTOK); for(size_t i = 0; i < projectMacros.GetCount(); i++) { cppCompileArgs.Add(wxString::Format(wxT("-D%s"), projectMacros.Item(i).Trim().Trim(false).c_str())); cCompileArgs.Add(wxString::Format(wxT("-D%s"), projectMacros.Item(i).Trim().Trim(false).c_str())); } if(buildConf->IsClangC11()) { cppCompileArgs.Add(wxT("-std=c++11")); cCompileArgs.Add(wxT("-std=c++11")); } if(buildConf->IsClangC14()) { cppCompileArgs.Add(wxT("-std=c++14")); cCompileArgs.Add(wxT("-std=c++14")); } } cppCompileArgs.insert(cppCompileArgs.end(), args.begin(), args.end()); cCompileArgs.insert(cCompileArgs.end(), args.begin(), args.end()); // Remove some of the flags which are known to cause problems to clang int where = wxNOT_FOUND; where = cppCompileArgs.Index(wxT("-fno-strict-aliasing")); if(where != wxNOT_FOUND) cppCompileArgs.RemoveAt(where); where = cppCompileArgs.Index(wxT("-mthreads")); if(where != wxNOT_FOUND) cppCompileArgs.RemoveAt(where); where = cppCompileArgs.Index(wxT("-pipe")); if(where != wxNOT_FOUND) cppCompileArgs.RemoveAt(where); where = cppCompileArgs.Index(wxT("-fmessage-length=0")); if(where != wxNOT_FOUND) cppCompileArgs.RemoveAt(where); where = cppCompileArgs.Index(wxT("-fPIC")); if(where != wxNOT_FOUND) cppCompileArgs.RemoveAt(where); // Now do the same for the "C" arguments where = cCompileArgs.Index(wxT("-fno-strict-aliasing")); if(where != wxNOT_FOUND) cCompileArgs.RemoveAt(where); where = cCompileArgs.Index(wxT("-mthreads")); if(where != wxNOT_FOUND) cCompileArgs.RemoveAt(where); where = cCompileArgs.Index(wxT("-pipe")); if(where != wxNOT_FOUND) cCompileArgs.RemoveAt(where); where = cCompileArgs.Index(wxT("-fmessage-length=0")); if(where != wxNOT_FOUND) cCompileArgs.RemoveAt(where); where = cCompileArgs.Index(wxT("-fPIC")); if(where != wxNOT_FOUND) cCompileArgs.RemoveAt(where); return cmpArgs; }