How to force a static archive to be recreated when another file changes

I have the following sample project illustrating the issue:

cmake_minimum_required(VERSION 3.16)
project(proj LANGUAGES CXX)

# Allow using response files.
if(APPLE)
    set(CMAKE_CXX_ARCHIVE_CREATE "libtool -o <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()

set(cpp_file "${CMAKE_CURRENT_BINARY_DIR}/core.cpp")
file(WRITE "${cpp_file}" "int core() { return 1;}")

set(response_file "${CMAKE_CURRENT_BINARY_DIR}/response_file.rsp")
file(WRITE "${response_file}" "-v")

add_library(foo STATIC "${cpp_file}")
target_sources(foo PRIVATE "${response_file}")
set_target_properties(foo PROPERTIES STATIC_LIBRARY_OPTIONS "@${response_file}")

# Make foo archiving rerun if the response file changes.
# Doesn't work for static libraries, only works for shared library targets.
set_target_properties(foo PROPERTIES LINK_DEPENDS "${response_file}")

I have a static library foo built by cmake, which is supposed to additionally apply the options from an external response file. The response file is generated outside of CMake.
I add the response file to STATIC_LIBRARY_OPTIONS of the target.

With the current project, if i touch the response file, foo is not rebuilt.

If foo were a shared library, I could use the LINK_DEPENDS property to achieve my goal.

Is there a way to model this in CMake with static libraries?

Note I would like a solution that works for any arbitrary file as a dependency (e.g. a timestamp file), not necessarily something that appears on the command line of the archiver invocation or in `STATIC_LIBRARY_OPTIONS`.

Thanks!

The best I could come up with so far is to create an object library with an empty source file, add the response file to its OBJECT_DEPENDS property, and then link the object library into the static library.

set(object_file "${CMAKE_CURRENT_BINARY_DIR}/object.cpp")
file(WRITE "${object_file}" "")
add_library(obj OBJECT "${object_file}")
set_property(SOURCE "${object_file}" PROPERTY OBJECT_DEPENDS "${response_file}")

target_link_libraries(foo PRIVATE $<LINK_ONLY:obj>)

This achieves the rebuilding part, but is suboptimal due to extra needless compilation.

Add the response file as a source for the target you would like to be rebuilt when the response file changes

I tried that, it doesn’t work.

See the code above, it has.

target_sources(foo PRIVATE "${response_file}")

I wonder if that approach not working is related to the behavior of having the OPTIMIZE_DEPENDENCIES target property set to true? Maybe worth checking if you have that enabled and see if disabling it makes any difference.

Thanks for the hint, but it doesn’t make a difference. Neither setting it to ON/OFF nor undefined.

Given the documentation for OPTIMIZE_DEPENDENCIES, I thought maybe i can force a file-level dependency by adding a custom_command indirection, but that didn’t help either.

This was my attempt:

cmake_minimum_required(VERSION 3.16)
project(proj LANGUAGES CXX)

# Allow using response files.
if(APPLE)
    set(CMAKE_CXX_ARCHIVE_CREATE "libtool -o <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()

set(cpp_file "${CMAKE_CURRENT_BINARY_DIR}/core.cpp")
file(CONFIGURE OUTPUT "${cpp_file}" CONTENT "int core() { return 1;}")

set(response_file "${CMAKE_CURRENT_BINARY_DIR}/response_file.rsp")
set(response_file_fake "${CMAKE_CURRENT_BINARY_DIR}/response_file_fake.txt")
file(CONFIGURE OUTPUT "${response_file}" CONTENT "-v")

add_custom_command(
    OUTPUT "${response_file_fake}"
    COMMAND ${CMAKE_COMMAND} -E touch "${response_file_fake}"
    DEPENDS "${response_file}"
)

add_library(foo STATIC "${cpp_file}")
target_sources(foo PRIVATE "${response_file_fake}" "${response_file}")
set_target_properties(foo PROPERTIES STATIC_LIBRARY_OPTIONS "@${response_file}")

touching the response file still doesn’t force archive recreation, even though the custom_command rule is triggered.

The response file is only used at the linking step, so I’m wondering if adding it as a source file is the wrong place for it. The LINK_DEPENDS target property seems conceptually like the place the response file should be added, but I don’t know off hand if it is used for the static archiver. If this was a shared library, that would seem the right property to add it to. EDIT: I just saw you already mentioned this in your original post. Potentially we need a STATIC_LINK_DEPENDS property to more easily achieve what you’re trying to do.