Skip to content

Add C++ header generation#10801

Merged
wilzbach merged 7 commits into
dlang:masterfrom
MoonlightSentinel:headers
Feb 21, 2020
Merged

Add C++ header generation#10801
wilzbach merged 7 commits into
dlang:masterfrom
MoonlightSentinel:headers

Conversation

@MoonlightSentinel

@MoonlightSentinel MoonlightSentinel commented Feb 18, 2020

Copy link
Copy Markdown
Contributor

Squashed rebase of #9971 without the changes to the existing C++ tests (as proposed in #9971 (comment)).

CC @edi33416, @TurkeyMan, @wilzbach

@dlang-bot

Copy link
Copy Markdown
Contributor

Thanks for your pull request and interest in making D better, @MoonlightSentinel! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "master + dmd#10801"

@thewilsonator thewilsonator left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! First review pass, Indentation:

Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
buf.printf(" {}\n");
}

version (none)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any ideas what this version none ins for?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure but the versioned code generates an additional constructor to set all fields, e.g.

S2(_d_int a, _d_int b, _d_long c) { this->a = a; this->b = b; this->c = c; }

for

extern (C++) struct S2
{
    int a = 42;
    int b;
    long c;

    this(int a) {}
}

@Geod24 Geod24 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use a changelog entry describing the user-facing interface.
Things that immediately come to mind:

  • What happens when doing dmd a.d b.d c.d -HC ?
  • Mention the scope (only applies to extern(C) and extern(C++) declarations, ignore everything else)
  • Mention the limitations (semantic not run)

