EXCLUDE_FROM_ALL changes lead to overly aggressive include_external_msproject() dependency behavior
This problem was originally reported on the CMake users mailing list, pasting in the essentials here for easier reference.
Original problem description
We have a fairly large CMake project which uses include_extenal_msproject() when we are producing Visual Studio solutions to bring in projects produced using another build metadata generator. We've noticed most of our Visual Studio builds have started failing after switching to CMake 3.14.0-rc2 (not sure where betweenn 3.13.4 and 3.14.0-rc2 this issue was introduced).
An example of how the behavior differs can be realised with the following example:
dependencies/CMakeLists.txt:
# several duplications of the following block exist replacing fooN with
foo1, foo2, foo3, etc.
add_library(fooN_cmake STATIC IMPORTED GLOBAL)
if(MSVC)
include_external_msproject(fooN_cmake_extern "fooN.vcproj")
else()
# other external things happen here using ExternalProject_add to end
up creating fooN_cmake_extern for non-VS/non-Windows builds.
endif()
add_dependencies(fooN_cmake fooN_cmake_extern)
set_property(TARGET fooN_cmake PROPERTY INTERFACE_INCLUDE_DIRECTORIES "path to foo include files")
set_property(TARGET fooN_cmake PROPERTY IMPORTED_LOCATION_DEBUG "path to foo static library")
# ... more properties possibly set
frontend1/CMakeLists.txt:
add_subdirectory(../dependencies "${CMAKE_CURRENT_BINARY_DIR}/ext_deps" EXCLUDE_FROM_ALL)
add_executable(frontend1 main.c)
target_link_libraries(frontend1 foo1_cmake foo2_cmake)
frontend2/CMakeLists.txt:
add_subdirectory(../dependencies "${CMAKE_CURRENT_BINARY_DIR}/ext_deps" EXCLUDE_FROM_ALL)
add_executable(frontend2 main.c)
target_link_libraries(frontend2 foo3_cmake foo2_cmake)
The old behavior: we could invoke CMake using a source directory of frontend1 or frontend2 to get Visual Studio solutions. Only the Visual Studio projects which are imported using include_extenal_msproject() that are dependencies of that particular frontend are included in the solution i.e. the VS solution for frontend1 will not include foo3_cmake as part of the build at all. I expect this due to the use of EXCLUDE_FROM_ALL.
The new behavior: all frontends will include every single project defined using include_extenal_msproject that CMake encounters. They will all attempt to be built regardless of if there is a dependency. I would only have expected this behavior if EXCLUDE_FROM_ALL was not set when using add_subdirectory().
Follow-up comment
I've verified that the revision you pointed me to (24b6e483) is where the behavior broke (I built CMake using the revision directly before this one and everything still works fine). I'm no expert with CMake development - could someone chime in on whether what I am seeing is expected or whether something has inadvertently been broken?
Testing this is actually quite simple. There is no need to even have valid external vcproj files on the file system - CMake does not appear to care if they exist or not when generating the solution. The most trivial test I can give to reproduce the behavior is:
./CMakeLists.txt:
cmake_minimum_required(VERSION 3.4)
project(frontend_test)
add_subdirectory(deps "${CMAKE_CURRENT_BINARY_DIR}/ext_deps" EXCLUDE_FROM_ALL)
add_executable(frontend1 main.c)
target_link_libraries(frontend1 foo1_cmake)
./main.c:
/* nothing - unimportant for the test */
./deps/CMakeLists.txt:
cmake_minimum_required(VERSION 3.4)
add_library(foo1_cmake STATIC IMPORTED GLOBAL)
include_external_msproject(foo1_cmake_extern "foo1.vcproj")
add_dependencies(foo1_cmake foo1_cmake_extern)
set_property(TARGET foo1_cmake PROPERTY IMPORTED_LOCATION_DEBUG "foo1.lib")
add_library(foo2_cmake STATIC IMPORTED GLOBAL)
include_external_msproject(foo2_cmake_extern "foo2.vcproj")
add_dependencies(foo2_cmake foo2_cmake_extern)
set_property(TARGET foo2_cmake PROPERTY IMPORTED_LOCATION_DEBUG "foo2.lib")
Invoking CMake before revision 24b6e483 and opening the solution will show that Visual Studio would like to open foo1_cmake_extern (and it will show as unavailable in the solution explorer on account of the file not actually existing).
Invoking CMake at or after revision 24b6e483 and opening the solution will show that Visual Studio would like to open foo1_cmake_extern AND foo2_cmake_extern (and both will show as unavailable in the solution explorer on account of the file not actually existing).