# FetchContent\_Populate() no good documentation - build step

**URL:** https://discourse.cmake.org/t/fetchcontent-populate-no-good-documentation-build-step/15499
**Category:** Code
**Created:** [February 6, 2026, 10:44pm UTC](https://discourse.cmake.org/t/fetchcontent-populate-no-good-documentation-build-step/15499 "2026-02-06T22:44:16Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![anon74639460](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/da6949/32.png) [@anon74639460](https://discourse.cmake.org/u/anon74639460)
#### Post date: [February 6, 2026, 10:44pm UTC](https://discourse.cmake.org/t/fetchcontent-populate-no-good-documentation-build-step/15499/1 "2026-02-06T22:44:16Z")

</div>

Hello,

I have scoured through this until I almost went blind.

[https://cmake.org/cmake/help/latest/module/FetchContent.html](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.

```auto
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

```auto
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:

```auto
– 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

```auto
*** 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.

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [February 14, 2026, 4:36am UTC](https://discourse.cmake.org/t/fetchcontent-populate-no-good-documentation-build-step/15499/2 "2026-02-14T04:36:39Z")

</div>

`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 use[`FetchContent_Declare()`](https://cmake.org/cmake/help/latest/module/FetchContent.html#command:fetchcontent_declare) and [`FetchContent_MakeAvailable()`](https://cmake.org/cmake/help/latest/module/FetchContent.html#command:fetchcontent_makeavailable) instead. The main use case for `FetchContent_Populate()` is in [CMake script mode](https://cmake.org/cmake/help/latest/manual/cmake.1.html#script-processing-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.

---

<div class="post-metadata">

### Author: ![anon74639460](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/da6949/32.png) [@anon74639460](https://discourse.cmake.org/u/anon74639460)
#### Post date: [February 14, 2026, 2:36pm UTC](https://discourse.cmake.org/t/fetchcontent-populate-no-good-documentation-build-step/15499/3 "2026-02-14T14:36:36Z")

</div>

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.

# 

```auto
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.

```auto

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

```auto
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.