Comment thread src/dmd/root/dcompat.h Outdated
Comment thread test/compilable/extra-files/dtoh-postscript.sh Outdated
Comment thread test/compilable/extra-files/dtoh-postscript.sh Outdated
Comment thread src/dmd/globals.d
Comment thread src/dmd/dtoh.d
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d
OutBuffer buf;
buf.writestring("#pragma once\n");
buf.writeByte('\n');
buf.printf("// Automatically generated by dmd -HC\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether we should include the DMD version.
On one hand it's informative, on the other hand it would need to needless diff in the event a generated header is checked in and its generation is part of the process (it doesn't make sense to me, but I'm sure someone will do it).
Same issue would arise with a timestamp. However I can see a value in knowing a bit more about how the header was generated.

Last but not least, having the full command line might be helpful too. Things like -version and -debug will affect the output, won't they ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, that could be useful to track down errors but also annoying for diffs (and maybe reproducible builds). Maybe this behavior should be customizable via an optional argument to -HC. But i think this could be added later.

Last but not least, having the full command line might be helpful too. Things like -version and -debug will affect the output, won't they ?

I think so.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the very least, use __VENDOR__, as it's not only dmd that would use this option.

@Geod24

Geod24 commented Feb 18, 2020

Copy link
Copy Markdown
Member

As a side note, something that would be a life-saver for people using C++ interop easily is an automatic offsetof / sizeof check (in the form of static assert). But currently semantic isn't run so that's not doable.

@MoonlightSentinel

Copy link
Copy Markdown
Contributor Author

As a side note, something that would be a life-saver for people using C++ interop easily is an automatic offsetof / sizeof check (in the form of static assert). But currently semantic isn't run so that's not doable.

This could be added later. But for now the main goal is to integrate an initial version s.t. @TurkeyMan and other people can start contributing as well.

@MoonlightSentinel

Copy link
Copy Markdown
Contributor Author

I've added a preliminary changelog but I'm unsure whether we should promote it right away.

Some remaining TODO's:

  • Actually implement generating separate header files (the directory passed to -HDd is currently treated as a prefix for the file passed to -HDf
  • Cleanup generated header files (e.g. decide whether #define or typedef is used)
  • (Opt-in) metadata as proposed in Add C++ header generation #10801 (comment)
  • Missing semantic analysis

But these should mostly be resolved in further PR's.

@wilzbach

Copy link
Copy Markdown
Contributor

but I'm unsure whether we should promote it right away.

Maybe state "experimental" support? So that it's clear that not everything is fully tested and bug reports are welcome.

But these should mostly be resolved in further PR's.

Yes, please keep this one as small/low-effort as possible so that people can finally start testing it. Thank you very much for taking this to the finish line!!

@MoonlightSentinel

Copy link
Copy Markdown
Contributor Author

Maybe state "experimental" support? So that it's clear that not everything is fully tested and bug reports are welcome.

Done

Yes, please keep this one as small/low-effort as possible so that people can finally start testing it. Thank you very much for taking this to the finish line!!

Gotcha. Maybe such big features should be developed on a dedicated branch in the future. That would offer similar benefits to a draft PR while also keeping the work publicly accessible (everbody can make a small PR without adopting the entire stalled PR)

@RazvanN7

RazvanN7 commented Feb 19, 2020

Copy link
Copy Markdown
Contributor

@Geod24 @MoonlightSentinel Semantic is run before generating the cpp header files. The generateCPP function is called in mars.d after full semantic analysis has been performed. I think that the reason for this is that you may have structs that have fields that are template instances (T!int a). Also, you want to make sure that the code is correct before generating C++ header files.

@wilzbach

Copy link
Copy Markdown
Contributor

Maybe such big features should be developed on a dedicated branch in the future. That would offer similar benefits to a draft PR while also keeping the work publicly accessible (everbody can make a small PR without adopting the entire stalled PR)

FYI: We have tried this before and even made nightly builds of these branches available. No one ever downloaded those (I guess it also was a problem of people not knowing about it). Additionally, you run the high risk of the branch having lots of merge conflicts with master, so IMHO the best thing we can do are feature flags (in some way, e.g. -preview or now this flag).

@RazvanN7

Copy link
Copy Markdown
Contributor

Actually implement generating separate header files (the directory passed to -HDd is currently treated as a prefix for the file passed to -HDf

This is not possible (should be read as hard to implement) for the dmd codebase, due to the differences between C++ and D when it comes to importing (vs includes) and forward references.

@edi33416 tried this but it didn't work for the dmd codebase (I can't remember the reason though, it was something about having duplicate forward declarations). You can still generate individual header files, it's just that you have to invoke the compiler for every .d file separately.

@MoonlightSentinel

MoonlightSentinel commented Feb 19, 2020

Copy link
Copy Markdown
Contributor Author

@Geod24 @MoonlightSentinel Semantic is run before generating the cpp header files. The generateCPP function is called in mars.d after full semantic analysis has been performed. I think that the reason for this is that you may have structs that have fields that are template instances (T!int a). Also, you want to make sure that the code is correct before generating C++ header files.

That is (sadly) not entirely true as some checks are delayed until IR / code generation (and hence occur after the header generation). E.g.

extern(C++) void foo(string s) {}

fails to compile

Error: Internal Compiler Error: type string cannot be mapped to C++

but does not issue an error when using -c -o-. Then -HC still generates a header containing

extern _d_void foo(DArray<_d_char> s);

@MoonlightSentinel

MoonlightSentinel commented Feb 19, 2020

Copy link
Copy Markdown
Contributor Author

FYI: We have tried this before and even made nightly builds of these branches available.

Thanks, I did not know that. Seems like it's usually not the best idea.

@MoonlightSentinel

MoonlightSentinel commented Feb 19, 2020

Copy link
Copy Markdown
Contributor Author

This is not possible (should be read as hard to implement) for the dmd codebase, due to the differences between C++ and D when it comes to importing (vs includes) and forward references.

Agreed, this will be a bigger project for the future but i think it could be workable (at least by automating the proposed workaround)

@MoonlightSentinel

Copy link
Copy Markdown
Contributor Author

What's up with the weird spacing and random braces in the generated changelog?

@MoonlightSentinel

Copy link
Copy Markdown
Contributor Author

Eliminated the remaining style issues and got the tests passing by switching from separate files to TEST_OUTPUT sections (hence it currently includes #10807 to avoid duplication for -m32 and -m32mscoff).

@wilzbach

Copy link
Copy Markdown
Contributor

What's up with the weird spacing and random braces in the generated changelog?

Fix: dlang/tools#390

@MoonlightSentinel MoonlightSentinel force-pushed the headers branch 2 times, most recently from 0ac8330 to ef47cce Compare February 21, 2020 00:24
- Documentation for dtoh.d
- Removed redundant static
- Add missing members to globals.h
- Generate .h instead of .out files in tests
- Add a changelog

@thewilsonator thewilsonator left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise looks good to me.

Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
Comment thread src/dmd/dtoh.d Outdated
@RazvanN7

Copy link
Copy Markdown
Contributor

So what's the plan to remove all the .h files from dmd-fe? We won't be able to market this feature if we aren't using it in-house.

@thewilsonator

Copy link
Copy Markdown
Contributor

Step 0: merge this.
Step 1: let @TurkeyMan submit bug reports
Step 2: Fix them.
Step 3: Wait for @ibuclaw to get this into a GCC release.
Step 4: Wait again for that release to be the version used to build subsequent versions of GCC.
Step 5: Make the release that contains fixes from step 2 the oldest version used to build DMD.
Step 6: rm -rf *.h

@RazvanN7

Copy link
Copy Markdown
Contributor

Let's get this in! It seems that the buildkite failure is due to some version mismatch. probably unrelated to this PR.

@Geod24

Geod24 commented Feb 21, 2020

Copy link
Copy Markdown
Member

Let's get this in! It seems that the buildkite failure is due to some version mismatch. probably unrelated to this PR.

Correct: dlang/ci#410

@Geod24

Geod24 commented Feb 21, 2020

Copy link
Copy Markdown
Member

I'll try to give this a review this weekend.

@wilzbach

Copy link
Copy Markdown
Contributor

Step 3: Wait for @ibuclaw to get this into a GCC release.
Step 4: Wait again for that release to be the version used to build subsequent versions of GCC.
Step 5: Make the release that contains fixes from step 2 the oldest version used to build DMD.
Step 6: rm -rf *.h

All these steps aren't required. We talked about this before. It's no problem because:
A) we can check-in the header file into source code (with a CI check enforcing this)
B) DMD frontend requires a working D compiler, so it's absolutely reasonable to except that the build.d build script will be able to generate the headers
I think we still want to go with option A for now as it will provide LDC/GDC with a nice git history of all header file changes for a release.

- remove unused variables
- sort import in mars.d
- remove unecessary braces
- pointer style
- replace duplication with goto
- TODO comments for missing implementation
- Replace Type[...].ty check + cast with isType[...]
- Remove leftover comment
- Guard against multiple initializations
- Add a dshell test

@wilzbach wilzbach left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Glad to get this finally started!

@wilzbach wilzbach merged commit 44112eb into dlang:master Feb 21, 2020
@TurkeyMan

Copy link
Copy Markdown
Contributor

🎉🎉🎉

Awesome! Thank you so much everyone for working this through!

@ibuclaw

ibuclaw commented Feb 22, 2020

Copy link
Copy Markdown
Member

A) we can check-in the header file into source code (with a CI check enforcing this)

I think this was my suggestion, it reminds contributors to regenerate the headers (it can be a make rule) before submitting the PR. Keeping it checked in is harmless anyway.

There will always need to be a header present for the initial bootstrap (assume that for the next 2-3 years, the baseline D compiler doesn't have -HC), otherwise you won't be able to build the C++ parts of gdc and ldc..

@ibuclaw

ibuclaw commented Feb 22, 2020

Copy link
Copy Markdown
Member

Also, this needs a little extra work, as the module in its current form both imports dmd-specific modules and doesn't export the main entrypoint to C++.

@Geod24

Geod24 commented Feb 24, 2020

Copy link
Copy Markdown
Member

Templates seems completely unhandled, and due to the way the FE treats alias, I doubt they will be simple to handle.
Also while I was playing around with this I accidentally hit an ICE: https://issues.dlang.org/show_bug.cgi?id=20604

@MoonlightSentinel MoonlightSentinel deleted the headers branch February 25, 2020 01:37
@yebblies

yebblies commented Mar 5, 2020

Copy link
Copy Markdown
Contributor

From 2015-09-16 to 2020-02-22! (#5082 #8591 #9971 #10801) It lives!

@ibuclaw

ibuclaw commented Mar 10, 2020

Copy link
Copy Markdown
Member

@yebblies glad to hear from you as always. :-)

@ibuclaw ibuclaw added the Feature:dtoh C++ header generation label Sep 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature:dtoh C++ header generation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants