bool TranslationUnitManager::CreateCompilationDatabase(cbProject* proj) { wxJSONValue root; auto count = proj->GetFilesCount(); for (int i = 0; i < count ; ++i) { ProjectFile* projFile = proj->GetFile(i); auto targetNames = projFile->GetBuildTargets(); if (targetNames.IsEmpty()) continue; auto target = proj->GetBuildTarget(targetNames[0]); auto* compiler = CompilerFactory::GetCompiler(target->GetCompilerID()); wxJSONValue currNode; currNode["directory"] = wxString("."); //Compilation database cannot read windows style slashes wxString filePath = projFile->file.GetFullPath(); currNode["file"] = UnixFilename(filePath,wxPATH_UNIX); CommandLineGenerator dc(compiler, proj); wxString commandLine; wxArrayString commandArray = dc.GetCompileFileCommand(target,projFile); for (const auto& z : commandArray) { commandLine.Append(z); } if (commandLine.IsEmpty()) continue; currNode["command"] = UnixFilename(commandLine,wxPATH_UNIX); root.Append(currNode); } wxJSONWriter writer; wxFileOutputStream outFile("compile_commands.json"); writer.Write(root,outFile); return true; }
// Don't call this function from within the scope of: // ClangPlugin::OnEditorHook // ClangPlugin::OnTimer int ClangPlugin::UpdateCompileCommand(cbEditor* ed) { wxString compileCommand; ProjectFile* pf = ed->GetProjectFile(); m_UpdateCompileCommand++; if ( m_UpdateCompileCommand > 1 ) { // Re-entry is not allowed m_UpdateCompileCommand--; return 0; } ProjectBuildTarget* target = nullptr; Compiler* comp = nullptr; if (pf && pf->GetParentProject() && !pf->GetBuildTargets().IsEmpty()) { target = pf->GetParentProject()->GetBuildTarget(pf->GetBuildTargets()[0]); comp = CompilerFactory::GetCompiler(target->GetCompilerID()); } cbProject* proj = (pf ? pf->GetParentProject() : nullptr); if ( (!comp) && proj) comp = CompilerFactory::GetCompiler(proj->GetCompilerID()); if (!comp) { cbProject* tmpPrj = Manager::Get()->GetProjectManager()->GetActiveProject(); if (tmpPrj) comp = CompilerFactory::GetCompiler(tmpPrj->GetCompilerID()); } if (!comp) comp = CompilerFactory::GetDefaultCompiler(); if (pf && (!pf->GetBuildTargets().IsEmpty()) ) { target = pf->GetParentProject()->GetBuildTarget(pf->GetBuildTargets()[0]); if (pf->GetUseCustomBuildCommand(target->GetCompilerID() )) compileCommand = pf->GetCustomBuildCommand(target->GetCompilerID()).AfterFirst(wxT(' ')); } if (compileCommand.IsEmpty()) compileCommand = wxT("$options $includes"); CompilerCommandGenerator* gen = comp->GetCommandGenerator(proj); if (gen) gen->GenerateCommandLine(compileCommand, target, pf, ed->GetFilename(), g_InvalidStr, g_InvalidStr, g_InvalidStr ); delete gen; wxStringTokenizer tokenizer(compileCommand); compileCommand.Empty(); wxString pathStr; while (tokenizer.HasMoreTokens()) { wxString flag = tokenizer.GetNextToken(); // make all include paths absolute, so clang does not choke if Code::Blocks switches directories if (flag.StartsWith(wxT("-I"), &pathStr)) { wxFileName path(pathStr); if (path.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE)) flag = wxT("-I") + path.GetFullPath(); } compileCommand += flag + wxT(" "); } compileCommand += GetCompilerInclDirs(comp->GetID()); m_UpdateCompileCommand--; if (compileCommand != m_CompileCommand) { m_CompileCommand = compileCommand; return 1; } return 0; }
void ClangPlugin::OnTimer(wxTimerEvent& event) { if (!IsAttached()) return; const int evId = event.GetId(); if (evId == idEdOpenTimer) { cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); if (!ed || !IsProviderFor(ed)) return; else if (m_Proxy.GetTranslationUnitId(ed->GetFilename()) != wxNOT_FOUND) { m_DiagnosticTimer.Start(DIAGNOSTIC_DELAY, wxTIMER_ONE_SHOT); return; } wxString compileCommand; ProjectFile* pf = ed->GetProjectFile(); ProjectBuildTarget* target = nullptr; Compiler* comp = nullptr; if (pf && pf->GetParentProject() && !pf->GetBuildTargets().IsEmpty() ) { target = pf->GetParentProject()->GetBuildTarget(pf->GetBuildTargets()[0]); comp = CompilerFactory::GetCompiler(target->GetCompilerID()); if (pf->GetUseCustomBuildCommand(target->GetCompilerID())) { compileCommand = pf->GetCustomBuildCommand(target->GetCompilerID()).AfterFirst(wxT(' ')); } } if (compileCommand.IsEmpty()) compileCommand = wxT("$options $includes"); cbProject* proj = (pf ? pf->GetParentProject() : nullptr); if (!comp && proj) comp = CompilerFactory::GetCompiler(proj->GetCompilerID()); if (!comp) { cbProject* tmpPrj = Manager::Get()->GetProjectManager()->GetActiveProject(); if (tmpPrj) comp = CompilerFactory::GetCompiler(tmpPrj->GetCompilerID()); } if (!comp) comp = CompilerFactory::GetDefaultCompiler(); comp->GetCommandGenerator(proj)->GenerateCommandLine(compileCommand, target, pf, ed->GetFilename(), g_InvalidStr, g_InvalidStr, g_InvalidStr ); wxStringTokenizer tokenizer(compileCommand); compileCommand.Empty(); wxString pathStr; while (tokenizer.HasMoreTokens()) { wxString flag = tokenizer.GetNextToken(); // make all include paths absolute, so clang does not choke if Code::Blocks switches directories if (flag.StartsWith(wxT("-I"), &pathStr)) { wxFileName path(pathStr); if (path.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE)) flag = wxT("-I") + path.GetFullPath(); } compileCommand += flag + wxT(" "); } compileCommand += GetCompilerInclDirs(comp->GetID()); if (FileTypeOf(ed->GetFilename()) == ftHeader) // try to find the associated source { const wxString& source = GetSourceOf(ed); if (!source.IsEmpty()) { m_Proxy.CreateTranslationUnit(source, compileCommand); if (m_Proxy.GetTranslationUnitId(ed->GetFilename()) != wxNOT_FOUND) return; // got it } } m_Proxy.CreateTranslationUnit(ed->GetFilename(), compileCommand); m_DiagnosticTimer.Start(DIAGNOSTIC_DELAY, wxTIMER_ONE_SHOT); } else if (evId == idReparseTimer) { EditorManager* edMgr = Manager::Get()->GetEditorManager(); cbEditor* ed = edMgr->GetBuiltinActiveEditor(); if (!ed) return; if (ed != m_pLastEditor) { m_TranslUnitId = m_Proxy.GetTranslationUnitId(ed->GetFilename()); m_pLastEditor = ed; } if (m_TranslUnitId == wxNOT_FOUND) return; std::map<wxString, wxString> unsavedFiles; for (int i = 0; i < edMgr->GetEditorsCount(); ++i) { ed = edMgr->GetBuiltinEditor(i); if (ed && ed->GetModified()) unsavedFiles.insert(std::make_pair(ed->GetFilename(), ed->GetControl()->GetText())); } m_Proxy.Reparse(m_TranslUnitId, unsavedFiles); DiagnoseEd(m_pLastEditor, dlMinimal); } else if (evId == idDiagnosticTimer) { cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); if (!ed) return; if (ed != m_pLastEditor) { m_TranslUnitId = m_Proxy.GetTranslationUnitId(ed->GetFilename()); m_pLastEditor = ed; } if (m_TranslUnitId == wxNOT_FOUND) return; DiagnoseEd(ed, dlFull); } else event.Skip(); }