0

I'm using a class of threads with a header and cpp file. When I put both of them and empty test file it writes:

g++ -g -pedantic -ansi -Wall -Werror -std=c++03 -I../include  -c -o test.o test.cpp
g++ -g  test.o thread.o   -o test
thread.o: In function `Thread::~Thread()':
/home/tomer/work/mt/hash2/cpp/thread.cpp:15: undefined reference to `pthread_detach'
thread.o: In function `Thread::start()':
/home/tomer/work/mt/hash2/cpp/thread.cpp:40: undefined reference to `pthread_create'
thread.o: In function `Thread::join()':
/home/tomer/work/mt/hash2/cpp/thread.cpp:49: undefined reference to `pthread_join'
thread.o: In function `Thread::cancel()':
/home/tomer/work/mt/hash2/cpp/thread.cpp:58: undefined reference to `pthread_cancel'
thread.o: In function `Thread::detach()':
/home/tomer/work/mt/hash2/cpp/thread.cpp:66: undefined reference to `pthread_detach'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'test' failed
make: *** [test] Error 1

I just tried to comppile Thread.h and Thread.cpp

//Thread.h looks like this:
#ifndef THREAD_H
#define THREAD_H

#include <cstddef>
#include <pthread.h>
#include <string>

class Thread
{
public:
    Thread(size_t a_userID = 0);
    virtual ~Thread();

    bool start();
    void join();
    void cancel();
    void detach();


private:
    static void* threadMainFunction(void *);
    virtual void run() = 0;
    bool isAlive(std::string a_msg);

private:
    bool m_joinable;

protected:
    pthread_t m_threadID;
    size_t m_userID;
};

#endif

//Thread.cpp looks like this:
#include <exception>
#include "Thread.h"
#include <iostream>
Thread::Thread(size_t a_userID)
: m_joinable(true)
, m_threadID(0)
, m_userID(a_userID)
{
}

Thread::~Thread()
{
    if(m_joinable)
    {
        pthread_detach(m_threadID);
    }
}

void* Thread::threadMainFunction(void *a_thread)
{
    Thread* thread = reinterpret_cast<Thread*>(a_thread);
    try
    {
        thread->run();
    }
    catch(const std::exception& e)
    {
        std::cout<<"what exepction\n";
        std::cerr << e.what() << '\n';
    }
    catch(...)
    {
        throw;
    }
    return 0;
}

bool Thread::start()
{
    int r = pthread_create(&m_threadID, 0, threadMainFunction, this);
    return r == 0;
}

void Thread::join()
{
    if(isAlive("Thread::join on thread not started"))
    {
        void *status;
        pthread_join(m_threadID, &status);
        m_joinable = false;
    }
}

void Thread::cancel()
{
    if(isAlive("Thread::cancel on thread not started"))
    {
        pthread_cancel(m_threadID);
    }
}

void Thread::detach()
{
    if(isAlive("Thread::detach on thread not started"))
    {
        pthread_detach(m_threadID);
    }
}

bool Thread::isAlive(std::string a_msg)
{
    if(m_threadID == 0)
    {
        throw(std::runtime_error(a_msg));
        return false;
    }
    return true;
}

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
Tomer Barak
  • 49
  • 1
  • 4

1 Answers1

1

The issue you are facing here is not a build issue, but a link issue. When building thread.o, the compiler knows pthread_create exists and is defined somewhere because declared in the pthread.h header.

If you used nm to look at the symbols used in thread.o, you would see something similar to this:

U _pthread_create
U _pthread_detach
...

This tells you that thread.o references multiple Undefined symbols including pthread_create. In other words, the machine code for pthread_create is unknown at this point. This is perfectly fine until you need to link your object files into an executable file, which is the role of the linker.

At this stage, you must tell the linker where to find these undefined symbols, perhaps from another object file or a static/shared library. For pthread, the symbols are defined in libpthread, which you can likely find in a system directory as libpthread.a. You can tell g++ to link this library by adding -lpthread (note that lib from libpthread is omitted when using -l):

g++ -g test.o thread.o -o test -lpthread

In general, if you use symbols referenced in a static library lib${LIBNAME}.a available in ${LIBDIR} directory, you can tell the linker to use it with:

g++ -g *.o -L$LIBDIR -l${LIBNAME}
Jon
  • 126
  • 3