【问题标题】:Xcode and Curses.h with Error opening terminalXcode 和 Curses.h 打开终端时出错
【发布时间】:2011-06-22 14:33:30
【问题描述】:

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

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

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

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

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

感谢您的帮助!

【问题讨论】:

    标签: xcode macos gcc terminal curses


    【解决方案1】:

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

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

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

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

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

    要在调试会话结束时选择关闭终端,请在 Run 方案中选择 Post-actions 并添加 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 毫秒是不跳过pselect 的最小时间。也许这个超时取决于机器,我不知道。您可以通过#ifdef ... #endif 或其他一些检查来包装此调用,也许通过特殊的命令行参数检查来排除释放模式下的一点等待开销。

    【讨论】:

    • 玩得很好@C0DEF52。这是很多啤酒花,但它们仍然有效,在您发布 4 年后。如果没有这些步骤,使用Xcodencurses 将是零乐趣。
    • @rustyMagnet 很高兴您发现该解决方案很有用。
    【解决方案2】:

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

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

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

    ps x | grep lldb
    

    然后

    kill 12345
    

    12345 是 ps 给我的进程 ID。

    【讨论】:

    • 不错的发现。有同样的问题——实际上没有用,但很高兴知道他们正在解决这个问题。在它没有做很多事情之后,还必须杀死你提到的进程。
    • 很高兴不仅仅是我。我猜大约有 20% 的时间我必须终止该进程。即使它确实“工作”,调试器也经常触发我没想到的信号(主要是 SIGSTOP)。等待 XCode 9 (!)
    【解决方案3】:

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

    ./build/Debug/myprogram
    

    如果您想使用 IDE 调试器(即 gdb),您可以附加 到过程。先获取进程id,

    gdb> attach mypid
    

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

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

    【讨论】:

      【解决方案4】:

      按照 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 所有,以相反的顺序对它们进行排序,然后简单地分派它们。

      这对我帮助很大!我希望它也对其他人有所帮助!

      -TechnoPak

      【讨论】:

        猜你喜欢
        • 2017-02-07
        • 2011-10-10
        • 2021-11-27
        • 1970-01-01
        • 1970-01-01
        • 2015-04-19
        • 2011-10-11
        • 2019-06-27
        相关资源
        最近更新 更多