You can view, comment on, or merge this pull request online at:
https://github.com/geany/geany/pull/2299
-- Commit Summary --
* filetypesprivate.h: Don't include build.h
-- File Changes --
M src/filetypesprivate.h (20)
-- Patch Links --
https://github.com/geany/geany/pull/2299.patch https://github.com/geany/geany/pull/2299.diff
@ntrel pushed 1 commit.
f5c09882b170fe14edeebacf7b3047383a4e31c6 Fix missing build.h include
I'm not seeing how this is an improvement, to be honest.
@kugel- There are about 3 files that include filetypesprivate.h but not build.h. This speeds up rebuilding after changes to build.h.
I think it's fine to keep it locally while you work intensively on the build stuff but IMO it's not a general improvement (actually the opposite since it forces you to do forward declaration). Maybe others think different though.
b4n requested changes on this pull request.
I have to agree with @kugel- here: if the file uses a symbol defined in a header, it should include it. Manually introducing forward declarations should IMO be left to breaking circular dependencies alone. Also, I don't know how it is on your machine, but here with a not-to-recent laptop, compilation time is not so bad I feel we need to resort to such workarounds.
This doesn't make any sense, the point of including headers is so that definitions are available to compilers for checking and optimisations. By making them opaque pointers that is defeated.
@ntrel if you find there is a problem with compile speed raise an issue so it can be assessed.
This doesn't make any sense, the point of including headers is so that definitions are available to compilers for checking and optimisations. By making them opaque pointers that is defeated.
I disagree. If items inside ```struct GeanyBuildCommand``` are private and shall only be used inside ```build.c``` then it is practicable to use a forward declaration and hide the struct items. No code outside ```build.c``` can then use the struct in a wrong way. Of course this requires functions to access/use all aspects of ```struct GeanyBuildCommand```. As the ```struct GeanyFiletypePrivate``` only uses pointers to ```struct GeanyBuildCommand``` the compiler has all information it needs and can still do type checks etc. (it is still a ```struct GeanyBuildCommand *``` not a ```void *```). If something was missing then there would be a compiler error. But I would prefer a forward declaration with typedef.
As long as the items of ```struct GeanyBuildCommand``` shall only be used in ```build.c``` and if it shall stay like that in the future then I actually consider this good style.
As long as the items of struct GeanyBuildCommand shall only be used in build.c
Yes, but then they shouldn't be in `filetypesprivate.h` at all. Without checking I presume something uses them via these pointers, or they should be removed totally. And if the pointers are being used then the definitions are needed.
Yes, but then they shouldn't be in ```filetypesprivate.h```
Why? Even if the struct items are not accessed then you still need the pointers to the memory for the filetype specific build commands. So I agree we might need to include ```build.h``` for the function declarations but I like the forward declaration to keep the header file as small as possible.
the opposite since it forces you to do forward declaration
How is that a negative vs including an entire header that is not needed?
if the file uses a symbol defined in a header, it should include it. Manually introducing forward declarations should IMO be left to breaking circular dependencies alone.
The point of including headers explicitly per-file is to reduce dependencies on source files. Otherwise we would have geany.h include all headers itself.
We already use forward struct declarations in many headers, most of them are not private structs:
``` $ grep -E 'struct \w+;' src/*.h src/editor.h:37:struct GeanyDocument; src/filetypes.h:38:struct GeanyDocument; src/geanyentryaction.h:42:struct _GeanyEntryActionPrivate; src/geanymenubuttonaction.h:42:struct _GeanyMenubuttonActionPrivate; src/keyfile.h:36:struct StashGroup; src/pluginutils.h:34:struct GeanyPlugin; src/pluginutils.h:35:struct GeanyDocument; src/search.h:87:struct GeanyDocument; /* document.h includes this header */ src/search.h:88:struct _ScintillaObject; src/search.h:89:struct Sci_TextToFind; src/templates.h:57:struct filetype; ```
@elextr: I did a code search in Geany of these pointers: ``` /* TODO: move to structure in build.h and only put a pointer here */ GeanyBuildCommand *filecmds; GeanyBuildCommand *ftdefcmds; GeanyBuildCommand *execcmds; GeanyBuildCommand *homefilecmds; GeanyBuildCommand *homeexeccmds; GeanyBuildCommand *projfilecmds; GeanyBuildCommand *projexeccmds; ``` They are all used only with ```g_free```, ```SETPTR``` or direct address comparison. No one of that is passed to any function declared in ```build.h``` outside of ```build.c```.
The pointers are only in filetypesprivate.h so they are allocated with each filetype. They would otherwise be private to build.c.
@LarsGit223 at least `projfilecmds` is being accessed outside `build.c`, in `project.c`, so it's not actually completely private to `build.c`. If it was, build.h should have had the forward declaration, and `build.c` the complete one.
@ntrel `struct _GeanyEntryActionPrivate` and `struct _GeanyMenubuttonActionPrivate` are forward declarations because the definition is totally private, in the corresponding source file (that includes its header). This is perfectly fine IMO because not only it's the only way to make a structure totally opaque, but the forward declaration is also included by the code having the definition, so the compiler can do a check that those are compatible. Some of the ones you mentioned are to break circular dependencies (e.g. search.h's one looks like that), so we don't have much choice. All others that aren't required for breaking circular dependencies should be removed and the proper header included IMO.
The point of including headers explicitly per-file is to reduce dependencies on source files.
It also helps controlling what uses what, and have more generic parts not entangled between them. But that's not really the point IMO, we could have a single header and that'd be mostly fine by me. What matters IMO is that declarations can be checked against their definition, to avoid conflicts and such. If declarations start popping everywhere, it makes it a *lot* harder to change them or check if they make sense. OK a structure can only change name (which is bad enough), but if we'd extend this to e.g. prototypes it's diving into madness if that function signature becomes incorrect. So basically my take is, as much as possible, keep only one declaration (in the .h) to have minimal effort when modifying it, and have that declaration be used together with the definition (.h included in the .c) so the compiler can actually check the declaration is correct for us.
This makes this change not worth it IMO, as it trades a tiny bit of compilation time for maintenance and safety costs. That's not a deal I'm wanting to make.
@b4n
@LarsGit223 at least projfilecmds is being accessed outside build.c, in project.c, so it's not actually completely private to build.c. If it was, build.h should have had the forward declaration, and build.c the complete one.
Maybe I was not precise enough. The ```GeanyBuildCommand``` pointers are used outside of ```build.c``` but only for: - address comparison - calls to g_free - calls to SETPTR
So the struct items are only used privately in ```build.c```. Therefore a forward declaration seems to be enough, including ```build.h``` is not required (at the moment).
If declarations start popping everywhere, it makes it a lot harder to change them or check if they make sense. OK a structure can only change name (which is bad enough), but if we'd extend this to e.g. prototypes it's diving into madness if that function signature becomes incorrect.
I don't understand this at all. Prototypes are irrelevant, I don't understand what you mean. Please explain what you mean about the struct name changing being bad enough. You would get a compile error.
as it trades a tiny bit of compilation time for maintenance and safety costs
How so? There is no safety loss.
@LarsGit223 As @b4n said, if the intent is to hide the definition of GeanyBuildCommand, then the forward declaration should be in build.h (perhaps along with a typedef) to express that intent. With this patch, the intent is rather "just avoid including build.h" instead of making an opaque type.
the intent is to hide the definition of GeanyBuildCommand, then the forward declaration should be in build.h
That wasn't the intent because I thought the struct fields were needed by the API, but I see now they are not needed. The definition could be moved to build.c. So we would have a forward declaration then, so I don't see what all this fuss has been about.
The definition could be moved to build.c
I probably won't do that, this pull is more important to me. It's possible that struct might be useful to access outside build.c later.
I don't know how it is on your machine, but here with a not-to-recent laptop, compilation time is not so bad
This pull saves me several seconds build time, which is useful. (That's with using a resurrected [makefile.win32](https://github.com/ntrel/geany/commits/makewin32), autotools on Windows is *painfully* slow). But it's also important to avoid unnecessary dependencies on files from a conceptual PoV.
That's with using a resurrected makefile.win32, autotools on Windows is painfully slow
After `configure` - which _is_ super slow on Windows, but rarely needs to be run unless you're hacking the build system - it's just running a Makefile anyway and shouldn't be very different from a hand-made Makefile if it's performing the same build tasks.
I don't understand this at all. Prototypes are irrelevant, I don't understand what you mean.
It's another kind of forward declarations, and if we start with structs "just because", where do we stop?
Please explain what you mean about the struct name changing being bad enough. You would get a compile error.
It makes things confusing because they get named differently depending on where they are used. And the error you'd get if you renamed the definition ("incomplete type") is really not as explicit as "no such type", and triggers "huh, what include did I miss?" rather than "oh bummer, forgot to edit this".
Anyway, I really don't get why do this kind of stuff for gaining a couple seconds when compiling. IMO, it makes the code worse for no gain, and although I don't like the very change here, I'm most fearful of where that path can lead if it's taken a step too far.
@ntrel as I said, if you are having an issue with compilation speed, raise an issue on compilation speed so it can be investigated, nobody else is complaining of compile speed, so maybe its something in your setup.
Don't just raise a random PR with what you think is the solution.
@elextr libtool on Windows is the problem with the autotools build, I have no expectation that it can be made faster. My laptop is very old, raising an issue will not help that ;-) This pull is just doing what we always did when Enrico and I maintained the project, not over-including headers unnecessarily. There is no downside to this change, no one has pointed a valid one out. But I'm not interested in arguing about this anymore, Colomban is the maintainer so it's up to him.
if you are having an issue with compilation speed, raise an issue on compilation speed so it can be investigated
See #2305
Closed #2299.
github-comments@lists.geany.org