Reputation: 125
I am trying to build a program using CMake that depends on a third party library. This third party library contains a CMakeLists.txt
file so what I want to do is keep the source code of the third party library within my project directory, and build it using add_subdirectory(path/to/lib)
, and then link my target against the static library that the third party library generated.
my CMakeLists.txt:
cmake_minimum_version(VERSION 3.10)
project(my_project)
add_subdirectory("${CMAKE_SOURCE_DIR}/extern/somelib")
# my-code:
# somelib CMakeLists.txt file has a project name: SOMELIB
# which lets me access the directory where the files are built
# on windows it builds to /Release, on mac and linux it just builds
# to the binary dir
set(SOMELIB_LIBS "${SOMELIB_BINARY_DIR}/Release")
add_executable(my_program my_main.cpp)
target_link_libraries(my_program "${SOMELIB_LIBS}/SOMELIB.lib" "${SOMELIB_LIBS}/SOMELIBmain.lib")
I then make a build directory and from that directory I do:
cmake -G "Visual Studio 15 2017" ..
cmake --build .
The build command fails with a "LINK : fatal error LNK1181: cannot open input file 'extern/somelib/Release/SOMELIBmain.lib' ..."
My workaround for now has been to comment out the part that says "#my-code", build the somelib dependency first which generates the static libraries, and then uncomment out my-code and build again which then works correctly.
How can I tell CMake to build the subdirectory first, and then link against the static libraries that it generated?
Upvotes: 3
Views: 7360
Reputation: 2146
Short answer: tell CMake that there is dependency between its targets.
target_link_libraries(my_program PRIVATE SOMELIB SOMELIBmain)
CMake will evaluate SOMELIBs locations for you and link my_program
against SOMELIB
and SOMELIBmain
[1]. Works for both Debug and Release configurations and also for Linux.
You shouldn't have to worry where CMake places build files[2] and this is what so called "modern CMake" is trying to achieve. I will leave here just brief description but check link on the bottom of answer[3].
Anyway, the key concept is that whenever you create library/executable (target), you list its usage+build requirements and dependencies to other targets. You declare dependencies using target_link_libraries(<your_lib> KEYWORD <dependencies>)
. Such line will not only make <you_lib>
link against listed dependencies, it will inherit their usage requirements (usually, public include directories) and order CMake to build dependent libraries before <your_lib>
.
The beauty of it is that even if SOMELIB
does not follow modern CMake ideas (does not declare build/usage requirements), you still should be able to do just with this single line.
[1] I assumed that CMake targets are named same as output library names, but it is not mandatory. For OP's case it turned out that static library targets are suffixed with -static
, so he had to write SOMELIB-static SOMELIBmain-static
[2] Unfortunately, it is not so easy with shared libraries on Windows (DLLs)
[3] I'd start with this blog entry: https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/
Upvotes: 3