doxygen 使用简介(C,C++为代码作注释)

来自:http://www.cnblogs.com/wishma/archive/2008/07/24/1250339.html

doxygen注释块

doxygen注释块其实就是在C”C++注释块的基础添加一些额外标识, 使doxygen把它识别出来, 并将它组织到生成的文档中去。

在每个代码项中都可以有两类描述, 这两类描述将在文档中格式化在一起: 一种就是brief描述, 另一种就是detailed。 两种都是可选的,但不能同时没有。

顾名思义, 简述(brief)就是在一行内简述地描述。而详细描述(detailed description)则提供更长, 更详细的文档。

在doxygen中, 有多种方法将注释块标识成详细描述:

  1. 你可以使用JavaDoc风格,即在C风格注释块开始使用两个星号’*’, 就像这样:
  2. /**
  3.  * … 描述 …
  4.  */
  5. 或者你使用Qt风格代码注释,即在C风格注释块开始处添加一个叹号’!’:
  6. /*!
  7.  * … 描述 …
  8.  */

注释块中间的星号是可选, 所以将注释块写成:

/*!

… 描述 …

*/

同样也是有效的.

  1. 第三种方法就是使用连续两个以上C++注释行所组成的注释块,而每个注释行开始处要多写一个斜杠或写一个叹号。像下行这样:
  2. ///
  3. /// … 描述 …
  4. ///

或者

//!

//!… 描述 …

//!

  1. 一些人喜欢使他们的注释块在文档中显得更为显目,所以你也可以这么做:
  2. /////////////////////////////////////////////////
  3. /// … 描述 …
  4. /////////////////////////////////////////////////

简述同样也可以同种写法:

  1. 一种是在一个doxygen注释块中使用“brief . 这个命令只对当前一个文字段有效, 所以详细描述应该与之间隔一个空行.

像这样:

/*! “brief 这里是简要描述.

*         这里仍然是简要描述.

*

* 详细描述从这里开始.

*/

  1. 如果在doxygen配置文件将JAVADOC_AUTOBRIEF设置成YES。则JavaDoc风格将注释块中的第一个句子视为简要描述, 这个句子可以以句号’.’、空格或者空行来结束:
  2. /** 这里是简述, 并由句号结束. 详细描述从这里
  3.  * 开始.
  4.  */

这个功能同样多行C++行注释段中有效:

/// 这里是简述, 并由句号结束. 详细描述从这里

/// 开始..

  1. 第三种方法就是详细描述注释段紧跟在一行C++注释段后面,至多隔一个空行, 如下面两个例子:
  2. /// 简述.
  3. /** 详细描述. */

或者

//! 简述.

 

//! 详细描述

//! 从这里开始.

注意最后一个例子, 例子那个空行是用来分隔简述注释段和详细描述段的, 不能去掉.而且JAVADOC_AUTOBRIEF不应该被设置成YES.

看上去doxygen是相当富有弹性, 但下面的例子是非法的:

//! 这个简述因为是多行的

//! 会被认为是详细描述..

/*! 而这里则是另外的详细描述.

*/

因为doxygen只允许一个简要和一个详细描述。

此外, 如果在一个代码项的声明之前有简要描述而且在其定义之前也有简要描述, 那么doxygen只使用声明之前的描述。而如果详细描述出现了同样的情况, doxygen则会使用定义之前的描述, 另外的描述会被忽略掉。

这里有一个使用Qt风格的C++代码:

//! A test class.

/*!

A more elaborate class description.

*/

 

class Test

{

public:

 

//! An enum.

/*! More detailed enum description. */

enum TEnum {

TVal1, /*!< Enum value TVal1. */

TVal2, /*!< Enum value TVal2. */

TVal3 /*!< Enum value TVal3. */

}

//! Enum pointer.

/*! Details. */

*enumPtr,

//! Enum variable.

/*! Details. */

enumVar;

 

//! A constructor.

/*!

A more elaborate description of the constructor.

*/

Test();

 

//! A destructor.

/*!

A more elaborate description of the destructor.

*/

~Test();

 

//! A normal member taking two arguments and returning an integer value.

/*!

“param a an integer argument.

“param s a constant character pointer.

“return The test results

“sa Test(), ~Test(), testMeToo() and publicVar()

*/

int testMe(int a,const char *s);

 

//! A pure virtual member.

/*!

“sa testMe()

“param c1 the first argument.

“param c2 the second argument.

*/

virtual void testMeToo(char c1,char c2) = 0;

 

//! A public variable.

/*!

Details.

*/

int publicVar;

 

//! A function variable.

/*!

Details.

*/

int (*handler)(int a,int b);

};

 

