|
|
Log in / Subscribe / Register

Compiling kernel UAPI headers with C++

By Jonathan Corbet
September 13, 2018
Linux kernel developers tend to take a dim view of the C++ language; it is seen, rightly or wrongly, as a sort of combination of the worst (from a system-programming point of view) features of higher-level languages and the worst aspects of C. So it takes a relatively brave person to dare to discuss that language on the kernel mailing lists. David Howells must certainly be one of those; he not only brought up the subject, but is working to make the kernel's user-space API (UAPI) header files compatible with C++.

If somebody were to ask why this goal is desirable, they would not be the first to do so. The question has not actually gotten a complete answer, but some possible motivations come to mind. The most obvious one is that some developers might actually want to write programs in C++ that need access to the kernel's API; there is no accounting for taste, after all. For most system calls, the details of the real kernel API (as opposed to the POSIX-like API exposed by the C library) tend to be hidden, but there are exceptions; the most widespread of those is almost certainly the ioctl() system call. There is a large set of structures used with ioctl(); their definition is a big part of the kernel's UAPI. If a C++ compiler cannot compile those UAPI definitions, then those ioctl() calls cannot be invoked from C++.

C++ got its start as a sort of superset of C, so most C code could, in the early days, be compiled with a C++ compiler. The two languages have diverged over the years, though, making it easier to write C code that can no longer be compiled in that way. A look at the changes in Howells's patch set gives some good examples of where things can go wrong.

One common stumbling point is the use of identifiers that C++ has claimed as keywords. The drm_i810_dma structure, for example, contains a member called virtual, while struct virtio_net_ctrl_header has a member called class. Given the frequent use of members called private in the kernel, it is surprising that only one (struct keyctl_dh_params) seems to have made it into the UAPI. The C++ compiler gets rather grumpy when it encounters those keywords used as identifiers, so something needs to change if the UAPI headers are to be acceptable to it.

One developer suggested that, for example, C++ developers could be asked to compile their programs with a command-line option like -Dclass=_class to sidestep the problem. It turns out, though, that this approach, while it is indeed effective at getting the structure in question to compile under C++, has a certain risk of creating unintended difficulties elsewhere in the program. So a different approach is necessary. The solution that was chosen is to change the definition of the structure to look like this:

    struct virtio_net_ctrl_hdr {
	union {
    #ifndef __cplusplus
	    __u8 class;
    #endif
	    __u8 _class;
	};
	__u8 cmd;
    };

The addition of the anonymous union allows the old (C++ keyword) name to be used in C code, while also allowing the addition of a new name that can be used under either language. Changing the structures in this way was not universally popular, but there do not appear to be a lot of good alternatives, given that breaking code written in C is not acceptable.

There are various other problems to be solved; for example, ending a structure with an array of unspecified length is not allowed in C++. So a definition like the rather tersely named struct bkey:

    struct bkey {
	__u64	high;
	__u64	low;
	__u64	ptr[];
    };

must be changed by giving ptr an explicit dimension of zero. Other problems turn out to be simply bugs; some structures were defined using kernel-specific types that are not available in user space, for example. In at least one case, the structure involved should never have been exposed to user space to begin with and had never been used in communications with the kernel. Cleaning such things up makes sense even if one does not care about the larger goal of C++ compatibility.

The final step in the patch series is the addition of a script that will feed (almost) all of the UAPI header files to g++ as part of the kernel's build process. The output of this compilation is discarded, but it serves a useful purpose; any developer who breaks the ability to compile those files under C++ will get some immediate feedback to that effect. At least, they will if they have g++ installed; otherwise the test is skipped to avoid breaking the kernel build as a whole. Should this series be merged, kernel developers will not necessarily like C++ any more than they do now, but they will at least be more friendly toward C++ developers trying to use their exported API headers.

Index entries for this article
KernelBuild system


to post comments

Compiling kernel UAPI headers with C++

