On Monday, 7 November 2022 at 22:05:38 UTC, Walter Bright wrote:
>The main application in the suite of financial tools I built for myself and ported to D from C uses the gtk3 and sqlite3 C libraries. Let's talk about gtk, which is a big system and has many convoluted and complex header files.
I dealt with gtk in my D code as you might expect. I created a gtk.d with hand-coded definitions and function prototypes such as
alias gconstpointer = immutable(void) *;
struct GtkWindow; // All structs that are dealt with by pointer only are defined this way
struct GtkTreeIter {
long[4] dontcare;
} /* A few structs like this need to be stack-allocated in D code, their addresses
passed to gtk functions. I check their sizes against globals containing
sizeofs in a the lone C file that is part of this application */
extern (C) void gtk_tree_selection_select_iter(GtkTreeSelection* selection, GtkTreeIter* iter);
This is the standard pre-ImportC approach. Messy and ugly, but it works. However, if the library functions and C header files change, the application will break in unpredictable and hard-to-debug ways. At the moment, I'm using gtk3, which will not change because they've moved on to gtk4 with a somewhat different API. But if I decide to update to gtk4, I would be subject to this risk using this method.
I read the ImportC documentation when it first became available and several times since. I did not come away from those readings with a clear idea of how to use it to rid myself of the above. Then I saw Walter's comment in the link above. Aha -- you can just import header files in D code! The documentation does not say that, unless I've missed something. I think the relevant section is 41.3.2, which, given 'import hello', says "which will, if hello is not a D file, and has an extension .i or .c, compile hello with ImportC". No mention of .h files. Walter's comment made two things clear -- how to use ImportC in my case and that the documentation needs to be corrected and improved with an example of importing a C header file. Importing header files so you can directly use C libraries is a major reason why ImportC is an important addition to D and it should be crystal clear in the documentation how to do it.
With my improved understanding, I decided to give ImportC a try. All my D source files already had 'import gtk' statements, to get at my hand-coded definitions above. So no change was needed, since the goal was now to import gtk.h. I simply changed my makefile for this application to, in the invocations of dmd that compile my D source files, include the standard pkg-conf call that expands primarily into '-I's, indicating where to find all the gtk header files. A little post-processing of that expansion was necessary with sed, because dmd expects -I in a slightly different format than clang. I also needed to remove a couple of switches that dmd doesn't support.
I also removed the checks on struct sizes (and their definitions in my C file), since the struct definitions are now available directly from the Gtk header files.
Then I got rid of all references in the makefile to my gtk.d source file. After a few false starts due to things I overlooked, the application built successfully. This all took less than an hour. I've done some cursory testing and it seems to work properly. I was quite amazed at how easy this was.
So based on my initial experience, Walter's statement about ImportC's usefulness seems to be correct (I will report if anything turns up in more thorough testing) and I congratulate him for this work; it really facilitates the use of C libraries. I think this should be prominent in any "Why D?" presentation or discussion, because ImportC greatly enhances D's competitive position, in my opinion. Marketing!
I will add that I've played with zig a bit, starting a couple of years ago, attracted by its translate-c capability, which is analogous to ImportC. At that time, I remember looking at D as a candidate for the work I wanted to do and being put off by the realization that to use it, I would need to do something like the above hackery. I did eventually come back to D despite this, because Zig was and is not ready and because of my misadventures with Rust, which I've already discussed in other posts.