Xcode 和 Curses.h 打开终端时出错

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4919373/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 20:11:30  来源:igfitidea点击:

Xcode and Curses.h with Error opening terminal

xcodemacosgccterminalcurses

提问by archieoi

I am trying to compile a simple curse project with Xcode.
The program compiles fine with g++ in terminal with the flag -lcurses, and runs fine.

我正在尝试使用 Xcode 编译一个简单的 curse 项目。
该程序在带有标志 -lcurses 的终端中使用 g++ 编译良好,并且运行良好。

Started of by creating a Command Line Tool with type c++.
imported curses.h into my main.
In the Target"program"Info -> General -> Linked Libraries, libCurses.dylib has been added.

首先创建一个 C++ 类型的命令行工具。
将curses.h 导入到我的主目录中。
在 Target"program"Info -> General -> Linked Libraries 中,添加了 libCurses.dylib。

It compiles fine but the terminal window will not open.
In the Debug Console the output is,

它编译正常,但终端窗口不会打开。
在调试控制台中,输出是,

Program loaded.
run
[Switching to process 3424]
Error opening terminal: unknown.
Running…

程序加载。
运行
[切换到进程 3424]
打开终端时出错:未知。
跑步…

I can go to build folder and just open the program in terminal but is there any way for xcode to open the terminal?

我可以去构建文件夹并在终端中打开程序但是xcode有什么方法可以打开终端吗?

Thanks for any help!

谢谢你的帮助!

回答by C0DEF52

I had the same problem with ncurses debugging in Xcode. Finally I've found a good way for me to manage debugging with Terminal.app that allows to debug ncurses.

我在 Xcode 中调试 ncurses 时遇到了同样的问题。最后,我找到了一种使用 Terminal.app 管理调试的好方法,它允许调试 ncurses。

As we know, to initialise and use ncurses we need to run our application in terminal. But Xcode doesn't open terminal when we press run button. So, if we request environment variable TERMfrom code, we'll get NULL. This is why application crashes on initscr().

众所周知,要初始化和使用 ncurses,我们需要在终端中运行我们的应用程序。但是当我们按下运行按钮时,Xcode 不会打开终端。所以,如果我们TERM从代码中请求环境变量,我们会得到NULL. 这就是应用程序崩溃的原因initscr()

So, it is needed to launch Terminal.app, execute our process there and attach a debugger to it. It can be achieved through Scheme setup. I did it in Xcode 11.4. I created a new macOS Command Line Tool project based on Language:C++. Also I added libncurses.tbddependency in Frameworks and Libraries.

因此,需要启动 Terminal.app,在那里执行我们的进程并为其附加调试器。可以通过 Scheme 设置来实现。我是在 Xcode 11.4 中完成的。我创建了一个基于Language:C++. 我libncurses.tbd还在Frameworks and Libraries.

Go to Product > Scheme > Edit scheme..., select Runscheme and Runaction and navigate to Infotab. You'll see Launchset to Automatically. Change it to Wait for the executable to be launched. enter image description here

转到Product > Scheme > Edit scheme...,选择Run方案和Run操作并导航到Info选项卡。你会看到Launch设置为Automatically。将其更改为Wait for the executable to be launched. 在此处输入图片说明

Select Pre-actionsin the Runscheme and add New Run Script Action. Change Provide build settings fromfrom Noneto your build target. Add the following code there:

Pre-actionsRun方案中选择并添加New Run Script Action. 更改Provide build settings fromNone您的构建目标。在那里添加以下代码:

osascript -e 'tell application "Terminal"' -e 'delay 0.5' -e 'activate' -e "do script (\"$TARGET_BUILD_DIR/$PRODUCT_NAME\")" -e 'end tell' &

enter image description here

在此处输入图片说明

To optionally close terminal in the end of debugging session select Post-actionsin the Runscheme and add New Run Script Action. Add the following code:

要在调试会话结束时选择性地关闭终端,请Post-actionsRun方案中选择并添加New Run Script Action. 添加以下代码:

osascript -e 'activate application "Terminal"' -e 'delay 0.5' -e 'tell application "System Events"' -e 'tell process "Terminal"' -e 'keystroke "w" using {command down}' -e 'end tell' -e 'end tell'

enter image description hereActually osascript will always create at least two terminal windows but if you will leave the first one opened it will create and destroy the second one with your session automatically through Pre and Post actions.

在此处输入图片说明实际上 osascript 将始终创建至少两个终端窗口,但是如果您将第一个窗口保持打开状态,它将通过 Pre 和 Post 操作自动创建和销毁第二个与您的会话。

You will probably also meet a problem with debugger attaching. I don't know exact reason why Xcode don't want to attach debugger when process executes externally but I found this issue. Also I found stdinstream in weird state during debugging session beginning as well. So, I wrote a workaround based on pselectcall. I'm asking stdinfor any data until it doesn't return success. I found that after these manipulations debugger will feel OK and stdinrequests will be OK as well. Here is my code example:

