0

As an example suppose four folders(app1, app2, app3 and main) such as below

main
|__ CMakeLists.txt
\__ module1
|______ CMakeLists.txt
|______ sub1.cpp
|______ sub1.h
\__ library5
|______ CMakeLists.txt
|______ sub5.cpp
|______ sub5.h
\__app1
\__app2
\__app3

Which output of module1 is module1.dll and output of library5 is lib5.dll. Folder of app1 must contain module1.dll and lib5.dll, app2 needs lib5.dll and finally app3 needs module1.dll(number of apps, modules and libs are more than this example and as I explain below we don't want to change modules/libraries's CMakeLists.txt, just main's CMakeLists.txt is ours).

PS:

I have a cmake project which has several libraries and modules. They included in my project using add_subdirectory command (note that my project just made up from multiple modules and it has not any add_library or add_target).

I need to copy outputs of libraries/modules without changing their CMakeLists.txt (add_custom_command with POST_BUILD option actually is not a good choice because at this point I need to change CMakeLists.txt of libraries/modules which they are not just belong to my project). On the other hand it must done in outer(major) CMakeLists.txt which has others(libraries/modules).

I tried some other commands such as file (COPY ) and configure_file() but I think they operate in generating cmake-cache phase and just can copy resource files which are exist in pre-build phase.

Moreover, In another approach I write a bash script file to copy the files and call it in major CMakeLists.txt via bellow command.

add_custom_target (copy_all
        COMMAND ${CMAKE_SOURCE_DIR}/copy.sh ${files}
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)

The files has the list of files. But the copy not performed! I manually test the script which works as desired. But I don't have any idea why it can not operate at call in CMakeLists.txt.

What can I do to copy sub-projects outputs to some locations from major CMakeLists.txt?

Bonje Fir
  • 787
  • 8
  • 25
  • 2
    Possible duplicate of [Copying executable and DLLs to User specified location using CMake in windows](https://stackoverflow.com/questions/20752036/copying-executable-and-dlls-to-user-specified-location-using-cmake-in-windows) – Florian Aug 23 '17 at 07:38
  • @Florian Question is as what **A custom command** solution solved but I need a `cmake` command s.t. I add it to `CMakeLists.txt` which others pull the project can use that. – Bonje Fir Aug 23 '17 at 07:48
  • If you want a CMake-native command, why is this question tagged [tag:bash]? – tripleee Aug 23 '17 at 07:51
  • @tripleee it is not forced to use CMake-native command. Since I explained a solution which I used bash script, I hoped somebody can suggest a solution which can edit it. thanks – Bonje Fir Aug 23 '17 at 07:54
  • 2
    @BonjeFir I've chosen the Q/A because it lists all possibilities. Can you please specify which artifacts you want to copy? If it's just e.g. the libraries, something like `LIBRARY_OUTPUT_PATH` in the root `CMakeLists.txt` does the trick. See ["Parent CMakeLists.txt overwriting child CMakeLists.txt output directory options"](https://stackoverflow.com/questions/32414587/parent-cmakelists-txt-overwriting-child-cmakelists-txt-output-directory-options). – Florian Aug 23 '17 at 08:16
  • @Florian Actually I need to copy several .dll(.mexw64) files beside some other applications(also not to add system path). These applications are different from each other (i.e. we have different destinations and even one .dll must copy to multiple places). Moreover, I must mention that again I don't want to modify libraries`CMakeLists.txt`. Thanks – Bonje Fir Aug 23 '17 at 09:41
  • @BonjeFir Is the executable that needs the DLLs part of your root `CMakeLists.txt`? Then you could add it as a post-build step there. Could you please add a [mcve] of your main `CMakeLists.txt` and of `copy.sh` to your question? The dependencies are not clear from you question/comment, but very important to how/where/when you copy the build artifacts of your sub-projects. – Florian Aug 23 '17 at 11:34
  • @Florian I add a simplification structure and scenario at the bottom of above question. Moreover the script is like bellow `#!/bin/bash for target in $@; do if [ -f ${target} ]; then cp ${target} "Path/to/apps" else echo "ERROR: File ${target} not found!" fi done ` – Bonje Fir Aug 23 '17 at 12:08
  • @Florian Precisely all apps folders belong to root of main and modules are in main/projects and libraries are in main/lib/third party. – Bonje Fir Aug 23 '17 at 13:25

1 Answers1

2

The Setup

To simplify it a little, let's say you have:

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(PostBuildCopyFromRoot)

add_subdirectory(module)

module/CMakeLists.txt

file(WRITE "module.h" "int ModuleFunc();")
file(WRITE "module.cpp" "int ModuleFunc() { return 1; }")

add_library(module SHARED "module.cpp" "module.h")
target_include_directories(module PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
set_target_properties(module PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS 1)

app/app.mexw64

The Problem

If you now just add to following to the root CMakeLists.txt:

add_custom_command(
    TARGET module
    POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy
        "$<TARGET_FILE:module>"
        "app/$<TARGET_FILE_NAME:module>"
)

You will get from CMake:

CMake Warning (dev) at CMakeLists.txt:8 (add_custom_command):
  Policy CMP0040 is not set: The target in the TARGET signature of
  add_custom_command() must exist.  Run "cmake --help-policy CMP0040" for
  policy details.  Use the cmake_policy command to set the policy and
  suppress this warning.

  TARGET 'module' was not created in this directory.

Solutions

You can always overwrite command behaviors:

    function(add_library _target)
        _add_library(${_target} ${ARGN})

        add_custom_command(
            TARGET ${_target}
            POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy
                "$<TARGET_FILE:${_target}>"
                "${CMAKE_SOURCE_DIR}/app/$<TARGET_FILE_NAME:${_target}>"
        )
    endfunction()

NOTE: Put the code snippets before the add_subdirectory() call

References

Florian
  • 39,996
  • 9
  • 133
  • 149
  • Thanks for your answer but as you can see in the hierarchy `apps` have not any `CMakeLists.txt`. Actually they are `Matlab` codes which use `.dll`s(as `.mexw64` file). – Bonje Fir Aug 26 '17 at 06:09
  • @BonjeFir Updated my code accordingly. But that would copy the DLL into the source tree. – Florian Aug 27 '17 at 10:33