c++shared-librariesundefined-symbol

The problem with explicitly linking the library


I have written a dynamic library libsort.so and connected it implicitly. Then I connected it explicitly through the keyboard. After compiling, I got the error undefined symbol. The file sort.cpp and sort.h are the sources of the dynamic library, example.cpp this is the program that I have connected the library to.

// sort.cpp
#include <bits/stdc++.h>
#include <iostream>

void merge(int array[], int const left, int const mid, int const right) {
  int const subArrayOne = mid - left + 1;
  int const subArrayTwo = right - mid;

  auto *leftArray = new int[subArrayOne], *rightArray = new int[subArrayTwo];

  for (auto i = 0; i < subArrayOne; i++)
    leftArray[i] = array[left + i];
  for (auto j = 0; j < subArrayTwo; j++)
    rightArray[j] = array[mid + 1 + j];

  auto indexOfSubArrayOne = 0, indexOfSubArrayTwo = 0;
  int indexOfMergedArray = left;

  while (indexOfSubArrayOne < subArrayOne && indexOfSubArrayTwo < subArrayTwo) {
    if (leftArray[indexOfSubArrayOne] <= rightArray[indexOfSubArrayTwo]) {
      array[indexOfMergedArray] = leftArray[indexOfSubArrayOne];
      indexOfSubArrayOne++;
    } else {
      array[indexOfMergedArray] = rightArray[indexOfSubArrayTwo];
      indexOfSubArrayTwo++;
    }
    indexOfMergedArray++;
  }

  while (indexOfSubArrayOne < subArrayOne) {
    array[indexOfMergedArray] = leftArray[indexOfSubArrayOne];
    indexOfSubArrayOne++;
    indexOfMergedArray++;
  }

  while (indexOfSubArrayTwo < subArrayTwo) {
    array[indexOfMergedArray] = rightArray[indexOfSubArrayTwo];
    indexOfSubArrayTwo++;
    indexOfMergedArray++;
  }
  delete[] leftArray;
  delete[] rightArray;
}

void mergeSort(int array[], int const begin, int const end) {
  if (begin >= end)
    return;

  int mid = begin + (end - begin) / 2;
  mergeSort(array, begin, mid);
  mergeSort(array, mid + 1, end);
  merge(array, begin, mid, end);
}

void printArray(int A[], int size) {
  for (int i = 0; i < size; i++)
    std::cout << A[i] << " ";
  std::cout << std::endl;
}

int rand_int(int min, int max) {
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<int> dist(min, max);
  return dist(gen);
}
// sort.h
void merge(int array[], int const left, int const mid, int const right);
void mergeSort(int array[], int const begin, int const end);
void printArray(int A[], int size);
int rand_int(int min, int max);
// example.cpp
#include <dlfcn.h>
#include <iostream>

int main(int argc, char *argv[]) {
  int (*rand)(int, int);
  void (*print_arr)(int[], int);
  void (*merge_s)(int[], int, int);

  void *ext_library = dlopen("/home/nikita/C++/shared/libsort.so", RTLD_LAZY);
  if (!ext_library) {
    std::cerr << "Error loading library: " << dlerror() << std::endl;
    return 1;
  }

  rand = (int (*)(int, int))dlsym(ext_library, "rand_int");
  print_arr = (void (*)(int[], int))dlsym(ext_library, "printArray");
  merge_s = (void (*)(int[], int, int))dlsym(ext_library, "mergeSort");

  if (!print_arr || !merge_s || !rand) {
    std::cerr << "Error loading symbols: " << dlerror() << std::endl;
    dlclose(ext_library);
    return 1;
  }

  int n = rand(5, 25);
  int *arr = new int[n];

  print_arr(arr, n);
  merge_s(arr, 0, n - 1);
  print_arr(arr, n);

  dlclose(ext_library);

  return 0;
}

example.cpp I compiled with the command g++ example.cpp -o example -ldl. I run it with the command ./example, then I got an error

Error loading symbols: /home/nikita/C++/shared/libsort.so: undefined symbol: mergeSort

I tried to change the compiler to clang, compilation is still successful, but when running ./example, the error remains the same.


Solution

  • I rewrote the library sources using extern C, after which everything worked fine.

    // sort.cpp
    #include <bits/stdc++.h>
    #include <iostream>
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void merge(int array[], int const left, int const mid, int const right) {
      int const subArrayOne = mid - left + 1;
      int const subArrayTwo = right - mid;
    
      auto *leftArray = new int[subArrayOne], *rightArray = new int[subArrayTwo];
    
      for (auto i = 0; i < subArrayOne; i++)
        leftArray[i] = array[left + i];
      for (auto j = 0; j < subArrayTwo; j++)
        rightArray[j] = array[mid + 1 + j];
    
      auto indexOfSubArrayOne = 0, indexOfSubArrayTwo = 0;
      int indexOfMergedArray = left;
    
      while (indexOfSubArrayOne < subArrayOne && indexOfSubArrayTwo < subArrayTwo) {
        if (leftArray[indexOfSubArrayOne] <= rightArray[indexOfSubArrayTwo]) {
          array[indexOfMergedArray] = leftArray[indexOfSubArrayOne];
          indexOfSubArrayOne++;
        } else {
          array[indexOfMergedArray] = rightArray[indexOfSubArrayTwo];
          indexOfSubArrayTwo++;
        }
        indexOfMergedArray++;
      }
    
      while (indexOfSubArrayOne < subArrayOne) {
        array[indexOfMergedArray] = leftArray[indexOfSubArrayOne];
        indexOfSubArrayOne++;
        indexOfMergedArray++;
      }
    
      while (indexOfSubArrayTwo < subArrayTwo) {
        array[indexOfMergedArray] = rightArray[indexOfSubArrayTwo];
        indexOfSubArrayTwo++;
        indexOfMergedArray++;
      }
      delete[] leftArray;
      delete[] rightArray;
    }
    
    void mergeSort(int array[], int const begin, int const end) {
      if (begin >= end)
        return;
    
      int mid = begin + (end - begin) / 2;
      mergeSort(array, begin, mid);
      mergeSort(array, mid + 1, end);
      merge(array, begin, mid, end);
    }
    
    void printArray(int A[], int size) {
      for (int i = 0; i < size; i++)
        std::cout << A[i] << " ";
      std::cout << std::endl;
    }
    
    int rand_int(int min, int max) {
      std::random_device rd;
      std::mt19937 gen(rd());
      std::uniform_int_distribution<int> dist(min, max);
      return dist(gen);
    }
    
    #ifdef __cplusplus
    }
    #endif
    
    // sort.h
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void merge(int array[], int const left, int const mid, int const right);
    void mergeSort(int array[], int const begin, int const end);
    void printArray(int A[], int size);
    int rand_int(int min, int max);
    
    #ifdef __cplusplus
    }
    #endif
    
    // example.cpp
    #include <dlfcn.h>
    #include <iostream>
    #include <ostream>
    
    int main(int argc, char *argv[]) {
      int (*rand)(int, int);
      void (*print_arr)(int[], int);
      void (*merge_s)(int[], int, int);
    
      void *ext_library = dlopen("/home/nikita/C++/shared/libsort.so", RTLD_LAZY);
      if (!ext_library) {
        std::cerr << "Error loading library: " << dlerror() << std::endl;
        return 1;
      }
    
      rand = (int (*)(int, int))dlsym(ext_library, "rand_int");
      print_arr = (void (*)(int[], int))dlsym(ext_library, "printArray");
      merge_s = (void (*)(int[], int, int))dlsym(ext_library, "mergeSort");
    
      if (!print_arr || !merge_s || !rand) {
        std::cerr << "Error loading symbols: " << dlerror() << std::endl;
        dlclose(ext_library);
        return 1;
      }
    
      int n = rand(5, 25);
      int *arr = new int[n];
    
      for (int i = 0; i < n; i++)
        *(arr + i) = rand(-100, 100);
    
      std::cout << "Исходный массив: " << std::endl;
      print_arr(arr, n);
      merge_s(arr, 0, n - 1);
      std::cout << "Отсортированный масиив: " << std::endl;
      print_arr(arr, n);
    
      dlclose(ext_library);
    
      return 0;
    }
    

    Apparently, the function names have been subjected to the "name mangling" process by the C++ compiler. I fixed this error using extern C.