Search code examples
c++linkerboost-pythonbjamb2

Undefined symbol from C++ compiled using bjam


I have a Python application interfacing with C++ via Boost Python. The C++ segment of the application is built using Bjam (Bjam make file can be found at bottom of question). The C++ compiles (and appears to link) fine.

Shortly after the Python executes it complains about an undefined symbol, referenced from a C++ file. This C++ file includes a C++ header where the undefined symbol is declared. If I remove the reference to the problematic variable, the code continues executing fine.

If I run nm on the library it lists the symbol with a U (undefined).

Could someone help why I am receiving this undefined symbol runtime error? I think it's probably because I haven't included something in my gcc path?

The python code calls a C++ method, which creates an object using a variable defined in C_NAMESPACE:

/dir/folder1/bridge.cpp

#include "c.h"

namespace CPP
{
    void calledByPython()
    {
        MyClass x(C_NAMESPACE::VAR);
        // continues
    }
}

which is located in the header file c.h:

/dir/folder2/c.h

#ifndef C_H
#define C_H

namespace C_NAMESPACE
{
    extern const std::string VAR;
}

where the source file looks like:

/dir/folder2/c.cpp

#include "c.h"

namespace
{
    const std::string VAR = "something";
}

and I am building this C++ using bjam:

import python ;

lib gbclientlib : : <name>gbclient <search>$(gbclient_dir)/lib <link>static  ;
explicit gbclientlib ;  

project gb
  : requirements
        <location>. 
        <cxxflags>"-std=c++11 -Wno-deprecated -I /dir/folder1/ -I /dir/folder2/"
;

python-extension _bridge : bridge.cpp ;

Solution

  • When C++ code gets compiled, the names get mangled. C code does not get mangled. C++ name-mangling poses a problem for exposing functions...anywhere really.

    The solution to the problem is to wrap C++ calls under C-like interfaces so that the name doesn't get mangled. For example, to return your std::string VAR to C (and ultimately Python):

    extern "C"
    {
       const char* get_var(void){ return VAR.c_str();}
    }
    

    Boost.Python knows all this and tries to make things easier for you by hiding the extern "C" bits with macros like BOOST_PYTHON_MODULE

    The extern "C" trick is used predominately to expose C++ code to other languages. (C#, however, has CLR and PInvoke)