Can we use "ImportC" used yet?

jfondren julian.fondren at gmail.com
Fri Oct 15 20:45:35 UTC 2021


On Friday, 15 October 2021 at 18:39:10 UTC, rempas wrote:
> Cause I can't find an option in the latest DMD release and 
> because the ImportC 
> [page](https://dlang.org/spec/importc.html#importing) seems to 
> be incomplete (even saying it's under construct), I'm wondering 
> if ImportC exists even as prototype but it's hidden or if it's 
> not available at all. Anyone knows?

There's no option, you just use a normal import statement when 
the module is named .c instead of .d

I say 'just' but typical C uses the C preprocessor and can't be 
imported as-is.

Here's an example in three files:

```d
// fstat.d
void main() {
     import std.stdio : writeln;
     import sys_stat : stat_t, fstat;

     stat_t buf;
     writeln(fstat(0, &buf));
     writeln(buf);
}
```

```c
// sys_stat_wrapper.c
#define __restrict restrict
#include <sys/stat.h>
typedef struct stat stat_t;
```

```make
# Makefile
fstat: fstat.d sys_stat.c
	dmd $<

sys_stat.c: sys_stat_wrapper.c
	gcc -E -P $< > $@
```

this is importing sys_stat.c , making space on the stack for a 
stat_t (what's that?), calling fstat on fd 0, and then writing 
the output, which might look like

```
0
stat(27, 11, 1, 8592, 1000, 5, 0, 34824, 0, 1024, 0, 
timespec(1634329152, 581807916), timespec(1634329152, 581807916), 
timespec(1634272061, 581807916), [0, 0, 0])
9
```

the d programmer did not have to carefully `extern (C)` an fstat 
function, nor define a struct, nor care about issues like an evil 
platform padding its struct with some bytes and overwriting the 
stack unless the d programmer accounts for that. This is all 
nice. But you still had to write those three lines of C, to 
smuggle `struct stat` into d and to suppress non-standard 
`__restrict`. And you still need to invoke the C preprocessor as 
a build step.

The next inconvenient thing is: what about when you want a c 
`#define` in d? Say, fstat's potential errors. You have to 
smuggle those as well, and because the C preprocessor fights you, 
you have to not just stuff those people in a box but also prepare 
new names for them. (And if platforms vary in errors? More build 
system work.)

```c
// sys_stat_wrapper.c, continued
#include <errno.h>
enum errors {
     ebadf = EBADF,
     eio = EIO,
     eoverflow = EOVERFLOW,
};
```

```d
// fstat.d, continued
     import sys_stat : errors, ebadf;
     writeln(ebadf);
     writeln(errors.eoverflow);
}
```

Of course you can rename when importing as usual, or have a 
separate .d module that cleans this interface up where the C 
preprocessor can't interfere.

For function-like `#defines`, perhaps you'll want to write a C 
function that uses it.

In conclusion, ImportC exists and you can use it, and 
complications like smuggling structs are discussed in that page. 
If you're going to wrap a new C library especially, it can take 
on 99% the tedium for you. If you're going to burn down an 
importc-by-hand work that you have already and replace it with 
ImportC, it might be better to wait for dub and gdc to catch up. 
As annoying as it might be to have C constants in your code, they 
do compile with fewer build steps.


More information about the Digitalmars-d-learn mailing list