void CMakePlugin::OnExportMakefile(clBuildEvent& event) { const wxString project = event.GetProjectName(); const wxString config = event.GetConfigurationName(); // Get settings const CMakeProjectSettings* settings = GetSettingsManager()->GetProjectSettings(project, config); // Doesn't exists or not enabled if (!settings || !settings->enabled) { // Unable to export makefile event.Skip(); return; } // Get project directory - this is directory where the makefile is stored const wxFileName projectDir = GetProjectDirectory(project); // Targets forward inspired by // https://gist.github.com/doitian/4978329 // Content of the generated makefile wxString content = wxString() << "# Generated by CMakePlugin\n" ".PHONY: all clean $(MAKECMDGOALS)\n" "\n" ; // Parent project is set if (!settings->parentProject.IsEmpty()) { // Configure parent project instead const wxString& parentProject = settings->parentProject; settings = GetSettingsManager()->GetProjectSettings(parentProject, config); // Parent project not found if (!settings || !settings->enabled) { CL_ERROR("Unable to find or not enabled parent project " "'" + parentProject + "' for project '" + project + "'"); return; } // Get parent project directory wxFileName parentProjectDir = GetProjectDirectory(parentProject); parentProjectDir.MakeRelativeTo(projectDir.GetFullPath()); // Path is relative so UNIX path system can be used const wxString parentProjectDirEsc = parentProjectDir.GetPath(wxPATH_NO_SEPARATOR, wxPATH_UNIX); // Redirect make to the parent project content << "# Parent project\n" "PARENT := " << parentProjectDirEsc << "\n" "PARENT_MAKEFILE := " << parentProject << ".mk\n" "\n" "all:\n" "\t$(MAKE) -C \"$(PARENT)\" -f \"$(PARENT_MAKEFILE)\" " << project << "\n" "\n" "clean:\n" "\t$(MAKE) -C \"$(PARENT)\" -f \"$(PARENT_MAKEFILE)\" " << project << " clean\n" "\n" ; } else { // Macro expander // FIXME use IMacroManager (unable to find it yet) MacroManager* macro = MacroManager::Instance(); wxASSERT(macro); // Get variables // Expand variables for final project const wxString cmake = GetConfiguration()->GetProgramPath(); wxFileName sourceDir = wxFileName::DirName(macro->Expand(settings->sourceDirectory, GetManager(), project, config)); wxFileName buildDir = wxFileName::DirName(macro->Expand(settings->buildDirectory, GetManager(), project, config)); // Source dir must be relative to build directory (here is cmake called) sourceDir.MakeRelativeTo(buildDir.GetFullPath()); // Build dir must be relative to project directory buildDir.MakeRelativeTo(projectDir.GetFullPath()); // Relative paths const wxString sourceDirEsc = sourceDir.GetPath(wxPATH_NO_SEPARATOR, wxPATH_UNIX); const wxString buildDirEsc = buildDir.GetPath(wxPATH_NO_SEPARATOR, wxPATH_UNIX); // Generated makefile content << "CMAKE := \"" << cmake << "\"\n" "BUILD_DIR := " << buildDirEsc << "\n" "SOURCE_DIR := " << sourceDirEsc << "\n" "CMAKE_ARGS := " << CreateArguments(*settings, *m_configuration.get()) << "\n" "\n" "# Building project(s)\n" "$(or $(lastword $(MAKECMDGOALS)), all): $(BUILD_DIR)/Makefile\n" "\t$(MAKE) -C \"$(BUILD_DIR)\" $(MAKECMDGOALS)\n" "\n" "# Building directory\n" "$(BUILD_DIR):\n" "\t$(CMAKE) -E make_directory \"$(BUILD_DIR)\"\n" "\n" "# Rule that detects if cmake is called\n" "$(BUILD_DIR)/Makefile: .cmake_dirty | $(BUILD_DIR)\n" "\tcd \"$(BUILD_DIR)\" && $(CMAKE) $(CMAKE_ARGS) \"$(SOURCE_DIR)\"\n" "\n" "# This rule / file allows force cmake run\n" ".cmake_dirty:\n" "\t@echo '' > .cmake_dirty\n" "\n" ; } // Path to makefile - called project directory required wxFileName makefile = projectDir; makefile.SetName(project); makefile.SetExt("mk"); // Read old content from disk wxString oldContent; bool ok = ReadFileWithConversion(makefile.GetFullPath(), oldContent); // Write only if there are some changes if (!ok || content != oldContent) { // Write make file content wxFile file(makefile.GetFullPath(), wxFile::write); if (!file.Write(content)) { CL_ERROR("Unable to write custom makefile (CMakePlugin): " + makefile.GetFullPath()); } } }
void CallGraph::OnShowCallGraph(wxCommandEvent& event) { // myLog("wxThread::IsMain(%d)", (int)wxThread::IsMain()); IConfigTool* config_tool = m_mgr->GetConfigTool(); MacroManager* macro = MacroManager::Instance(); wxASSERT(macro); config_tool->ReadObject(wxT("CallGraph"), &confData); if(!wxFileExists(GetGprofPath()) || !wxFileExists(GetDotPath())) return MessageBox(_T("Failed to locate required tools (gprof, dot). Please check the plugin settings."), wxICON_ERROR); clCxxWorkspace* ws = m_mgr->GetWorkspace(); if(!ws) return MessageBox(_("Unable to get opened workspace."), wxICON_ERROR); wxFileName ws_cfn = ws->GetWorkspaceFileName(); wxString projectName = ws->GetActiveProjectName(); wxString errMsg; ProjectPtr proj = ws->FindProjectByName( projectName, errMsg ); wxString projPath = proj->GetProjectPath(); BuildMatrixPtr mtx = ws->GetBuildMatrix(); if(!mtx) return MessageBox(_("Unable to get current build matrix."), wxICON_ERROR); wxString build_config_name = mtx->GetSelectedConfigurationName(); BuildConfigPtr bldConf = ws->GetProjBuildConf(projectName, build_config_name); if(!bldConf) return MessageBox(_("Unable to get opened workspace."), wxICON_ERROR); wxString projOutputFn = macro->Expand( bldConf->GetOutputFileName(), m_mgr, projectName, build_config_name ); #ifdef __WXMSW__ if( ! projOutputFn.Lower().EndsWith( wxT(".exe") ) ) projOutputFn += wxT(".exe"); #endif //__WXMSW__ // myLog("WorkspaceFileName = \"%s\"", ws_cfn.GetFullPath()); // myLog("projectName \"%s\"", projectName); // myLog("build_config_name = \"%s\"", build_config_name); // myLog("projOutputFn = \"%s\"", projOutputFn); // myLog("projPath = \"%s\"", projPath); wxFileName cfn(projPath + wxFileName::GetPathSeparator() + projOutputFn); cfn.Normalize(); // base path const wxString base_path = ws_cfn.GetPath(); // check source binary exists wxString bin_fpath = cfn.GetFullPath(); if(!cfn.Exists()) { bin_fpath = wxFileSelector("Please select the binary to analyze", base_path, "", ""); if(bin_fpath.IsEmpty()) return MessageBox("selected binary was canceled", wxICON_ERROR); cfn.Assign(bin_fpath, wxPATH_NATIVE); } if(!cfn.IsFileExecutable()) return MessageBox("bin/exe isn't executable", wxICON_ERROR); // check 'gmon.out' file exists wxFileName gmon_cfn( cfn.GetPath() + wxFileName::GetPathSeparator() + GMON_FILENAME_OUT); gmon_cfn.Normalize(); wxString gmonfn = gmon_cfn.GetFullPath(); if(!gmon_cfn.Exists()) { gmonfn = wxFileSelector("Please select the gprof file", gmon_cfn.GetPath(), "gmon", "out"); if(gmonfn.IsEmpty()) return MessageBox("selected gprof was canceled", wxICON_ERROR); gmon_cfn.Assign(gmonfn, wxPATH_NATIVE); } wxString bin, arg1, arg2; bin = GetGprofPath(); arg1 = bin_fpath; arg2 = gmonfn; wxString cmdgprof = wxString::Format("%s %s %s", bin, arg1, arg2); // myLog("about to wxExecute(\"%s\")", cmdgprof); wxProcess* proc = new wxProcess(wxPROCESS_REDIRECT); // wxStopWatch sw; const int err = ::wxExecute(cmdgprof, wxEXEC_SYNC, proc); // on sync returns 0 (success), -1 (failure / "couldn't be started") // myLog("wxExecute() returned err %d, had pid %d", err, (int)proc->GetPid()); wxInputStream* process_is = proc->GetInputStream(); if(!process_is || !process_is->CanRead()) return MessageBox(_("wxProcess::GetInputStream() can't be opened, aborting"), wxICON_ERROR); // start parsing and writing to dot language file GprofParser pgp; pgp.GprofParserStream(process_is); // myLog("gprof done (read %d lines)", (int) pgp.lines.GetCount()); delete proc; ConfCallGraph conf; config_tool->ReadObject(wxT("CallGraph"), &conf); DotWriter dotWriter; // DotWriter dotWriter.SetLineParser(&(pgp.lines)); int suggestedThreshold = pgp.GetSuggestedNodeThreshold(); if(suggestedThreshold <= conf.GetTresholdNode()) { suggestedThreshold = conf.GetTresholdNode(); dotWriter.SetDotWriterFromDialogSettings(m_mgr); } else { dotWriter.SetDotWriterFromDetails(conf.GetColorsNode(), conf.GetColorsEdge(), suggestedThreshold, conf.GetTresholdEdge(), conf.GetHideParams(), conf.GetStripParams(), conf.GetHideNamespaces()); wxString suggest_msg = wxString::Format(_("The CallGraph plugin has suggested node threshold %d to speed-up " "the call graph creation. You can alter it on the call graph panel."), suggestedThreshold); MessageBox(suggest_msg, wxICON_INFORMATION); } dotWriter.WriteToDotLanguage(); // build output dir cfn.Assign(base_path, ""); cfn.AppendDir(CALLGRAPH_DIR); cfn.Normalize(); if(!cfn.DirExists()) cfn.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); cfn.SetFullName(DOT_FILENAME_TXT); wxString dot_fn = cfn.GetFullPath(); dotWriter.SendToDotAppOutputDirectory(dot_fn); cfn.SetFullName(DOT_FILENAME_PNG); wxString output_png_fn = cfn.GetFullPath(); // delete any existing PNG if(wxFileExists(output_png_fn)) wxRemoveFile(output_png_fn); wxString cmddot_ln; cmddot_ln << GetDotPath() << " -Tpng -o" << output_png_fn << " " << dot_fn; // myLog("wxExecute(\"%s\")", cmddot_ln); wxExecute(cmddot_ln, wxEXEC_SYNC | wxEXEC_HIDE_CONSOLE); // myLog("dot done"); if(!wxFileExists(output_png_fn)) return MessageBox(_("Failed to open file CallGraph.png. Please check the project settings, rebuild the project " "and try again."), wxICON_INFORMATION); // show image and create table in the editor tab page uicallgraphpanel* panel = new uicallgraphpanel( m_mgr->GetEditorPaneNotebook(), m_mgr, output_png_fn, base_path, suggestedThreshold, &(pgp.lines)); wxString tstamp = wxDateTime::Now().Format(wxT(" %Y-%m-%d %H:%M:%S")); wxString title = wxT("Call graph for \"") + output_png_fn + wxT("\" " + tstamp); m_mgr->AddEditorPage(panel, title); }