-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[lldb][windows] use Windows APIs to print to the console #149493
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
[lldb][windows] use Windows APIs to print to the console #149493
Conversation
@llvm/pr-subscribers-llvm-support @llvm/pr-subscribers-lldb Author: Charles Zablit (charles-zablit) ChangesThis patch sets the codepage of the parent Windows console to This fixes a rendering issue where the characters defined in This solution is based on this SO thread and this patch downstream. rdar://156064500 Full diff: https://github.com/llvm/llvm-project/pull/149493.diff 2 Files Affected:
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
index c0c26cc5f1954..d3e981de81313 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
@@ -41,6 +41,10 @@ LLDB_PLUGIN_DEFINE(PlatformWindows)
static uint32_t g_initialize_count = 0;
+#if defined(_WIN32)
+std::optional<UINT> g_prev_console_cp = std::nullopt;
+#endif
+
PlatformSP PlatformWindows::CreateInstance(bool force,
const lldb_private::ArchSpec *arch) {
// The only time we create an instance is when we are creating a remote
@@ -98,6 +102,7 @@ void PlatformWindows::Initialize() {
default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
Platform::SetHostPlatform(default_platform_sp);
#endif
+ SetConsoleCodePage();
PluginManager::RegisterPlugin(
PlatformWindows::GetPluginNameStatic(false),
PlatformWindows::GetPluginDescriptionStatic(false),
@@ -108,6 +113,7 @@ void PlatformWindows::Initialize() {
void PlatformWindows::Terminate() {
if (g_initialize_count > 0) {
if (--g_initialize_count == 0) {
+ ResetConsoleCodePage();
PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance);
}
}
@@ -808,3 +814,17 @@ extern "C" {
return Status();
}
+
+void PlatformWindows::SetConsoleCodePage() {
+ #if defined(_WIN32)
+ g_prev_console_cp = GetConsoleOutputCP();
+ SetConsoleOutputCP(CP_UTF8);
+ #endif
+}
+
+void PlatformWindows::ResetConsoleCodePage() {
+ #if defined(_WIN32)
+ if (g_prev_console_cp)
+ SetConsoleOutputCP(*g_prev_console_cp);
+ #endif
+}
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
index 771133f341e90..d14aa52e5e1c8 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
@@ -80,6 +80,14 @@ class PlatformWindows : public RemoteAwarePlatform {
size_t GetSoftwareBreakpointTrapOpcode(Target &target,
BreakpointSite *bp_site) override;
+ /// Set the current console's code page to UTF-8 and store the previous
+ /// codepage in \a g_prev_console_cp.
+ static void SetConsoleCodePage();
+
+ /// Reset the current console's code page to the value stored
+ /// in \a g_prev_console_cp if any.
+ static void ResetConsoleCodePage();
+
std::vector<ArchSpec> m_supported_architectures;
private:
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Windows Terminal is the default on Windows 10 at least. I think buildbot launches things in conhost, but if utf-8 there was a problem for tests, we would have seen it before now. |
From my understanding, the original issue in jq is that they did not reset the codepage after the program had exited. My patch does reset it if lldb gracefully exits. The Another temporary fix for this while we figure out a long term solution could be to force the use of the ANSI characters on windows. |
Yes that makes sense, Windows Terminal doesn't default to utf-8 either. I was thinking of something else. What if we added this new code, and it tried to set utf-8 and a test relied on that. However, this is not a problem because we already test this annotation feature via conhost and it has no problems. So even if the calls do nothing, it doesn't matter. In other words: tests on Windows aren't scraping the output of the terminal, they'll be reading strings internally and not care about the code page. Which is a good thing. |
From my understanding of the thread you linked, there are 3 ways to approach this:
|
I added |
Then setting the code page is probably the best idea, requiring the least amount of effort. As far as I know, |
Thanks for clarifying, I corrected the 4th option. 2b8c692 does not look like such big of a change, is |
A
I agree, that would probably be of a similar size here (i.e. check for the file handle and call the windows impl if needed). |
Thanks for the information! I was able to use the Windows API and the existing code from |
lldb/source/Host/common/File.cpp
Outdated
NativeFile::NativeFile(FILE *fh, bool transfer_ownership) | ||
: m_descriptor(kInvalidDescriptor), m_own_descriptor(false), m_stream(fh), | ||
m_options(), m_own_stream(transfer_ownership) { | ||
#ifdef _WIN32 | ||
int fd = _fileno(fh); | ||
is_windows_console = | ||
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR; | ||
#endif | ||
} | ||
|
||
NativeFile::NativeFile(int fd, OpenOptions options, bool transfer_ownership) | ||
: m_descriptor(fd), m_own_descriptor(transfer_ownership), | ||
m_stream(kInvalidStream), m_options(options), m_own_stream(false) { | ||
#ifdef _WIN32 | ||
is_windows_console = | ||
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR; | ||
#endif | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you not just delegate to the fd constructor? Simply inline the _fileno
call in the delegation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That isn't quite equivalent as the implementation (for better or worse), remembers whether it was constructed with a FD or a FILE* and then uses the appropriate method to implement read/write operations.
lldb/source/Host/common/File.cpp
Outdated
@@ -247,6 +248,28 @@ uint32_t File::GetPermissions(Status &error) const { | |||
return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); | |||
} | |||
|
|||
NativeFile::NativeFile() | |||
: m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you replace this with an inline initializer in the header file? Then you can just = default
the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, thanks!
Hi @Nerixyz, is there anything else I can add to this patch to get it merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't approve anything, but it works for me on Windows 11 👍
@@ -853,4 +853,6 @@ raw_ostream &operator<<(raw_ostream &OS, const std::optional<T> &O) { | |||
|
|||
} // end namespace llvm | |||
|
|||
bool write_console_impl(int FD, llvm::StringRef Data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be in some llvm
namespace - not in the global one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed by using an instance of raw_fd_ostream
instead.
@@ -853,4 +853,6 @@ raw_ostream &operator<<(raw_ostream &OS, const std::optional<T> &O) { | |||
|
|||
} // end namespace llvm | |||
|
|||
bool write_console_impl(int FD, llvm::StringRef Data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is making an internal API that only makes sense on Windows public — would be possible to just use a raw_fd_ostream in lldb::File.cpp instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using an instance of raw_fd_ostream
works. Thanks!
|
||
NativeFile::NativeFile(FILE *fh, bool transfer_ownership) | ||
: m_stream(fh), m_own_stream(transfer_ownership) { | ||
#ifdef _WIN32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a comment here explains why we do something special on Windows and (just once sentence) on why/how this works?
This patch uses the Windows APIs to print to the Windows Console, through `llvm::raw_fd_ostream`. This fixes a rendering issue where the characters defined in `DiagnosticsRendering.cpp` (`"╰"` for instance) are not rendered properly on Windows out of the box, because the default codepage is not `utf-8`. This solution is based on [this patch downstream](https://github.com/swiftlang/swift/pull/40632/files#diff-e948e4bd7a601e3ca82d596058ccb39326459a4751470eec4d393adeaf516977R37-R38). rdar://156064500
This patch uses the Windows APIs to print to the Windows Console, through `llvm::raw_fd_ostream`. This fixes a rendering issue where the characters defined in `DiagnosticsRendering.cpp` (`"╰"` for instance) are not rendered properly on Windows out of the box, because the default codepage is not `utf-8`. This solution is based on [this patch downstream](https://github.com/swiftlang/swift/pull/40632/files#diff-e948e4bd7a601e3ca82d596058ccb39326459a4751470eec4d393adeaf516977R37-R38). rdar://156064500
The following buildbots are broken after this patch Please take a look and fix. |
Please fix the issue or revert ASAP to make buildbots green. |
Could not fix it quickly enough. Opened a revert PR: #154423 |
…9493)" (#154423) This reverts commit f55dc08 in order to fix the issue reported [here](#149493 (comment)).
…onsole (#149493)" (#154423) This reverts commit f55dc08 in order to fix the issue reported [here](llvm/llvm-project#149493 (comment)).
This patch uses the Windows APIs to print to the Windows Console, through
llvm::raw_fd_ostream
.This fixes a rendering issue where the characters defined in
DiagnosticsRendering.cpp
("╰"
for instance) are not rendered properly on Windows out of the box, because the default codepage is notutf-8
.This solution is based on this patch downstream.
rdar://156064500