您可能还会遇到调试器附加问题。我不知道为什么 Xcode 在外部执行进程时不想附加调试器的确切原因,但我发现了这个问题。我还在stdin调试会话开始期间发现流处于奇怪的状态。所以,我写了一个基于pselect调用的解决方法。我要求stdin提供任何数据,直到它不返回成功为止。我发现在这些操作之后,调试器会感觉正常,stdin请求也会正常。这是我的代码示例:

#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>

bool g_has_terminal = false; // Check this global variable before ncurses calls

bool ensure_debugger_attached_woraround(int timeout_ms)
{
    fd_set fd_stdin;
    FD_ZERO(&fd_stdin);
    FD_SET(STDIN_FILENO, &fd_stdin);
    struct timespec timeout = { timeout_ms / 1000, (timeout_ms % 1000) * 1000000 };

    do
    {
        errno = 0;
    }
    while (pselect(STDIN_FILENO + 1, &fd_stdin, NULL, NULL, &timeout, NULL) < 0 && errno == EINTR);

    if (errno != 0)
    {
        fprintf(stderr, "Unexpected error %d", errno);
        return false;
    }

    return true;
}

int main(int argc, const char *argv[])
{
    if (!ensure_debugger_attached_woraround(700))
        return 1;

    char *term = getenv("TERM");

    g_has_terminal = (term != NULL);

    if (g_has_terminal)
        g_has_terminal = (initscr() != NULL);

    // Some ncurses code. Maybe you should terminate if g_has_terminal is not set

    if (g_has_terminal)
    {
        printw("Press any key to exit...");
        refresh();

        getch();

        endwin();
    }

    return 0;
}

ensure_debugger_attached_woraroundis called with a timeout 700 milliseconds. I tried different values and found 500 ms is the minimal one to not skip pselect. Maybe this timeout is machine depended I don't know. You can wrap this call by #ifdef ... #endifor by some other checks, maybe by special command line argument check to exclude a little wait overhead in the release mode.

ensure_debugger_attached_woraround调用超时 700 毫秒。我尝试了不同的值,发现 500 ms 是不跳过的最小值pselect。也许这个超时取决于机器我不知道。您可以通过#ifdef ... #endif或通过其他一些检查来包装这个调用,也许通过特殊的命令行参数检查来排除释放模式下的一些等待开销。

回答by wayne

There is no terminal to attach to in the Xcode IDE. Instead run the program from a shell (via Terminal application)

在 Xcode IDE 中没有要附加的终端。而是从 shell 运行程序(通过终端应用程序)

./build/Debug/myprogram

If you want to use the IDE debugger (which is just gdb) you can attach to the process. Fist get the process id,

如果您想使用 IDE 调试器(只是 gdb),您可以附加到该进程。拳头获取进程ID,

gdb> attach mypid

For a more convenient method, I'll quote Step into Xcode: Mac OS X development

为了更方便的方法,我将引用 Step into Xcode: Mac OS X development

Open the Executables group in the Groups & Fileslist, select the application, open an Info window, and in the Debugging tab, uncheck Start executable after starting debugger. When you're ready to debug, start the debugger, and then then launch the target application in its friendly environment. In the debugger's gdb console, type attach myprogram, and your debugging sesssion is under way.

打开Groups & Files列表中的 Executables 组 ,选择应用程序,打开 Info 窗口,然后在 Debugging 选项卡中,取消选中Start executable after started debugger。当您准备好调试时,启动调试器,然后在友好的环境中启动目标应用程序。在调试器的 gdb 控制台中,输入attach myprogram,您的调试会话正在进行中。

回答by Peter Hull

In XCode 8 you can choose to run within the terminal, from the Edit Scheme... Options page. XCode 8 screenshot

在 XCode 8 中,您可以选择在终端内运行,从 Edit Scheme... Options 页面。 XCode 8 截图

Though in my quick testing it doesn't seem to work all that well; it sometimes (not always) seems to 'lose' the debuggee, or the debuggee never starts, and thinks it's still running. If you try to exit, Xcode gets stuck. I have found that if you find and then kill a process called lldb-rpc-serveryou can avoid having to force-quit.

虽然在我的快速测试中它似乎并没有那么好;它有时(并非总是)似乎“丢失”了被调试对象,或者被调试对象从未启动,并认为它仍在运行。如果您尝试退出,Xcode 会卡住。我发现,如果您找到并杀死一个名为的进程lldb-rpc-server,则可以避免强制退出。

In more detail (in case this helps anyone) whenever the debuggee fails to start, I open a Terminal and type

更详细地(以防这对任何人有帮助)每当调试对象无法启动时,我都会打开一个终端并键入

ps x | grep lldb

then

然后

kill 12345

where 12345is the process ID that ps gives me.

12345ps 给我的进程 ID在哪里。