FetchContent_Populate() no good documentation - build step

Hello,

I have scoured through this until I almost went blind.

https://cmake.org/cmake/help/latest/module/FetchContent.html

Have the following section in a cmake file because I need a much newer version of libtool libraries than Ubuntu 18.04 has.

if (CMAKE_SYSTEM_NAME MATCHES “(Linux|OpenBSD|FreeBSD|NetBSD|DragonFly)”)
# CMake is an odd duck. If you provide SOURCE_DIR definition for
# external project, PREFIX will not create the other directories.
# CMake ASS-U-ME-s all external projects are CMAKE builds. Not
# the case with libtool and so many other things.
#
# The hacky looking path for the configure command is a result of
# CMake forcing its own directory structure on external project.
#

include(ExternalProject)
include(FetchContent)

FetchContent_Populate(
    ls_libtool
    SUBBUILD_DIR "${CMAKE_BINARY_DIR}/ls_libtool"
    URL https://ftp.gnu.org/gnu/libtool/libtool-2.5.4.tar.gz
    DOWNLOAD_NO_PROGRESS ON 
    DOWNLOAD_EXTRACT_TIMESTAMP false
    CONFIGURE_COMMAND ${CMAKE_BINARY_DIR}/ls_libtool/src/ls_libtool/configure --prefix=${LIBTOOL_INSTALL_PREFIX} "CFLAGS=-g -O0 ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}"
    BUILD_COMMAND make 
    INSTALL_COMMAND make install
    
)

message( "*******ls_libtool_SOURCE_DIR:  ${ls_libtool_SOURCE_DIR}")
message( "*******ls_libtool_BINARY_DIR:  ${ls_libtool_BINARY_DIR}")

target_link_libraries(LsCsCore  PUBLIC ${LIBTOOL_INSTALL_PREFIX}/lib/libltdl)

target_include_directories(LsCsCore
PUBLIC
$<BUILD_INTERFACE:${LIBTOOL_INSTALL_PREFIX}/include>
$<INSTALL_INTERFACE:include>)
endif()


Just to round out the environment

developer@developer-U1804-VirtualBox:~/github_projects/ls-cs$ cmake --version
cmake version 4.2.3

CMake suite maintained and supported by Kitware (kitware.com/cmake).


When this executes (for lack of a better term) I get the following:

– Build files have been written to: /home/developer/github_projects/LsCs_local_build/ls_libtool
[1/9] Creating directories for ‘ls_libtool-populate’
[1/9] Performing download step (download, verify and extract) for ‘ls_libtool-populate’
– Downloading…
dst=‘/home/developer/github_projects/LsCs_local_build/ls_libtool/ls_libtool-populate-prefix/src/libtool-2.5.4.tar.gz’
timeout=‘none’
inactivity timeout=‘none’
– Using src=‘https://ftp.gnu.org/gnu/libtool/libtool-2.5.4.tar.gz’
– Downloading… done
– extracting…
src=‘/home/developer/github_projects/LsCs_local_build/ls_libtool/ls_libtool-populate-prefix/src/libtool-2.5.4.tar.gz’
dst=‘/home/developer/github_projects/LsCs_local_build/src/core/ls_libtool-src’
– extracting… [tar xf]
– extracting… [analysis]
– extracting… [rename]
– extracting… [clean up]
– extracting… done
[2/9] No update step for ‘ls_libtool-populate’
[3/9] No patch step for ‘ls_libtool-populate’
[5/9] No configure step for ‘ls_libtool-populate’
[6/9] No build step for ‘ls_libtool-populate’
[7/9] No install step for ‘ls_libtool-populate’
[8/9] No test step for ‘ls_libtool-populate’
[9/9] Completed ‘ls_libtool-populate’
*******ls_libtool_SOURCE_DIR:  /home/developer/github_projects/LsCs_local_build/src/core/ls_libtool-src
*******ls_libtool_BINARY_DIR:  /home/developer/github_projects/LsCs_local_build/src/core/ls_libtool-build


Later on the build gags because

*** Building LSCS
ninja: error: ‘ls_libtool/install/lib/libltdl’, needed by ‘src/core/libLsCsCore.so.0.2.1’, missing and no known rule to make it


I put all of the information in that block required by externalproject to build and that will, you just cannot use the thing because the location of header files and built libraries does not exist during configuration.

All I want is for CMake to pull down this non-CMake project and build it so I can use the headers and libraries as part of my project. Bundling them up for deployment and all.

How do I make build and install steps for the populate? I cannot find anything on this.

Thanks in advance.

FetchContent_Populate() only populates content, and it is only meant to be used in CMake’s script mode now. If you want to add the populated content to your build, you should use FetchContent_MakeAvailable() instead. The start of the documentation for FetchContent_Populate() states this:

The FetchContent_Populate() command is a self-contained call which can be used to perform content population as an isolated operation. It is rarely the right command to use, projects should almost always useFetchContent_Declare() and FetchContent_MakeAvailable() instead. The main use case for FetchContent_Populate() is in CMake script mode as part of implementing some other higher level custom feature.

