将日志插入项目中的每个函数的脚本?
我已经继承了一个相当大的代码库,90%的C++,我需要赶紧加快速度。在宽目录树结构中有数百个.cc文件。将日志插入项目中的每个函数的脚本?
它相当复杂,并没有日志。为了弄清楚一些主要的子系统是如何工作的,我想在每个函数中插入一个函数调用。
例如,给定一个.cc文件充满了这样的东西:
void A::foo(int a, int b) {
// ...
}
void A::bar() {
// ...
}
void B::bleh(const string& in) {
// ...
}
我希望得到这样的:
void A::foo(int a, int b) {
LOG(debug) << "A::foo() called.";
// ...
}
void A::bar() {
LOG(debug) << "A::bar() called.";
// ...
}
void B::bleh(const string& in) {
LOG(debug) << "B::bleh() called.";
// ...
}
这可以通过Python脚本来完成,CMD脚本,电源外壳脚本等。如果有办法让VS做到这一点,那就太好了。无论什么作品。不一定要漂亮,我不检查任何这个。
此外,它不一定需要得到一切。例如。嵌套类,头文件中的实现等。
已经为增加使用VS宏分析代码类似的东西,这里的代码
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Public Module Module1
Function GetOutputWindowPane(ByVal Name As String, Optional ByVal show As Boolean = True) As OutputWindowPane
Dim window As Window
Dim outputWindow As OutputWindow
Dim outputWindowPane As OutputWindowPane
window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
If show Then window.Visible = True
outputWindow = window.Object
Try
outputWindowPane = outputWindow.OutputWindowPanes.Item(Name)
Catch e As System.Exception
outputWindowPane = outputWindow.OutputWindowPanes.Add(Name)
End Try
outputWindowPane.Activate()
Return outputWindowPane
End Function
Const ToInsert As String = "/* Inserted text :D */"
Sub AddProfilingToFunction(ByVal func As CodeFunction2)
Dim editPoint As EditPoint2 = func.StartPoint.CreateEditPoint()
While editPoint.GetText(1) <> "{"
editPoint.CharRight()
End While
editPoint.CharRight()
editPoint.InsertNewLine(1)
Dim insertStartLine As Integer = editPoint.Line
Dim insertStartChar As Integer = editPoint.LineCharOffset
editPoint.Insert(ToInsert)
GetOutputWindowPane("Macro Inserted Code").OutputString(_
editPoint.Parent.Parent.FullName & _
"(" & insertStartLine & "," & insertStartChar & _
") : Inserted Code """ & ToInsert & """" & vbCrLf)
End Sub
Sub AddProfilingToProject(ByVal proj As Project)
If Not proj.CodeModel() Is Nothing Then
Dim EventTitle As String = "Add Profiling to project '" & proj.Name & "'"
GetOutputWindowPane("Macro Inserted Code").OutputString("Add Profiling to project '" & proj.Name & "'" & vbCrLf)
DTE.UndoContext.Open(EventTitle)
Try
Dim allNames As String = ""
For i As Integer = 1 To proj.CodeModel().CodeElements.Count()
If proj.CodeModel().CodeElements.Item(i).Kind = vsCMElement.vsCMElementFunction Then
AddProfilingToFunction(proj.CodeModel().CodeElements.Item(i))
End If
Next
Finally
DTE.UndoContext.Close()
End Try
GetOutputWindowPane("Macro Inserted Code").OutputString(vbCrLf)
End If
End Sub
Sub AddProfilingToSolution()
GetOutputWindowPane("Macro Inserted Code").Clear()
If Not DTE.Solution Is Nothing And DTE.Solution.IsOpen() Then
For i As Integer = 1 To DTE.Solution.Projects.Count()
AddProfilingToProject(DTE.Solution.Projects.Item(i))
Next
End If
End Sub
End Module
(这也是集团在一个单一的“撤消”命令,并列出了所有在其自己的输出窗口中改变一切)
PS 记住更改“常量ToInsert的String = ...”你确实要插入
运行时分析器会给你提供这些信息:它会告诉你每个例程调用了哪些子例程,以及多少次(但不是按什么顺序) 。
是啊,我已经尝试了很多不同(免费)廓线仪,包括从一个代码微软。要么他们都吮吸,要么我太愚蠢,不知道如何使用它们。如果你有一个体面的工具的链接,以及一些关于如何获得上述信息的指示,我会非常乐意放弃。在这一点上,插入一些日志似乎更容易。 – 2009-09-18 03:26:01
我在年龄段没有使用过。我使用的(来自Numega)已经出售给Compuware,然后转售现在归“Micro Focus”所有:http://www.microfocus.com/products/DevPartner/StudioProfessionalEditionCapabilities.asp#6他们的网站说你可以下载它的试用版。 – ChrisW 2009-09-18 03:36:20
几年前我在VS做过。
正则表达式将帮助你。
顺便说一句,不要插入不同的字符串。您可以添加相同的字符串,如:
LOG(debug) << __FUNCTION__ << " called.";
编辑
这样的正则表达式(有效期仅为VS):
(void|char|int):b+:i\:\::i\([^(]*\):b*\{
您应该根据扩展您的需求正则表达式。
啊是的,__FUNCTION __...好点。你不会碰巧有一个体面的正则表达式,你会吗? – 2009-09-18 03:39:38
@jeffamaphone:我将正则表达式的示例添加到我的回答中 – Dmitriy 2009-09-18 03:46:32
如果所有的函数声明遵循一个简单的模式,但它不可能捕获大型复杂代码库中的所有函数,因为函数声明可能采用非常不寻常的形式(其中有些很难与其他类型的声明区分开来)。 – 2009-09-18 04:24:24
由于您使用的Visual C++,似乎你只需要调用的函数的名称,有可能进一步使用以下命令行来自动完成这个切换到cl.exe
:
-
/Gh
:启用_penter
函数调用 -
/GH
:启用_pexit
函数调用
基本上,提供这些开关意味着,编译器将自动只要任何函数开始或结束,就会向名为_penter()
和_pexit()
的函数注入调用。然后,您可以提供一个单独编译的模块来实现这两个函数,它们(a)调用一些辅助函数库(例如DbgHelp)来确定被调用函数的名称,或者(b)仅从栈中获取返回地址并打印它逐字地 - 之后,通过查看例如,写一个脚本来将这些地址转换成函数名称如果您将/link /MAP:mymapfile.txt
传递给cl.exe
,则生成链接器映射文件。
当然,你需要把你的_penter()
和_pexit()
放在一个单独的模块中,/Gh
和/GH
关闭以避免无限递归! :)
嘿,那可能很有趣。谢谢。 – 2009-09-18 04:55:33
您不需要用于prolog/epilog函数的单独模块。 '_penter()'和'_pexit()'定义如下:'extern“C”void __declspec(naked)_cdecl _penter(void)'。裸体功能没有检测到,所以没有递归机会。您不必担心子函数的递归,但可以使用线程局部变量检查来解决,以便在调用任何子项之前尽早在_penter()和_pexit()中解决。 – Adisak 2010-10-19 20:43:05
这是一个有趣的方法! +1。我敢打赌,VS IDE比一个手工构建的正则表达式更好地发现函数定义的开始。但假设“CodeModel”与IntelliSense使用的是相同的东西,在我的经验中,仍然会有一些情况依然窒息。 – 2009-09-18 06:02:56
这也很漂亮。我会给它一个镜头。 – 2009-09-18 16:19:49
有没有办法排除头文件(.h和.inl)?另外,也许排除模板? – 2009-09-18 17:34:13