arghol
arghol

Reputation: 795

Creating a library in CMake depending on source files not available when generating build files

I have a CMake configuration file building two libraries:

  1. a third-party library (here called ThirdPartyLib) containing a real-time OS / board support package from a supplier. It is built outside CMake using the autotools toolchain.
  2. an extended version of the former library (here called ExtendedThirdPartyLib)

Unfortunately, some source code that I need (various tools) are not built in the ordinary build script for (1). Since I don't want to mess with the suppliers build script I want to add another library (2), building the missing files and thus extending the library from the supplier.

I want to able to do something like this in CMakeFiles.txt:

cmake_minimum_required(VERSION 3.2)
project(bsp)
include(ExternalProject)

ExternalProject_Add(
  ThirdPartyLib
  URL <http://some.url/bsp.tar.bz2
  BUILD_COMMAND make -C ../external/ThirdPartyLib/src
)
set_target_properties(ThirdPartyLib PROPERTIES EXCLUDE_FROM_ALL TRUE)

add_library(ExtendedThirdPartyLib
  ${CMAKE_CURRENT_BINARY_DIR}/some/path/missing_file1.c
  ${CMAKE_CURRENT_BINARY_DIR}/some/path/missing_file2.c
)
add_dependencies(ExtendedThirdPartyLib ThirdPartyLib)
target_include_directories(ExtendedThirdPartyLib PUBLIC
  ${CMAKE_CURRENT_BINARY_DIR}/some/path/include
)
target_link_libraries(ExtendedThirdPartyLib ThirdPartyLib)

The problem here is that the path to missing_file1.c and missing_file2.c are not valid when CMake is generating the build files (they are extracted from the tarball from the supplier). CMake exits with an error output saying: "Cannot find source file".

Is there a neat way to make this work? I.e. is it possible to convince CMake that certain non-existant input files will exist when building of the library begins? Or is there any other recommended way to solve this issue?

(I have temporary made local copies of the files I need to build from the suppliers tarball, but that is of course not a good solution. If those files are changed in future versions of the suppliers package and I forget to overwrite my local copies it could be a horrible mess...

Another "solution" would be to create a small makefile outside CMake and use another ExternalProject_Add in the CMakeFiles.txt somehow. But that's not a good solution either, e.g. if compile and linker flags are modified I need to remember to change the makefile too.)

Upvotes: 2

Views: 1353

Answers (1)

compor
compor

Reputation: 2329

Personally, I dislike the ExternalProject_Add command, because it does way too many things for my taste, but I've digressed.

What if you do something like this, where bar is simulating your ExtendedThirdPartyLib target, since it depends on generated files

cmake_minimum_required(VERSION 3.11)

project(lol C)

set(SOURCES lol.c) # only this file exists

add_library(lol ${SOURCES})

set(FOO_FILES "foo1.c" "foo2.c")

add_custom_command(OUTPUT ${FOO_FILES}
  COMMAND ${CMAKE_COMMAND} -E touch ${FOO_FILES}
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
  COMMENT "Creating ${FOO_FILES}"
  VERBATIM)

add_custom_target(foo DEPENDS ${FOO_FILES})

add_library(bar ${FOO_FILES})

add_dependencies(bar foo)

target_link_libraries(lol bar)

The whole approach hinges on the fact that the method, where produced/generated files are procured, is explicitly defined via the custom command and associated custom target.

You should modify the custom command to extract the required files (e.g. could even call some external script) from the tarball (which might require downloading with curl or something similar).

Upvotes: 1

Related Questions