Posted Sep 13, 2018 17:56 UTC (Thu) by xtifr (guest, #143) [Link]

Hmm. I wonder if anyone has looked at adding compatibility (in the same sense) with ObjC and ObjC++. I think those are easier--it might just fall out naturally from this effort--but it might be nice to check. They're not languages I use, but I do like the idea of increasing compatibility *in general*.

Basically, I think it would be nice, at a *minimum*, to support any languages which A) can usually directly import C headers (otherwise there's no point) and B) are included in the Gnu Compiler Collection.

Compiling kernel UAPI headers with C++

Posted Sep 13, 2018 20:48 UTC (Thu) by ballombe (subscriber, #9523) [Link] (2 responses)

I have to ask: why not use extern "C" instead ? Most C libraries do that.

extern "C"

Posted Sep 13, 2018 20:57 UTC (Thu) by corbet (editor, #1) [Link] (1 responses)

The extern "C" declaration changes things like linkage, but won't help with problems like the use of keywords as identifiers.

extern "C"

Posted Sep 15, 2018 10:14 UTC (Sat) by pbonzini (subscriber, #60935) [Link]

Also, the kernel API does not include any external symbols, since all entry points are accessible through architecture dependent mechanisms and the C symbols are provided by glibc. The headers only include structs and constants.

glibc does use extern "C" of course.

Compiling kernel UAPI headers with C++

Posted Sep 13, 2018 22:02 UTC (Thu) by mirabilos (subscriber, #84359) [Link] (10 responses)

Naming it _class is not going to end well, either. Underscores around the name or _t at the end are reserved by various standards.

See https://stackoverflow.com/a/25090719/2171120 for example.

Compiling kernel UAPI headers with C++

Posted Sep 13, 2018 22:57 UTC (Thu) by Karellen (subscriber, #67644) [Link]

According to the page you linked to, underscore+lowercase letter is only reserved for identifiers with file scope. Using underscore+lowercase as an identifier with struct/union(/class) scope should be fine.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 6:40 UTC (Fri) by epa (subscriber, #39769) [Link] (7 responses)

Yes, better not to contribute to underscore inflation. Calling it 'klass' would make more sense.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 8:45 UTC (Fri) by eru (subscriber, #2753) [Link] (2 responses)

Why not "cla$$"? Dollars in identifiers work fine in GCC.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 9:00 UTC (Fri) by naptastic (guest, #60139) [Link] (1 responses)

But then what happens when we want to use UAPI from PHP? Better to call it "claß".

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 11:17 UTC (Fri) by grawity (subscriber, #80596) [Link]

Then you reference it as ${"cla\$\$"} from PHP.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 18:12 UTC (Fri) by mm7323 (subscriber, #87386) [Link] (3 responses)

Java often uses 'clazz' in and around reflection.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 21:21 UTC (Fri) by mirabilos (subscriber, #84359) [Link] (2 responses)

C tends to be terse, so perhaps “cls” would be more welcome, despite its use in Python.

I was more thinking of “what kind of class is it?”, cmdclass, devclass, or so. Also, isvirtual.

Compiling kernel UAPI headers with C++

Posted Sep 15, 2018 20:29 UTC (Sat) by epa (subscriber, #39769) [Link] (1 responses)

I suggested 'klass' because of its use in Python. Although I see now that PEP 8 advises against it, wanting to add underscores instead. (A mistake, in my view.) I picked it up from the old O'Reilly Learning Python book, first edition, back in the day. Perhaps it is just too old school, or should I say old skool.

Compiling kernel UAPI headers with C++

Posted Sep 16, 2018 20:43 UTC (Sun) by k8to (guest, #15413) [Link]

Any convention around "use the word but don't use the word" is going to be awkward unless you've just accepted it.

Compiling kernel UAPI headers with C++

Posted Sep 20, 2018 1:26 UTC (Thu) by brooksmoses (guest, #88422) [Link]

As another commenter pointed out: At least in C++, the reserved set is not all names that start with an underscore. Except in the global namespace, it's "Each name that contains a double underscore or begins with an underscore followed by an uppercase letter...." So "_class" is not a reserved name outside of the global namespace.

More importantly, though: Even if it were a reserved name, though, the rest of that sentence in the standard is "...is reserved to the implementation for any use." The kernel headers are widely understood to be part of the implementation, just like the libc headers, and thus it's entirely acceptable for them to use reserved names.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 0:51 UTC (Fri) by ikm (guest, #493) [Link] (8 responses)

Might I suggest s/Linux kernel developers/Linus/? Otherwise I think it's unfair both for C++ and for said kernel developers, who may or may not agree with Linus on this.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 10:12 UTC (Fri) by error27 (subscriber, #8346) [Link] (7 responses)

Why are you bringing Linus into it when it's Greg complaining?

The article is obviously making a joke. We don't all hate C++. David Howels thinks C++ is great and Andrew Morton likes it. The rest of us think C++ is like Brussels sprouts. We don't hate it. It's not hurting anyone. It's probably full of vitamins. The only thing is nobody can understand why people eat it.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 12:38 UTC (Fri) by ncm (guest, #165) [Link] (4 responses)

You clearly haven't had brussels sprouts prepared right. I used to think I didn't like them, but had only had been served bad ones. Now I would rather have (correctly prepared) brussels sprouts than french fries.

C++ has had "class", "private", and "virtual" keywords for 30+ years, longer than there has been a Linux. You know that those names were inserted in public-facing headers gleefully to make things difficult for C++ coders. It is hard to feel sorry for the kernel people responsible, Linus most especially.

All efforts to make it harder to switch from C to C++ have contributed directly to hundreds of security holes, only a fraction yet identified. Today, it is irresponsible to start a new project in C, or in C-like C++. In modern C++, C idioms that create stupid security failures are unnecessary, and not used. (But you do still need to avoid integer overflow!)

If you are still avoiding brussells sprouts and C++, it is time to try them again. Prepare to be pleasantly surprised. Coding C++ is, more than anything else, faster than coding C, and the code is always at least as fast, and is often noticeably faster.

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 13:00 UTC (Fri) by Paf (subscriber, #91811) [Link] (1 responses)

There have definitely not been any explicit efforts to prevent people from using C++ with these headers. It’s irrelevant to those who wrote them. They haven’t done anything to help either - and that’s been enough.

A C developer using “private” isn’t even thinking about C++, nor should they be without explicit reason to do so. (“So C++ can use the headers” is a good reason, but it has to be an explicitly articulated goal or people won’t consider it.)

Compiling kernel UAPI headers with C++

Posted Sep 16, 2018 16:49 UTC (Sun) by ncm (guest, #165) [Link]

You can say so, but I remember the chortling when "class" was added.

Compiling kernel UAPI headers with C++

Posted Sep 15, 2018 17:22 UTC (Sat) by marcH (subscriber, #57642) [Link] (1 responses)

> You clearly haven't had brussels sprouts prepared right.

So they really are like C++! You can prepare them right, it's just most people don't.

Compiling kernel UAPI headers with C++

Posted Sep 20, 2018 22:40 UTC (Thu) by gerdesj (subscriber, #5446) [Link]

Compiling kernel UAPI headers with C++

Posted Sep 16, 2018 16:17 UTC (Sun) by rweikusat2 (subscriber, #117920) [Link]

Brussels sprouts become pretty disgusting when boiled or stewed. Braised in oil for the right time, they can be quite nice.

Compiling kernel UAPI headers with C++

Posted Sep 16, 2018 20:46 UTC (Sun) by k8to (guest, #15413) [Link]

I'm super glad you brought up brussel sprouts. People might be willing to re-evaluate their opinions about those!

(Programming languages.. not so much.)

Compiling kernel UAPI headers with C++

Posted Sep 14, 2018 11:34 UTC (Fri) by jezuch (subscriber, #52988) [Link]

Thanks for writing this up! The patch series immediately caught my eye. I know some people compile C code with a C++ compiler because C++ corrects at least some of C's warts and can warn about them. The GCC folks also moved to a very limited subset of C++ that would allow them to reduce amount of boilerplate code in several places (and more, I guess?). So I was curious about the motivation :)

Brave one

Posted Sep 15, 2018 6:58 UTC (Sat) by meuh (guest, #22042) [Link]

David Howells is also the brave person who bring us the UAPI, see The UAPI header file split.

Compiling kernel UAPI headers with C++

Posted Oct 7, 2018 16:09 UTC (Sun) by mcfrisk (guest, #40131) [Link]

Would be nice if the Linux kernel uapi headers would compile even with a C compiler... https://lkml.org/lkml/2017/8/6/162

Some subsystem maintainers were really helpful but several not. Maybe it's the generic case of unmaintained subsystems. As so many patches where in my queue and on lkml for years I also kind of gave up on this. I hope the C++ compatibility work proceeds and fixes the many common root causes already seen when compiling the headers with plain C compilers.

The developer doing this kind of work needs to be a known good kernel maintainer or has at least to have a blessing from one them, or the developer needs to attend and hold presentations about the topic in kernel conferences before progress can be made. I wasn't and didn't, so don't really know how to proceed with my work. Just sending same patches over and over again to lkml doesn't work.

One of my motivations was to check UAPI headers for ABI breaks between kernel versions and the tooling naturally expects that they would compile: https://github.com/lvc/abi-compliance-checker


Copyright © 2018, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds