1

Situation:

Let's say I have 2 libraries (libA.a, libB.a) I want to use in an executable (exec.cpp). My libA includes foo(x) which is used in libB's function bar(y). Thus, I include the header of libA in libB, and then include the header of libB in my executable and link both:

A.h:

#ifndef LIB_A_INCLUDED
#define LIB_A_INCLUDED

int foo(int x);

#endif

A.cpp:

int foo(int x) {
    //DO stuff
}

B.h

#ifndef LIB_B_INCLUDED
#define LIB_B_INCLUDED

#include <A.h>

int bar(int y);

#endif

B.cpp:

int bar(int y) {
    foo(y);
    //more stuff
}

The CMakeLists file for the two libaries looks like this (for libB there's also an include_directories call to include A.h):

cmake_minimum_required(VERSION 3.15)
project(libA)

set(CMAKE_CXX_STANDARD 14)

add_library(libA A.h A.c)

Exec.cpp:

#include<B.h>

int main() {
    bar(42);
    return 0;
}

The CMakeLists file for the executable looks like this:

cmake_minimum_required(VERSION 3.15)
project(Exec)

set(CMAKE_CXX_STANDARD 14)
include_directories("PATH_TO_HEADER_A/A.h" "PATH_TO_HEADER_B/B.h")

add_executable(Exec main.cpp)

target_link_libraries(Exec "PATH_TO_LIB_A/libA.a;PATH_TO_LIB_B/libB.a")

Problem

This does not work! It yields:

/usr/bin/ld: PATH_TO_LIB_B/libB.a(B.c.o): in function `bar':

/usr/bin/ld: PATH_TO_LIB_B/B.cpp:95: undefined reference to `foo'

However, when I change Exec.cpp to:

#include<B.h>

int main() {
    bar(42);
    foo(31415);
    return 0;
}

It compiles and works as expected - it seems the linker does not link libA when no functions of libA are used in exec.cpp directly, even though these functions are used in libB which is definitely using foo.

Question

Is there a way to force the link? How do I get this to work?

Kevin
  • 16,549
  • 8
  • 60
  • 74
The_Reto
  • 11
  • 1
  • Link order of the libraries matters, see that answer to duplicate question: https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix/24675715#24675715 – Tsyvarev Nov 23 '19 at 21:34
  • What's the correct order then? Because I did think about the order - thats why libA is first in the target_link_libraries list. It makes sense to me why that would be the case but shouldn't the "lower" (in my case libA as it's used in libB which in turn is used by the executable) libraries be linked first? Also why does it work once I use 'foo(x)' in the executable without changing anything else? – The_Reto Nov 24 '19 at 00:13
  • A citation from the referenced answer: "In general, if library A depends on library B, then libA MUST appear before libB in the linker flags.". In your case `libB` depends from the `libA`, so `libB` should come **before** `libA` in `target_link_libraries` call. – Tsyvarev Nov 24 '19 at 08:03

1 Answers1

1

Your libB doesn't know about the implementation of foo (providing the header for libA is not enough). One way to resolve this is to use target_link_libraries() in your libB CMake file to link libA to libB. You could change your libB CMake to look something like this:

cmake_minimum_required(VERSION 3.15)
project(libB)

set(CMAKE_CXX_STANDARD 14)

add_library(libB B.h B.cpp)
target_include_directories(libB PUBLIC PATH_TO_HEADER_A)    
target_link_libraries(libB PUBLIC "PATH_TO_LIB_A/libA.a")

Based on feedback, adding an example showing how the ordering to the linker matters, per the linked duplicate question. It appears each library is built by a separate instance of CMake, so this may be more pertinent; the executable's CMake should re-order the linked libraries to place libB first. (Also, removing the header names from the include_directories() call, as it is not necessary.):

cmake_minimum_required(VERSION 3.15)
project(Exec)

set(CMAKE_CXX_STANDARD 14)
include_directories(PATH_TO_HEADER_A PATH_TO_HEADER_B)

add_executable(Exec main.cpp)

target_link_libraries(Exec PATH_TO_LIB_B/libB.a PATH_TO_LIB_A/libA.a)
Kevin
  • 16,549
  • 8
  • 60
  • 74
  • As this is the first answer on MANY of the simmilar questions on the internet, I have tried it (pretty much in all possible permutations). **This does not fix the problem.** – The_Reto Nov 24 '19 at 00:02
  • @The_Reto Ok, it may not have worked if you create each library in a separate instance of CMake (running CMake three separate times, but I expanded my answer to include an example of the situation described in the linked duplicate question. – Kevin Nov 24 '19 at 00:19