添加-lncurses后G++仍无法链接ncurses问题求助
我用g编译调用ncurses库的C程序时,出现链接错误,提示initscr、cbreak等ncurses函数未定义,但用clang++编译能正常通过。我已经通过源码安装了ncurses,且确认库可用。以下是编译报错信息、Makefile及代码,求解决链接问题。
编译报错输出
CC main.cpp ./main main.cpp: In function ‘int main(int, char**)’: main.cpp:34:34: warning: format not a string literal and no format arguments [-Wformat-security] 34 | wprintw(window_one, text.c_str()); | ^ main.cpp:38:34: warning: format not a string literal and no format arguments [-Wformat-security] 38 | wprintw(window_two, text.c_str()); | ^ /usr/bin/ld: /tmp/cct3HGZR.o: in function `main': /home/ubuntu/side-projects/slides/main.cpp:13: undefined reference to `initscr' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:14: undefined reference to `cbreak' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:16: undefined reference to `stdscr' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:16: undefined reference to `keypad' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:18: undefined reference to `start_color' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:19: undefined reference to `init_pair' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:21: undefined reference to `stdscr' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:21: undefined reference to `wbkgd' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:23: undefined reference to `LINES' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:24: undefined reference to `COLS' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:27: undefined reference to `printw' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:28: undefined reference to `refresh' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:33: undefined reference to `wmove' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:34: undefined reference to `wprintw' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:35: undefined reference to `wrefresh' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:37: undefined reference to `COLS' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:37: undefined reference to `COLS' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:37: undefined reference to `LINES' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:38: undefined reference to `wprintw' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:39: undefined reference to `wrefresh' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:41: undefined reference to `stdscr' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:41: undefined reference to `wgetch' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:45: undefined reference to `endwin' /usr/bin/ld: /tmp/cct3HGZR.o: in function `create_newwin(int, int, int, int)': /home/ubuntu/side-projects/slides/main.cpp:52: undefined reference to `newwin' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:53: undefined reference to `box' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:55: undefined reference to `wrefresh' /usr/bin/ld: /tmp/cct3HGZR.o: in function `destroy_win(_win_st*)': /home/ubuntu/side-projects/slides/main.cpp:60: undefined reference to `wborder' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:61: undefined reference to `wrefresh' /usr/bin/ld: /home/ubuntu/side-projects/slides/main.cpp:62: undefined reference to `delwin' collect2: error: ld returned 1 exit status make: *** [Makefile:9: all] Error 1
Makefile内容
CC = g++ CFLAGS = -g -lncurses -Wall SRC = main.cpp OUT = ./main .PHONY: all all: ${SRC} @echo "CC " ${SRC} ${OUT} @${CC} ${CFLAGS} ${SRC} -o ${OUT} @echo "Done" .PHONY: clean clean: @echo "Cleaning Directory" @rm -rf ${OUT} @echo "Done"
C++代码
#include <ncurses.h> #include <string> WINDOW *create_newwin(int height, int width, int starty, int startx); void destroy_win(WINDOW *local_win); int main(int argc, char *argv[]) { WINDOW *window_one; WINDOW *window_two; int startx, starty, width, height; int ch; initscr(); cbreak(); keypad(stdscr, TRUE); start_color(); init_pair(1, COLOR_BLUE, COLOR_RED); bkgd(COLOR_PAIR(1)); height = LINES; width = COLS / 2; starty = 0; startx = 0; printw("Press F1 to exit"); refresh(); window_one = create_newwin(height, width, starty, startx); std::string text = "test"; wmove(window_one, height / 2, text.size() / 2); wprintw(window_one, text.c_str()); wrefresh(window_one); window_two = create_newwin(LINES, COLS / 2, 0, COLS / 2); wprintw(window_two, text.c_str()); wrefresh(window_two); while((ch = getch()) != KEY_F(1)) { switch(ch) {} } endwin(); return 0; } WINDOW *create_newwin(int height, int width, int starty, int startx) { WINDOW *local_win; local_win = newwin(height, width, starty, startx); box(local_win, 0, 0); wrefresh(local_win); return local_win; } void destroy_win(WINDOW *local_win) { wborder(local_win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); wrefresh(local_win); delwin(local_win); }
解决方案
问题根源
g和clang在处理链接库参数的顺序上有差异:链接库参数-lncurses必须放在源文件/目标文件之后。你的Makefile里把-lncurses放在了CFLAGS中,编译时会先于源文件main.cpp被处理,导致g无法正确找到ncurses库中的符号;而clang对参数顺序的容错性更高,所以能正常编译。
另外,源码安装的ncurses可能不在系统默认的库搜索路径中,需要额外指定头文件和库的路径。
修复步骤
调整Makefile的参数顺序:
将链接库参数从CFLAGS中分离出来,单独用LDFLAGS存放,并且编译时将LDFLAGS放在源文件之后。如果是源码安装的ncurses,还需要添加-I指定头文件路径(比如/usr/local/include),-L指定库路径(比如/usr/local/lib)。修改后的Makefile:
CC = g++ CFLAGS = -g -Wall # 如果源码安装的ncurses不在默认路径,取消下面两行注释 # INCLUDES = -I/usr/local/include # LDFLAGS = -L/usr/local/lib -lncurses # 如果是系统默认路径,直接用下面的LDFLAGS LDFLAGS = -lncurses SRC = main.cpp OUT = ./main .PHONY: all all: ${SRC} @echo "CC " ${SRC} ${OUT} @${CC} ${CFLAGS} ${INCLUDES} ${SRC} -o ${OUT} ${LDFLAGS} @echo "Done" .PHONY: clean clean: @echo "Cleaning Directory" @rm -rf ${OUT} @echo "Done"验证库路径(可选):
如果源码安装后还是找不到库,可以用ncursesw-config --cflags --libs命令获取正确的编译和链接参数,替换到Makefile中:# 执行该命令会输出类似内容: # -I/usr/local/include/ncursesw -L/usr/local/lib -lncursesw把输出的参数分别对应到
INCLUDES和LDFLAGS中即可。解决格式安全警告(可选):
编译时的-Wformat-security警告,是因为wprintw需要格式字符串。可以把代码中的wprintw(window_one, text.c_str());改为wprintw(window_one, "%s", text.c_str());,消除警告。
内容的提问来源于stack exchange,提问作者boomcreeper11

