文章目录
- 1. 目的和问题
- 2. 解决思路
- 2.1 `FILTER_PATTERNS` 选项
- 2.2 基于 Python 的 `FILTER_PATTERNS` 选项
- 2.3 sledcpp.py 脚本
- 3. 完整工程
- 3.1 目录结构
- 3.2 `hello.h` 文件内容
- 3.3 `CHANGELOG.md` 文件内容
- 3.4 `generate_doxyfile.py` 文件内容
- 3.5 `docs/root.md`
- 3.6 `docs/changelog.md`
- 3.7 运行整个工程
1. 目的和问题
项目代码的 changelog.md 有特殊用处和格式, 用它生成 doxygen 的 html 网页时, 内容不足, 需要添加额外内容; 这些额外内容直接放在 changelog.md 里会导致整个工程的编译、打包出错。
解决思路是另外写一个 docs/changelog.md 文件, 让它包含根目录的 changelog.md:
ChangeLog {#changelog}
====
This page lists change logs for each released version.<br/>
#include "../CHANGELOG.md"
其中 #include "../CHANGELOG.md"
意思是要用 C/C++ 编译器(其实是C预处理器),把内容替换过来。
原本的 changelog.md 内容为 :
预期结果如下,其中头部的 ChangeLog
标题和 This page lists chagne logs for each released version.
是增加的内容
在 Windows 上则是得到了非预期结果:
2. 解决思路
2.1 FILTER_PATTERNS
选项
容易在 StackOverflow 找到解决方案的大致方向: 在 Doxyfile 里配置 FILTER_PATTERNS
选项:
FILTER_PATTERNS = *.md="cpp -P "
这样的写法可以在 Linux / MacOSX 系统上生成预期结果, 但在 Windows 下没有 cpp 这个预处理命令使用。
其中 -P
意思是把替换后的内容输出到屏幕。
尝试过一些方法, 不过失败了, 报错内容是一个 doxygen 警告:
explicit link request to ‘include’ could not be resolved
简单罗列这些失败的方法:
- 直接用 VS2022 的 cl.exe 的路径
失败: 可能是路径有空格,也可能是 cl.exe 的 /P
参数不支持导致的。
- 找到了 mcpp 这个开源项目和它的魔改版本(https://github.com/zeroc-ice/mcpp)
失败: mcpp 的魔改版本不支持 -P
参数
- 封装 VS2022 的 cl.exe 为
cpp.cmd
脚本
失败: 和方法1 差不多。
2.2 基于 Python 的 FILTER_PATTERNS
选项
cross platform FILTER_PATTERNS in doxygen 这个问答中提示, 可以用 Python 脚本作为 FILTER_PATTERNS
的参数。于是可以自行实现一个替代 cpp
命令的 Python 脚本, 让它支持 #include "xxx"
替换为 xxx
文件的具体内容即可。
2.3 sledcpp.py 脚本
我实现的替代 cpp 命令的脚本名为 sledcpp.py, 内容如下
# sledcpp: a naive C Pre-Processor implementation
# Author: Zhuo Zhang <imzhuo#foxmail.com>
#
# Currently only support expanding `#include` directive once
# Used in generating doxygen webpages from markdown files which include another file
#
# Created: 2023-05-30 10:38:29
# Modified: 2023-05-30 10:38:48
import sys
import os
def getLinesOfTextFile(filepath):
lines = []
with open(filepath, encoding='utf-8') as fin:
for line in fin.readlines():
lines.append(line.strip())
return lines
def expand_file_once(filepath):
fileDir = os.path.dirname(filepath)
with open(filepath) as fin:
for line in fin.readlines():
line = line.strip()
if line.startswith('#include'):
startPos = len('#include')
depfile = line[startPos:].strip().split('"')[1]
deppath = os.path.join(fileDir, depfile)
deplines = getLinesOfTextFile(deppath)
for item in deplines:
print(item)
else:
print(line)
if __name__ == '__main__':
if len(sys.argv) != 2:
print('Usage: python {:s} filepath'.format(sys.argv[0]))
exit(1)
filepath = sys.argv[1]
expand_file_once(filepath)
3. 完整工程
3.1 目录结构
➜ b tree
.
├── CHANGELOG.md
├── docs
│ ├── changelog.md
│ └── root.md
├── Doxyfile
├── generate_doxyfile.py
├── hello.h
├── html
└── sledcpp.py
3.2 hello.h
文件内容
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void hello(const char* name);
#ifdef __cplusplus
}
#endif
3.3 CHANGELOG.md
文件内容
## 0.0.1
- [feat] Add `hello()`.
- [docs] Generate doxygen html website.
3.4 generate_doxyfile.py
文件内容
由于 Doxyfile 中需要配置 markdown 文件的绝对路径(尝试过相对路径,无法得到正确结果),而每个人电脑上的路径不一样, 这里提供 python 脚本 generate_doxyfile.py
来生成 Doxyfile
来解决路径问题。
此外还需要注意, 路径里不能带中文, 即使是 Linux 下也不能有中文。
generate_doxyfile.py
内容如下
import os
class CodeWriter(object):
def __init__(self, indent_len):
self.lines = []
self.indent_num = 0
self.indent_len = indent_len
def write(self, content):
padding = (self.indent_len * self.indent_num) * ' '
line = padding + content
self.lines.append(line)
def save(self, filename):
with open(filename, 'w') as fout:
for line in self.lines:
fout.write(line + "\n")
def tab(self):
self.indent_num += 1
def backspace(self):
if (self.indent_num > 0):
self.indent_num -= 1
def generate_doxyfile():
w = CodeWriter(8)
w.write('PROJECT_NAME = "x"')
w.write('GENERATE_TREEVIEW = YES')
w.write('GENERATE_HTML = YES')
w.write('GENERATE_LATEX = NO')
w.write('')
w.write('EXTRACT_ALL = YES')
w.write('EXTRACT_STATIC = YES')
w.write('')
w.write('INPUT = hello.h \\')
w.tab()
curDir = os.getcwd().replace('\\', '/')
line = '{:s}/docs/root.md \\'.format(curDir)
w.write(line)
line = '{:s}/docs/changelog.md'.format(curDir)
w.write(line)
w.backspace()
w.write('# cpp command, the C Pre Processor, works on Linux/MacOSX, but failed on Windows')
line = '# FILTER_PATTERNS = {:s}/docs/changelog.md="cpp -P "'.format(curDir)
w.write(line)
w.write('# Implement an alternative of cpp with Python wors for Windows, Linux and MacOSX')
line = 'FILTER_PATTERNS = {:s}/docs/changelog.md="python {:s}/sledcpp.py "'.format(curDir, curDir)
w.write(line)
w.save("Doxyfile")
if __name__ == '__main__':
generate_doxyfile()
例如我生成的 Doxyfile 内容为
PROJECT_NAME = "x"
GENERATE_TREEVIEW = YES
GENERATE_HTML = YES
GENERATE_LATEX = NO
EXTRACT_ALL = YES
EXTRACT_STATIC = YES
INPUT = hello.h \
D:/dbg/a/docs/root.md \
D:/dbg/a/docs/changelog.md
# cpp command, the C Pre Processor, works on Linux/MacOSX, but failed on Windows
# FILTER_PATTERNS = D:/dbg/a/docs/changelog.md="cpp -P "
# Implement an alternative of cpp with Python wors for Windows, Linux and MacOSX
FILTER_PATTERNS = D:/dbg/a/docs/changelog.md="python D:/dbg/a/sledcpp.py "
3.5 docs/root.md
是生成的网页的主页。
# MainPage
Hello, World!
3.6 docs/changelog.md
这个文件是关键文件。最关键一行是 #include "../CHANGELOG.md"
.
ChangeLog {#changelog}
====
This page lists change logs for each released version.<br/>
#include "../CHANGELOG.md"
3.7 运行整个工程
python generate_doxyfile.py
doxygen
cd html
python -m http.server 7080