2

I'm writing adapter (shared library) to some fpga API. I've got libsomelib.a and its API - somelibAPI.h. Here is a minimal example of my adapter:

somelib_adapter.h:

#include <string>

namespace details {
#include "somelibAPI.h"
}

class somelib_adapter {
public:
  std::string foo();
};

somelib_adapter.cpp:

#include "somelib_adapter.h"
using namespace details;

std::string somelib_adapter::foo() {
  char result[64];
  somelibAPI_call(result);
  return std::string(result);
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.8)
project(untitled1)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES somelib_adapter.cpp somelib_adapter.h)
FIND_LIBRARY(SOMELIB_LIBRARIES
        NAMES libsomelib.a
        PATHS "${SRC_CPP_DIRECTORY}")

add_library(untitled1 SHARED ${SOURCE_FILES})

set(untitled1 -Wl,--whole-archive ${SOMELIB_LIBRARIES} -Wl,--no-whole-archive)
target_link_libraries(untitled1 some_other_shared_lib_used_by_somelib)

cmake finds libsomelib.a but when I'm trying to nm libuntitled1.so | c++filt it does not contain symbols location of somelibAPI_call. What's more, there is an undefined reference error with executable I made to test it. What may be wrong?

EDIT: libsomelib.a is compiled with -fPIC

EDIT2: I see I misunderstood some example. Now Ive got target_link_libraries(untitled1 -Wl,--whole-archive ${SOMELIB_LIBRARIES} -Wl,--no-whole-archive some_other_shared_lib_used_by_somelib) but there is another problem: /usr/bin/ld: ../libsomelib.a(somelibAPI.o): relocation R_X86_64_32 against .rodata.str1.1 can not be used when making a shared object; recompile with -fPIC

  • Your code sets *variable* `untitled1`, but **never uses** it. Just add needed linker flags directly to `target_link_libraries` call. – Tsyvarev Nov 20 '17 at 17:18
  • @Tsyvarev: see EDIT2 – pingwindyktator Nov 20 '17 at 17:33
  • According to the error message, your `libsomelib.a` has not actually built with `-fPIC`. BTW, with `make VERBOSE=1` you may see actual compilation and linking commands used in build process. You may check these commands for containing required flags. – Tsyvarev Nov 20 '17 at 18:25
  • Following @Tsyvarev observations, you should see [this question related to -fPIC](https://stackoverflow.com/questions/5311515/gcc-fpic-option) or [this](https://stackoverflow.com/questions/19364969/compilation-fails-with-relocation-r-x86-64-32-against-rodata-str1-8-can-not) – JTejedor Nov 20 '17 at 22:12

1 Answers1

6

This is, in general, not possible, unless you recompile the static library.

The problem here is that dynamic libraries have to be generated with position independent code, so that they can be loaded dynamically into the address space of an existing process. That is, the compiler must generate the code in a specific way so that it is suitable for execution from a shared library.

Since we do not have this requirement for static libraries, a compiler is free to create position-dependent code there (which is exactly what happened in your case), which prohibits it from being linked into a shared library later. So for this to work, you need to change compilation of the static library to make it aware that it will be linked into a shared library later on. Only by recompiling the static library with the correct options can you make this work.

The exact way to set the correct build options of course depends on the build system used for building that static library. For example, for a static library built with CMake, you could change its build script so that it sets the POSITION_INDEPENDENT_CODE target property on the static library target.

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166