0

I'm using a library that comes with the usual AutoTools generated configure && make && make install procedure. The library contains a main (shared) library and some tools and is mostly written in C.

Now I am running into a problem, where one of the builds of one of the tools fails when using an instrumenter (Score-P which wraps compiler calls to do its magic).

I narrowed it down to the following facts:

libMain uses C files and 1 C++ file, C files get compiler with gcc and C++ file with g++. The library gets linked with g++ as a shared lib.
binTool uses C files only but links against libMain.

This works without the instrumenter. However when used, it adds extra libs when linking with g++ that use C++ features. Linking binTool with gcc then gives undefined reference to 'operator delete[](void*)' (and a few similar ones)

First: Could someone explain to me, why I have to be careful when linking against a shared library (use g++ even though the binary is only using C code)? I was under the impression, that linking of shared binaries is finalized so linking that should not pull in any new dependencies or that the dependencies are already resolved (in this case libMain would know it needs libc++ and have it already referenced/stored/whatever-elf-is-doing)

Second: From reading the AutoTools docu I found that the linker for a program is chosen based on its source files. As libMain uses a C++ file it is linked with g++. binTool uses C files only hence it is linked with gcc. But binTool links also libMain which was C++-linked and seems to require to be linked with g++.
So where is the culprit? Is it AutoTools issuing the wrong linker command for binTool? Or should g++ have done something different when linking libMain?

For reference: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)

ldd libMain:

linux-vdso.so.1
librt.so.1
libpthread.so.0
libm.so.6 libc.so.6
libgcc_s.so.1
libdl.so.2
libnuma.so.1
libltdl.so.7

Flamefire
  • 5,313
  • 3
  • 35
  • 70
  • Your question is unclear, and should have some [MCVE]. Notice that on Linux a shared library can be linked with another one (when you build that library). In particular, you can (and probably should) build `libMain` by linkling it with `libstdc++` – Basile Starynkevitch Feb 23 '18 at 05:38
  • BTW, if `libMain` is open source, you'll better name it (and gives its URL) in your question, and you might make a bug report on it – Basile Starynkevitch Feb 23 '18 at 05:43
  • See also [this](https://stackoverflow.com/a/19424604/841108) very related answer – Basile Starynkevitch Feb 23 '18 at 05:44
  • Good idea, I normally do but in this case I failed to create a MWE. I didn't try at first because it would be complex (including at least 4 different files built into 2-3 libraries and a binary) But after researching **why** I failed to create a MWE (it did not reproduce the described behavior) I found the solution. – Flamefire Feb 23 '18 at 12:18

3 Answers3

1

As I commented, you can link a shared library (when building that library) with another one. See this answer for details. Read Drepper's How To Write Shared Libraries paper.

Probably, you should re-configure and re-compile and re-build your libMain. You want to link it explicitly with -lstdc++ .

Perhaps passing some LDFLAGS=-lstdc++ or LIBES=-lstdc++ to the configure of that libMain might help. See this.

BTW, there are some autoconf-ed libraries coded in C++ and callable from a pure C program (for example libgccjit), and they are linked with -lstdc++

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Thanks but unfortunately that did not help. Using `g++` implies `-lstdc++` so no change due to that. I even found libTool doing something like `g++ -nostdlib ... -lstdc++` In any case the library did not show up in `ldd` which I found due to it being removed as supposedly unused. – Flamefire Feb 23 '18 at 12:24
0

The idea to accomplish your problem is to write a wrapper library which its header is in C and the body internally is compiled with C++ compiler so that it can call your C++ library functions.

Later you can link your C++ library with its C header to your application

Vicente Bolea
  • 1,409
  • 16
  • 39
  • `libMain` uses (partially) a C++ compiler and links with `g++` Besides that it is C-only (especially the headers) so this doesn't work. The main problem visible from the question is, that this (partially) C++ library does not contain a reference to `libstdc++` – Flamefire Feb 23 '18 at 12:29
0

I found a solution (TL&DR jump down to the fat SOLUTION):

The situation was far more difficult than I thought. What happens is: binTool links to shared library libMain which links to a shared library libExtraCxx.

  • binTool is a C program, hence linked with gcc
  • libMain contains a C++ file and is hence linked with g++. But it does not use any C++ library features so the linker omits libstdc++ from the libMain link process.
  • libExtraCxx is a C library intended to be linked into C programs by means of an automatic wrapper script. As libMain uses g++ it gets libExtraCxx linked in. This library is supposed to intercept the C++ new/delete calls and does so by using the GNU -wrap linker command and internally defines (manually) mangled versions of new/delete prefixed by __wrap_ and declares mangled versions of those prefixed by __real_.

Usually this works, because when a C++ linker would be used by binTool the wrapper would issue the -wrap commands and the libstdc++ provides the __real_ functions.

However the mistake is, that the libstdc++ does never get linked: libExtraCxx is a C library that just hooks into C++ functions. libMain does not use any C++ library functions and binTool is again a C program and no shared library linked into it has libstdc++ linked into that.

So one could point to 2 problems:

  1. libExtraCxx should have been a C++ library and links libstdc++ but I guess this "tricks" are done to explicitly avoid the dependency on a C++ library so it can be used by the GNU, Intel or Clang C++ compiler which might have different standard libraries.
  2. libMain should have libstdc++ not omitted. This can usually be done by passing -Wl,--no-as-needed to the compiler/linker as explained here.

I can't change libExtraCxx due to the amount of work involved, but I can pass arguments to the compiler, so I went with 2.

However simply doing configure <...> LDFLAGS=-Wl,--no-as-needed did not work. The flag was used but libstdc++ was not present.

I found the culprit to be libtool which is used by libMain: libtool 2.4.2 does not pass the flag at the right position AFAIK this bug#12880 is not fixed yet, so I was searching for more.

SOLUTION
I found a hack here: Simply use CXX="$CXX -Wl,--no-as-needed". This basically makes libtool think, that the flag is part of the compiler command and it won't reorder it leaving it at the beginning.

For reference: I was using starPU so libMain was actually libstarpu-1.2.so. The failed binary (binTool) is starpu_perfmodel_display. The "fake"-C++-Library is from Score-P libscorep_adapter_memory_event_cxx.so.5 I just changed the names to simplify them.

For SCORE-P the solution is a bit more complicated as one cannot simply change CXX. So full solution to compile starPU with ScoreP is:

SCOREP_WRAPPER=off ~/Downloads/starpu-1.2.3/configure --prefix /usr/local CC=scorep-gcc CXX=scorep-g++ FC=scorep-gfortran --with-mpicc=scorep-mpicc --with-mpifort=scorep-mpif77
And
make SCOREP_WRAPPER_INSTRUMENTER_FLAGS="--opencl --thread=pthread" SCOREP_WRAPPER_COMPILER_FLAGS="-Wl,--no-as-needed"

Explanation: SCOREP_WRAPPER_COMPILER_FLAGS will cause the wrapper to pass the flags to the compiler. As libTool is using the scorep wrapper it does not even see those flags so they get transparently added.

Flamefire
  • 5,313
  • 3
  • 35
  • 70