3

The problem is as followed: you have two files, one is for a library one is for the executable and you want to call a method defined in the library but declared in the executable:

lib.cpp:

extern void Method();


void DoStuff() {
    Method();
}

main.cpp:

#include <iostream>

void Method() {
    std::cout << "Do Stuff" << std::endl;
}

int main() {
    Method();
    return 0;
}

And now using cmake I just basically want to tell the library that the declaration of the DoStuff method is in the executable target.

Using this simple CMakeLists.txt leads to an undefined symbol linker error:

Undefined symbols for architecture x86_64:
  "Method()", referenced from:
     DoStuff() in lib.cpp.o

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(extern)

set(CMAKE_CXX_STANDARD 14)

add_library(myLib SHARED lib.cpp)    
add_executable(exe main.cpp)

target_link_libraries(exe myLib)

The only way I found was to go through a temporary static library and link my shared library with that static library which I think is quite nasty because I soon I add more classes to the exectuable I get duplicate symbols (which totally makes sense since they are duplicate)

add_library(tmpLib STATIC main.cpp)
target_link_libraries(myLib tmpLib)

I've browsing the interwebs for two nights now looking for a way to do that and I'm still left with absolutely no clue.

apouche
  • 9,703
  • 6
  • 40
  • 45

2 Answers2

1

The error happens during linking object files to create library file. Try OBJECT keyword in add_library instead of SHARED. This will create object files, but it won't link them. Then, you can use target_link_libraries the same way to link these object files to your executable. Since the linker will run once to create your executable and your executable includes the definition of Method, the linker shouldn't complain.

Also, extern specifier isn't necessary there, since functions have external linkage by default.

Depending on your linker, there might be an obscure way of telling it to ignore unresolved symbols, but this is highly unconventional, counter-intuitive, unexpected and confusing for other users/developers and your future self, therefore you should avoid it at all costs in real code. See this question for details.

Note: Your code works fine as-is on Debian 10 x64 with g++ 8.3.0, GNU ld 2.32.1.

ofo
  • 1,160
  • 10
  • 21
  • Do I understand correctly that the executable must find the definition when it is built, which will not happen if the library is `SHARED`? – Ziyuan May 14 '23 at 22:11
0

After many more hours of searching I finally found the solution.

set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined,dynamic_lookup")

is all it takes ! It tells the linker to find undefined symbol by dynamic_lookup for shared libraries. Note that is for macos linker only. For other gcc variants use should use -Wl,allow-shlib-undefined. More info about this on this SO Post

apouche
  • 9,703
  • 6
  • 40
  • 45