# Avoiding "TARGET was not created in this directory" errors

**URL:** <https://discourse.cmake.org/t/avoiding-target-was-not-created-in-this-directory-errors/11321>\
**Category:** Code\
**Created:** [July 24, 2024, 11:47pm UTC](https://discourse.cmake.org/t/avoiding-target-was-not-created-in-this-directory-errors/11321 "2024-07-24T23:47:36Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![tristan](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/96bed5/32.png) [@tristan](https://discourse.cmake.org/u/tristan)\
**Post date:** [July 24, 2024, 11:47pm UTC](https://discourse.cmake.org/t/avoiding-target-was-not-created-in-this-directory-errors/11321/1 "2024-07-24T23:47:36Z")

</div>

Not sure if this question is best attributed to the ‘Code’ or ‘Development’ group…

Because I always separate my projects for libraries and it’s tests. I tend to work around the error:

> CMake Error at test/CMakeLists.txt:62 (add\_custom\_command):  
> TARGET ‘my-library-target’ was not created in this directory.

I’m not even sure why this has to be an error, especially when the target was declared in a parent project. Is there any way to relax this error? Is there any consideration to reconsider this class of errors?

This workaround is generally okay:

> <https://stackoverflow.com/questions/40294146/alternative-to-cmake-post-build-command-when-target-is-in-subdirectory>

I wrapped it into a more generic function.

```cmake
set(copy_target_thing_meta_counter 0)

# CopyTargetThing(
# COMMAND_NAME <name>
# SOURCE <TARGET | VARIABLE>
# DESTINATION <TARGET | VARIABLE>
# )
# where TARGET -> PROPERTY INPUT_TARGET
# where VARIABLE -> INPUT_VARIABLE

# PROPERTY can be like TARGET_RUNTIME_DLLS or TARGET_FILE or whatever

    # Example usage
    CopyTargetThing(
        COMMAND_NAME "CopyMyLibraryDependenciesForTests"
        SOURCE
            TARGET
                PROPERTY "TARGET_RUNTIME_DLLS"
                INPUT_TARGET my-library::my-library
        DESTINATION
            VARIABLE
                INPUT_VARIABLE MyDesiredDirectory
    )

# The auto generated command name is so cryptic to try to avoid Windows path length issues
function(CopyTargetThing)

    set(oneValueArgs COMMAND_NAME)
    set(multiValueArgs SOURCE DESTINATION)
    cmake_parse_arguments(copy_target "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if (NOT copy_target_SOURCE)
        message(FATAL_ERROR "CopyTargetThing(SOURCE) must be specified.")
    endif()

    if (NOT copy_target_DESTINATION)
        message(FATAL_ERROR "CopyTargetThing(DESTINATION) must be specified.")
    endif()

    set(multiValueArgs TARGET VARIABLE)
    cmake_parse_arguments(source_args "" "" "${multiValueArgs}" ${copy_target_SOURCE})
    cmake_parse_arguments(destination_args "" "" "${multiValueArgs}" ${copy_target_DESTINATION})

    if (NOT source_args_TARGET AND NOT source_args_VARIABLE)
        message(FATAL_ERROR "CopyTargetThing(SOURCE) must specify either TARGET or VARIABLE.")
    endif()

    if (NOT destination_args_TARGET AND NOT destination_args_VARIABLE)
        message(FATAL_ERROR "CopyTargetThing(DESTINATION) must specify either TARGET or VARIABLE.")
    endif()

    set(source)
    set(destination)
    set(meta_command_name "CTT_")

    set(oneValueArgs PROPERTY INPUT_TARGET INPUT_VARIABLE)
    if (source_args_TARGET)
        cmake_parse_arguments(source_args "" "${oneValueArgs}" "" ${source_args_TARGET})
        if (NOT source_args_PROPERTY)
            message(FATAL_ERROR "CopyTargetThing(SOURCE TARGET) must specify PROPERTY.")
        endif()
        if (NOT source_args_INPUT_TARGET)
            message(FATAL_ERROR "CopyTargetThing(SOURCE TARGET) must specify INPUT_TARGET.")
        endif()
        set(source "$<${source_args_PROPERTY}:${source_args_INPUT_TARGET}>")
        get_target_property(source_output_name ${source_args_INPUT_TARGET} OUTPUT_NAME)
        string(APPEND meta_command_name "T_${source_output_name}_")
    else()
        cmake_parse_arguments(source_args "" "${oneValueArgs}" "" ${source_args_VARIABLE})
        if (NOT source_args_INPUT_VARIABLE)
            message(FATAL_ERROR "CopyTargetThing(SOURCE VARIABLE) must specify INPUT_VARIABLE.")
        endif()
        set(source "${source_args_VARIABLE}")
        string(APPEND meta_command_name "V_${source_args_VARIABLE}_")
    endif()

    if (destination_args_TARGET)
        cmake_parse_arguments(destination_args "" "${oneValueArgs}" "" ${destination_args_TARGET})
        if (NOT destination_args_PROPERTY)
            message(FATAL_ERROR "CopyTargetThing(DESTINATION TARGET) must specify PROPERTY.")
        endif()
        if (NOT destination_args_INPUT_TARGET)
            message(FATAL_ERROR "CopyTargetThing(DESTINATION TARGET) must specify INPUT_TARGET.")
        endif()
        set(destination "$<${destination_args_PROPERTY}:${destination_args_INPUT_TARGET}>")
        get_target_property(destination_output_name ${destination_args_INPUT_TARGET} OUTPUT_NAME)
        string(APPEND meta_command_name "T_${destination_output_name}")
    else()
        cmake_parse_arguments(destination_args "" "${oneValueArgs}" "" ${destination_args_VARIABLE})
        if (NOT destination_args_INPUT_VARIABLE)
            message(FATAL_ERROR "CopyTargetThing(DESTINATION VARIABLE) must specify INPUT_VARIABLE.")
        endif()
        set(destination "${${destination_args_INPUT_VARIABLE}}")
        string(APPEND meta_command_name "V_${destination_args_INPUT_VARIABLE}")
    endif()

    if (copy_target_COMMAND_NAME)
        set(meta_command_name "${copy_target_COMMAND_NAME}")
    else() # finish up generating the command name
        string(APPEND meta_command_name "_${copy_target_thing_meta_counter}")
        math(EXPR copy_target_thing_meta_counter "${copy_target_thing_meta_counter} + 1")
        set(copy_target_thing_meta_counter ${copy_target_thing_meta_counter} PARENT_SCOPE)
    endif()

    message(DEBUG "CopyTargetThing() - source: ${source}")
    message(DEBUG "CopyTargetThing() - destination: ${destination}")
    message(DEBUG "CopyTargetThing() - meta_command_name: ${meta_command_name}")

    add_custom_target(
        "${meta_command_name}"
        ALL
        COMMAND ${CMAKE_COMMAND} -E copy ${source} ${destination}
    )

    add_dependencies(
        "${meta_command_name}"
        ${source_args_INPUT_TARGET}
    )

endfunction()

```

But honestly I feel like I’m going about this the wrong way. Is there any better way to go about using target properties from generator expressions in sub-projects? Is this function ridiculous? Obviously it is rough around the edges and just a quick hack, but is the idea of this function ridiculous?

I will say one downside is that it creates targets that I dont need and they get all up in my business in my IDE.  
 ![CopyTargetThing_creates_targets](https://discourse.cmake.org/uploads/default/original/2X/9/999c6e9d9551e4be6b66193d7b29c7b944483c31.png)  
If I had bunch of these `CopyTargetThing()` calls it would be pretty annoying.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [July 25, 2025, 2:01pm UTC](https://discourse.cmake.org/t/avoiding-target-was-not-created-in-this-directory-errors/11321/2 "2025-07-25T14:01:04Z")

</div>

`add_custom_command` can only attach commands to targets in the _current_ directory. Parent directory’s targets are not accessible. This is stated in [the docs](https://cmake.org/cmake/help/latest/command/add_custom_command.html#build-events):

> [@](#):
>
> This defines a new command that will be associated with building the specified `<target>`. The `<target>` must be defined in the current directory; targets defined in other directories may not be specified.
