<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Wrong install path expansion in multi-configuration generated build (VS 2017)"
   href="https://bugs.llvm.org/show_bug.cgi?id=41030">41030</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Wrong install path expansion in multi-configuration generated build (VS 2017)
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>Build scripts
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Windows NT
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>cmake
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>richard.musil@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=21583" name="attach_21583" title="Patch file">attachment 21583</a> <a href="attachment.cgi?id=21583&action=edit" title="Patch file">[details]</a></span>
Patch file

I am using Visual Studio 2017 build tools (cmake version 3.12.18081601-MSVC_2)
to build LLVM project(s) by running this commands:

<span class="quote">> cmake -G "Visual Studio 15 2017" -A x64 -Thost=x64 -DCMAKE_INSTALL_PREFIX=D:\Dev\LLVM-ng -DLLVM_ENABLE_PROJECTS=clang;clang-tools-extra;compiler-rt;debuginfo-tests;libclc;libcxx;libcxxabi;libunwind;lld;llvm;parallel-libs;polly;pstl ..
> cmake --build . --target INSTALL --config Release</span >

Build phase passes alright (--target ALL_BUILD) but install phase bugs out with
an error about missing file source(s). This happens at two occasions when
compiler-rt libs and clang headers are going to be installed.

When looking at corresponding cmake_install.cmake file for compiler-rt libs I
noticed following snippets:

<build-1>/projects/compiler-rt/lib/asan/cmake_install.cmake

<span class="quote">> if("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "xasanx" OR NOT CMAKE_INSTALL_COMPONENT)
>   if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Dd][Ee][Bb][Uu][Gg])$")
>     file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/clang/9.0.0/lib/windows" TYPE STATIC_LIBRARY FILES "D:/Work_OSS/llvm-project/llvm/build-1/$(Configuration)/lib/clang/9.0.0/lib/windows/clang_rt.asan-x86_64.lib")
>   elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$")
>     file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/clang/9.0.0/lib/windows" TYPE STATIC_LIBRARY FILES "D:/Work_OSS/llvm-project/llvm/build-1/$(Configuration)/lib/clang/9.0.0/lib/windows/clang_rt.asan-x86_64.lib")
>   elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Mm][Ii][Nn][Ss][Ii][Zz][Ee][Rr][Ee][Ll])$")
>     file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/clang/9.0.0/lib/windows" TYPE STATIC_LIBRARY FILES "D:/Work_OSS/llvm-project/llvm/build-1/$(Configuration)/lib/clang/9.0.0/lib/windows/clang_rt.asan-x86_64.lib")
>   elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ww][Ii][Tt][Hh][Dd][Ee][Bb][Ii][Nn][Ff][Oo])$")
>     file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/clang/9.0.0/lib/windows" TYPE STATIC_LIBRARY FILES "D:/Work_OSS/llvm-project/llvm/build-1/$(Configuration)/lib/clang/9.0.0/lib/windows/clang_rt.asan-x86_64.lib")
>   endif()
> endif()</span >

where the problem is $(Configuration) in the path. So even though the multiple
configurations (Release, Debug, etc.) are properly expanded in the script, they
are all set with the same (wrong) path.

The corresponding script responsible for this is
compiler-rt/cmake/Modules/AddCompilerRT.cmake, this function in particular:

<span class="quote">> function(set_target_output_directories target output_dir)
>   # For RUNTIME_OUTPUT_DIRECTORY variable, Multi-configuration generators
>   # append a per-configuration subdirectory to the specified directory.
>   # To avoid the appended folder, the configuration specific variable must be
>   # set 'RUNTIME_OUTPUT_DIRECTORY_${CONF}':
>   # RUNTIME_OUTPUT_DIRECTORY_DEBUG, RUNTIME_OUTPUT_DIRECTORY_RELEASE, ...
>   if(CMAKE_CONFIGURATION_TYPES)
>     foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
>       string(TOUPPER "${build_mode}" CONFIG_SUFFIX)"${output_dir}")
>       set_target_properties("${target}" PROPERTIES
>           "ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
>           "LIBRARY_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
>           "RUNTIME_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir})
>     endforeach()
>   else()
>     set_target_properties("${target}" PROPERTIES
>         ARCHIVE_OUTPUT_DIRECTORY ${output_dir}
>         LIBRARY_OUTPUT_DIRECTORY ${output_dir}
>         RUNTIME_OUTPUT_DIRECTORY ${output_dir})
>   endif()
> endfunction()</span >

Where ${output_dir} contains the path with "$(Configuration)". It seems that
the author's idea was that this will get expanded, but when looking at cmake
doc, and in particular at target properties
(<a href="https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html">https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html</a>) it
says only 'generator expression' gets expanded, but not platform specific build
time variables.

It seems that some cmake scripts authors were already aware of that as for
example llvm/cmake/modules/AddLLVM.cmake, which took this approach:

<span class="quote">> if(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".")
>   foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
>     string(TOUPPER "${build_mode}" CONFIG_SUFFIX)
>     if(ARG_BINARY_DIR)
>       string(REPLACE ${CMAKE_CFG_INTDIR} ${build_mode} bi ${ARG_BINARY_DIR})
>       set_target_properties(${target} PROPERTIES "RUNTIME_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${bi})
>     endif()
>     if(ARG_LIBRARY_DIR)
>       string(REPLACE ${CMAKE_CFG_INTDIR} ${build_mode} li ${ARG_LIBRARY_DIR})
>       set_target_properties(${target} PROPERTIES "ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${li})
>     endif()
>     if(module_dir)
>       string(REPLACE ${CMAKE_CFG_INTDIR} ${build_mode} mi ${module_dir})
>       set_target_properties(${target} PROPERTIES "LIBRARY_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${mi})
>     endif()
>   endforeach()
> else()</span >

I.e. generating configuration specific target properties and replacing
"$(Configuration)" by the desired config.

When looking at the cmake doc, I also noticed that while non
multi-configuration target properties (e.g. RUNTIME_OUTPUT_DIRECTORY) are
supposed  to be suffixed by multi-configuration generator with the
configuration name, this _does not_ happen, when the property contains
expression generator.

In short, the original function can be fixed by using "$<CONFIG>" expression
generator, like this:

<span class="quote">> function(set_target_output_directories target output_dir)
>   # If we are using multi-configuration generator ensure proper folder
>   # expansion by using $<CONFIG> generator expression
>   if(CMAKE_CONFIGURATION_TYPES)
>     string(REPLACE "${CMAKE_CFG_INTDIR}" "$<CONFIG>" output_dir "${output_dir}")
>   endif()
>   set_target_properties("${target}" PROPERTIES
>       ARCHIVE_OUTPUT_DIRECTORY ${output_dir}
>       LIBRARY_OUTPUT_DIRECTORY ${output_dir}
>       RUNTIME_OUTPUT_DIRECTORY ${output_dir})
> endfunction()</span >

The other occurrence related to clang headers is of the similar kind (applied
to "install" cmake command), so I am not going to dissect it here, only
interesting point is that it was not present in 7.0.1 release and apparently
crept into the current branch later.

As the bug only manifests itself in the install phase I assume the install
phase is not normally validated before release. I would suggest adding it to
the validation.

Proposed patch attached is generated against current master.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>