1

I'm working with a device that provides conio.h, conio.c. In my c++ code, whenever I call getch(), I get these errors

/usr/bin/ld: CMakeFiles/hello.dir/main.cpp.o: undefined reference to symbol '_Z5getchv'
//usr/lib/libPhantomIOLib42.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
CMakeFiles/hello.dir/build.make:96: recipe for target 'hello' failed
make[2]: *** [hello] Error 1
CMakeFiles/Makefile2:82: recipe for target 'CMakeFiles/hello.dir/all' failed
make[1]: *** [CMakeFiles/hello.dir/all] Error 2
Makefile:90: recipe for target 'all' failed
make: *** [all] Error 2

I know conio is not standard but it seems the company addresses the OS issue by

#if defined(WIN32)
#include <windows.h>
#include <conio.h>
#else
#include "conio.h"
#include <string.h"
#endif

where conio.h is

#ifndef __CONIO_H_
#define __CONIO_H_

#ifdef _cplusplus
extern "C" {
#endif // _cplusplus

int _kbhit();
int getch();

#ifdef _cplusplus
}
#endif // _cplusplus

#endif // __CONIO_H

and conio.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

static struct termios term_attribs, term_attribs_old;

static void restore_term(void)
{
    if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_attribs_old) < 0)
    {
        perror("tcsetattr: ");
        exit(-1);
    }
}

int _kbhit()
{
    static int initialized;
    
    fd_set rfds;
    struct timeval tv;
    int retcode;
    
    if(!initialized)
    {
        if(tcgetattr(STDIN_FILENO, &term_attribs) < 0)
        {
            perror("tcgetattr: ");
            exit(-1);
        }

        term_attribs_old = term_attribs;

        if(atexit(restore_term))
        {
            perror("atexit: ");
            exit(-1);
        }

        term_attribs.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
        term_attribs.c_iflag &= ~(IXON | BRKINT | INPCK | ICRNL | ISTRIP);
        term_attribs.c_cflag &= ~(CSIZE | PARENB);
        term_attribs.c_cflag |= CS8;
        term_attribs.c_cc[VTIME] = 0;
        term_attribs.c_cc[VMIN] = 0;

        if(tcsetattr(STDIN_FILENO, TCSANOW, &term_attribs) < 0)
        {
            perror("tcsetattr: ");
            exit(-1);
        }

        initialized = 1;
    }   

    FD_ZERO(&rfds);
    FD_SET(STDIN_FILENO, &rfds);
    memset(&tv, 0, sizeof(tv));
    
    retcode = select(1, &rfds, NULL, NULL, &tv);
    if(retcode == -1 && errno == EINTR)
    {
        return 0;
    }
    else if(retcode < 0)
    {
        perror("select: ");
        exit(-1);
    }
    else if(FD_ISSET(STDIN_FILENO, &rfds))
    {
        return retcode;
    }
    
    return 0;
}

int getch()
{
    fd_set rfds;
    int retcode;

    FD_ZERO(&rfds);
    FD_SET(STDIN_FILENO, &rfds);
    
    retcode = select(1, &rfds, NULL, NULL, NULL);
    if(retcode == -1 && errno == EINTR)
    {
        return 0;
    }
    else if(retcode < 0)
    {
        perror("select: ");
        exit(-1);
    }

    return getchar();
}

My CMakeLists.txt is

cmake_minimum_required(VERSION 3.10)
project(project2 VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_FLAGS "-W -O2 -DNDEBUG -Dlinux")
add_executable(hello main.cpp conio.c conio.h)
target_link_libraries(hello HDU HD rt ncurses stdc++ m)

From the conio., I see _cplusplus which should address the c++ code. Why there an error and to fix it? My OS is ubuntu 18.04. One of the Makefiles provided by the company is

CXX=g++
CXXFLAGS+=-W -fexceptions -O2 -DNDEBUG -Dlinux -Iinclude
LIBS = -lHDU -lHD -lrt -lncurses -lstdc++ -lm

TARGET=ServoLoopDutyCycle
HDRS=include/StatsSampler.h
SRCS=src/ServoLoopDutyCycle.cpp \
     src/StatsSampler.cpp \
     src/conio.c
OBJS=$(patsubst %.cpp,%.o,$(patsubst %.c,%.o,$(SRCS)))

.PHONY: all
all: $(TARGET)

$(TARGET): $(SRCS)
    $(CXX) $(CXXFLAGS) -o $@ $(SRCS) $(LIBS)

.PHONY: clean
clean:
    -rm -f $(OBJS) $(TARGET)
CroCo
  • 5,531
  • 9
  • 56
  • 88
  • The missing symbol is `getch()` and it's defined in ncurses, so something goes wrong when trying to link with ncurses. Edit: Wait a second - you've defined your own `getch()` but still try to link with ncurses? – Ted Lyngmo Mar 31 '22 at 19:56
  • @TedLyngmo this is what I'm expecting. The examples provided by the company link against `ncurses` yet uses the customized header for `conio.h`. Is this correct ? – CroCo Mar 31 '22 at 19:58
  • No, you'll have two definitions of `getch()` but it seems it fails to find any of them – Ted Lyngmo Mar 31 '22 at 19:58
  • but the code works fine in c compiler using their Makefile. May be the issue from my CMakeLists? – CroCo Mar 31 '22 at 19:59
  • @TedLyngmo please the Makefile provide by the company but it seems to me it is similar to my CMakeLists. – CroCo Mar 31 '22 at 20:06
  • 3
    Note that the symbol name is *mangled*, the compiler thinks it is a C++ function. It isn't. You need `extern "C"`. – Hans Passant Mar 31 '22 at 20:06
  • @HansPassant there is `extern "C"` in the code unless if there is a flag needs to be passed. – CroCo Mar 31 '22 at 20:08
  • 2
    Wow, the solution was a typo. You forgot one underscore in `__cplusplus` :-D – Ted Lyngmo Mar 31 '22 at 20:10
  • @TedLyngmo this is from the company files. Does it make any difference? – CroCo Mar 31 '22 at 20:11
  • It doesn't matter where the files come from. `_cplusplus` doesn't have any impact on the compiler and it'll search for those functions with c++ linkage. Make it `__cplusplus` in `conio.h` and everything works. – Ted Lyngmo Mar 31 '22 at 20:13
  • @TedLyngmo wow it did solve the issue but I'm checking the company's library, there are a lot of `conio.h` copies and all of them have one underscore. Is this a typo? I'm curious because when I run their codes, they work fine. See the Makefile I've provided. – CroCo Mar 31 '22 at 20:17
  • Not sure. They could be using a compiler that accepts `_cplusplus` as a bonus - or there's a `#define _cplusplus __cplusplus` somewhere that saves their builds. If you don't want to mess with all the `conio.h` copies, add that `#define` to your own files before including `conio.h`. – Ted Lyngmo Mar 31 '22 at 20:20
  • @TedLyngmo nice catch. I was losing my mind about it. thank you. – CroCo Mar 31 '22 at 20:24
  • 1
    I was heading that way myself for a while :-) You're welcome! – Ted Lyngmo Mar 31 '22 at 20:24
  • 1
    @TedLyngmo after checking `usr/include` for this library, I see two underscores whereas the examples shipped contain one underscore. this is nasty issue. – CroCo Mar 31 '22 at 20:34

0 Answers0