Search code examples
cmacosmenuclangncurses

Clang on macOS fails linking lmenu from ncurses


I'm new to using the ncurses library, so I've been trying to recreate some of the examples on this page, http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/index.html.

I've gotten the section about creating menus, specifically example 21. The program I've written works on Linux, specifically Ubuntu 18.04, but I'm not able to compile when I'm using the Menu library. All the other example programs I've written using JUST ncurses compiles fine without issue, it's just when I try to use the Menu library.

The command I'm using to build on Linux and macOS is,

gcc libmenutest.c -o test -lmenu -lncurses

I've tried moving -lmenu -lncurses about and changing the order on macOS to no success. I've installed ncurses via brew and tried using gcc-8 from brew, but no success there either.

I'm running a practically fresh install of macOS and the latest command line tools. I can see libmenu in /usr/lib, same as libncurses. So I'm really confused why the compiler isn't find it.

Here's some test code I've been trying to diagnose the problem with.

#include <curses.h>
#include <menu.h>
#include <stdlib.h>

#define ARRAY_SIZE(a) (sizeof a / sizeof a[0])

int main (void)
{
  int i;
  int nchoices;

  char *choices[] = {
    "Choice 1", "Choice 2", "Choice 3", "Exit", (char *) NULL,
  };

  // Test that the types are present, this should test for the include headers
  ITEM **items;
  MENU *menu;
  WINDOW *win;

  // This will test for includes and to see if libncurses can be linked
  initscr ();
  noecho ();
  cbreak ();
  keypad (stdscr, TRUE);

  // this bit will test for libmenu include and if it can be linked
  nchoices = ARRAY_SIZE (choices);
  items = calloc (nchoices, sizeof (ITEM *));
  if (items == NULL) exit (1);
  for (i = 0; i < nchoices; i++)
    items[i] = new_item (choices[i], choices[i]);

  // write smarmy message to screen :^^^^^^)
  printw ("This worked :^)");
  refresh ();
  getch ();

  // clean up
  for (i = 0; i < nchoices; i++)
    free_item (items[i]);
  endwin ();

  return 0;
}

Here's the output which I'm getting right now...

Undefined symbols for architecture x86_64:
  "_free_item", referenced from:
      _main in libmenutest-0f0c39.o
  "_new_item", referenced from:
      _main in libmenutest-0f0c39.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Solution

  • You can do the following:

    brew install ncurses
    

    Since macOS already contains a ncurses version brew installs its alternative version in /usr/local/opt/ncurses.

    So that the compiler and linker can access it, your build command should now look like this:

    gcc -I/usr/local/opt/ncurses/include -L/usr/local/opt/ncurses/lib libmenutest.c -o test -lmenu -lncurses
    

    When you finally call your program, the following is output:

    This worked :^) 
    

    CMake

    For the folks using CMake your CMakeLists.txt could look like this:

    cmake_minimum_required(VERSION 3.14)
    project(libmenutest C)
    
    set(CMAKE_C_STANDARD 99)
    
    include_directories(/usr/local/opt/ncurses/include)
    
    link_directories(/usr/local/opt/ncurses/lib)
    
    add_executable(libmenutest libmenutest.c)
    
    target_link_libraries(libmenutest menu ncurses)