Background I have a project that uses other smaller projects. These projects themselves are made of other projects. A lot of this is legacy or has other managerial-fiat reasons for being arranged as is, so rolling everything into a single project is not an option. Some libraries are pre-compiled on remote shares.
I have 2 main subprojects that are giving me a headache:
Project Foo is an executable and library that links several static subprojects (foo_subproject_1
, foo_subproject_n
). These subprojects are further linked against static libraries in remote locations (some_lib
, some_other_lib
). Project Foo's executable compiles, links, and runs correctly
Project Bar is an executable that links several other projects, including libFoo. Linking fails with "undefined reference to " foo_subproject
functions
As far as I can tell, the two projects are arranged similarly with their linkage instructions. Looking on SO, I discover that linking static libraries against static libraries shouldn't work, but then I'm confused as to how Project Foo is compiled successfully.
gcc and g++ 4.9.2 are the compilers (extern "C" problems of having some parts in C and some in C++ have already been checked for)
Question
I have misunderstood something about either or both how CMake add_subdirectory works, or about how the linker works. Can someone please explain how Project Foo works successfully, and Project Bar (doesn't) works as expected?
Update I looked closer at foo_lib.a and foo_runtime.
I should have determined that something was off to start with, because foo_runtime is nearly 100MB in size, and foo_lib is only 10KB.
nm
reveals that foo_lib.a references a few dozen symbols, most of which are undefined. foo_runtime meanwhile references everything.
Equally confusing is that foo_subproject_1.a is similarly mostly undefined. Again, this is what I expect to see; but I don't understand how foo_runtime can be built from this?
I'm still unclear as to why some_library -> subproject -> foo_runtime
is successful, but some_library -> subproject -> foo_lib -> bar
isn't. At this stage of my investigations, I am expecting both commands to fail.
Project Foo is arranged (using CMake) thusly:
cmake_minimum_required(VERSION 2.6)
project(foo)
set(FOO_SRCS
# source and headers for main foo project
)
# Project Foo libraries are subdirectories within this project
add_subdirectory(subs/foo_subproject_1)
add_subdirectory(subs/foo_subproject_2)
# Runtime executable
add_executable(foo_runtime main.c ${FOO_SRCS})
target_link_libraries(foo_runtime foo_subproject_1 foo_subproject_2)
# Library version (static library)
add_library(foo_lib STATIC ${FOO_SRCS})
target_link_libraries(foo_lib foo_subproject_1 foo_subproject_2)
Project Foo's subdirectories loosely have the following architecture:
cmake_minimum_required(VERSION 2.6)
project(foo_subproject_<n>)
set(FOO_SUBPROJECT_<N>_SRCS
# source and headers for subproject
)
# foo_subproject's remote libraries are all static
add_library(some_lib STATIC IMPORTED)
set_target_properties(some_lib PROPERTIES IMPORTED_LOCATION /path/to/libsome_lib.a)
add_library(some_other_lib STATIC IMPORTED)
set_target_properties(some_other_lib PROPERTIES IMPORTED_LOCATION /path/to/libsome_other_lib.a)
include_directories(/paths/to/libs/include/)
# Static library for foo_subproject_N, links against static libs above
add_library(foo_subproject_<N> STATIC ${FOO_SUBPROJECT_<N>_SRCS})
target_link_libraries(foo_subproject_<N> some_library some_other_library)
Project Bar is arranged thusly:
cmake_minimum_required(VERSION 2.6)
project(bar)
set(BAR_SRCS
# source and headers for main bar project
)
# Project Bar libraries are remote from Bar's perspective
add_library(foo_lib STATIC IMPORTED)
set_target_properties(foo_lib PROPERTIES IMPORTED_LOCATION /path/to/foo/libfoo_lib.a)
include_directories(/path/to/foo/include/)
# Runtime executable
add_executable(bar main.c ${BAR_SRCS} foo_lib)
Project Bar fails to link (compiles ok) with multiple errors of the form:
bar_frobulator.cpp:123: undefined reference to 'foo_subproject_1_init_frobulation'
where foo_subproject_1_init_frobulation
lives in foo_subproject_1
Can someone please explain how Project Foo works successfully, and Project Bar (doesn't) works as expected?
In short: Creating STATIC library doesn't involve linking step!
In the Foo project you have an executable foo_runtime
, which "works" because it is linked with proper libraries (e.g. with library foo_subproject_1
which defines foo_subproject_1_init_frobulation
symbol).
An executable bar
from Bar project doesn't perform that linking, so it fails. The line
target_link_libraries(bar foo_lib)
links with foo_lib
, but this library doesn't defines the needed symbol foo_subproject_1_init_frobulation
.
Note, that the line
target_link_libraries(foo_lib foo_subproject_1 foo_subproject_2)
in the Foo project doesn't perform actual linking: in general, building a static library doesn't involve linking step.
Given line just propagates include directories (and other compile-features) from foo_subproject_*
libraries to the foo_lib
one.
Because static library foo_lib
doesn't track its dependency, you need to link bar
with a library, which knows that. E.g., make foo_lib
shared, or combine foo_subproject_*
libraries into archive library, as suggested by the referenced question How to combine several C/C++ libraries into one?.
Alternatively, you may build Foo
subproject within Bar
one and, instead of creation of IMPORTED foo_lib
target, use "normal" foo_lib
target, created within Foo
project. In that case, line
target_link_libraries(bar foo_lib)
would mean for CMake to (actually) link bar
with foo_subproject_*
libraries, because those libraries are "linked" (in CMake sense) into foo_lib
. Again, the last "linking" has a meaning only for CMake: the file foo_lib.a
doesn't aware about needing of foo_subproject_*
libraries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With