I'm writing build configuration with cmake: besides main project with own code there are some external libraries. For sake of easy updating of these libraries (zlib, libpng, ...) I don't want to modify its cmakelists files, but I need specific libraries targets (to use in target_link_libraries() for example).
Another restrictions is that I can't just say that my code needs external libraries installed, all things must be located in one source code tree and must be built together.
To keep everything libraries provide structured (libs, headers) I want to install (like make install
does) libraries to local building folder and then include generated cmake-file to import needed targets to my project.
I suppose flow as follows:
add_subdirectory()
Problem is to automate step 2 (need to trigger install
target after add_subdiretory
inside main project CMakeLists.txt). I can build and install all libraries and then build own code, but this isn't convenient.
So question is how can I tell cmake to do intermediate install during build?
A little working example here:
file structure:
prj/CMakeLists.txt
prj/src/main.cpp
lib/CMakeLists.txt
lib/include/libheader.h
lib/src/libsource.cpp
prj/CMakeLists.txt
project(TestProject)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_VERBOSE_MAKEFILE on)
set(WORK_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# supposed to use add_subdirectory here (with forced install).
# and then include prespecified include-file as here.
include_directories(${WORK_DIR}/../lib/build/install/include)
include(${WORK_DIR}/../lib/build/install/lib/libtargets.cmake)
add_executable(main ${WORK_DIR}/src/main.cpp)
target_link_libraries(main library_target)
lib/CMakeLists.txt
project(TestLib)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_VERBOSE_MAKEFILE on)
set(WORK_DIR ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${WORK_DIR}/include)
add_library(library_target STATIC ${WORK_DIR}/src/libsource.cpp)
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install)
install(FILES ${WORK_DIR}/include/libheader.h DESTINATION include)
install(TARGETS library_target DESTINATION lib EXPORT libtargets)
install(EXPORT libtargets DESTINATION lib)
prj/src/main.cpp
#include <iostream>
#include "libheader.h"
using std::cout;
int main()
{
cout << getRandomNumber() << "\n";
return 0;
}
lib/include/libheader.h
#ifndef _LIBHEADER_H_
#define _LIBHEADER_H_
int getRandomNumber();
#endif
lib/src/libsource.cpp
#include <iostream>
#include "libheader.h"
int getRandomNumber()
{
return 4; // guaranteed to be random.
}
You can use following command to build all:
pushd . && mkdir lib/build && cd lib/build && cmake .. && make && make install && popd && pushd . && mkdir prj/build && cd prj/build && cmake .. && make || popd
EDIT: desired cmakelists in main project:
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install)
add_subdirectory(${WORK_DIR}/../lib ${CMAKE_CURRENT_BINARY_DIR}/lib.d)
# force install here, somehow
# because if not we will get "include could not find load file" here.
include(${CMAKE_CURRENT_BINARY_DIR}/install/lib/libtargets.cmake)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/install/include)
sorry, I have no privilege to put comment
So, I put the reference link here
https://cmake.org/Bug/view.php?id=14311
this is also useful when including prebuilt library binaries in the project.
add_library(prebuilt STATIC IMPORTED) set_property(TARGET prebuilt PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libprebuilt.a)
install(TARGETS other_built_targets prebuilt EXPORT project-export RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib )
Making prebuilt an imported target makes in convenient to use in the project and treats it further like any other target.
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