-2

I am trying to compile a C++ shared library with cmake. Here is a minimal reproducible example from this third-party code demonstrating the issue:

Content of CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(foobar)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
    -I/usr/include/c++/ \
    -I${CMAKE_INCLUDE_PATH} ")

add_library(foobar SHARED src/foobar.cpp)

Content of foobar.cpp:

class Foobar {
public:
    Foobar() {}
    virtual ~Foobar() {}
};

I am getting this linking error which doesn't make sense, since shared libraries don't need a main function:

$ cmake .
...
$ make
[ 50%] Building CXX object CMakeFiles/foobar.dir/src/foobar.cpp.o
[100%] Linking CXX shared library libfoobar.so
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: /usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/lib/../lib/Scrt1.o: in function `_start':
(.text+0x1c): undefined reference to `main'
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: (.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/foobar.dir/build.make:97: libfoobar.so] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/foobar.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

With a slightly different flag order, I am getting this linking error:

relocation XYZ against `vtable for Foobar::~Foobar' can not be used 
when making a shared object; recompile with -fPIC
Étienne
  • 4,773
  • 2
  • 33
  • 58
  • OK. Leaving the first paragraph which I removed there for context: I just want to document this problem which I had and for which I didn't find a solution on stackoverflow. The issue is kind of obvious with this simplified example, but it took me a while to find out in the real project which was significantly bigger. – Étienne May 22 '23 at 11:41
  • @Friedrich this is some code from an external component I am just integrating. I didn't write this. – Étienne May 22 '23 at 13:25
  • I missed the fact that you did not write the code. Even so, I wouldn't blame you for it. I didn't mean to accuse you and apologize for my poor choice of words. About the code, it looks broken, it is broken and you should raise an issue with the maintainer of the external component. I downvoted the question. The error message may be misleading but at the heart of it it's just the familiar anti-pattern of trying to outsmart CMake by setting `CMAKE_CXX_FLAGS`. – Friedrich May 22 '23 at 13:56
  • 1
    Setting `CMAKE_CXX_COMPILER` after the `project()` call is plain wrong: https://stackoverflow.com/a/63944545/3440745. In case of **cross-compiling**, the variable should be set in the **toolchain file**. – Tsyvarev May 22 '23 at 15:52

1 Answers1

0

The issue is that the CMake variable CMAKE_INCLUDE_PATH is empty per default, and therefore adding -I${CMAKE_INCLUDE_PATH} to CMAKE_CXX_FLAGS causes g++ to be called with a flag -I missing a parameter for the directory path. g++ then interprets the next parameter -shared as the path of the include directory (linux directory names can start with a dash, so g++ has no way to know that the next parameter is not the name of the directory). Calling make VERBOSE=1 shows the issue:

aarch64-linux-gnu-g++ -fPIC -I/usr/include/c++/ -I -shared -Wl,-soname,libfoobar.so -o libfoobar.so CMakeFiles/foobar.dir/src/foobar.cpp.o

Thus g++ is not trying to compile a shared library, but an executable file, and complains about the lack of a main function.

A slightly different variant of this is when -fPIC is directly after -I while compiling the c++ file, then the linker complains that the c++ file was compiled without -fPIC and needs to be recompiled with -fPIC.

Étienne
  • 4,773
  • 2
  • 33
  • 58
  • 3
    Just another reason to use `(target_)include_directories` for this kind of stuff. This kind of compiler-specific stuff should likely not be part of a toolchain file anyways; otherwise you just add a unnecessary restriction to a compiler understanding the flags to your project: Set [`CMAKE_CXX_FLAGS_INIT`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_INIT.html) in the toolchain file... – fabian May 22 '23 at 11:50