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

Support console stderr redirection #169

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions ctru-rs/src/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
//! The [`Console`] works as a virtual shell that renders on screen all output of `stdout`. As such, it is useful as a basic interface to show info to the user,
//! such as in simple "Hello World" applications or more complex software that does not need much user interaction.
//!
//! Have a look at [`Soc::redirect_to_3dslink()`](crate::services::soc::Soc::redirect_to_3dslink) for a better alternative when debugging applications.

//! Have a look at [`redirect_stderr`] or [`Soc::redirect_to_3dslink`](crate::services::soc::Soc::redirect_to_3dslink) for better alternatives when debugging applications.
use std::cell::{RefMut, UnsafeCell};

use ctru_sys::{consoleClear, consoleInit, consoleSelect, consoleSetWindow, PrintConsole};
use ctru_sys::{
consoleClear, consoleDebugInit, consoleInit, consoleSelect, consoleSetWindow, PrintConsole,
};

use crate::services::gfx::{Flush, Screen, Swap};

Expand Down Expand Up @@ -38,6 +39,18 @@ pub enum Dimension {
Height,
}

/// Destination for stderr redirection with [`redirect_stderr`].
#[doc(alias = "debugDevice")]
#[repr(u32)]
pub enum Destination {
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if we should call this Destination or Redirect or what. I'm open to suggestions about that.

Copy link
Member

Choose a reason for hiding this comment

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

Destination or RedirectTarget maybe?

Also I doubt more would ever be added but maybe #[non_exhaustive] would be good, in case we wanted to make e.g. a Socket target that would use redirect_to_3dslink under the hood or something like that

/// Print stderr to the active [`Console`] window. This is the default behavior.
Console = ctru_sys::debugDevice_CONSOLE,
/// Print stderr via [`ctru_sys::svcOutputDebugString`]. This allows you to capture error and panic messages with `GDB` or other debuggers.
Debugger = ctru_sys::debugDevice_SVC,
/// Swallow outputs from stderr.
Null = ctru_sys::debugDevice_NULL,
}

/// A [`Screen`] that can be used as a target for [`Console`].
pub trait ConsoleScreen: Screen + Swap + Flush {}
impl<S: Screen + Swap + Flush> ConsoleScreen for S {}
Expand Down Expand Up @@ -66,6 +79,12 @@ pub struct Console<'screen> {
screen: RefMut<'screen, dyn ConsoleScreen>,
}

/// Send output from stderr to the specified [`Destination`]. This function can be used to capture error and panic messages with `GDB` or other debuggers.
#[doc(alias = "consoleDebugInit")]
pub fn redirect_stderr(dest: Destination) {
unsafe { consoleDebugInit(dest as _) }
}
Copy link
Member

Choose a reason for hiding this comment

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

This looks fine to me offhand, I wonder how it behaves if you also use redirect_to_3dslink with stderr = true ? I think they use the same mechanism under the hood, so maybe whichever you call first gets overridden by the second one?

Copy link
Member Author

@FenrirWolf FenrirWolf Mar 15, 2024

Choose a reason for hiding this comment

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

I took a look inside libctru and the mechanisms are dfferent. consoleDebugInit changes the underlying devoptab for stderr and 3dslinkConnectToHost replaces stderr's file descriptor via dup2. So unless I'm mistaken, 3dslink redirection will always take priority over console redirection.

Copy link
Member

Choose a reason for hiding this comment

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

That behaviour should be properly documented.


impl<'screen> Console<'screen> {
/// Initialize a console on the chosen screen.
///
Expand Down
Loading