How can I automatically generate / update header files from cpp files without using an IDE?
Solution 1
As I myself am very curious about answers to your first question unfortunately I am not able to give you any good advice here.
To at least give you an answer to your second question: This is the somewhat semi-automatic way I use to manually add missing or adjust changed declarations in out of sync header files.
use the compiler with warnings enabled (!) to spot missing / changed declarations:
Adjust declarations
After changing the signature of a function definition gcc
will throw an error like the following one:
-
error: conflicting types for ‘....’
note: previous declaration of ‘....’ was here
Fixing this one is relatively easy as both a reference to the definition and the corresponding declaration are already given in the error message.
As I am an emacs
user I can't tell you the way this is done in vi
, but I am quite sure there is an equally simple way to automatically jump to this spots.
All that has to be done is:
jump to location one copy the line
jump to location two replace old line with the copy and add a trailing
;
Missing declarations
If on the other a new function was added without adding it's prototype to the corresponding header file gcc
will throw something like:
-
warning: implicit declaration of function ...
Fixing this one a tag table comes in handy. Again I don't know for sure how this is handled in vi
, but I am quite sure there is some way to quickly jump to the function definition given by its name in the compiler warning as well.
Workflow here looks like this:
jump to function ....'s definition, copy line
switch to header file, paste line and add a trailing
;
While this method is anything but elegant it has turned out to be working for those cases in which I forgot to adjust the header to keep it in sync with the source file, which can be done with a few keystrokes.
A broken Example
To demonstrate its application by example here a minmal program that needs it's headers to be fixed:
/* main.c */
#include "add.h"
int main (int argc, char *argv[]) {
int a=0, b=0;
add (a, b);
sub (a, b);
return 0;
}
Both functions add
and sub
are defined in add.c
shown below:
/* add.c */
#include "add.h"
int add (int a, int b) {
return a + b;
}
int sub (int a, int b) {
return a - b;
}
The culprit add.h
shows both a signature mismatch of the function add
and a missing declaration of the function sub
:
/* add.h */
long add (long a, long b);
Trying to compile will result in:
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
Fixing the example
Missing declarations
The first problem:
main.c:7: warning: implicit declaration of function ‘sub’
Is due to the fact that a declaration of sub
is missing in add.h
Finding the right signature:
- C-x` (next-error) will jump to the location of the error
- M-. (gtags-find-tag) will prompt for the tag to lookup
-
RET will jump to the definition of
sub
as the symbol at point is the default - M-z{ (zap-to-char) C-y (yank) to copy the signature
Up to here all steps could have also be done automatically by a keyboard macro as no intervention was needed. The next part will have to be done by hand:
- open the "correct" header file
- and navigate to the spot where the declaration should be entered
As the choice of "correct" header file and "correct" location most probably is a matter of taste in contrast to the steps taken so far I don't think there's much automation possible here.
Finally the last step is to paste the copied signature:
- C-yM-y paste the copied signature
-
DEL; to replace
{
with;
Adjusting declarations
Next the mismatch between add
s declaration and definition has to be fixed.
add.c:3: error: conflicting types for ‘add’
add.h:2: note: previous declaration of ‘add’ was here
To copy the new signature from the definition:
- C-x` (next-error) will jump to the location of the definition
- M-z{ (zap-to-char) C-y (yank) to copy the signature
To replace the declaration:
- C-x` (next-error) will jump to the location of the declaration
- M-z; (zap-to-char) to delete the old declaration
- C-yM-y now paste the copied signature
-
DEL; to replace
{
with;
And back again
Since two buffers have been poped:
- M-2M-x burry-buffer should go back to buffer that was visited before
Summary
As you can see while not a too time consuming process constantly jumping back and forth to fix missing or wrong declarations using this approach is still a rather tedious task I only use it to fix up declarations that I mistyped or completely missed in the first run.
Manually placing the "correct" declarations into the header still is the main approach that I take.
As laying out the API prior to implementing it might not be the worst idea IMHO this strategy shouldn't be a choice too bad.
Solution 2
There is a program called makeheaders
from the fossil
project (vcs alternative to git).
You can easily compile it from source code.
I also suggest that you read the doc.
Solution 3
On UNIX-type systems, typically IDEs don't handle this job (in my experience). The build tool (which is not usually bundled with IDEs such as Eclipse, Emacs, etc.) will do this work.
In modern systems the best way to handle this is to let the compiler do it: after all, the compiler knows best. GCC, and most other UNIX/POSIX compilers, have options that will emit make-style dependency declarations during the compilation of a source file. You simply arrange for this in your makefile, then include the output files in your makefile, and it all works very well.
See, for example: http://make.mad-scientist.net/autodep.html
Then check out the GCC options such as -MMD -MP
(these are preprocessor options).
Related videos on Youtube
barbaz
Updated on April 03, 2021Comments
-
barbaz about 3 years
I am using VIM for C++ development for quite some years now and I don't want to debate the question whether to use an IDE or powerful text editor for software development. Up to now I've been involved mostly with a header-only template library where everything is either a template or declared inline, thus .cpp files don't play a major role.
Recently I'm more involved in "traditional" C++ development, facing the old issue of header / non-header file synchronization. I'm wondering if there are any command-line tools around that could be used in a make target or be integrated into VIM to handle this job, i.e. update header files based on .cpp files. Basically, declarations of classes / structs or (template and inline) implementations should be ignore int he header files, while function declarations should be added, removed or updated based on the .cpp file.
I'm aware of the lzz tool, however, that requires you to actually code in an additional, third file format that is then preprocessed to .h / .cpp files before the actual compilation.
Is there anything around that can do the job? How do other non-IDE developers handle this problem?
-
Daniel about 11 yearsAre you really aware of lzz? It seems rather elegant to me, and the format is almost normal C++, so vi, emacs or whatever else shouldn't have a problem with it. And it addresses exactly your need. It gets tricky to write clean generic rules if you use the feature to generate inlines and templates to separate files, as then you'll have a different result set, based on the content. I'm still thinking about a way to handle this with makepp automatically.
-
aleung over 5 yearsmakeheaders utility is able to generate header files from c or cpp files.
-
-
barbaz about 11 yearsI'm not sure I understand your answer correctly. I don't want to auto-generate my make targets, I want to auto-generate my .h files themselves.
-
john about 11 yearsI'm pretty confident that almost every programmer does that job by hand. In fact you're only the second person I've ever come across who wanted to do it automatically. Which is strange because you talk about it as if it were a commonplace thing.
-
barbaz about 11 years@john interesting. I'm actually pretty sure that most people use IDEs such as VS that handle this for you.
-
barbaz about 11 yearsInteresting approach, gets pretty nasty though in case one doesn't follow a very strict one-line function signature code style. With function signatures spanning multiple lines or the opening curly brace being in the same line with the function signature this gets more and more complicated...
-
mikyra about 11 years@barbaz: As I already said - not very elegant indeed. Until now I never came across the multiline declaration problem but I don't think it would be that hard to to also limit copying the declaration down to a single keystroke, e.g. using a macro for search forward {, backward one character, exchange point and mark, copy region ... or something like that.
-
john about 11 years@barbaz No version of VS that I've ever used does this for you. Eclipse doesn't either.
-
David about 11 yearsI will add here that in addition to function declarations, I frequently find myself throwing all sorts of stuff in the class declaration [public enums, for example] that help define the user interface for the class. You can't automate this kind of thing without using some other language. Because I am curious, do you build libraries or monolithic apps?
-
mikyra about 11 years@David As I am working with pure C (no ++) I can't tell if the described workaround would still be adaptable to a project using all bells and whistles of the C++ language. If you as an experienced C++ user appreciate it impossible most probably it is. Statically linked convenience libraries are the only own ones that I use, so most probably monolithic app would be the term to use.
-
MadScientist about 11 yearsI'm with john. I don't even know how this could work. Sure, you can get the basic methods added to the class definition, but you can't know the subclassing, you (often) can't know the members or the types of the members, obviously no inline functions will be available, etc. I've never heard of an IDE that generates header files from cpp files.
-
barbaz about 11 yearsMy error then. I always imagined IDE people to have buttons for "add new member variable" or "add new member function" etc. And for changing a functions signature I would expect an IDE to supply refactoring tools, but if also IDEs require the user to change the signature in two files redundantly then apparently nobody seems to be disturbed by this? I'm surprised...
-
David about 11 yearsPractically speaking, no project should use all the bells and whistles of C++. People will talk about all the features that are in the language, but you have to have a design. Whether or not you are going to use templates, references, or exceptions affects how you compose your software, and what you expect users to do in their applications. If you are just rebranding a convenience library but keeping the functions, don't get crazy, just give it all a namespace [then refactor when it makes sense]. Use what makes sense, but be clear about your concepts.