A bit further down in those docs, there’s this statement which explains why your use of CONFIGURE_COMMAND, BUILD_COMMAND, and INSTALL_COMMAND is inappropriate:

The following options are explicitly prohibited (they are disabled by the FetchContent_Populate() command):

  • CONFIGURE_COMMAND
  • BUILD_COMMAND
  • INSTALL_COMMAND
  • TEST_COMMAND

If you’re happy to have your ls_libtool dependency built as its own external project as a sub-build rather than as part of the main build, use ExternalProject_Add() instead of any of the FetchContent_... machinery. Since the ls_libtool dependency appears to be a non-CMake project, it isn’t really appropriate for the FetchContent use case.

Thanks Craig!

I forgot to come back and answer my own question. After intense slamming of head against keyboard and wall given libtool’s lack of documentation, I did find the solution. There really is only one way to do it.

CMake is an odd duck. If you provide SOURCE_DIR definition for

external project, PREFIX will not create the other directories.

CMake ASS-U-ME-s all external projects are CMAKE builds. Not

the case with libtool and so many other things.



The hacky looking path for the configure command is a result of

CMake forcing its own directory structure on external project.



include(ExternalProject)

set(LS_LIBTOOL_BYPRODUCTS
“${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.a”
“${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.la”
“${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.so”
“${LIBTOOL_INSTALL_PREFIX}/include/ltdl.h”
“${LIBTOOL_INSTALL_PREFIX}/include/libltdl/lt_dlloader.h”
“${LIBTOOL_INSTALL_PREFIX}/include/libltdl/lt_error.h”
“${LIBTOOL_INSTALL_PREFIX}/include/libltdl/lt_system.h”
)

NOTE: If you change the file here you may need to change the libldtl install version.

Must provide BUILD_BYPRODUCTS when using ninja-build

ExternalProject_Add(
ls_libtool
PREFIX “${CMAKE_BINARY_DIR}/ls_libtool”
DOWNLOAD_DIR “${CMAKE_BINARY_DIR}”
URL https://ftp.gnu.org/gnu/libtool/libtool-2.5.4.tar.gz
DOWNLOAD_NO_PROGRESS ON
DOWNLOAD_EXTRACT_TIMESTAMP false

UPDATE_COMMAND ${CMAKE_COMMAND} -E copy 
    ${CMAKE_SOURCE_DIR}/libtool-configure.ac
    ${CMAKE_BINARY_DIR}/ls_libtool/src/ls_libtool/configure.ac
    
CONFIGURE_COMMAND ${CMAKE_BINARY_DIR}/ls_libtool/src/ls_libtool/configure --prefix=${LIBTOOL_INSTALL_PREFIX} "CFLAGS=-g -O0" "CXXFLAGS=-g -O0"
BUILD_COMMAND make 
BUILD_BYPRODUCTS ${LS_LIBTOOL_BYPRODUCTS}

)


BUILD_BYPRODUCTS is extremely important. Very little documentation on it, but if you are using ninja with CMake, nothing works without it. Theoretically CMake would deploy these according to the doc, it don’t happen.



libtool headers and libraries



install(
FILES
${LIBTOOL_INSTALL_PREFIX}/include/ltdl.h
DESTINATION ${LSCS_INST_INCLUDE}
COMPONENT Development
)

install(
FILES
${LIBTOOL_INSTALL_PREFIX}/include/libltdl/lt_dlloader.h
${LIBTOOL_INSTALL_PREFIX}/include/libltdl/lt_error.h
${LIBTOOL_INSTALL_PREFIX}/include/libltdl/lt_system.h
DESTINATION ${LSCS_INST_INCLUDE}
COMPONENT Development
)

NOTE:: Need dynamic way of determining major version of library or a for loop finding each

This hard coding bad.

install(
FILES
${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.a
${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.la
${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.so
${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.so.7
${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.so.7.3.3
DESTINATION ${LSCS_INST_LIB}
COMPONENT Development
COMPONENT Runtime
)

To finish out the discussion

if (CMAKE_SYSTEM_NAME MATCHES “(Linux|OpenBSD|FreeBSD|NetBSD|DragonFly)”)

add_library(ls_libtool_ep SHARED IMPORTED GLOBAL)

add_dependencies(ls_libtool_ep  ls_libtool)
set_target_properties(ls_libtool_ep PROPERTIES IMPORTED_LOCATION "${LIBTOOL_INSTALL_PREFIX}/lib/libltdl.so")

include_directories( "${LIBTOOL_INSTALL_PREFIX}/include" )

add_dependencies(LsCsCore ls_libtool)

target_link_libraries(LsCsCore PRIVATE ls_libtool_ep)


That’s how you both make libtools available to your project and control the build order.

I do thank you for your feedback. It reminded me to come back here and document the solution.