diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 5a383e0c3..9f318ece9 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -276,9 +276,10 @@ void cmGlobalVisualStudio71Generator // Write a dsp file into the SLN file, Note, that dependencies from // executables to the libraries it uses are also done here void cmGlobalVisualStudio71Generator -::WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild, - const char* platformMapping) +::WriteProjectConfigurations( + std::ostream& fout, const char* name, + const std::set& configsPartOfDefaultBuild, + const char* platformMapping) { std::string guid = this->GetGUID(name); for(std::vector::iterator i = this->Configurations.begin(); @@ -287,7 +288,9 @@ void cmGlobalVisualStudio71Generator fout << "\t\t{" << guid << "}." << *i << ".ActiveCfg = " << *i << "|" << (platformMapping ? platformMapping : "Win32") << std::endl; - if(partOfDefaultBuild) + std::set::const_iterator + ci = configsPartOfDefaultBuild.find(*i); + if(!(ci == configsPartOfDefaultBuild.end())) { fout << "\t\t{" << guid << "}." << *i << ".Build.0 = " << *i << "|" diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index dc8cfebfb..f96a7d94b 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -61,10 +61,10 @@ protected: const char* name, const char* path, cmTarget &t); virtual void WriteProjectDepends(std::ostream& fout, const char* name, const char* path, cmTarget &t); - virtual void WriteProjectConfigurations(std::ostream& fout, - const char* name, - bool partOfDefaultBuild, - const char* platformMapping = NULL); + virtual void WriteProjectConfigurations( + std::ostream& fout, const char* name, + const std::set& configsPartOfDefaultBuild, + const char* platformMapping = NULL); virtual void WriteExternalProject(std::ostream& fout, const char* name, const char* path, diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index fc5db99a9..6f9c02809 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -10,6 +10,7 @@ See the License for more information. ============================================================================*/ #include "windows.h" // this must be first to define GetCurrentDirectory +#include #include "cmGlobalVisualStudio7Generator.h" #include "cmGeneratedFileStream.h" #include "cmLocalVisualStudio7Generator.h" @@ -243,20 +244,23 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( const char* expath = target->GetProperty("EXTERNAL_MSPROJECT"); if(expath) { + std::set allConfigurations(this->Configurations.begin(), + this->Configurations.end()); this->WriteProjectConfigurations( fout, target->GetName(), - true, target->GetProperty("VS_PLATFORM_MAPPING")); + allConfigurations, target->GetProperty("VS_PLATFORM_MAPPING")); } else { - bool partOfDefaultBuild = this->IsPartOfDefaultBuild( - root->GetMakefile()->GetProjectName(), target); + const std::set& configsPartOfDefaultBuild = + this->IsPartOfDefaultBuild(root->GetMakefile()->GetProjectName(), + target); const char *vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); if (vcprojName) { this->WriteProjectConfigurations(fout, vcprojName, - partOfDefaultBuild); + configsPartOfDefaultBuild); } } } @@ -582,9 +586,10 @@ cmGlobalVisualStudio7Generator // Write a dsp file into the SLN file, Note, that dependencies from // executables to the libraries it uses are also done here void cmGlobalVisualStudio7Generator -::WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild, - const char* platformMapping) +::WriteProjectConfigurations( + std::ostream& fout, const char* name, + const std::set& configsPartOfDefaultBuild, + const char* platformMapping) { std::string guid = this->GetGUID(name); for(std::vector::iterator i = this->Configurations.begin(); @@ -593,7 +598,9 @@ void cmGlobalVisualStudio7Generator fout << "\t\t{" << guid << "}." << *i << ".ActiveCfg = " << *i << "|" << (platformMapping ? platformMapping : "Win32") << "\n"; - if(partOfDefaultBuild) + std::set::const_iterator + ci = configsPartOfDefaultBuild.find(*i); + if(!(ci == configsPartOfDefaultBuild.end())) { fout << "\t\t{" << guid << "}." << *i << ".Build.0 = " << *i << "|" @@ -825,26 +832,34 @@ cmGlobalVisualStudio7Generator } } -bool cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild(const char* project, - cmTarget* target) +std::set +cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild(const char* project, + cmTarget* target) { - if(target->GetPropertyAsBool("EXCLUDE_FROM_DEFAULT_BUILD")) - { - return false; - } + std::set activeConfigs; // if it is a utilitiy target then only make it part of the // default build if another target depends on it int type = target->GetType(); if (type == cmTarget::GLOBAL_TARGET) { - return false; + return activeConfigs; } - if(type == cmTarget::UTILITY) + if(type == cmTarget::UTILITY && !this->IsDependedOn(project, target)) { - return this->IsDependedOn(project, target); + return activeConfigs; } - // default is to be part of the build - return true; + // inspect EXCLUDE_FROM_DEFAULT_BUILD[_] properties + for(std::vector::iterator i = this->Configurations.begin(); + i != this->Configurations.end(); ++i) + { + const char* propertyValue = + target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i->c_str()); + if(cmSystemTools::IsOff(propertyValue)) + { + activeConfigs.insert(*i); + } + } + return activeConfigs; } //---------------------------------------------------------------------------- diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index db59dd67e..8ba1f4462 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -105,10 +105,10 @@ protected: const char* name, const char* path, cmTarget &t); virtual void WriteProjectDepends(std::ostream& fout, const char* name, const char* path, cmTarget &t); - virtual void WriteProjectConfigurations(std::ostream& fout, - const char* name, - bool partOfDefaultBuild, - const char* platformMapping = NULL); + virtual void WriteProjectConfigurations( + std::ostream& fout, const char* name, + const std::set& configsPartOfDefaultBuild, + const char* platformMapping = NULL); virtual void WriteSLNGlobalSections(std::ostream& fout, cmLocalGenerator* root); virtual void WriteSLNFooter(std::ostream& fout); @@ -138,8 +138,8 @@ protected: std::string ConvertToSolutionPath(const char* path); - bool IsPartOfDefaultBuild(const char* project, - cmTarget* target); + std::set IsPartOfDefaultBuild(const char* project, + cmTarget* target); std::vector Configurations; std::map GUIDMap; diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index a6ed2a645..c3ec3f218 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -257,9 +257,10 @@ cmGlobalVisualStudio8Generator //---------------------------------------------------------------------------- void cmGlobalVisualStudio8Generator -::WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild, - const char* platformMapping) +::WriteProjectConfigurations( + std::ostream& fout, const char* name, + const std::set& configsPartOfDefaultBuild, + const char* platformMapping) { std::string guid = this->GetGUID(name); for(std::vector::iterator i = this->Configurations.begin(); @@ -269,7 +270,9 @@ cmGlobalVisualStudio8Generator << "|" << this->GetPlatformName() << ".ActiveCfg = " << *i << "|" << (platformMapping ? platformMapping : this->GetPlatformName()) << "\n"; - if(partOfDefaultBuild) + std::set::const_iterator + ci = configsPartOfDefaultBuild.find(*i); + if(!(ci == configsPartOfDefaultBuild.end())) { fout << "\t\t{" << guid << "}." << *i << "|" << this->GetPlatformName() << ".Build.0 = " << *i << "|" diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index 5009f2960..2c9424d9c 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -74,10 +74,10 @@ protected: static cmIDEFlagTable const* GetExtraFlagTableVS8(); virtual void WriteSLNHeader(std::ostream& fout); virtual void WriteSolutionConfigurations(std::ostream& fout); - virtual void WriteProjectConfigurations(std::ostream& fout, - const char* name, - bool partOfDefaultBuild, - const char* platformMapping = NULL); + virtual void WriteProjectConfigurations( + std::ostream& fout, const char* name, + const std::set& configsPartOfDefaultBuild, + const char* platformMapping = NULL); virtual bool ComputeTargetDepends(); virtual void WriteProjectDepends(std::ostream& fout, const char* name, const char* path, cmTarget &t); diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h index 65c89fad4..9dd7848d3 100644 --- a/Source/cmSetTargetPropertiesCommand.h +++ b/Source/cmSetTargetPropertiesCommand.h @@ -156,7 +156,9 @@ public: "\n" "The EXCLUDE_FROM_DEFAULT_BUILD property is used by the visual " "studio generators. If it is set to 1 the target will not be " - "part of the default build when you select \"Build Solution\"." + "part of the default build when you select \"Build Solution\". " + "This can also be set on a per-configuration basis using " + "EXCLUDE_FROM_DEFAULT_BUILD_." ; } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index a81fa3ec1..7c62ea8f1 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -265,6 +265,21 @@ void cmTarget::DefineProperties(cmake *cm) "whatever file extension is required by the host app for your " "bundle."); + cm->DefineProperty + ("EXCLUDE_FROM_DEFAULT_BUILD", cmProperty::TARGET, + "Exclude target from \"Build Solution\".", + "This property is only used by Visual Studio generators 7 and above. " + "When set to TRUE, the target will not be built when you press " + "\"Build Solution\"."); + + cm->DefineProperty + ("EXCLUDE_FROM_DEFAULT_BUILD_", cmProperty::TARGET, + "Per-configuration version of target exclusion from \"Build Solution\". ", + "This is the configuration-specific version of " + "EXCLUDE_FROM_DEFAULT_BUILD. If the generic EXCLUDE_FROM_DEFAULT_BUILD " + "is also set on a target, EXCLUDE_FROM_DEFAULT_BUILD_ takes " + "precedence in configurations for which it has a value."); + cm->DefineProperty ("FRAMEWORK", cmProperty::TARGET, "This target is a framework on the Mac.", diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 03a538fe7..f2a198cff 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1442,6 +1442,35 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} --test-command VSMidl) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSMidl") + + if(NOT MSVC60 AND NOT CMAKE_TEST_MAKEPROGRAM MATCHES "[mM][sS][bB][uU][iI][lL][dD]\\.[eE][xX][eE]") + # The test (and tested property) works with .sln files, so it's skipped when: + # * Using VS6, which doesn't use .sln files + # * cmake --build is set up to use MSBuild, since the MSBuild invocation does not use the .sln file + set(_last_test "") + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + add_test(NAME VSExcludeFromDefaultBuild-${config} COMMAND ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/VSExcludeFromDefaultBuild" + "${CMake_BINARY_DIR}/Tests/VSExcludeFromDefaultBuild" + --build-config ${config} + --build-two-config + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project VSExcludeFromDefaultBuild + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --test-command ${CMAKE_COMMAND} + -D "activeConfig=${config}" + -D "allConfigs=${CMAKE_CONFIGURATION_TYPES}" + -D "dir=${CMake_BINARY_DIR}/Tests/VSExcludeFromDefaultBuild" + -P "${CMake_SOURCE_DIR}/Tests/VSExcludeFromDefaultBuild/ResultTest.cmake") + if(_last_test) + set_property(TEST VSExcludeFromDefaultBuild-${config} PROPERTY DEPENDS ${_last_test}) + endif() + set(_last_test "VSExcludeFromDefaultBuild-${config}") + endforeach() + unset(_last_test) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSExcludeFromDefaultBuild") + endif() endif() if (APPLE) diff --git a/Tests/VSExcludeFromDefaultBuild/CMakeLists.txt b/Tests/VSExcludeFromDefaultBuild/CMakeLists.txt new file mode 100644 index 000000000..d30414b4b --- /dev/null +++ b/Tests/VSExcludeFromDefaultBuild/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 2.8.9) +project(VSExcludeFromDefaultBuild) + +# First step is to clear all .exe files in output so that possible past +# failures of this test do not prevent it from succeeding. +add_custom_target(ClearExes ALL + COMMAND "${CMAKE_COMMAND}" + -Ddir=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/ClearExes.cmake + VERBATIM) + +# Make sure ClearExes is executed before other targets are built +function(add_test_executable target) + add_executable("${target}" ${ARGN}) + add_dependencies("${target}" ClearExes) +endfunction() + +add_test_executable(DefaultBuilt main.c) + +add_test_executable(AlwaysBuilt main.c) +set_target_properties(AlwaysBuilt PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD FALSE) + +add_test_executable(NeverBuilt main.c) +set_target_properties(NeverBuilt PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) + +foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} Config) + add_test_executable(BuiltIn${config} main.c) + set_target_properties(BuiltIn${config} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE EXCLUDE_FROM_DEFAULT_BUILD_${Config} FALSE) + add_test_executable(ExcludedIn${config} main.c) + set_target_properties(ExcludedIn${config} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_${Config} TRUE) +endforeach() diff --git a/Tests/VSExcludeFromDefaultBuild/ClearExes.cmake b/Tests/VSExcludeFromDefaultBuild/ClearExes.cmake new file mode 100644 index 000000000..ece30ad00 --- /dev/null +++ b/Tests/VSExcludeFromDefaultBuild/ClearExes.cmake @@ -0,0 +1,4 @@ +file(GLOB exeFiles "${dir}/*.exe") +foreach(exeFile IN LISTS exeFiles) + file(REMOVE "${exeFile}") +endforeach() diff --git a/Tests/VSExcludeFromDefaultBuild/ResultTest.cmake b/Tests/VSExcludeFromDefaultBuild/ResultTest.cmake new file mode 100644 index 000000000..8fb00bfad --- /dev/null +++ b/Tests/VSExcludeFromDefaultBuild/ResultTest.cmake @@ -0,0 +1,23 @@ +message(STATUS "Testing configuration ${activeConfig}.") + +macro(TestExists exeName) + set(exeFile "${dir}/${activeConfig}/${exeName}.exe") + if(${ARGN} EXISTS "${exeFile}") + message(STATUS "File ${exeFile} was correctly found ${ARGN} to exist.") + else() + message(FATAL_ERROR "File ${exeFile} was expected ${ARGN} to exist!") + endif() +endmacro() + +TestExists(DefaultBuilt) +TestExists(AlwaysBuilt) +TestExists(NeverBuilt NOT) +foreach(config ${allConfigs}) + if(config STREQUAL activeConfig) + TestExists(BuiltIn${config}) + TestExists(ExcludedIn${config} NOT) + else() + TestExists(BuiltIn${config} NOT) + TestExists(ExcludedIn${config}) + endif() +endforeach() diff --git a/Tests/VSExcludeFromDefaultBuild/main.c b/Tests/VSExcludeFromDefaultBuild/main.c new file mode 100644 index 000000000..8488f4e58 --- /dev/null +++ b/Tests/VSExcludeFromDefaultBuild/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +}