How can I automatically generate / update header files from cpp files without using an IDE?

20,648

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 adds 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).

Share:
20,648

Related videos on Youtube

barbaz
Author by

barbaz

Updated on April 03, 2021

Comments

  • barbaz
    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
      Daniel about 11 years
      Are 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
      aleung over 5 years
      makeheaders utility is able to generate header files from c or cpp files.
  • barbaz
    barbaz about 11 years
    I'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
    john about 11 years
    I'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
    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
    barbaz about 11 years
    Interesting 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
    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
    john about 11 years
    @barbaz No version of VS that I've ever used does this for you. Eclipse doesn't either.
  • David
    David about 11 years
    I 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
    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
    MadScientist about 11 years
    I'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
    barbaz about 11 years
    My 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
    David about 11 years
    Practically 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.