Xcode和Curses.h打开终端时出错
我正在尝试用Xcode编译一个简单的诅咒项目。Xcode和Curses.h打开终端时出错,xcode,macos,gcc,terminal,curses,Xcode,Macos,Gcc,Terminal,Curses,我正在尝试用Xcode编译一个简单的诅咒项目。 该程序在带有-lcurses标志的终端中使用g++进行良好编译,并且运行良好。 创建了一个C++类型的命令行工具。 将curses.h导入我的main。 在目标“程序”信息->常规->链接库中,添加了libCurses.dylib 它可以正常编译,但终端窗口不会打开。 在调试控制台中,输出为, 已加载程序。 运行 [切换到流程3424] 打开终端时出错:未知。 正在运行… 我可以进入build文件夹,在terminal中打开程序,但是xcode有没
该程序在带有-lcurses标志的终端中使用g++进行良好编译,并且运行良好。
创建了一个C++类型的命令行工具。
将curses.h导入我的main。
在目标“程序”信息->常规->链接库中,添加了libCurses.dylib
在调试控制台中,输出为,
已加载程序。
运行
[切换到流程3424]
打开终端时出错:未知。
正在运行…
我可以进入build文件夹,在terminal中打开程序,但是xcode有没有办法打开终端 谢谢你的帮助!
Xcode IDE中没有要连接的终端。 而是从shell运行程序(通过终端应用程序) 如果您想使用IDE调试器(只是gdb),您可以附加 这是一个过程。首先获取进程id
gdb> attach mypid
为了获得更方便的方法,我将引用Xcode:MacOSX开发的步骤
在中打开可执行文件组
组和文件列表,选择应用程序,打开信息窗口,然后
在“调试”选项卡中,取消选中“开始”
启动调试器后可执行。
准备调试时,启动
调试器,然后启动
智能交通系统中的目标应用
环境在调试器的gdb中
控制台,键入attach myprogram,和
您的调试任务正在进行中
我在Xcode中调试ncurses时也遇到同样的问题。最后,我找到了一种使用Terminal.app管理调试的好方法,它允许调试ncurses 正如我们所知,要初始化和使用ncurses,我们需要在终端上运行我们的应用程序。但当我们按下运行按钮时,Xcode并没有打开终端。所以,如果我们从代码中请求环境变量
TERM
,我们将得到NULL
。这就是应用程序在initscr()上崩溃的原因
因此,需要启动Terminal.app,在那里执行我们的流程,并将调试器附加到它。可以通过方案设置来实现。我是在Xcode 11.4中完成的。我基于语言:
C++
创建了一个新的macOS命令行工具项目。我还在框架和库中添加了libncurses.tbd
依赖项
转到Product>Scheme>Edit Scheme…
,选择Run
Scheme和Run
action并导航到Info
选项卡。您将看到Launch
自动设置为。将其更改为等待启动可执行文件
。
在运行
方案中选择预操作
,然后添加新运行脚本操作
。将提供构建设置从从无更改为构建目标。在此处添加以下代码:
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
call编写了一个变通方法。我要求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;
}
#包括
#包括
#包括
#包括
#包括
#包括
bool g_has_terminal=false;//在调用ncurses之前检查此全局变量
bool确保\u调试器\u已连接\u工作区(int超时\u毫秒)
{
fd_设置fd_标准;
FD_ZERO(和FD_stdin);
FD_集(标准文件号和标准文件号);
结构timespec timeout={timeout\u ms/1000,(timeout\u ms%1000)*1000000};
做
{
errno=0;
}
而(pselect(STDIN\u FILENO+1,&fd\u STDIN,NULL,NULL,&timeout,NULL)<0&&errno==EINTR);
如果(错误号!=0)
{
fprintf(标准,“意外错误%d”,错误号);
返回false;
}
返回true;
}
int main(int argc,const char*argv[]
{
如果(!确保安装了调试器(700))
返回1;
char*term=getenv(“术语”);
g_有_终端=(term!=NULL);
如果(g_有_终端)
g_具有_端子=(initscr()!=NULL);
//一些ncurses代码。如果g_has_终端未设置,可能应该终止
如果(g_有_终端)
{
printw(“按任意键退出…”);
刷新();
getch();
endwin();
}
返回0;
}
确保调用\u debugger\u attached\u worround
时超时700毫秒。我尝试了不同的值,发现500毫秒是不可跳过的最小值pselect
。也许这个超时是由机器决定的,我不知道。您可以通过#ifdef#endif
或其他一些检查,可能通过特殊的命令行参数检查,以排除释放模式中的一些等待开销。在XCode 8中,您可以选择在终端内运行,从编辑方案。。。选项页。
尽管在我的快速测试中,它似乎并不那么有效;它有时(并非总是)似乎“丢失”调试对象,或者调试对象从未启动,并认为它仍在运行。如果您试图退出,Xcode就会被卡住。我发现,如果找到并杀死一个名为lldb rpc server
的进程,就可以避免强制退出
更详细地说(如果这对任何人都有帮助),只要调试对象无法启动
#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;
}
ps x | grep lldb
kill 12345