3

My current project requires a library that is built with a Makefile. I would like to compile this library during my project compilation time; this feature is the main selling point of FetchContent and it works pretty well with CMake dependencies. Nevertheless, I am unable to get it to work with Makefiles, nor can I find examples on how to do so.

FetchContent_Declare(
    make_lib
    URL http://url/library_code.tar.gz 
    BUILD_COMMAND ${CMAKE_COMMAND} -E env make -j 8
    BUILD_IN_SOURCE true  
    BINARY_DIR ""
)

FetchContent_GetProperties(make_lib)
if (NOT make_lib_POPULATED)
    FetchContent_Populate(make_lib)

    # here I would like to declare imported libraries:
    add_library(make_lib::libA STATIC IMPORTED GLOBAL)
    target_include_directories(make_lib::libA INTERFACE ${make_lib_SOURCE_DIR}/include)
    set_property(TARGET make_lib::libA   PROPERTY IMPORTED_LOCATION <path to "to be built" lib>)

endif()
  • Is a "compile-time" execution of make possible at all?
  • If so, could it be parallel?
  • Is it possible to declare imported targets using the dependency-compiled library?
Kevin
  • 16,549
  • 8
  • 60
  • 74
Luis Ayuso
  • 2,967
  • 1
  • 14
  • 15
  • "*Is a "compile-time" execution of make possible at all*"... what do you mean by this? Running `make` is **typically** considered compile-time anyway, so I'm not sure why it wouldn't be in your case. Could you be more specific about *when* you want `make` to run for this library? – Kevin Nov 04 '19 at 14:59
  • When using CMake, scripts can be typically executed at two different stages, configuration time ( when running the make command) or compilation time ( when executing your generator... For the case ninja, or make). The above example has a nested makefile which could be executed at either time, but i qm having trouble to get it to work in the later case. I am sorry if i did not formulated the question correctly. But you answer did not quite solve my doubts. – Luis Ayuso Nov 05 '19 at 15:45
  • Ok, that makes more sense. I originally did not completely understand your question. I updated my answer with more detail about one possible solution. Hope this helps! – Kevin Nov 06 '19 at 23:05

1 Answers1

6

The FetchContent_* commands simply fetch content or metadata from a particular external resource, and populate CMake variables; they do not actually perform any configure, build, or install steps. Thus, any options related to these steps is explicitly ignored when calling FetchContent_Declare(). That includes these options:

  • CONFIGURE_COMMAND
  • BUILD_COMMAND
  • INSTALL_COMMAND
  • TEST_COMMAND

From the FetchContent documentation:

This module enables populating content at configure time via any method supported by the ExternalProject module. Whereas ExternalProject_Add() downloads at build time, the FetchContent module makes content available immediately, allowing the configure step to use the content in commands like add_subdirectory(), include() or file() operations.

This doesn't apply to your use case, as the calls like add_subdirectory() would fail because there are no CMake files in the external library.

As mentioned in this post, ExternalProject_Add() makes more sense in your situation. Your call may look something like this:

ExternalProject_Add(make_lib
    DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}
    URL http://url/library_code.tar.gz
    UPDATE_COMMAND ""
    SOURCE_DIR ${make_lib_SOURCE_DIR}
    BUILD_IN_SOURCE 1
    CONFIGURE_COMMAND ""
    BUILD_COMMAND "make -j8"
    INSTALL_COMMAND "${make_lib_install_commands}"
)

add_library(make_lib_libA STATIC IMPORTED GLOBAL)
set_property(TARGET make_lib_libA 
    PROPERTY IMPORTED_LOCATION 
    ${make_lib_SOURCE_DIR}/path/to/make_lib_libA.a
)

add_dependencies(myOtherLib make_lib)

Note, BUILD_COMMAND here will not be ignored, but will run make -j8 at compile-time. You should also be able to declare the imported library as your code laid out. But importantly, do remember to call add_dependencies() which tells CMake your make_lib is used by another target; otherwise, make-lib will not build.

After calling ExternalProject_Add(), you can use ExternalProject_Get_Property() to query information about the external project target. The linked example shows how to get the source directory of the project, which could be useful for getting the location of built library.

Kevin
  • 16,549
  • 8
  • 60
  • 74
  • 1
    Could you please be more concise on how it should look like? my example writes a BUILD_COMMAND that gets ignored, and there is no configure, test, nor install for this library. You still do not explain how to declare an imported target of what you just downloaded. And I quite do not understand how cmake forwards the number of jobs to the nested makefile, for starters I use ninja to build. – Luis Ayuso Nov 01 '19 at 13:19
  • 1
    How would this work? When we link `myOtherLib` with `make_lib_libA`, the generator will complain that `make_lib_libA.a` used by `myOtherLib` is not found (because it doesn't exist yet). – Neat Jun 07 '22 at 17:06