瀏覽代碼

Add policy CMP0019 to skip include/link variable re-expansion

Historically CMake has always expanded ${} variable references in the
values given to include_directories(), link_directories(), and
link_libraries().  This has been unnecessary since general ${}
evaluation syntax was added to the language a LONG time ago, but has
remained for compatibility with VERY early CMake versions.

For a long time the re-expansion was a lightweight operation because it
was only processed once at the directory level and the fast-path of
cmMakefile::ExpandVariablesInString was usually taken because values did
not have any '$' in them.  Then commit d899eb71 (Call
ExpandVariablesInString for each target's INCLUDE_DIRECTORIES,
2012-02-22) made the operation a bit heavier because the expansion is
now needed on a per-target basis.  In the future we will support
generator expressions in INCLUDE_DIRECTORIES with $<> syntax, so the
fast-path in cmMakefile::ExpandVariablesInString will no longer be taken
and re-expansion will be very expensive.

Add policy CMP0019 to skip the re-expansion altogether in NEW behavior.
In OLD behavior perform the expansion but improve the fast-path
heuristic to match ${} but not $<>.  If the policy is not set then warn
if expansion actually does anything.  We expect this to be encountered
very rarely in practice.
Brad King 13 年之前
父節點
當前提交
711b63f7e0

+ 63 - 12
Source/cmMakefile.cxx

@@ -814,7 +814,7 @@ bool cmMakefile::NeedBackwardsCompatibility(unsigned int major,
 void cmMakefile::FinalPass()
 void cmMakefile::FinalPass()
 {
 {
   // do all the variable expansions here
   // do all the variable expansions here
-  this->ExpandVariables();
+  this->ExpandVariablesCMP0019();
 
 
   // give all the commands a chance to do something
   // give all the commands a chance to do something
   // after the file has been parsed before generation
   // after the file has been parsed before generation
@@ -2122,21 +2122,33 @@ void cmMakefile::AddExtraDirectory(const char* dir)
   this->AuxSourceDirectories.push_back(dir);
   this->AuxSourceDirectories.push_back(dir);
 }
 }
 
 
+static bool mightExpandVariablesCMP0019(const char* s)
+{
+  return s && *s && strstr(s,"${") && strchr(s,'}');
+}
 
 
-// expand CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR in the
-// include and library directories.
-
-void cmMakefile::ExpandVariables()
+void cmMakefile::ExpandVariablesCMP0019()
 {
 {
-  // Now expand variables in the include and link strings
+  // Drop this ancient compatibility behavior with a policy.
+  cmPolicies::PolicyStatus pol = this->GetPolicyStatus(cmPolicies::CMP0019);
+  if(pol != cmPolicies::OLD && pol != cmPolicies::WARN)
+    {
+    return;
+    }
+  cmOStringStream w;
 
 
-  // May not be necessary anymore... But may need a policy for strict
-  // backwards compatibility
   const char *includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
   const char *includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
-  if (includeDirs)
+  if(mightExpandVariablesCMP0019(includeDirs))
     {
     {
     std::string dirs = includeDirs;
     std::string dirs = includeDirs;
     this->ExpandVariablesInString(dirs, true, true);
     this->ExpandVariablesInString(dirs, true, true);
+    if(pol == cmPolicies::WARN && dirs != includeDirs)
+      {
+      w << "Evaluated directory INCLUDE_DIRECTORIES\n"
+        << "  " << includeDirs << "\n"
+        << "as\n"
+        << "  " << dirs << "\n";
+      }
     this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
     this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
     }
     }
 
 
@@ -2146,10 +2158,17 @@ void cmMakefile::ExpandVariables()
     {
     {
     cmTarget &t = l->second;
     cmTarget &t = l->second;
     includeDirs = t.GetProperty("INCLUDE_DIRECTORIES");
     includeDirs = t.GetProperty("INCLUDE_DIRECTORIES");
-    if (includeDirs)
+    if(mightExpandVariablesCMP0019(includeDirs))
       {
       {
       std::string dirs = includeDirs;
       std::string dirs = includeDirs;
       this->ExpandVariablesInString(dirs, true, true);
       this->ExpandVariablesInString(dirs, true, true);
+      if(pol == cmPolicies::WARN && dirs != includeDirs)
+        {
+        w << "Evaluated target " << t.GetName() << " INCLUDE_DIRECTORIES\n"
+          << "  " << includeDirs << "\n"
+          << "as\n"
+          << "  " << dirs << "\n";
+        }
       t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
       t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
       }
       }
     }
     }
@@ -2157,13 +2176,45 @@ void cmMakefile::ExpandVariables()
   for(std::vector<std::string>::iterator d = this->LinkDirectories.begin();
   for(std::vector<std::string>::iterator d = this->LinkDirectories.begin();
       d != this->LinkDirectories.end(); ++d)
       d != this->LinkDirectories.end(); ++d)
     {
     {
-    this->ExpandVariablesInString(*d, true, true);
+    if(mightExpandVariablesCMP0019(d->c_str()))
+      {
+      std::string orig = *d;
+      this->ExpandVariablesInString(*d, true, true);
+      if(pol == cmPolicies::WARN && *d != orig)
+        {
+        w << "Evaluated link directory\n"
+          << "  " << orig << "\n"
+          << "as\n"
+          << "  " << *d << "\n";
+        }
+      }
     }
     }
   for(cmTarget::LinkLibraryVectorType::iterator l =
   for(cmTarget::LinkLibraryVectorType::iterator l =
         this->LinkLibraries.begin();
         this->LinkLibraries.begin();
       l != this->LinkLibraries.end(); ++l)
       l != this->LinkLibraries.end(); ++l)
     {
     {
-    this->ExpandVariablesInString(l->first, true, true);
+    if(mightExpandVariablesCMP0019(l->first.c_str()))
+      {
+      std::string orig = l->first;
+      this->ExpandVariablesInString(l->first, true, true);
+      if(pol == cmPolicies::WARN && l->first != orig)
+        {
+        w << "Evaluated link library\n"
+          << "  " << orig << "\n"
+          << "as\n"
+          << "  " << l->first << "\n";
+        }
+      }
+    }
+
+  if(!w.str().empty())
+    {
+    cmOStringStream m;
+    m << this->GetPolicies()->GetPolicyWarning(cmPolicies::CMP0019)
+      << "\n"
+      << "The following variable evaluations were encountered:\n"
+      << w.str();
+    this->IssueMessage(cmake::AUTHOR_WARNING, m.str());
     }
     }
 }
 }
 
 

+ 1 - 1
Source/cmMakefile.h

@@ -693,7 +693,7 @@ public:
   /**
   /**
    * Expand variables in the makefiles ivars such as link directories etc
    * Expand variables in the makefiles ivars such as link directories etc
    */
    */
-  void ExpandVariables();
+  void ExpandVariablesCMP0019();
 
 
   /**
   /**
    * Replace variables and #cmakedefine lines in the given string.
    * Replace variables and #cmakedefine lines in the given string.

+ 17 - 0
Source/cmPolicies.cxx

@@ -491,6 +491,23 @@ cmPolicies::cmPolicies()
     "CMAKE_SHARED_LIBRARY_<Lang>_FLAGS whether it is modified or not and "
     "CMAKE_SHARED_LIBRARY_<Lang>_FLAGS whether it is modified or not and "
     "honor the POSITION_INDEPENDENT_CODE target property.",
     "honor the POSITION_INDEPENDENT_CODE target property.",
     2,8,9,0, cmPolicies::WARN);
     2,8,9,0, cmPolicies::WARN);
+
+  this->DefinePolicy(
+    CMP0019, "CMP0019",
+    "Do not re-expand variables in include and link information.",
+    "CMake 2.8.10 and lower re-evaluated values given to the "
+    "include_directories, link_directories, and link_libraries "
+    "commands to expand any leftover variable references at the "
+    "end of the configuration step.  "
+    "This was for strict compatibility with VERY early CMake versions "
+    "because all variable references are now normally evaluated during "
+    "CMake language processing.  "
+    "CMake 2.8.11 and higher prefer to skip the extra evaluation."
+    "\n"
+    "The OLD behavior for this policy is to re-evaluate the values "
+    "for strict compatibility.  "
+    "The NEW behavior for this policy is to leave the values untouched.",
+    2,8,11,0, cmPolicies::WARN);
 }
 }
 
 
 cmPolicies::~cmPolicies()
 cmPolicies::~cmPolicies()

+ 1 - 0
Source/cmPolicies.h

@@ -68,6 +68,7 @@ public:
     CMP0018, ///< Ignore language flags for shared libs, and adhere to
     CMP0018, ///< Ignore language flags for shared libs, and adhere to
     /// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C}
     /// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C}
     /// instead.
     /// instead.
+    CMP0019, ///< No variable re-expansion in include and link info
 
 
     /** \brief Always the last entry.
     /** \brief Always the last entry.
      *
      *

+ 2 - 0
Tests/RunCMake/CMP0019/CMP0019-NEW.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0019 NEW)
+include(CMP0019-code.cmake)

+ 2 - 0
Tests/RunCMake/CMP0019/CMP0019-OLD.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0019 OLD)
+include(CMP0019-code.cmake)

+ 40 - 0
Tests/RunCMake/CMP0019/CMP0019-WARN-stderr.txt

@@ -0,0 +1,40 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+  Policy CMP0019 is not set: Do not re-expand variables in include and link
+  information.  Run "cmake --help-policy CMP0019" for policy details.  Use
+  the cmake_policy command to set the policy and suppress this warning.
+
+  The following variable evaluations were encountered:
+
+  Evaluated directory INCLUDE_DIRECTORIES
+
+    /usr/include/\${VAR_INCLUDE};/usr/include/normal
+
+  as
+
+    /usr/include/VAL_INCLUDE;/usr/include/normal
+
+  Evaluated target some_target INCLUDE_DIRECTORIES
+
+    /usr/include/\${VAR_INCLUDE};/usr/include/normal
+
+  as
+
+    /usr/include/VAL_INCLUDE;/usr/include/normal
+
+  Evaluated link directory
+
+    /usr/lib/\${VAR_LINK_DIRS}
+
+  as
+
+    /usr/lib/VAL_LINK_DIRS
+
+  Evaluated link library
+
+    \${VAR_LINK_LIBS}
+
+  as
+
+    VAL_LINK_LIBS
+
+This warning is for project developers.  Use -Wno-dev to suppress it.$

+ 1 - 0
Tests/RunCMake/CMP0019/CMP0019-WARN.cmake

@@ -0,0 +1 @@
+include(CMP0019-code.cmake)

+ 9 - 0
Tests/RunCMake/CMP0019/CMP0019-code.cmake

@@ -0,0 +1,9 @@
+set(VAR_INCLUDE "VAL_INCLUDE")
+set(VAR_LINK_DIRS "VAL_LINK_DIRS")
+set(VAR_LINK_LIBS "VAL_LINK_LIBS")
+add_custom_target(some_target)
+include_directories("/usr/include/\${VAR_INCLUDE}" /usr/include/normal)
+link_directories("/usr/lib/\${VAR_LINK_DIRS}"  /usr/lib/normal)
+link_libraries("\${VAR_LINK_LIBS}" normal)
+add_custom_target(other_target)
+set_property(TARGET other_target PROPERTY INCLUDE_DIRECTORIES "")

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

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

+ 5 - 0
Tests/RunCMake/CMP0019/RunCMakeTest.cmake

@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0019-WARN)
+run_cmake(CMP0019-OLD)
+run_cmake(CMP0019-NEW)

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -45,6 +45,7 @@ macro(add_RunCMake_test test)
     )
     )
 endmacro()
 endmacro()
 
 
+add_RunCMake_test(CMP0019)
 add_RunCMake_test(GeneratorExpression)
 add_RunCMake_test(GeneratorExpression)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(Languages)