CMake: Relink on File Change

~ 3 Minute Read.

In the last blog post (“We­bXR in C++”) there was a mi­nor in­con­ve­nience left in the cmake ex­am­ple. If you change the library_webxr.js, it will not re­link and there­fore your out­put .js ac­com­pa­ny­ing the WASM would not get re­gen­er­at­ed.

I thought — “Hey, let’s fix that re­al quick and then write about that!”. Two hours lat­er I found a so­lu­tion for you:

Gen­er­ate a dum­my .cpp file for the li­brary when­ev­er li­brary_we­bxr.js changes

add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/webxr.cpp
    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/webxr.cpp
    DEPENDS library_webxr.js)

Us­ing that file, you can cre­ate emp­ty li­brary. This will cause it to be re­com­piled when li­brary_we­bxr.js changes. Tran­si­tive­ly any­thing that links to it will be re­linked. I’m al­so adding library_webxr.js and webxr.h here so that they show up in IDEs:

add_library(webxr STATIC webxr.h library_webxr.js
    ${CMAKE_CURRENT_BINARY_DIR}/webxr.cpp)
target_include_directories(webxr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

Fi­nal­ly, adding the link­er flag:

# "link" the webxr javascript library when linking to webxr
# Next release of CMake will contain "INTERFACE_LINK_OPTIONS"!
if(NOT CMAKE_VERSION VERSION_LESS 3.12.0)
    set_property(TARGET webxr APPEND_STRING PROPERTY
        INTERFACE_LINK_OPTIONS
            " --js-library ${CMAKE_CURRENT_SOURCE_DIR}/library_webxr.js")
else()
    # *UGLY HACK* to get --js-library into the link parameters. May only work if webxr
    # target is linked last, so be aware of that or use cmake >= 3.12.0
    # Also, note that there is no whitespace prefix as in the above.
    set_property(TARGET webxr APPEND_STRING PROPERTY
        INTERFACE_LINK_LIBRARIES
            "--js-library ${CMAKE_CURRENT_SOURCE_DIR}/library_webxr.js")
endif()

Now you can link the tar­get webxr to your own tar­get that de­pends on it and should be re­linked with changes to the javascript file:

target_link_libraries(your-target PRIVATE webxr)

Note that the webxr tar­get in this case may need to be linked last, be­cause of the ug­ly work­around for CMake not sup­port­ing INTERFACE_LINK_OPTIONS (which was added two weeks ago in this com­mit) un­til the soon to be re­leased ver­sion 3.12.0. A safer op­tion would be to just add the link­er flags to the de­pend­ing tar­get man­u­al­ly. See the pre­vi­ous blog post for more de­tails.

Found so­lu­tion in 120 min­utes, writ­ten in 20 min­utes, ed­it­ed in 5 min­utes.