executable target not relinking when custom target updated

Hi,

I’m trying to write some cmake that will copy a bunch of files in a source directory to a destination directory and relink the destination app, but only if one of the files in the source directory has been modified. Here’s what I’ve come up with so far and it’s almost working, it’s just failing to relink the app after copying the dir:

# Copy assets from 'source' target (usually a lib) to 'target' target (usually an exe)
#
# Pretty ugly as it also checks for modified asset files but it (almost) seems to work.
#
# Also, asset files are only enumed at cmake config time, so if you add an asset you'll have to run cmake config again.
#
function(target_copy_assets target source)

    get_target_property(SRC_DIR ${source} SOURCE_DIR)
    get_target_property(DST_DIR ${target} BINARY_DIR)

    set(SRC_ASSETS_DIR "${SRC_DIR}/assets")
    set(DST_ASSETS_DIR "${DST_DIR}/assets")
    set(STAMP_FILE "${DST_DIR}/${source}_assets.stamp")
    file(GLOB_RECURSE SRC_FILES "${SRC_ASSETS_DIR}/*")

    #message("SRC_ASSETS_DIR: ${SRC_ASSETS_DIR}")
    #message("DST_ASSETS_DIR: ${DST_ASSETS_DIR}")
    #message("STAMP_FILE: ${STAMP_FILE}")
    #message("SRC_FILES: ${SRC_FILES}")

    # Copy assets dir and touch stampfile.
    add_custom_command(
        OUTPUT "${STAMP_FILE}"
        COMMAND "${CMAKE_COMMAND}" -E copy_directory "${SRC_ASSETS_DIR}" "${DST_ASSETS_DIR}"
        COMMAND "${CMAKE_COMMAND}" -E touch "${STAMP_FILE}"
        DEPENDS "${SRC_FILES}"
        VERBATIM
    )

    # Make target dependent on stampfile.
    set(assets_target ${target}_${source}_assets)
    add_custom_target(${assets_target} DEPENDS "${STAMP_FILE}")
    add_dependencies(${target} ${assets_target})

endfunction()

I use it in cmake files for executables like this (note: scene here is a library target with some assets in it I want copied):

add_executable(helloworld main.cpp)
target_link_libraries(helloworld scene)
target_copy_assets(helloworld scene)

It almost works, whenever I touch a file in the scene source ‘assets’ dir, it updates the timestamp file and copies the dir. However, it does not cause helloworld to relink, any ideas?

Bye,
Mark

Ok, it looks like people are either stumped, or it’s an incredibly stupid question!

Am I safe to assume it’s the former, ie: there’s nothing obviously wrong with the code and that it should be linking?

You’re not creating any actual dependency between your asset files, and your target. As far as CMake is concerned. All helloworld needs to link is main.cpp.o which is made from main.cpp automatically, so main.cpp is the only file that will cause a relink.

To figure this out, you’ll need to answer, why should editing those files and copying them over cause a relink?

As a side not, if you’re trying to create a build dependency with some files, using any sort of file globbing isn’t recommended since such a setup won’t do anything when files are added.

You’re not creating any actual dependency between your asset files, and your target

This is what the ‘stamp’ file and custom target are supposed to be doing, although I agree it does looks like this is where things are going wrong.

The idea is that the exe ends up being dependent on both main.cpp and the custom target, and the custom target is what is dependent on the STAMP_FILE that gets touched every time the dir is copied.

You have to do it this round about way because you can only use add_dependencies with targets, not individual source files. So to add a source file dependecy to a target, you need to create a new custom target that DEPENDS on the source file, and use that instead. I wanted to make this a stand alone function but could come up with a nice way to generate custom target names.

This seems to be the general solution people on SO use for this sort of problem and I think I get the idea but I can’t see why it’s not working.

Sorry, my view of the code wasn’t scrolled enough to see these lines:

    set(assets_target ${target}_${source}_assets)
    add_custom_target(${assets_target} DEPENDS "${STAMP_FILE}")
    add_dependencies(${target} ${assets_target})

Which means that part of my response is pretty much useless. I tried your function myself, and when doing so I got this line:

**Consolidate compiler generated dependencies of target helloworld**

This tells me that cmake checked which dependencies were built by a compiler before deciding (not) to relink. So, that brings us back to the question. Why do you want to relink when copying these asset files? In general, asset files wouldn’t need to trigger a relink, since they don’t affect the contents of the final executable.

Thanks for trying that out!

I need to relink because it’s an ‘emscripten’ build, and part of the emscripten link process involves packing a user specified data dir (eg: the ‘assets’ dir above) into a single ‘.data’ file that emscripten uses at runtime to fake a filesystem. So emscripten links actually produce up to 4 files: .html, .js, .wasm, .data.

I did try a ‘.cpp’ extension for the stamp file after your last reply thinking the dependency system might be ignoring unknown source file types, but same result.

Maybe if I use a plain library target instead of a custom target with a single dummy ‘stamp.cpp’ source file? That way, the dependencies would be the same as if it was a ‘normal’ build, although it still seems odd that a custom target should behave differrently to a library target in the first place but then I stuggle to understand many of cmake’s subtleties!

This looks promising too, will give it a go tomorrow:

https://cmake.org/cmake/help/latest/prop_tgt/LINK_DEPENDS.html

Yep, LINK_DEPENDS works well although I have to do some file GLOBbing on all the .stamps for a target.

My plan is to replace the ‘assets’ dir GLOB hack with a cusomt/dummy target for assets that explicitly lists all files.

Thanks for the help!