8

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

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

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

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

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

谢谢你的帮助!

4

4 回答 4

13

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

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

因此,需要启动 Terminal.app,在那里执行我们的进程并将调试器附加到它。可以通过Scheme setup来实现。我在 Xcode 11.4 中做到了。我创建了一个新的 macOS 命令行工具项目,基于Language: C++. 我libncurses.tbd还在Frameworks and Libraries.

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

Pre-actions在方案中选择Run并添加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' &

在此处输入图像描述

要在调试会话结束时选择关闭终端,请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'

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

您可能还会遇到调试器附加问题。我不知道 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_woraround调用超时 700 毫秒。我尝试了不同的值,发现 500 ms 是不可跳过的最小时间pselect。也许这个超时取决于机器,我不知道。您可以通过或通过其他一些检查来包装此调用#ifdef ... #endif,也许通过特殊的命令行参数检查来排除发布模式下的一点等待开销。

于 2015-08-12T17:19:47.903 回答
5

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

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

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

ps x | grep lldb

然后

kill 12345

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

于 2016-09-15T11:39:58.047 回答
4

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

./build/Debug/myprogram

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

gdb> attach mypid

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

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

于 2011-04-29T18:52:52.597 回答
0

继续 Peter Hull 的回答,在 Scheme->Run->Options 中选择“Console - Use Terminal”也对我有用。

关于没有正确退出的 lldb-rpc-server:可以简单地将以下内容添加到 Product->Scheme->Edit Scheme->Run->Post-actions:

ps -ef |grep lldb-rpc-server |grep -v grep | awk '{print $2}' | sort -rn | while read PID ; do kill $PID ; done

这将找到 lldb-rpc-server 进程,无论如何它都应该归您的用户 ID 所有,以相反的顺序对它们进行排序,然后简单地分派它们。

Xcode-Run-PostAction-kill-lldb-rpc-server

这对我帮助很大!我希望它也能帮助别人!

-TechnoPak

于 2020-10-14T10:38:24.497 回答