Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build React Native Windows with C++ 20 #12219

Closed
wants to merge 9 commits into from

Conversation

NickGerleman
Copy link
Collaborator

@NickGerleman NickGerleman commented Oct 10, 2023

Changes:

Build flags:

  1. Change compiler flag for ABI internals to build with C++ 20
  2. Remove the /await flag which was used to enable experimental coroutines TS support in C++ 17
    1. CppWinRT will also set this for you if you don't set stdcpp20 it looks like
  3. Build integration-test-app and automation-channel with C++ 20, so we can get rid of their legacy coroutine usage (not strictly required)

Coroutines:

  1. Replace coroutine functions with std::experimental::coroutine_handle with std::coroutine_handle
  2. Replace std::future usage in coroutines with concurrency:task since the former relies on coroutine extensions not part of the C++ 20 standard (provided previously by /await)
    1. This is recommended by https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/concurrency#asynchronously-return-a-non-windows-runtime-type

C++ 20 breaking changes

  1. Replace a usage of allocator.construct() (deprecated in C++ 17 but silenced in RNW, removed in C++ 20) with placement new.
  2. Use wstring when passing unicode file paths. u8string() is now its own type in C++ 20, that doesn't play nice with libraries not meant to support it, and there isn't a zero-cost way to convert between it and std::string. Using wstring APIs for fs path sink lets us avoid that, and ends up avoiding extra conversions/allocations since the path is already UTF-16 internally, and we previously converted to utf8, to convert back to utf16.
  3. Interpret some string literal u8 strings in test data as char* using reinterepret_cast. This is sadly the portable way to do this, without relying on MSVC setting /utf-8 (which this project does).
  4. Fix "Explicit template specialization cannot have a storage class" by moving a function outside of a struct

Folly:

  1. Update folly to take in facebook/folly@abbd46b
  2. Set FOLLY_CFG_NO_COROUTINES to avoid building Folly coroutine bits, not used by RN (consistent with Android/iOS build)
  3. Made Fix MSVC Warning when compiling format.cpp facebook/folly#2078 to fix a warning explicitly set by /sdl in folly
  4. Suppressed C4244 which showed in some Folly concurrency bits. This is already suppressed in other places, but the alternative would be to make an upstream PR or fork
  5. Updated the forked files in TEMP_UntilFollyUpdate

Before merging

  1. We should take in a new version of Folly with the change in Fix MSVC Warning when compiling format.cpp facebook/folly#2078
    1. The original author of ContexprMath.h is on PTO until the end of the month, but I might be able to wrangle someone to accept it (RNW could otherwise fork, like done in other places, but best to avoid the debt)
  2. We should be sure it is okay to suppress C4244 when building Folly (just Folly, not Folly header users). Some other places already do this though. Otherwise we might need to add a static_cast somewhere.

Effect to RNW consumers