点击这里查看doxygen产生的HTML文档.

只有一行的注释段包含的是简述, 而多行的注释段则包含的是详细描述.

简要描述可以被用来进行class、namespace或者文件的成员描述, 被以较小的斜体字型显示出来。(这种描述可以通过将BRIEF_MEMBER_DESC设置成NO来隐藏。)默认情况下,简要描述会被显示成详细描述的第一个句子。(这同样可以通过将REPEAT_BRIEF设置成NO来屏蔽。)在Qt风格中, 两种描述都是可选的。

默认情况下, JavaDoc风格的注释段和Qt风格的注释段的行为是相同的。但这样, 就不符合JavaDoc标准, 注释段的第一个句应该自动识别为简要描述。你应该设置JAVADOC_AUTOBRIEFyly YES, 来启用这个功能。如果你设置了这个选项并想在句子中间放置一个句号, 你应该在后面添加一个反斜杠和一个空格. 就像下面的例子一样:

/** Brief description (e.g.” using only a few words). Details follow. */

Here is the same piece of code as shown above, this time documented using the JavaDoc style and JAVADOC_AUTOBRIEF set to YES:

/**

* A test class. A more elaborate class description.

*/

 

class Test

{

public:

 

/**

* An enum.

* More detailed enum description.

*/

 

enum TEnum {

TVal1, /**< enum value TVal1. */

TVal2, /**< enum value TVal2. */

TVal3 /**< enum value TVal3. */

}

*enumPtr, /**< enum pointer. Details. */

enumVar; /**< enum variable. Details. */

 

/**

* A constructor.

* A more elaborate description of the constructor.

*/

Test();

 

/**

* A destructor.

* A more elaborate description of the destructor.

*/

~Test();

 

/**

* a normal member taking two arguments and returning an integer value.

* @param a an integer argument.

* @param s a constant character pointer.

* @see Test()

* @see ~Test()

* @see testMeToo()

* @see publicVar()

* @return The test results

*/

int testMe(int a,const char *s);

 

/**

* A pure virtual member.

* @see testMe()

* @param c1 the first argument.

* @param c2 the second argument.

*/

virtual void testMeToo(char c1,char c2) = 0;

 

/**

* a public variable.

* Details.

*/

int publicVar;

 

/**

* a function variable.

* Details.

*/

int (*handler)(int a,int b);

};

 

点击这里查看doxygen产生的HTML文档.

不像其它的文档系统 , doxygen允许在代码项的定义之前面放置成员(包括全局函数)的注释。这种方法可以在源文件中进行文档注释工作。这就是使得头文件可以比较简洁, 使代码的实现人员更容易阅读。比较折中的方案就是在声明的地方添加简要描述, 在实现的地方添加详细描述。

在成员后面放置文档

如果你想对文件、结构体、联合体、类或者枚举的成员进行文档注释的话, 并且要在成员中间添加注释, 而这些注释往往都是在每个成员后面。为此, 你可以使用在注释段中使用'<‘标识

Here are some examples:

int var; /*!< Detailed description after the member */

This block can be used to put a Qt style detailed documentation block after a member. Other ways to do the same are:

int var; /**< Detailed description after the member */

或者

int var; //!< Detailed description after the member

//!

或者

int var; ///< Detailed description after the member

///

Most often one only wants to put a brief description after a member. This is done as follows:

int var; //!< Brief description after the member

或者

int var; ///< Brief description after the member

Note that these blocks have the same structure and meaning as the special comment blocks in the previous section only the < indicates that the member is located in front of the block instead of after the block.

Here is an example of the use of these comment blocks:

/*! A test class */

 

class Test

{

public:

/** An enum type.

* The documentation block cannot be put after the enum!

*/

enum EnumType

{

int EVal1,     /**< enum value 1 */

int EVal2      /**< enum value 2 */

};

void member();   //!< a member function.

 

protected:

int value;       /*!< an integer value */

};

点击这里查看doxygen产生的HTML文档.

警告:

这种注释方法只能在成员参数中使用。它们不能用在描述文件、类、联合体、名字空间和枚举本身。此外, 在下一节提到的结构化命令(如”class)在这种注释段中是无效的。

在其它地方进行注释

虽然我们一般是在声明和定义的前面添加文档注释块, 但也许出于某种情况需要将文档放在其它什么位置上。比如我们需要编写一段实际上不存在的文件的描述。因此, Doxygen允许将文档放置在任何位置。(除了在函数体内或在一个普通的注释段)

为了达到这种目的, 你唯一要做的就是在注释段中使用结构化命令。

结构化命令(就像其它命令)由一个反斜杠(“), 或 JavaDoc风格中使用的@来做开头, 后面紧跟着命令名字和一些参数。例如, 你想注释一个名为Test的类,如下例:

/*! “class Test

“brief A test class.

 

A more detailed class description.

*/

命令”class被用来指示代码段中包含着关于Test类的文档.其它的结构化命令有:

  • “struct生成C结构的文档.
  • “union生成联合体的文档.
  • “enum生成枚举的文档.
  • “fn生成函数的文档.
  • “var生成变量或typedef或枚举值的文档.
  • “def生成#define定义的文档.
  • “file生成关于一个文件的文档.
  • “namespace生成名字空间的文档.
  • “package生成Java包的文档.
  • “interface生成IDL接口的文档.

参看特殊命令得到更多关于这些命令或其它命令的详细信息.

对C++类的成员进行文档注释时, 必须对类本身进行文档注释。这同样对名字空间有效。要对全局函数、typedef、枚举或宏定义进行文档注释, 则必须先对包含它们的文件进行文档(这通常是头文件).

再重复一下, 因为它经常被忘记: 如果要对全局项目(如:函数、typedefs、枚举或宏等), 你必须必须对定义它们的文件进行文档注释。换一句话, 你至少在文件写下

/*! “file */

/** @file */

这样的注释.

下面是一个名为structcmd.h头文件的例子, 里面包含了使用结构化命令的例子:

/*! “file structcmd.h

“brief A Documented file.

 

Details.

*/

 

/*! “def MAX(a,b)

“brief A macro that returns the maximum of “a a and “a b.

 

Details.

*/

 

/*! “var typedef unsigned int UINT32

“brief A type definition for a .

 

Details.

*/

 

/*! “var int errno

“brief Contains the last error code.

 

“warning Not thread safe!

*/

 

/*! “fn int open(const char *pathname,int flags)

“brief Opens a file descriptor.

 

“param pathname The name of the descriptor.

“param flags Opening flags.

*/

 

/*! “fn int close(int fd)

“brief Closes the file descriptor “a fd.

“param fd The descriptor to close.

*/

 

/*! “fn size_t write(int fd,const char *buf, size_t count)

“brief Writes “a count bytes from “a buf to the filedescriptor “a fd.

“param fd The descriptor to write to.

“param buf The data buffer to write.

“param count The number of bytes to write.

*/

 

/*! “fn int read(int fd,char *buf,size_t count)

“brief Read bytes from a file descriptor.

“param fd The descriptor to read from.

“param buf The buffer to read into.

“param count The number of bytes to read.

*/

 

#define MAX(a,b) (((a)>(b))?(a):(b))

typedef unsigned int UINT32;

int errno;

int open(const char *,int);

int close(int);

size_t write(int,const char *, size_t);

int read(int,char *,size_t);

点击这里查看doxygen产生的HTML文档.

因为例子中的每个注释都包含了结构化命令, 所以所有的注释块都可以移动到其它的地方, 而不会对生成的文档产生影响。这种方法的坏处是当原型发生了改变 , 你不得不改变结构化命令的参数。因此, 在使用它们之前, 应该认真考虑一下是否真正需要使用它们。

 

Doxygen – Generate documentation from source code

Refer to http://www.stack.nl/~dimitri/doxygen/

Doxygen is the de facto standard tool for generating documentation from annotated C++ sources, but it also supports other popular programming languages such as C, Objective-C, C#, PHP, Java, Python, IDL (Corba, Microsoft, and UNO/OpenOffice flavors), Fortran, VHDL, Tcl, and to some extent D.

Doxygen can help you in three ways:

  1. It can generate an on-line documentation browser (in HTML) and/or an off-line reference manual (in $\mbox{\LaTeX}$) from a set of documented source files. There is also support for generating output in RTF (MS-Word), PostScript, hyperlinked PDF, compressed HTML, and Unix man pages. The documentation is extracted directly from the sources, which makes it much easier to keep the documentation consistent with the source code.
  2. You can configure doxygen to extract the code structure from undocumented source files. This is very useful to quickly find your way in large source distributions. Doxygen can also visualize the relations between the various elements by means of include dependency graphs, inheritance diagrams, and collaboration diagrams, which are all generated automatically.
  3. You can also use doxygen for creating normal documentation (as I did for the doxygen user manual and web-site).

Doxygen is developed under Mac OS X and Linux, but is set-up to be highly portable. As a result, it runs on most other Unix flavors as well. Furthermore, executables for Windows are available.

visual studio里的几个输出的设置及一些文件的作用

来源:
http://tdcqljhwy.blog.163.com/blog/static/1716847812013858579593/

首先是 OutPut Directory ,它的值不会直接影响到你文件的输出,但它会间接的影响其他输出,比方说默认值中包含有$(OutDir).

Intermediate Directory ,中间目录,生成的obj文件,预编译头,预编译相关的idb及pdb,buildlog都会在这里.

idb 是系统生的成的状态信息,可以加速随后的编译

pdb 包含调试信息

Linker->General->OutPut File,输出文件,虽然填的是exe的路径,但.ilk文件会按这个路径输出.

Linker->Debugging->Genrerate Program Database File,输出的pdb文件

Linker->Advanced->Import Library 指示了将随同dll生成的lib文件输出的文件名和路径

DSW:全称是Developer   Studio   Workspace,最高级别的配置文件,记录了整个工作空间的配置信息,她是一个纯文本的文件,在vc创建新项目的时候自动生成
DSP:全称是Developer   Studio   Project,也是一个配置文件,不过她记录的是一个项目的所有配置信息,纯文本文件
OPT:与DSW、DSP配合使用的配置文件,她记录了与机器硬件有关的信息,同一个项目在不同的机器上的opt文件内容是不同的
CLW:记录了跟ClassWizard相关的信息,如果丢失了clw文件,那么在Class   View面板里就没有类信息
PLG:实际上是一个超文本文件,可以用Internet   Explorer打开,记录了Build的过程,是一个日志型文件
RC:资源描述文件,记录了所有的资源信息,在资源编辑器里作的修改,实际上都是对RC文件的修改
RC2:附加的资源描述文件,不能直接资源编辑器修改,只能手工添加,可以用来添加额外的资源
RES:经过资源编辑器编译之后的资源文件,以二进制方式存放
SBR:编译器生成的浏览信息文件,在代码导航的时候非常有用,她需要在编译时指定/FR或者/Fr开关
BSC:BSCMAKE.EXE将所有的SBR文件作为输入,经过处理之后输出一个BSC文件,在代码导航的时候实际用到的是BSC文件
ILK:当选定渐增型编译连接时,连接器自动生成ILK文件,记录连接信息
PDB:全称是Program   DataBase,即程序数据库文件,用来记录调试信息,是一个相当重要的文件,没有他,程序无法正常调试
LIB:如果项目输出是Dll的话,一般会输出一个跟项目同名的Lib文件,记录输出的函数信息
EXP:同Lib,是跟Dll一起生成的输出文件
PCH:全称是PreCompiled   Header,就是预先编译好的头文件,在编译时指定/Yu开关时编译器自动生成

关于,ilk文件及渐增式编译连接

:       VS2005编译时出现这样的错误:
: Compiling…
: Image.cpp
: Linking…
: LINK : warning LNK4076: invalid incremental status file “Debug/code.ilk”;
:             linking nonincrementally
: code.exe – 0 error(s), 1 warning(s)

原因:

VC编译时可以选择incremental linking(渐增式编译),也就是每次重新编译并不编译
所有的源文件,只编译改动过的文件。而编译器怎么知道哪些编译过哪些每编译过呢,
除了检查修改时间外,这个ilk文件也是很重要的信息。
如果你因为误操作或者VC自己的BUG引起了ilk文件的损坏,下一次编译时当然无法根据
ilk进行incremental linking了。但是在这种情况下也没什么大问题,VC自己会解决的,
所以也只出了一个警告。

解决办法:

把Dubug目录下.ilk文件强行删掉再重新编译一次就行了。

CMake编译项目集成Gcov/Lcov代码覆盖率测试

来源:http://blog.csdn.net/lostaway/article/details/40948841

原文链接:http://blog.yeyuzhen.cn/?p=203

脑补链接:什么是CMake? 什么是代码覆盖率测试? 什么是 Gcov?

最近不怎么顺利的面试经历,让我觉得自己其实是一个2B程序员。应该是懒的原因,涉及到某技术的实现原理啥的,就觉得很烦人。能用就好,何必执着?所以,一个技术问题下来,都是“晚节不保”。自己更关心的是诸如“如何细粒度化任务,以提高开发效率?”、“如何实践代码覆盖率测试,提高程序的鲁棒性?”这类问题。唉~貌似逼格(项目经理)和现实(程序员)存在不小的差距。

日常开发中,我就很注重测试的环节——功能测试、性能测试。我常和组员说,“代码写的不好可以慢慢学,但是测试一定要用心,程序是一点点测出来的”,“能测出来的问题,不算Bug”。但是经过长期的“感性”测试,不免问自己,“测这些用例就OK了?”、“这块代码有没有问题?”、“测试要如何度量?”。后来了解到“代码覆盖率测试”这么个好东西,可以初步解决测试度量的问题。

完整演示项目Github地址:CMakeGcovSupport

[plain] view plain copy

  1. 初始项目目录结构:
  2. CMakeGcovSupport
  3. ├── CMakeLists.txt
  4. ├── bin
  5. ├── build
  6. ├── include
  7. │   └── name.h
  8. ├── libgreeting
  9. │   ├── CMakeLists.txt
  10. │   ├── include
  11. │   │   └── greeting.h
  12. │   └── src
  13. │       ├── CMakeLists.txt
  14. │       ├── greeting.cpp
  15. │       └── yelp.cpp
  16. └── src
  17.     ├── CMakeGcovSupport.cpp
  18.     ├── CMakeLists.txt
  19.     └── name.cpp

示例程序是个很简单的输出一行问候语的程序。为了演示复杂目录结构下CMake集成Gcov的方法,故意将输出问候语的函数单独放到了 libgreeting 静态库中。执行如下编译命令:

$ cd CMakeGcovSupport
$ mkdir build
$ cd build
$ cmake -DENABLE_COVERAGE=ON ..
$ gmake all

执行 CMake 外部编译之后,CMake 在 build 目录内为我们生成了 .gcno 文件:

[plain] view plain copy

  1. CMakeGcovSupport
  2. ├── CMakeLists.txt
  3. ├── bin
  4. │   └── CMakeGcovSupport
  5. ├── build
  6. │   ├── ……
  7. │   ├── libgreeting
  8. │   │   ├── ……
  9. │   │   └── src
  10. │   │       ├── CMakeFiles
  11. │   │       │   ├── ……
  12. │   │       │   ├── greeting.dir
  13. │   │       │   │   ├── ……
  14. │   │       │   │   ├── greeting.cpp.gcno
  15. │   │       │   │   ├── greeting.cpp.o
  16. │   │       │   │   ├── ……
  17. │   │       │   │   ├── yelp.cpp.gcno
  18. │   │       │   │   └── yelp.cpp.o
  19. │   │       │   └── ……
  20. │   │       └── ……
  21. │   └── src
  22. │       ├── CMakeFiles
  23. │       │   ├── ……
  24. │       │   ├── CMakeGcovSupport.dir
  25. │       │   │   ├── CMakeGcovSupport.cpp.gcno
  26. │       │   │   ├── CMakeGcovSupport.cpp.o
  27. │       │   │   ├── ……
  28. │       │   │   ├── name.cpp.gcno
  29. │       │   │   ├── name.cpp.o
  30. │       │   │   └── ……
  31. │       │   └── progress.marks
  32. │       └── ……
  33. ├── include
  34. ├── libgreeting
  35. └── src

为了避免接下来执行程序过程中,未覆盖的源码文件的覆盖率信息丢失,我们需要对覆盖率信息进行初始化操作:

$ cd CMakeGcovSupport
$ lcov -d build -z
$ lcov -d build -b . --no-external --initial -c -o CMakeGcovSupportInitialCoverage.info

然后我们执行 bin 中的 CMakeGcovSupport, main() 函数中将会调用 Greeting() 和 Name()  函数,而不会调用到 Yelp() 函数。

$ cd CMakeGcovSupport
$ cd bin
$ ./CMakeGcovSupport
$ Hello, gcov.

这时,我们去 .gcno 所在目录,会看到有同名的 .gcda 覆盖率数据文件生成了。执行以下命令,生成覆盖率测试报告:

$ cd CMakeGcovSupport
$ lcov -d build -b . --no-external -c -o CMakeGcovSupportCoverage.info
$ genhtml -o CMakeGcovSupportCoverageReport --prefix=`pwd` CMakeGcovSupportInitialCoverage.info CMakeGcovSupportCoverage.info

用浏览器打开 CMakeGcovSupportCoverageReport 目录中的 index.html 查看覆盖率报告(Mac + Lcov1.10):

Linux + Lcov1.11覆盖率结果(不会误包含外部头文件覆盖率信息):

以上就是CMake项目初步集成 Gcov/Lcov 的方式。但是,还未深度集成到 CMake 编译过程中,而且覆盖率报告还存在一些瑕疵。下一步计划解决应用“–no-external”选项之后依旧会包含外部头文件覆盖率信息的问题,以及不显示头文件覆盖率信息的问题。最终深度集成 CMake 的效果希望是自定义如下命令:

$ gmake InitialCoverage   # 初始化覆盖率信息命令
$ gmake ReportCoverage  # 生成覆盖率测试报告命令

 

参考

[1] 测试覆盖(率)到底有什么用?

[2] Linux 下 C/C++ 项目代码覆盖率的产生方法

[3] User Manuals – lcov

[4] gcov lcov 覆盖 c/c++ 项目入门

[5] 使用gcov,lcov,genhtml进行代码覆盖率测试

[6] 关于C++ code coverage tool 的研究(1)

[7] 关于C++ code coverage tool 的研究(2)—GCOV 实现原理

[8] 关于C++ code coverage tool 的研究(3)—gcov使用实例

[9] CMake添加gcov代码覆盖测试支持

[10] Linux平台代码覆盖率测试工具GCOV简介

编辑历史:

V1.1,增加 Linux + Lcov1.11 下覆盖率报告截图,@2014-11-09

V1.0,初稿,@2014-11-08

gcov、lcov与genhtml 使用心得

来源: http://blog.sina.com.cn/s/blog_7e4ac8b501018b27.html

gcc是linux平台下的C、C++ 编译器

gcov是配合gcc产生覆盖信息报告的工具;

lcov是将gcov产生的报告信息,以更直观的方式显示出来工具

基本的使用方法分为4个阶段:

(一)、gcc编译:产生插装后的目标文件test、gcov结点文件 test.gcno

  #gcc –fprofile-arcsftest-coverage -o test test.c

  # ls

  test   test.c   test.gcno

  说明:参数 fprofile-arcsftest-coverage 告诉gcc编译器:(1)在目标文件test 插装跟踪代码;(2)生成供gcov使用 test.gcno [gcov node 文件]。

        因此,这里的生成的目标文件比正常编译的文件大。

(二)、运行目标文件:收集运行覆盖信息 test.gcda

   # ./test

     Success  — 这里是运行结果。

   # ls

     test test.c test.gcno test.gcda

  这里test.gcda运行结果,

(三)、gcov产生报告信息: test.c.gcov

  #gcov  test.c

    File ‘test.c’

    Lines executed: 87.50% of 8

    test.c: creating ‘test.c.gcov’

 #ls

    test test.c test.c.gcov test.gcda test.gcno

(四)、lcov:格式化test.c.gcov ,输出到 test.info文件

  #lcov -d . -t ‘test’ -o ‘test.info’ -b . -c

  说明:

       -d  . :参数 d指路径, “.” 指当前路径

       -t  “name” :指目标文件,这里 是 test

       -o  “filename” :输出格式化后的信息文件名

(五)、genhtml:根据信息文件(.info)产生html 文档,输出到一个文件夹中

   #genhtml -o result test.info

  说明: -o  directory :参数o (output)后面跟路径名称,在当前目录下创建指定目录,本例中是result

 

至此: 可以在result目录中打开index.html 浏览覆盖信息