# Execute Command Post Build - CMake / ESP-IDF (VS-Code with PIO)

**URL:** <https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869>\
**Category:** Code\
**Created:** [April 2, 2025, 8:47am UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869 "2025-04-02T08:47:50Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![K0I05](https://discourse.cmake.org/user_avatar/discourse.cmake.org/k0i05/32/5475_2.png) [@K0I05](https://discourse.cmake.org/u/K0I05)\
**Post date:** [April 2, 2025, 8:47am UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/1 "2025-04-02T08:47:50Z")

</div>

I’ve posted this in the esp-idf and platformio forums and am getting limited feedback. Hopefully, someone can help or point me in the right direction. I am using VS-Code with PlatformIO, developing with the ESP-IDF framework, and trying to get a custom command to execute post-build for components, but I am not having any luck. I tried the same with VS-Code with ESP-IDF and got the same results; the custom command is getting ignored.

This is what is in the CMakeLists.txt file in the component folder:

```auto
#
# Versioning Information for ESP-IDF Components with GitHub, GitVersion and CMake
#
# Inspired by: https://www.esp32.com/viewtopic.php?f=2&t=45054&p=146150#p146150
#
# Install Git-Version via command prompt: dotnet tool install --global GitVersion.Tool
# Create a GitVersion.yml file in the root of your project with the following content:
#
# major-version-bump-message: '\+semver:\s?(breaking|major)'
# minor-version-bump-message: '\+semver:\s?(feature|minor)'
# patch-version-bump-message: '\+semver:\s?(fix|patch)'
# commit-message-incrementing: Enabled
#
# Download CMake JSON-Parser: https://github.com/sbellus/json-cmake/blob/master/JSONParser.cmake
# Copy the CMake JSONParser.cmake file to the tools/cmake directory of your ESP-IDF installation.
# i.e. C:\Users\user\.platformio\packages\framework-espidf\tools\cmake
#
include( $ENV{IDF_PATH}/tools/cmake/version.cmake )
include( $ENV{IDF_PATH}/tools/cmake/JSONParser.cmake RESULT_VARIABLE JSONPARSER_FOUND )

# string compare JSONParser library availability
string( COMPARE NOTEQUAL "${JSONPARSER_FOUND}" "NOTFOUND" STR_CMP_RESULT )

# validate JSONParser library, version.h.in, pio_lib_sync.py, esp_cmp_sync.py, 
# library.json.in, and idf_component.yml.in files are available for preprocessing
if(STR_CMP_RESULT EQUAL 1 AND EXISTS "${CMAKE_SOURCE_DIR}/templates/component/include/version.h.in" 
    AND EXISTS "${CMAKE_SOURCE_DIR}/templates/components/${COMPONENT_NAME}/library.json.in" 
    AND EXISTS "${CMAKE_SOURCE_DIR}/templates/components/${COMPONENT_NAME}/idf_component.yml.in")

    # Get latest versioning information from git repository with GitVersion
    execute_process(
        COMMAND dotnet-gitversion
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        OUTPUT_VARIABLE GIT_VERSION_OUTPUT
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    # Instantiate json variable
    sbeParseJson( GIT_VERSION_JSON GIT_VERSION_OUTPUT )

    # Parse versioning variables from json output
    set( GIT_VERSION_DATE ${GIT_VERSION_JSON.CommitDate} )
    set( GIT_SEM_VERSION ${GIT_VERSION_JSON.MajorMinorPatch} )
    set( GIT_VERSION_MAJOR ${GIT_VERSION_JSON.Major} )
    set( GIT_VERSION_MINOR ${GIT_VERSION_JSON.Minor} )
    set( GIT_VERSION_PATCH ${GIT_VERSION_JSON.Patch} )
    set( GIT_FULL_SEM_VER ${GIT_VERSION_JSON.FullSemVer} )
    set( GIT_SHORT_SHA ${GIT_VERSION_JSON.ShortSha} )

    # Release json variable
    sbeClearJson( GIT_VERSION_JSON )

    # Components should be named as "esp_<component_name>"
    string( FIND "${COMPONENT_NAME}" "esp_" ESP_PREFIX )

    # Check if the component name starts with "esp_"
    if(ESP_PREFIX EQUAL -1)
        # Use the component name as is
        string( CONCAT COMPONENT_HEADER_NAME "" "${COMPONENT_NAME}" )
    else()
        # Parse component file name from component name
        string( REPLACE "esp_" "" COMPONENT_HEADER_NAME "${COMPONENT_NAME}" )
    endif()

    # Set the component header name to upper case
    string( TOUPPER "${COMPONENT_HEADER_NAME}" COMPONENT_HEADER_NAME_UPPER )

    # REMOVE TEMPLATE GENERATED FILES FROM COMPONENT DIRECTORY (FORCED REGENERATION)

    # Remove C header versioning file from component directory
    file( REMOVE "${COMPONENT_DIR}/include/${COMPONENT_HEADER_NAME}_version.h" )

    # Remove json library file from component directory
    file( REMOVE "${COMPONENT_DIR}/library.json" )

    # Remove yml idf component file from component directory
    file( REMOVE "${COMPONENT_DIR}/idf_component.yml" )

    # GENERATE FILES FROM TEMPLATES FOR COMPONENT DIRECTORY

    # Generate C header file from template with versioning information
    configure_file( "${CMAKE_SOURCE_DIR}/templates/component/include/version.h.in" "${COMPONENT_DIR}/include/${COMPONENT_HEADER_NAME}_version.h" @ONLY )

    # Generate json library file from template with versioning information
    configure_file( "${CMAKE_SOURCE_DIR}/templates/components/${COMPONENT_NAME}/library.json.in" "${COMPONENT_DIR}/library.json" @ONLY )

    # Generate yml idf component file from template with versioning information
    configure_file( "${CMAKE_SOURCE_DIR}/templates/components/${COMPONENT_NAME}/idf_component.yml.in" "${COMPONENT_DIR}/idf_component.yml" @ONLY )
endif()

# Register the component
idf_component_register(
    SRCS uuid.c
    INCLUDE_DIRS include
)

# Get global variables from idf build property
idf_build_get_property( cmp_reg_sync COMPONENT_REGISTRY_SYNC )
idf_build_get_property( cmp_reg_o COMPONENT_REGISTRY_OWNER )

# Validate if the component should be synchronized with esp-idf and platformio registries
string( COMPARE EQUAL "${cmp_reg_sync}" "ENABLED" STR_CMP_RESULT )

# Register the component with the ESP-IDF components and platformio registries
#if(STR_CMP_RESULT EQUAL 1)

    #add_custom_target(
    # my_component_sync
    # COMMAND python ${CMAKE_SOURCE_DIR}/stg/esp_cmp_sync.py OK
    # COMMENT "python testing with add_custom_command..."
    #)
    #add_dependencies( ${PROJECT_NAME}.elf my_component_sync )

    add_custom_command(
        TARGET ${COMPONENT_LIB}
        POST_BUILD
        COMMAND python ${CMAKE_SOURCE_DIR}/stg/pio_lib_sync.py OK
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        COMMENT "python testing with add_custom_command..."
    )

#endif()

```

Thanks in advance.

---

<div class="post-metadata">

**Author:** ![LegalizeAdulthood](https://discourse.cmake.org/user_avatar/discourse.cmake.org/legalizeadulthood/32/5282_2.png) [@LegalizeAdulthood](https://discourse.cmake.org/u/LegalizeAdulthood)\
**Post date:** [April 2, 2025, 3:41pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/2 "2025-04-02T15:41:56Z")

</div>

How is `${COMPONENT_LIB}` defined as a target? I couldn’t find it defined anywhere in the CMake script you posted.

---

<div class="post-metadata">

**Author:** ![K0I05](https://discourse.cmake.org/user_avatar/discourse.cmake.org/k0i05/32/5475_2.png) [@K0I05](https://discourse.cmake.org/u/K0I05)\
**Post date:** [April 2, 2025, 7:04pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/3 "2025-04-02T19:04:31Z")

</div>

The ESP-IDF build system sets it; for example, if the component name is “esp\_foo”. The ${COMPONENT\_LIB} is set to something like “\_\_idf\_esp\_foo”. I can confirm that it is getting set through a message but I get the impression that CMake/Make isn’t recognizing it as a target based on how the ESP-IDF build system initializes components. I tried add\_custom\_target using ${COMPONENT\_LIB} as a dependency, but it gets ignored as well.

[Preset Component Variables](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/build-system.html#preset-component-variables)

I haven’t tried “esp\_foo.c.o” as a target which is what I see during the build process before linking.

---

<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:** [April 2, 2025, 8:55pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/4 "2025-04-02T20:55:44Z")

</div>

Note that `add_custom_command(TARGET ... POST_BUILD ...)` requires that the target you give it is also defined in the same directory scope. Is that true for the target defined by `${COMPONENT_LIB}`?

---

<div class="post-metadata">

**Author:** ![LegalizeAdulthood](https://discourse.cmake.org/user_avatar/discourse.cmake.org/legalizeadulthood/32/5282_2.png) [@LegalizeAdulthood](https://discourse.cmake.org/u/LegalizeAdulthood)\
**Post date:** [April 2, 2025, 8:55pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/5 "2025-04-02T20:55:52Z")

</div>

Try using `COMPONENT_ALIAS` as the variable containing the target name; I suspect that `COMPONENT_LIB` is the path to the library file for the component and not a target.

---

<div class="post-metadata">

**Author:** ![LegalizeAdulthood](https://discourse.cmake.org/user_avatar/discourse.cmake.org/legalizeadulthood/32/5282_2.png) [@LegalizeAdulthood](https://discourse.cmake.org/u/LegalizeAdulthood)\
**Post date:** [April 2, 2025, 8:56pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/6 "2025-04-02T20:56:17Z")

</div>

> Note that `add_custom_command(TARGET ... POST_BUILD ...)` requires that the target you give it is also defined in the same directory scope.

Yes, this may require creating a custom target as well.

---

<div class="post-metadata">

**Author:** ![K0I05](https://discourse.cmake.org/user_avatar/discourse.cmake.org/k0i05/32/5475_2.png) [@K0I05](https://discourse.cmake.org/u/K0I05)\
**Post date:** [April 2, 2025, 9:51pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/7 "2025-04-02T21:51:13Z")

</div>

Thanks so much for the suggestions. Yes, the CMakeLists.txt above is in the component directory. ${COMPONENT\_DIR} is the component directory reference. However, I assume it is compiled outside the component directory in a cached build folder.

This should clarify things: [Sample Code Base (VS-Code + ESP-IDF)](https://github.com/K0I05/cmake_components_20250329/blob/main/components/esp_uuid/CMakeLists.txt)

---

<div class="post-metadata">

**Author:** ![LegalizeAdulthood](https://discourse.cmake.org/user_avatar/discourse.cmake.org/legalizeadulthood/32/5282_2.png) [@LegalizeAdulthood](https://discourse.cmake.org/u/LegalizeAdulthood)\
**Post date:** [April 2, 2025, 10:29pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/8 "2025-04-02T22:29:25Z")

</div>

You can determine if `COMPONENT_ALIAS` is a target with a little debugging snippet like:

```auto
if(NOT TARGET ${COMPONENT_ALIAS})
    message(FATAL_ERROR "${COMPONENT_ALIAS} is not a target!")
endif()

```

---

<div class="post-metadata">

**Author:** ![K0I05](https://discourse.cmake.org/user_avatar/discourse.cmake.org/k0i05/32/5475_2.png) [@K0I05](https://discourse.cmake.org/u/K0I05)\
**Post date:** [April 2, 2025, 11:00pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/9 "2025-04-02T23:00:07Z")

</div>

> [@LegalizeAdulthood](#):
>
> ```auto
> if(NOT TARGET ${COMPONENT_ALIAS})
> message(FATAL_ERROR "${COMPONENT_ALIAS} is not a target!")
> endif()
> 
> ```

I tried the following:

```auto
if(NOT TARGET ${COMPONENT_ALIAS})
    message("${COMPONENT_ALIAS} is not a target!")
else()
    message("${COMPONENT_ALIAS} is a target!")
endif()

if(NOT TARGET ${COMPONENT_LIB})
    message("${COMPONENT_LIB} is not a target!")
else()
    message("${COMPONENT_LIB} is a target!")
endif()

```

And both appear to be targets:

```auto
idf::esp_uuid is a target!
__idf_esp_uuid is a target!

```

---

<div class="post-metadata">

**Author:** ![LegalizeAdulthood](https://discourse.cmake.org/user_avatar/discourse.cmake.org/legalizeadulthood/32/5282_2.png) [@LegalizeAdulthood](https://discourse.cmake.org/u/LegalizeAdulthood)\
**Post date:** [April 3, 2025, 7:51pm UTC](https://discourse.cmake.org/t/execute-command-post-build-cmake-esp-idf-vs-code-with-pio/13869/10 "2025-04-03T19:51:11Z")

</div>

> [@K0I05](#):
>
> And both appear to be targets:

Then I’m guessing it comes back to the constraint on [add\_custom\_command](https://cmake.org/cmake/help/latest/command/add_custom_command.html#build-events):

> The `<target>` must be defined in the current directory; targets defined in other directories may not be specified.

…which implies that you’ll have to create a custom target, add the custom command to the custom target and then specify a dependency between your custom target and the target for the component.
