From 3ef0c40962312a97d5a083c79ec563045fe28de3 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 19 Aug 2020 16:41:24 -0400 Subject: WIN32_EXECUTABLE: Add support for generator expressions --- Help/prop_tgt/WIN32_EXECUTABLE.rst | 4 ++++ Help/release/dev/win32-executable-genex.rst | 5 ++++ Source/cmExtraCodeBlocksGenerator.cxx | 3 ++- Source/cmGeneratorTarget.cxx | 6 +++++ Source/cmGeneratorTarget.h | 3 +++ Source/cmGlobalGenerator.cxx | 6 ++--- Source/cmLocalGenerator.cxx | 2 +- Source/cmLocalVisualStudio7Generator.cxx | 2 +- Source/cmMakefileExecutableTargetGenerator.cxx | 3 ++- Source/cmVisualStudio10TargetGenerator.cxx | 20 ++++++++++++---- Tests/CMakeLists.txt | 4 ++++ Tests/CSharpWin32GenEx/CMakeLists.txt | 5 ++++ Tests/CSharpWin32GenEx/csharpwin32genex.cs | 9 +++++++ Tests/RunCMake/CMakeLists.txt | 4 ++++ Tests/RunCMake/Win32GenEx/CMakeLists.txt | 3 +++ Tests/RunCMake/Win32GenEx/RunCMakeTest.cmake | 28 ++++++++++++++++++++++ Tests/RunCMake/Win32GenEx/Win32GenEx-debug.cmake | 1 + Tests/RunCMake/Win32GenEx/Win32GenEx-release.cmake | 1 + Tests/RunCMake/Win32GenEx/Win32GenEx.cmake | 7 ++++++ Tests/RunCMake/Win32GenEx/main.c | 14 +++++++++++ 20 files changed, 118 insertions(+), 12 deletions(-) create mode 100644 Help/release/dev/win32-executable-genex.rst create mode 100644 Tests/CSharpWin32GenEx/CMakeLists.txt create mode 100644 Tests/CSharpWin32GenEx/csharpwin32genex.cs create mode 100644 Tests/RunCMake/Win32GenEx/CMakeLists.txt create mode 100644 Tests/RunCMake/Win32GenEx/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/Win32GenEx/Win32GenEx-debug.cmake create mode 100644 Tests/RunCMake/Win32GenEx/Win32GenEx-release.cmake create mode 100644 Tests/RunCMake/Win32GenEx/Win32GenEx.cmake create mode 100644 Tests/RunCMake/Win32GenEx/main.c diff --git a/Help/prop_tgt/WIN32_EXECUTABLE.rst b/Help/prop_tgt/WIN32_EXECUTABLE.rst index 060d166..eac28ae 100644 --- a/Help/prop_tgt/WIN32_EXECUTABLE.rst +++ b/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 `, except if the +target is managed (contains C# code.) diff --git a/Help/release/dev/win32-executable-genex.rst b/Help/release/dev/win32-executable-genex.rst new file mode 100644 index 0000000..f03203d --- /dev/null +++ b/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 `. diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 511168b..df68033 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/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; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 9611e14..7c526a0 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/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 { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 69c5faf..544b27a 100644 --- a/Source/cmGeneratorTarget.h +++ b/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, diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index cad5d1f..a192ffd 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/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 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 " diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2380cce..3cbc8ac 100644 --- a/Source/cmLocalGenerator.cxx +++ b/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 += " "; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 50ffe8d..ee7f74c 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/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. diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index bc288ac..9b5c6e6 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/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 { diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index db9dc53..fa6ad47 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/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) { diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e4e09fa..5d4ffae 100644 --- a/Tests/CMakeLists.txt +++ b/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) diff --git a/Tests/CSharpWin32GenEx/CMakeLists.txt b/Tests/CSharpWin32GenEx/CMakeLists.txt new file mode 100644 index 0000000..f4a8d00 --- /dev/null +++ b/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>) diff --git a/Tests/CSharpWin32GenEx/csharpwin32genex.cs b/Tests/CSharpWin32GenEx/csharpwin32genex.cs new file mode 100644 index 0000000..9892ee0 --- /dev/null +++ b/Tests/CSharpWin32GenEx/csharpwin32genex.cs @@ -0,0 +1,9 @@ +namespace CSharpWin32GenEx +{ + class CSharpWin32GenEx + { + public static void Main(string[] args) + { + } + } +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index bbb1952..fed2852 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/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() diff --git a/Tests/RunCMake/Win32GenEx/CMakeLists.txt b/Tests/RunCMake/Win32GenEx/CMakeLists.txt new file mode 100644 index 0000000..b646c4a --- /dev/null +++ b/Tests/RunCMake/Win32GenEx/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.18) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/Win32GenEx/RunCMakeTest.cmake b/Tests/RunCMake/Win32GenEx/RunCMakeTest.cmake new file mode 100644 index 0000000..d5529b0 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/Win32GenEx/Win32GenEx-debug.cmake b/Tests/RunCMake/Win32GenEx/Win32GenEx-debug.cmake new file mode 100644 index 0000000..74c5bd8 --- /dev/null +++ b/Tests/RunCMake/Win32GenEx/Win32GenEx-debug.cmake @@ -0,0 +1 @@ +include(Win32GenEx.cmake) diff --git a/Tests/RunCMake/Win32GenEx/Win32GenEx-release.cmake b/Tests/RunCMake/Win32GenEx/Win32GenEx-release.cmake new file mode 100644 index 0000000..74c5bd8 --- /dev/null +++ b/Tests/RunCMake/Win32GenEx/Win32GenEx-release.cmake @@ -0,0 +1 @@ +include(Win32GenEx.cmake) diff --git a/Tests/RunCMake/Win32GenEx/Win32GenEx.cmake b/Tests/RunCMake/Win32GenEx/Win32GenEx.cmake new file mode 100644 index 0000000..80f8b80 --- /dev/null +++ b/Tests/RunCMake/Win32GenEx/Win32GenEx.cmake @@ -0,0 +1,7 @@ +enable_language(C) + +add_executable(Win32GenEx main.c) +set_target_properties(Win32GenEx PROPERTIES + WIN32_EXECUTABLE $ + ) +target_compile_definitions(Win32GenEx PRIVATE $<$:USE_WIN32_MAIN>) diff --git a/Tests/RunCMake/Win32GenEx/main.c b/Tests/RunCMake/Win32GenEx/main.c new file mode 100644 index 0000000..1cf9f81 --- /dev/null +++ b/Tests/RunCMake/Win32GenEx/main.c @@ -0,0 +1,14 @@ +#ifdef USE_WIN32_MAIN +# include + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nShowCmd) +{ + return 0; +} +#else +int main(void) +{ + return 0; +} +#endif -- cgit v0.12