summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@qt.io>2020-07-16 08:15:04 (GMT)
committerJoerg Bornemann <joerg.bornemann@qt.io>2020-07-21 15:16:26 (GMT)
commit2cdaf43d966f8407f0fb75ceb131fdca16617915 (patch)
tree15e3284091c62ca73b22fa15ea1a93770c97305d
parentc7b7547d8da6b9a4225d111440d0cf6c2f55914d (diff)
downloadCMake-2cdaf43d966f8407f0fb75ceb131fdca16617915.zip
CMake-2cdaf43d966f8407f0fb75ceb131fdca16617915.tar.gz
CMake-2cdaf43d966f8407f0fb75ceb131fdca16617915.tar.bz2
Allow generator expressions in the EXCLUDE_FROM_ALL target property
This allows for setting EXCLUDE_FROM_ALL, conditional on the build configuration. However, only the Ninja Multi-Config generator supports different property values per config. All other multi-config generators will yield an error in that situation. Fixes: #20923
-rw-r--r--Help/prop_tgt/EXCLUDE_FROM_ALL.rst7
-rw-r--r--Source/cmGlobalCommonGenerator.cxx32
-rw-r--r--Source/cmGlobalCommonGenerator.h4
-rw-r--r--Source/cmGlobalGenerator.cxx31
-rw-r--r--Source/cmGlobalGenerator.h3
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx2
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx2
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx4
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/ExcludeFromAll/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake26
-rw-r--r--Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt1
-rw-r--r--Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt3
-rw-r--r--Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake6
-rw-r--r--Tests/RunCMake/ExcludeFromAll/main.c3
-rw-r--r--Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake17
-rw-r--r--Tests/RunCMake/ExcludeFromAll/single-config.cmake11
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake9
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake12
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake5
20 files changed, 168 insertions, 14 deletions
diff --git a/Help/prop_tgt/EXCLUDE_FROM_ALL.rst b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
index c9ece22..f0200f3 100644
--- a/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
+++ b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
@@ -19,3 +19,10 @@ If a target has ``EXCLUDE_FROM_ALL`` set to true, it may still be listed
in an :command:`install(TARGETS)` command, but the user is responsible for
ensuring that the target's build artifacts are not missing or outdated when
an install is performed.
+
+This property may use "generator expressions" with the syntax ``$<...>``. See
+the :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+Only the "Ninja Multi-Config" generator supports a property value that varies by
+configuration. For all other generators the value of this property must be the
+same for all configurations.
diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx
index 9dc86f4..5eff3b8 100644
--- a/Source/cmGlobalCommonGenerator.cxx
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -5,8 +5,12 @@
#include <memory>
#include <utility>
+#include <cmext/algorithm>
+
+#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
#include "cmProperty.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
@@ -31,6 +35,8 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const
lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
DirectoryTarget& dirTarget = dirTargets[currentBinaryDir];
dirTarget.LG = lg.get();
+ const std::vector<std::string>& configs =
+ lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
// The directory-level rule should depend on the target-level rules
// for all targets in the directory.
@@ -46,11 +52,18 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const
}
DirectoryTarget::Target t;
t.GT = gt.get();
- if (cmProp exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) {
- if (cmIsOn(*exclude)) {
- // This target has been explicitly excluded.
- t.ExcludeFromAll = true;
- } else {
+ const std::string EXCLUDE_FROM_ALL("EXCLUDE_FROM_ALL");
+ if (cmProp exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) {
+ for (const std::string& config : configs) {
+ cmGeneratorExpressionInterpreter genexInterpreter(lg.get(), config,
+ gt.get());
+ if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
+ // This target has been explicitly excluded.
+ t.ExcludedFromAllInConfigs.push_back(config);
+ }
+ }
+
+ if (t.ExcludedFromAllInConfigs.empty()) {
// This target has been explicitly un-excluded. The directory-level
// rule for every directory between this and the root should depend
// on the target-level rule for this target.
@@ -78,3 +91,12 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const
return dirTargets;
}
+
+bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig(
+ const DirectoryTarget::Target& t, const std::string& config)
+{
+ if (this->IsMultiConfig()) {
+ return cm::contains(t.ExcludedFromAllInConfigs, config);
+ }
+ return !t.ExcludedFromAllInConfigs.empty();
+}
diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h
index 7d16dac..f97b5f4 100644
--- a/Source/cmGlobalCommonGenerator.h
+++ b/Source/cmGlobalCommonGenerator.h
@@ -30,7 +30,7 @@ public:
struct Target
{
cmGeneratorTarget const* GT = nullptr;
- bool ExcludeFromAll = false;
+ std::vector<std::string> ExcludedFromAllInConfigs;
};
std::vector<Target> Targets;
struct Dir
@@ -41,6 +41,8 @@ public:
std::vector<Dir> Children;
};
std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const;
+ bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t,
+ const std::string& config);
};
#endif
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 49b73a8..d39fefa 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -2173,13 +2173,38 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
}
bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
- cmGeneratorTarget* target) const
+ const cmGeneratorTarget* target) const
{
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
return true;
}
- if (cmProp exclude = target->GetProperty("EXCLUDE_FROM_ALL")) {
- return cmIsOn(*exclude);
+ cmMakefile* mf = root->GetMakefile();
+ const std::string EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
+ if (cmProp exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
+ // Expand the property value per configuration.
+ unsigned int trueCount = 0;
+ unsigned int falseCount = 0;
+ const std::vector<std::string>& configs =
+ mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (const std::string& config : configs) {
+ cmGeneratorExpressionInterpreter genexInterpreter(root, config, target);
+ if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
+ ++trueCount;
+ } else {
+ ++falseCount;
+ }
+ }
+
+ // Check whether the genex expansion of the property agrees in all
+ // configurations.
+ if (trueCount && falseCount) {
+ std::ostringstream e;
+ e << "The EXCLUDED_FROM_ALL property of target \"" << target->GetName()
+ << "\" varies by configuration. This is not supported by the \""
+ << root->GetGlobalGenerator()->GetName() << "\" generator.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return trueCount;
}
// This target is included in its directory. Check whether the
// directory is excluded.
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 57c7808..c2c80c2 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -542,7 +542,8 @@ protected:
bool IsExcluded(cmStateSnapshot const& root,
cmStateSnapshot const& snp) const;
bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const;
- bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const;
+ bool IsExcluded(cmLocalGenerator* root,
+ const cmGeneratorTarget* target) const;
virtual void InitializeProgressMarks() {}
struct GlobalTargetInfo
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 2fcba9a..1664dd0 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -470,7 +470,7 @@ void cmGlobalGhsMultiGenerator::WriteAllTarget(
if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
- if (!cmIsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) {
+ if (!IsExcluded(t->GetLocalGenerator(), t)) {
defaultTargets.push_back(t);
}
}
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 48eb405..786cde7 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1357,7 +1357,7 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config);
configDeps.emplace_back(build.Outputs.front());
for (DirectoryTarget::Target const& t : dt.Targets) {
- if (!t.ExcludeFromAll) {
+ if (!IsExcludedFromAllInConfig(t, config)) {
this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config);
}
}
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index c31983b..d45fc01 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -416,7 +416,7 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
std::vector<std::string> depends;
for (DirectoryTarget::Target const& t : dt.Targets) {
// Add this to the list of depends rules in this directory.
- if ((!check_all || !t.ExcludeFromAll) &&
+ if ((!check_all || t.ExcludedFromAllInConfigs.empty()) &&
(!check_relink ||
t.GT->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
// The target may be from a different directory; use its local gen.
@@ -846,7 +846,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
cmLocalGenerator* tlg = gt->GetLocalGenerator();
if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
- gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ IsExcluded(lg.get(), gt.get())) {
continue;
}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index b037a6d..422d475 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -207,6 +207,7 @@ add_RunCMake_test(DisallowedCommands)
if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
add_RunCMake_test(ExportCompileCommands)
endif()
+add_RunCMake_test(ExcludeFromAll)
add_RunCMake_test(ExternalData)
add_RunCMake_test(FeatureSummary)
add_RunCMake_test(FPHSA)
diff --git a/Tests/RunCMake/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/ExcludeFromAll/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake b/Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake
new file mode 100644
index 0000000..25201e4
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake
@@ -0,0 +1,26 @@
+include(RunCMake)
+
+function(run_single_config_test label config exclude_from_all_value expectation)
+ set(case single-config)
+ message("-- Starting ${case} test: ${label}")
+ set(full_case_name "${case}-build-${config}")
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${full_case_name}/")
+ run_cmake_with_options(${case}
+ -DCMAKE_BUILD_TYPE=${config}
+ -DTOOL_EXCLUDE_FROM_ALL=${exclude_from_all_value})
+ set(RunCMake_TEST_NO_CLEAN 1)
+ include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+ run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config ${config})
+endfunction()
+
+run_single_config_test("explictly not excluded" Debug 0 "should_exist")
+run_single_config_test("excluded" Debug 1 "should_not_exist")
+
+if(RunCMake_GENERATOR MATCHES "^(Xcode|Visual Studio)")
+ run_cmake(error-on-mixed-config)
+else()
+ run_single_config_test("explicitly not excluded with genex"
+ Release $<CONFIG:Debug> "should_exist")
+ run_single_config_test("excluded with genex"
+ Debug $<CONFIG:Debug> "should_not_exist")
+endif()
diff --git a/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt
new file mode 100644
index 0000000..eee5278
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt
@@ -0,0 +1,3 @@
+CMake Error in CMakeLists.txt:
+ The EXCLUDED_FROM_ALL property of target "release_only_tool" varies by
+ configuration. This is not supported by the "[^"]+"
diff --git a/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake
new file mode 100644
index 0000000..6c0ed1d
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+set(CMAKE_CONFIGURATION_TYPES "Release;Debug" CACHE STRING "")
+
+add_executable(release_only_tool main.c)
+set_property(TARGET release_only_tool PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:Release>>")
diff --git a/Tests/RunCMake/ExcludeFromAll/main.c b/Tests/RunCMake/ExcludeFromAll/main.c
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/main.c
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake b/Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake
new file mode 100644
index 0000000..1c455f2
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake
@@ -0,0 +1,17 @@
+if(expectation STREQUAL "should_not_exist")
+ set(should_exist FALSE)
+elseif(expectation STREQUAL "should_exist")
+ set(should_exist TRUE)
+else()
+ message(FATAL_ERROR "Encountered unknown expectation: ${expectation}")
+endif()
+
+if(EXISTS "${TARGET_FILE_tool_${config}}")
+ if(NOT should_exist)
+ message(FATAL_ERROR "${TARGET_FILE_tool_${config}} should not exist.")
+ endif()
+else()
+ if(should_exist)
+ message(FATAL_ERROR "${TARGET_FILE_tool_${config}} should exist.")
+ endif()
+endif()
diff --git a/Tests/RunCMake/ExcludeFromAll/single-config.cmake b/Tests/RunCMake/ExcludeFromAll/single-config.cmake
new file mode 100644
index 0000000..71a9f06
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/single-config.cmake
@@ -0,0 +1,11 @@
+enable_language(C)
+add_executable(tool main.c)
+set_property(TARGET tool PROPERTY EXCLUDE_FROM_ALL "${TOOL_EXCLUDE_FROM_ALL}")
+
+include(../NinjaMultiConfig/Common.cmake)
+set(orig_CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES})
+if("${CMAKE_CONFIGURATION_TYPES}" STREQUAL "")
+ set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
+endif()
+generate_output_files(tool)
+set(CMAKE_CONFIGURATION_TYPES ${orig_CMAKE_CONFIGURATION_TYPES})
diff --git a/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake
new file mode 100644
index 0000000..a4d2758
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake
@@ -0,0 +1,9 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+ INCLUDE
+ ${TARGET_FILE_release_only_tool_Release}
+ ${TARGET_EXE_FILE_release_only_tool_Release}
+
+ EXCLUDE
+ ${TARGET_FILE_release_only_tool_Debug}
+ ${TARGET_EXE_FILE_release_only_tool_Debug}
+ )
diff --git a/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake
new file mode 100644
index 0000000..52f84ea
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+set(CMAKE_CONFIGURATION_TYPES "Release;Debug" CACHE STRING "")
+set(CMAKE_DEFAULT_BUILD_TYPE "Release" CACHE STRING "")
+set(CMAKE_CROSS_CONFIGS "all" CACHE STRING "")
+set(CMAKE_DEFAULT_CONFIGS "all" CACHE STRING "")
+
+add_executable(release_only_tool main.c)
+set_property(TARGET release_only_tool PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:Release>>")
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(release_only_tool)
diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
index 76b488e..9249724 100644
--- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
@@ -274,6 +274,11 @@ run_ninja(Install default-install build.ninja install)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}/install")
run_ninja(Install all-install build.ninja install:all)
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll-build)
+run_cmake_configure(ExcludeFromAll)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_cmake_build(ExcludeFromAll all "" all:all)
+
# FIXME Get this working
#set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AutoMocExecutable-build)
#run_cmake_configure(AutoMocExecutable)