[SAoC] 'DPP with Linux kernel headers' Project Thread

Cristian Becerescu cristian.becerescu at yahoo.com
Thu Oct 10 20:28:20 UTC 2019


It's time for a new update, so here we go. Sorry for those long 
posts :)

This past week I've dived deeper into the 3rd problem mentioned 
in the last update.
There were multiple problems when trying to generate and compile 
a D program from this DPP:

// foo.dpp
#include <linux/namei.h>

void main()
{
}

Problem #1 - Clang errors
Even though compiling a C program which included the same kernel 
header with clang worked, compiling it through dpp didn't. I've 
managed to find out that this happens because dpp appends some 
include directories by default, the problem being related to 
'/usr/include/' in particular (which is set through the function 
call systemPaths() from the D libclang [1]). Clang complains 
about undeclared identifiers and expected closed parenthesis, but 
I still have to investigate why including that directory to the 
include directories messes things up.

-------------------------------------------------

Problem #2 - Multi-line macro definition w/ casts
Consider this code from kernel.h:

#define u64_to_user_ptr(x) (		\
{					\
	typecheck(u64, x);		\
	(void __user *)(uintptr_t)x;	\
}					\					
)

In dpp, when translating this into D code, we also check for 
pairs of open and closed parenthesis [2]. When finding a '(', we 
increment the index of the tokens array until we find a matching 
')'. If the C code is valid (and in the above example it is), 
this should work well, but it doesn't, resulting in a fatal 
error: range violation. The reason is, as seen in [2], we only 
check for tokens with the ')' spelling, when, in reality, the 
last parenthesis of the macro is not spelled ')', but '\\\n)' 
('\' character, followed by newline, followed by the actual 
parenthesis).

-------------------------------------------------

Problem #3 - Aggregates with name being a D keyword
I'll give you an example:

// test.h
struct module;

void f(struct module *);

struct module {
	int a;
	int b;
};

Generating a D file from a DPP one which includes the above 
header will look like this:

// test.d, generated from test.dpp through the last version of 
d++ from github
// ...
extern(C)
{
	void f(module*) @nogc nothrow;
	struct module__
	{
		int a;
		int b;
	}
}

struct module;

void main() {}
// ...

Clearly there are multiple wrong things here:
- the module struct should be named module_ and not module__ 
(this is what dpp should do internally)
- even though the struct is renamed, the parameter types are not
- we are declaring the same structure again (with the original C 
spelling) outside of the extern(C) block because dpp thinks 
module was an undeclared structure
- compilation of this D program clearly doesn't work

The reasons for those bugs are a bit subtler, so I'm not going 
over them as it would make this post quite big.

-------------------------------------------------

I have implemented working solutions for all the above problems. 
They pass all the unit tests and I can also successfully generate 
an executable file from a .dpp which contains the linux/namei.h 
kernel header. I just have to clean some things and start making 
pull requests and maybe get some feedback.
Problem #1 is "solved" by not including that directory in the 
paths (just a workaround for the moment), but as I will 
investigate this further, I will try to see what the underlying 
problem really is (probably some collisions with other files).

Going from here, I will investigate if my changes impact other 
non-unit-tested C cases. Also, I will try running dpp with other 
kernel and non-kernel headers as well, making sure there are no 
other bugs or untreated edge cases.

Cristi


[1] https://code.dlang.org/packages/libclang
[2] 
https://github.com/atilaneves/dpp/blob/master/source/dpp/translation/macro_.d#L326


More information about the Digitalmars-d mailing list