Browse Source

Fix crash on $<TARGET_PROPERTY:...,LOCATION> genex (#16134)

Policy CMP0026 deprecated the LOCATION property, and we have long
provided a $<TARGET_FILE:...> generator expression.  However, if
a project tries to use $<TARGET_PROPERTY:...,LOCATION> we should
at least not crash.

The compatibility implementation of the LOCATION property uses
cmGlobalGenerator::CreateGenerationObjects to create the structures
needed to evaluate the property before generation starts.  The
implementation assumed that accessing the property could only be done
during configuration (via the typical get_property command use case).
The $<TARGET_PROPERTY:...,LOCATION> genex causes the LOCATION property
to be accessed during generation.  Calling CreateGenerationObjects
during generation blows away all the objects currently being used for
generation and is not safe.  Add a condition to call it only when
configuration is not finished.
Brad King 9 years ago
parent
commit
f500a784d0

+ 9 - 3
Source/cmTarget.cxx

@@ -1131,7 +1131,9 @@ const char* cmTarget::GetProperty(const std::string& prop,
         // target because the configuration type may not be known at
         // CMake time.
         cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
-        gg->CreateGenerationObjects();
+        if (!gg->GetConfigureDoneCMP0026()) {
+          gg->CreateGenerationObjects();
+        }
         cmGeneratorTarget* gt = gg->FindGeneratorTarget(this->GetName());
         this->Properties.SetProperty(propLOCATION, gt->GetLocationForBuild());
       }
@@ -1150,7 +1152,9 @@ const char* cmTarget::GetProperty(const std::string& prop,
           prop, this->ImportedGetFullPath(configName, false).c_str());
       } else {
         cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
-        gg->CreateGenerationObjects();
+        if (!gg->GetConfigureDoneCMP0026()) {
+          gg->CreateGenerationObjects();
+        }
         cmGeneratorTarget* gt = gg->FindGeneratorTarget(this->GetName());
         this->Properties.SetProperty(
           prop, gt->GetFullPath(configName, false).c_str());
@@ -1168,7 +1172,9 @@ const char* cmTarget::GetProperty(const std::string& prop,
             prop, this->ImportedGetFullPath(configName, false).c_str());
         } else {
           cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
-          gg->CreateGenerationObjects();
+          if (!gg->GetConfigureDoneCMP0026()) {
+            gg->CreateGenerationObjects();
+          }
           cmGeneratorTarget* gt = gg->FindGeneratorTarget(this->GetName());
           this->Properties.SetProperty(
             prop, gt->GetFullPath(configName, false).c_str());

+ 1 - 0
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake

@@ -28,6 +28,7 @@ run_cmake(COMPILE_LANGUAGE-add_test)
 run_cmake(COMPILE_LANGUAGE-unknown-lang)
 run_cmake(TARGET_FILE-recursion)
 run_cmake(OUTPUT_NAME-recursion)
+run_cmake(TARGET_PROPERTY-LOCATION)
 
 run_cmake(ImportedTarget-TARGET_PDB_FILE)
 if(LINKER_SUPPORTS_PDB)

+ 10 - 0
Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION-stderr.txt

@@ -0,0 +1,10 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+  Policy CMP0026 is not set: Disallow use of the LOCATION target property.
+  Run "cmake --help-policy CMP0026" for policy details.  Use the cmake_policy
+  command to set the policy and suppress this warning.
+
+  The LOCATION property should not be read from target "foo".  Use the target
+  name directly with add_custom_command, or use the generator expression
+  \$<TARGET_FILE>, as appropriate.
+
+This warning is for project developers.  Use -Wno-dev to suppress it.

+ 3 - 0
Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION.cmake

@@ -0,0 +1,3 @@
+enable_language(C)
+add_library(foo empty.c)
+add_custom_target(drive COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:foo,LOCATION>)