Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake's FetchContent with Makefile-built dependency

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?
like image 409
Luis Ayuso Avatar asked Oct 24 '25 02:10

Luis Ayuso


1 Answers

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.

like image 79
Kevin Avatar answered Oct 25 '25 20:10

Kevin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!