Xcode and Curses.h with Error opening terminal
I am开发者_StackOverflow中文版 trying to compile a simple curse project with Xcode.
The program compiles fine with g++ in terminal with the flag -lcurses, and runs fine.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.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…I can go to build folder and just open the program in terminal but is there any way for xcode to open the terminal?
Thanks for any help!
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.
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 TERM
from code, we'll get NULL
. This is why application crashes on 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.tbd
dependency in Frameworks and Libraries
.
Go to Product > Scheme > Edit scheme...
, select Run
scheme and Run
action and navigate to Info
tab. You'll see Launch
set to Automatically
. Change it to Wait for the executable to be launched
.
Select Pre-actions
in the Run
scheme and add New Run Script Action
. Change Provide build settings from
from None
to your build target. Add the following code there:
osascript -e 'tell application "Terminal"' -e 'delay 0.5' -e 'activate' -e "do script (\"$TARGET_BUILD_DIR/$PRODUCT_NAME\")" -e 'end tell' &
To optionally close terminal in the end of debugging session select Post-actions
in the Run
scheme and add New Run Script Action
. Add the following code:
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'
Actually 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.
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 stdin
stream in weird state during debugging session beginning as well. So, I wrote a workaround based on pselect
call. I'm asking stdin
for any data until it doesn't return success. I found that after these manipulations debugger will feel OK and stdin
requests will be OK as well. Here is my code example:
#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
is 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 ... #endif
or by some other checks, maybe by special command line argument check to exclude a little wait overhead in the release mode.
In XCode 8 you can choose to run within the terminal, from the Edit Scheme... Options page.
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-server
you can avoid having to force-quit.
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 12345
is the process ID that ps gives me.
There is no terminal to attach to in the Xcode IDE. Instead run the program from a shell (via Terminal application)
./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,
gdb> attach mypid
For a more convenient method, I'll quote Step into Xcode: Mac OS X development
Open the Executables group in the Groups & Files list, 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.
Follow on to Peter Hull's answer, selecting "Console - Use Terminal" in the Scheme->Run->Options worked for me too.
Regarding the lldb-rpc-server which does not exit properly: One can simply add the following to the 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
This will find the lldb-rpc-server processes, which should be owned by your userid anyway, sort them in reverse order, and simply dispatch them.
This helped me a lot! I hope it helps someone else too!
-TechnoPak
精彩评论