Browse Source

WIN32_EXECUTABLE: Add support for generator expressions

Kyle Edwards 5 years ago
parent
commit
3ef0c40962

+ 4 - 0
Help/prop_tgt/WIN32_EXECUTABLE.rst

@@ -11,3 +11,7 @@ configure use of the Microsoft Foundation Classes (MFC) for WinMain
 executables.  This property is initialized by the value of the
 :variable:`CMAKE_WIN32_EXECUTABLE` variable if it is set when
 a target is created.
+
+This property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`, except if the
+target is managed (contains C# code.)

+ 5 - 0
Help/release/dev/win32-executable-genex.rst

@@ -0,0 +1,5 @@
+win32-executable-genex
+----------------------
+
+* The :prop_tgt:`WIN32_EXECUTABLE` target property now supports
+  :manual:`generator expressions <cmake-generator-expressions(7)>`.

+ 2 - 1
Source/cmExtraCodeBlocksGenerator.cxx

@@ -689,7 +689,8 @@ int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target)
 {
   switch (target->GetType()) {
     case cmStateEnums::EXECUTABLE:
-      if ((target->GetPropertyAsBool("WIN32_EXECUTABLE")) ||
+      if ((target->IsWin32Executable(
+            target->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) ||
           (target->GetPropertyAsBool("MACOSX_BUNDLE"))) {
         return 0;
       }

+ 6 - 0
Source/cmGeneratorTarget.cxx

@@ -2266,6 +2266,12 @@ bool cmGeneratorTarget::IsBundleOnApple() const
     this->IsCFBundleOnApple();
 }
 
+bool cmGeneratorTarget::IsWin32Executable(const std::string& config) const
+{
+  return cmIsOn(cmGeneratorExpression::Evaluate(
+    this->GetSafeProperty("WIN32_EXECUTABLE"), this->LocalGenerator, config));
+}
+
 std::string cmGeneratorTarget::GetCFBundleDirectory(
   const std::string& config, BundleDirectoryLevel level) const
 {

+ 3 - 0
Source/cmGeneratorTarget.h

@@ -284,6 +284,9 @@ public:
       or CFBundle on Apple.  */
   bool IsBundleOnApple() const;
 
+  /** Return whether this target is a Win32 executable */
+  bool IsWin32Executable(const std::string& config) const;
+
   /** Get the full name of the target according to the settings in its
       makefile.  */
   std::string GetFullName(const std::string& config,

+ 3 - 3
Source/cmGlobalGenerator.cxx

@@ -335,13 +335,13 @@ bool cmGlobalGenerator::CheckTargetsForType() const
   bool failed = false;
   for (const auto& generator : this->LocalGenerators) {
     for (const auto& target : generator->GetGeneratorTargets()) {
-      if (target->GetType() == cmStateEnums::EXECUTABLE &&
-          target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+      if (target->GetType() == cmStateEnums::EXECUTABLE) {
         std::vector<std::string> const& configs =
           target->Makefile->GetGeneratorConfigs(
             cmMakefile::IncludeEmptyConfig);
         for (std::string const& config : configs) {
-          if (target->GetLinkerLanguage(config) == "Swift") {
+          if (target->IsWin32Executable(config) &&
+              target->GetLinkerLanguage(config) == "Swift") {
             this->GetCMakeInstance()->IssueMessage(
               MessageType::FATAL_ERROR,
               "WIN32_EXECUTABLE property is not supported on Swift "

+ 1 - 1
Source/cmLocalGenerator.cxx

@@ -1520,7 +1520,7 @@ void cmLocalGenerator::GetTargetFlags(
           return;
         }
 
-        if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+        if (target->IsWin32Executable(config)) {
           exeFlags +=
             this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
           exeFlags += " ";

+ 1 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -1113,7 +1113,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
       cmComputeLinkInformation& cli = *pcli;
       std::string linkLanguage = cli.GetLinkLanguage();
 
-      bool isWin32Executable = target->GetPropertyAsBool("WIN32_EXECUTABLE");
+      bool isWin32Executable = target->IsWin32Executable(configName);
 
       // Compute the variable name to lookup standard libraries for this
       // language.

+ 2 - 1
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -371,7 +371,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   this->LocalGenerator->AddConfigVariableFlags(
     linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName());
 
-  if (this->GeneratorTarget->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+  if (this->GeneratorTarget->IsWin32Executable(
+        this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) {
     this->LocalGenerator->AppendFlags(
       linkFlags, this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE"));
   } else {

+ 15 - 5
Source/cmVisualStudio10TargetGenerator.cxx

@@ -595,14 +595,24 @@ void cmVisualStudio10TargetGenerator::Generate()
           case cmStateEnums::MODULE_LIBRARY:
             outputType = "Module";
             break;
-          case cmStateEnums::EXECUTABLE:
-            if (this->GeneratorTarget->Target->GetPropertyAsBool(
-                  "WIN32_EXECUTABLE")) {
+          case cmStateEnums::EXECUTABLE: {
+            auto const win32 =
+              this->GeneratorTarget->GetSafeProperty("WIN32_EXECUTABLE");
+            if (win32.find("$<") != std::string::npos) {
+              this->Makefile->IssueMessage(
+                MessageType::FATAL_ERROR,
+                cmStrCat(
+                  "Target \"", this->GeneratorTarget->GetName(),
+                  "\" has a generator expression in its WIN32_EXECUTABLE "
+                  "property. This is not supported on managed executables."));
+              return;
+            }
+            if (cmIsOn(win32)) {
               outputType = "WinExe";
             } else {
               outputType = "Exe";
             }
-            break;
+          } break;
           case cmStateEnums::UTILITY:
           case cmStateEnums::INTERFACE_LIBRARY:
           case cmStateEnums::GLOBAL_TARGET:
@@ -3731,7 +3741,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
   }
 
   if (this->MSTools) {
-    if (this->GeneratorTarget->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+    if (this->GeneratorTarget->IsWin32Executable(config)) {
       if (this->GlobalGenerator->TargetsWindowsCE()) {
         linkOptions.AddFlag("SubSystem", "WindowsCE");
         if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {

+ 4 - 0
Tests/CMakeLists.txt

@@ -440,6 +440,10 @@ if(BUILD_TESTING)
     ADD_TEST_MACRO(CSharpOnly CSharpOnly)
     ADD_TEST_MACRO(CSharpLinkToCxx CSharpLinkToCxx)
     ADD_TEST_MACRO(CSharpLinkFromCxx CSharpLinkFromCxx)
+    ADD_TEST_MACRO(CSharpWin32GenEx CSharpWin32GenEx)
+    set_tests_properties(CSharpWin32GenEx PROPERTIES
+      PASS_REGULAR_EXPRESSION "Target \"CSharpWin32GenEx\" has a generator expression in its\n  WIN32_EXECUTABLE property\\.  This is not supported on managed executables\\."
+      )
   endif()
 
   ADD_TEST_MACRO(COnly COnly)

+ 5 - 0
Tests/CSharpWin32GenEx/CMakeLists.txt

@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.18)
+project(CSharpWin32GenEx CSharp)
+
+add_executable(CSharpWin32GenEx csharpwin32genex.cs)
+set_property(TARGET CSharpWin32GenEx PROPERTY WIN32_EXECUTABLE $<1:1>)

+ 9 - 0
Tests/CSharpWin32GenEx/csharpwin32genex.cs

@@ -0,0 +1,9 @@
+namespace CSharpWin32GenEx
+{
+    class CSharpWin32GenEx
+    {
+        public static void Main(string[] args)
+        {
+        }
+    }
+}

+ 4 - 0
Tests/RunCMake/CMakeLists.txt

@@ -732,3 +732,7 @@ add_RunCMake_test("CTestCommandExpandLists")
 
 add_RunCMake_test(PrecompileHeaders -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
 add_RunCMake_test("UnityBuild")
+
+if(WIN32)
+  add_RunCMake_test(Win32GenEx)
+endif()

+ 3 - 0
Tests/RunCMake/Win32GenEx/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.18)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 28 - 0
Tests/RunCMake/Win32GenEx/RunCMakeTest.cmake

@@ -0,0 +1,28 @@
+include(RunCMake)
+
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Win32GenEx-build)
+  run_cmake(Win32GenEx)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(Win32GenEx-debug-build ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR} --config Debug)
+  run_cmake_command(Win32GenEx-release-build ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR} --config Release)
+  unset(RunCMake_TEST_NO_CLEAN)
+else()
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Win32GenEx-debug-build)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+  run_cmake(Win32GenEx-debug)
+  unset(RunCMake_TEST_OPTIONS)
+
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(Win32GenEx-debug-build ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR})
+  unset(RunCMake_TEST_NO_CLEAN)
+
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Win32GenEx-release-build)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+  run_cmake(Win32GenEx-release)
+  unset(RunCMake_TEST_OPTIONS)
+
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(Win32GenEx-release-build ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR})
+  unset(RunCMake_TEST_NO_CLEAN)
+endif()

+ 1 - 0
Tests/RunCMake/Win32GenEx/Win32GenEx-debug.cmake

@@ -0,0 +1 @@
+include(Win32GenEx.cmake)

+ 1 - 0
Tests/RunCMake/Win32GenEx/Win32GenEx-release.cmake

@@ -0,0 +1 @@
+include(Win32GenEx.cmake)

+ 7 - 0
Tests/RunCMake/Win32GenEx/Win32GenEx.cmake

@@ -0,0 +1,7 @@
+enable_language(C)
+
+add_executable(Win32GenEx main.c)
+set_target_properties(Win32GenEx PROPERTIES
+  WIN32_EXECUTABLE $<CONFIG:Release>
+  )
+target_compile_definitions(Win32GenEx PRIVATE $<$<CONFIG:Release>:USE_WIN32_MAIN>)

+ 14 - 0
Tests/RunCMake/Win32GenEx/main.c

@@ -0,0 +1,14 @@
+#ifdef USE_WIN32_MAIN
+#  include <windows.h>
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+                     LPSTR lpCmdLine, int nShowCmd)
+{
+  return 0;
+}
+#else
+int main(void)
+{
+  return 0;
+}
+#endif