This change should not require updates to any of the consumers of Microsoft.ReactNative. Some care might need to be taken for Office/Win32 build with Folly at the ABI boundary in order to be sure we avoid any ODR violations (though, we're likely to be fine).

Microsoft Reviewers: Open in CodeFlow

@NickGerleman NickGerleman changed the title WIP: C++ 20 Build React Native Windows with C++ 20 Oct 11, 2023
@NickGerleman NickGerleman marked this pull request as ready for review October 11, 2023 09:00
@NickGerleman NickGerleman requested review from a team as code owners October 11, 2023 09:00
@NickGerleman
Copy link
Collaborator Author

This should allow removal of the patches mentioned in #12195, but some of the listed ones there were unrelated to C++ 20, and were related to casting instead. So it might be better to just remove everything at once in a future round of integrating changes.

@NickGerleman
Copy link
Collaborator Author

NickGerleman commented Oct 11, 2023

Failures for universal playground debug are also showing on last continuous: https://dev.azure.com/ms/react-native-windows/_build/results?buildId=504190

Hermes + Fabric E2ETest crash visiting the "TextInputs with key prop" RNTester page seems new though, and awfully strange. Looks like the job was able to upload a crash dump I can take a look at though.

Edit: The symbols weren't uploaded though 🤔.

image

@@ -20,6 +20,6 @@ struct Url {
std::string Target();
};

std::future<std::string> getApplicationDataPath(const wchar_t *childfolder);
concurrency::task<std::string> getApplicationDataPath(const wchar_t *childfolder);
Copy link
Member

Choose a reason for hiding this comment

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

While I understand the need for this change, it is very unfortunate one since we do not want to use the ConcRT library in Office (unless something changed recently). We must follow up on it and replace it with Mso::Future. Mso::Future does not support coroutines yet. Thus, we cannot use it here yet. @JunielKatarn, let's follow up on it. Until that this code cannot be adopted in Office.

Copy link
Member

Choose a reason for hiding this comment

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

I have checked our internal C++ alias and they do not recommend using std::future, ConcRT, or PPL (std::future is based on PPL).
I guess it was a reason why Raymond Chen created a new library that works well with C++/WinRT.
https://github.com/microsoft/wil/blob/master/include/wil/coroutine.h
This way we would need to add dependency on WIL, which we were avoiding so far.

Anyway, the change is good for now. We must follow up on that after the PR is merged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We have few enough cases that we could also likely convert these to WinRT types and just use IAsyncOperation. It's also not entirely ideal, but would avoid concurrency runtime usage. Let me know what you think of that.

Copy link
Member

Choose a reason for hiding this comment

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

IMHO, in the current situation it would be the best to use IAsyncOperation, but I do not know how difficult to apply it. I will leave it up to your judgement.

@vmoroz
Copy link
Member

vmoroz commented Oct 11, 2023

@NickGerleman, thank you for bringing the C++20 support to RNW! It must be good to go as soon as it can pass the tests.

@chiaramooney
Copy link
Contributor

Found a couple of issues that were filed the last time we looked into upgrading to C++20. @NickGerleman before merging can you check that these concerns are adressed?

@NickGerleman
Copy link
Collaborator Author

Found a couple of issues that were filed the last time we looked into upgrading to C++20. @NickGerleman before merging can you check that these concerns are adressed?

I think we should be able to close these out. I think they were likely addressed during a previous cppwinrt bump.

@NickGerleman NickGerleman requested a review from a team as a code owner October 17, 2023 21:24
@NickGerleman NickGerleman requested a review from a team as a code owner October 17, 2023 22:17
@acoates-ms
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines failed to run 1 pipeline(s).

.ado/jobs/e2e-test.yml Outdated Show resolved Hide resolved
@@ -0,0 +1,968 @@
/*
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

facebook/folly#2086 should hopefully land before next weeks Folly release, and also let us remove the fork of Hash.h

Copy link
Member

Choose a reason for hiding this comment

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

It is great to see changes to be done in Folly repo!
Just nitpicking on your folly PR: did you consider using "if constexpr" for signed/unsigned instead of cloning the constexpr_ipow template.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Folly targets C++ 14 as a minimum I believe.

@NickGerleman
Copy link
Collaborator Author

NickGerleman commented Oct 29, 2023

I plan to break apart this change into multiple smaller ones.

A revision of the all-in-one C++ 20 PR caused a crash n Fabric E2E tests. I wanted to look at the crash dump, alongside the pdb and DLL used by the build. The previous copy of this logic, reused for Fabric, was dependent on the structure for a C# appx build. This updates the direcotry based on what I locally observed for the Fabric E2E test build.
These projects make use of ts-specific `std::experimental` coroutine APIs. Bump to C++ 20, and C++ 20 standard coroutines. These both have WinRT binary boundaries, so this should have no interaction with other projects (and should have no impact to MSRN interop.
This sets a couple new preprocessor conditions:
1. `FOLLY_CFG_NO_COROUTINES` to prevent types like `folly::optional` from bringing in Folly's coroutine stack when Folly detects C++ 20 coroutines as available.
2. `_SILENCE_CXX20_U8PATH_DEPRECATION_WARNING`: Because the deprecation came before a suitable replacement API. This is more scoped than the `_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS` used by `React.Cpp.props`.
This API was deprecated in C++ 17, and removed from C++ 20. Replace it with placement new.
1. Both WinRT and std::filesystem use system-native UTF-16 paths on Windows. Defaulting to UTF16 lets us avoid conversion until needed, and fixes some instances of round-tripping between formats.
2. We rely on `path.u8string()` to return a Unicode representation of a path, but that API in C++ 20 returns `std::u8string` which is incompatible with every other existing utf-8 API. `path.string()` may convert to system codepage instead.
3. This makes coroutine usage more efficient when using `IAsyncOperation<winrt::hstring>`, the pattern to replace `std::future<std::string>` usage mechanically.

`std::filesystem::path` internally uses Windows native UTF-16 path. We use `u8string()` to convert to UTF-8.
`u8` is needed to portably ensure source is parsed as UTF-8 (though RNW already has build settings to do this)

In C++ 20, these are represented using `char8_t` instead of `char`, which makes them incompatible with the other UTF-8 string APIs.

This wraps C string literals with `reinterpret_cast`, to keep the portablility benefits of `u8` but also store into a `std::string`.
…lass"

Fixes "[Explicit template specialization cannot have a storage class](https://stackoverflow.com/questions/29041775/explicit-template-specialization-cannot-have-a-storage-class-member-method-spe)" in C++ 20 by moving a function outside of a struct.
This bumps Folly to 2023.10.16.00, and cherry-picks facebook/folly@e65afc9 which fixes some strict MSVC warnings seen in a new code, and one of the existing patches.

We can remove ConstexprMath.h`, `CacheLocality.cpp`, and the existing patch for `Hash.h` upon intake of `2023.11.06.` when that is pushed.

Folly is still being removed opportunistically from RN. We no longer use folly containers build folly futures on Android/iOS.
This moves projects in vnext to build with C++ 20 and C++ 20 coroutines. This should not impact the ABI of MSRN DLLs, but may need care for cases of Folly at legacy ABI boundary.

1. Set `<CppStandard>stdcpp20</CppStandard>` in `React.cpp.props`
2. Remove explicit usages of `/await` to opt into coroutines TS
3. Replace `std::experimental::coroutine_handle` with `std::coroutine_handle`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants