Linker process: symbol resolution

Hi, I’m trying to understand how are symbols resolved during the link phase of scripts.

I’m on OSX, using root 6 form brew:

$ brew info root6
homebrew/science/root6: stable 6.06.06 (bottled), HEAD

Here is the code I’m using:

// g++ -g -L/usr/local/lib/root -L/usr/local/opt/root6/lib/root -lCling -I/usr/local/etc/root/cling -I/usr/local/etc/root/ -std=c++14 -DDEBUG -o link-symbols link-symbols.cc
#include <vector>
#include <exception>
#include <sstream>
#include <iostream>
#include <fstream>

#include "cling/Interpreter/Interpreter.h"

cling::Interpreter* interpreter(nullptr);


const char * script =
  "namespace script {                      \n"
  "                                        \n"
  "  struct unresolved {                   \n"
  "    unresolved();                       \n"
  "    ~unresolved();                      \n"
  "                                        \n"
  "    int value();                        \n"
  "  };                                    \n"
  "                                        \n"
  "  extern \"C\" int __main() {           \n"
  "    return unresolved().value();        \n"
  "  }                                     \n"
  "                                        \n"
  "}                                       \n";

void setup() {

  std::string base_cling_directory = "/usr/local/etc/root";
  std::string include_root = "-I" + base_cling_directory;
  std::vector<const char*> args = {"-nostdinc++",
                                   "-std=c++14",
                                   "-DDEBUG",
                                   "-O3",
#ifdef __APPLE__
                                   "-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
#elif __linux__
                                   "-I/usr/include/c++/5", "-I/usr/include/x86_64-linux-gnu/c++/5", "-I/usr/include/c++/5/backward",
#else
  #error "Unknown compiler"
#endif
                                   include_root.c_str()};

  const std::string llvmdir = base_cling_directory + "/cling";
  interpreter               = new cling::Interpreter(args.size(), args.data(), llvmdir.c_str());
}

int main() {
  setup();

  if (interpreter->declare(script) != cling::Interpreter::CompilationResult::kSuccess) {
    printf("Failed to compile user script.\n");
    exit(-1);
  }

  printf("declare OK.\n");

  void* ptr = interpreter->getAddressOfGlobal("__main");
  printf("GOT %p for %s\n", ptr, "__main");
  if(!ptr) {
    exit(-1);
  }

  auto func = reinterpret_cast<int (*)()>(ptr);
  auto ret = func();
  printf("GOT %d result\n", ret);

  return 0;
}

struct unresolved in the script is valid c++ code, but its implementation is not defined.
I was expecting some link-time errors while trying to compile/execute the script, but instead I was random-like output:

$ ./link-symbols
declare OK.
GOT 0x10e055000 for __main
GOT 210373381 result

$ ./link-symbols
declare OK.
GOT 0x1105bb000 for __main
GOT 247028485 result

$ ./link-symbols
declare OK.
GOT 0x105271000 for __main
GOT 55520005 result

What is finally executed ? Is it possible to get a failure at some point when running this script ?

Thanks in advance for your help!

Vincent

(edit: script cleanup)

Hi,

I’ll have to debug why this happens - but the problem is connected to the fact that you cannot have an extern “C” declaration in a namespace. Once you put it onto the global scope it works as expected:

[cling]$ void* ptr = gCling->getAddressOfGlobal("__main")
IncrementalExecutor::executeFunction: symbol '_ZN6script10unresolved5valueEv' unresolved while linking [cling interface function]!
You are probably missing the definition of script::unresolved::value()
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZN6script10unresolvedC1Ev' unresolved while linking [cling interface function]!
You are probably missing the definition of script::unresolved::unresolved()
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZN6script10unresolvedD1Ev' unresolved while linking [cling interface function]!
You are probably missing the definition of script::unresolved::~unresolved()
Maybe you need to load the corresponding shared library?

Do you need me to hunt down why this fails when declaring extern “C” inside a namespace?

Cheers, Axel.