如何在不使用IDE的情况下从cpp文件自动生成/更新头文件
How can I automatically generate / update header files from cpp files without using an IDE?
我已经使用VIM进行C++开发好几年了,我不想争论是使用IDE还是强大的文本编辑器进行软件开发。到目前为止,我主要涉及的是一个只包含标头的模板库,其中的所有内容要么是模板,要么是内联声明的,因此.cpp文件不起主要作用。
最近,我更多地参与了"传统"C++开发,面临着头文件/非头文件同步的老问题。我想知道是否有任何命令行工具可以用于make目标或集成到VIM中来处理此任务,即基于.cpp文件更新头文件。基本上,类/结构或(模板和内联)实现的声明应该在头文件中忽略,而函数声明应该基于.cpp文件添加、删除或更新。
然而,我知道lzz工具,它要求您实际使用额外的第三种文件格式进行编码,然后在实际编译之前将其预处理为.h/.cpp文件。
周围有什么能胜任这项工作的吗?其他非IDE开发人员如何处理这个问题?
由于我自己对你第一个问题的答案很好奇,不幸的是,我无法在这里给你任何好的建议。
至少给你一个第二个问题的答案:这是我在不同步的头文件中手动添加丢失或调整更改声明的半自动方法。
使用启用了警告的编译器(!)来发现丢失/更改的声明:
调整声明
更改函数定义的签名后,gcc
将抛出如下错误:
error: conflicting types for ‘....’
note: previous declaration of ‘....’ was here
修复这个问题相对容易,因为错误消息中已经给出了对定义的引用和相应的声明。
由于我是emacs
用户,我无法告诉您vi
中的操作方式,但我确信有一种同样简单的方法可以自动跳转到这些位置。所要做的就是:
-
跳转到位置一复制行
-
跳转到位置2,用副本替换旧行,并添加一个尾随的
;
缺少声明
如果在另一方面添加了一个新函数,而没有将其原型添加到相应的头文件gcc
中,则会抛出以下内容:
warning: implicit declaration of function ...
修复这个标签表就派上了用场。同样,我不确定在vi
中是如何处理的,但我很确定有一些方法可以快速跳转到编译器警告中由其名称给出的函数定义。
这里的工作流程如下:
-
跳转到函数….'s定义,复制行
-
切换到头文件,粘贴行并添加尾部
;
虽然这个方法一点也不优雅,但它适用于那些我忘记调整标题以使其与源文件同步的情况,只需几次按键即可完成。
一个破碎的例子
为了通过示例演示其应用,这里有一个需要修复其标头的minmal程序:
/* main.c */
#include "add.h"
int main (int argc, char *argv[]) {
int a=0, b=0;
add (a, b);
sub (a, b);
return 0;
}
函数add
和sub
都在add.c
中定义,如下所示:
/* add.c */
#include "add.h"
int add (int a, int b) {
return a + b;
}
int sub (int a, int b) {
return a - b;
}
罪魁祸首add.h
显示了函数add
的签名不匹配和函数sub
的丢失声明:
/* add.h */
long add (long a, long b);
尝试编译将导致:
gcc -Wall main.c add.c
main.c: In function ‘main’:
main.c:7: warning: implicit declaration of function ‘sub’
add.c:3: error: conflicting types for ‘add’
add.h:2: note: previous declaration of ‘add’ was here
修复示例
缺少声明
第一个问题:
main.c:7: warning: implicit declaration of function ‘sub’
是由于add.h
中缺少sub
的声明
寻找正确的签名:
- C-x`(下一个错误)将跳转到错误位置
- M-(gtags-find标记)将提示要查找的标记
- RET将跳转到
sub
的定义,因为点处的符号是默认值 - M-z{(zap to char)2-y
到目前为止,所有步骤都可以通过键盘宏自动完成,因为不需要干预。下一部分必须手工完成:
- 打开"正确"的头文件
- 并导航到应输入声明的位置
与目前采取的步骤相比,选择"正确"的头文件和"正确"位置很可能是一个品味问题,我认为这里不可能实现太多自动化。
最后一步是粘贴复制的签名:
- C-yM-y粘贴复制的签名
- DEL用
;
代替{
调整声明
接下来,必须修复add
的声明和定义之间的不匹配。
add.c:3: error: conflicting types for ‘add’
add.h:2: note: previous declaration of ‘add’ was here
从定义复制新签名:
- C-x`(下一个错误)将跳转到定义的位置
- M-z{(zap to char)2-y
替换声明:
- C-x`(下一个错误)将跳转到声明的位置
- M-z(zap-to-char)删除旧声明
- C-yM-y现在粘贴复制的签名
- DEL用
;
代替{
然后再次返回
由于弹出了两个缓冲区:
- M-2M-xburry缓冲区应返回之前访问的缓冲区
摘要
正如您所看到的,虽然不是一个太耗时的过程,但使用这种方法不断来回跳跃以修复丢失或错误的声明仍然是一项相当乏味的任务,我只使用它来修复我在第一次运行中键入错误或完全丢失的声明。
手动将"正确"的声明放入头中仍然是我采取的主要方法。
由于在实现之前部署API可能不是IMHO最糟糕的想法,因此该策略不应该是一个太糟糕的选择。
fossil
项目中有一个名为makeheaders
的程序(vcs替代git)。您可以很容易地从源代码中编译它。我还建议你读一下医生。
请注意,当您的头文件和源文件不在同一目录中时,它不会很好地工作,因为您不能为生成的头文件指定输出目录。
我已经将其分叉以实现,允许使用过于特定的工作流指定输出目录,但这是一项非常棘手的工作,我甚至不愿意将您重定向到它。使用风险自负:https://github.com/cassepipe/makeheaders
根据我的经验,在UNIX类型的系统上,IDE通常不处理这项工作。构建工具(通常不与Eclipse、Emacs等IDE捆绑在一起)将完成这项工作。
在现代系统中,最好的处理方法是让编译器来做:毕竟,编译器最清楚。GCC和大多数其他UNIX/POSIX编译器都有在编译源文件期间发出make样式依赖声明的选项。您只需在您的makefile中对此进行安排,然后将输出文件包含在您的makefile中,一切都非常好。
例如,请参见:http://make.mad-scientist.net/autodep.html
然后检查GCC选项,如-MMD -MP
(这些是预处理器选项)。
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 命名空间中具有.h和.cpp文件的类
- 为什么我的主文件.cpp不打印头文件中的任何内容
- 生成文件错误 - 找不到文件 - *.cpp
- 如何在文件.cpp gtkmm中声明小部件
- 没有实现文件(.cpp)的派生类
- 如何使用"CMakeLists.txt"中的add_library将整个文件(.cpp,.h等)包含在目录中
- 如何在Linux / Windows操作系统上使用文件*.cpp一步编译下面的代码
- 关于 Linux .so 文件无法链接到主文件.cpp文件
- 文件.cpp从Windows到Linux
- Ubuntu C++ 编译器错误: g++: 错误: 文件.cpp: 没有这样的文件或目录
- 如何将文件.cpp编译为本机编译
- 使用模板类时,似乎无法包含除 main 以外的任何 cpp 文件.cpp
- 无法编译C++文件.cpp。C++98模式
- 为什么C++头文件不需要包含实现文件 (.cpp)
- 如何访问位于独立文件(.cpp)中的非成员函数
- 如何在Visual Studio Code中通过键盘快捷键切换头文件/cpp文件
- 如何将数据从stringstream写入文件(CPP)
- 为什么filestream不把空白写入文件cpp ?