5
votes

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:

  1. build external library with add_subdirectory()
  2. install external library files into local directory
  3. import targets using generated cmake-file
  4. use imported targets in primary project cmake files

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)
1
Take a look at ExternalProject moduleuser2288008

1 Answers

2
votes

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.