浏览代码

CMP0115: Require source file extensions to be explicit

Kyle Edwards 5 年之前
父节点
当前提交
fd50a75fa0

+ 8 - 0
Help/manual/cmake-policies.7.rst

@@ -51,6 +51,14 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used
 to determine whether to report an error on use of deprecated macros or
 functions.
 
+Policies Introduced by CMake 3.20
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0115: Source file extensions must be explicit. </policy/CMP0115>
+
 Policies Introduced by CMake 3.19
 =================================
 

+ 34 - 0
Help/policy/CMP0115.rst

@@ -0,0 +1,34 @@
+CMP0115
+-------
+
+.. versionadded:: 3.20
+
+Source file extensions must be explicit.
+
+In CMake 3.19 and below, if a source file could not be found by the name
+specified, it would append a list of known extensions to the name to see if
+the file with the extension could be found. For example, this would allow the
+user to run:
+
+.. code-block:: cmake
+
+  add_executable(exe main)
+
+and put ``main.c`` in the executable without specifying the extension.
+
+Starting in CMake 3.20, CMake prefers all source files to have their extensions
+explicitly listed:
+
+.. code-block:: cmake
+
+  add_executable(exe main.c)
+
+The ``OLD`` behavior for this policy is to implicitly append known extensions
+to source files if they can't be found. The ``NEW`` behavior of this policy is
+to not append known extensions and require them to be explicit.
+
+This policy was introduced in CMake version 3.20.  CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt

+ 5 - 0
Help/release/dev/explicit-source-extensions.rst

@@ -0,0 +1,5 @@
+explicit-source-extensions
+--------------------------
+
+* Source file extensions must now be explicit. See policy :policy:`CMP0115` for
+  details.

+ 6 - 2
Source/cmGeneratorTarget.cxx

@@ -1539,10 +1539,14 @@ bool processSources(cmGeneratorTarget const* tgt,
     for (std::string& src : entry.Values) {
       cmSourceFile* sf = mf->GetOrCreateSource(src);
       std::string e;
-      std::string fullPath = sf->ResolveFullPath(&e);
+      std::string w;
+      std::string fullPath = sf->ResolveFullPath(&e, &w);
+      cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
+      if (!w.empty()) {
+        cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace());
+      }
       if (fullPath.empty()) {
         if (!e.empty()) {
-          cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
           cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace());
         }
         return contextDependent;

+ 3 - 1
Source/cmPolicies.h

@@ -340,7 +340,9 @@ class cmMakefile;
          3, 19, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0114,                                                     \
          "ExternalProject step targets fully adopt their steps.", 3, 19, 0,   \
-         cmPolicies::WARN)
+         cmPolicies::WARN)                                                    \
+  SELECT(POLICY, CMP0115, "Source file extensions must be explicit.", 3, 20,  \
+         0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \

+ 45 - 16
Source/cmSourceFile.cxx

@@ -8,6 +8,7 @@
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
@@ -93,10 +94,11 @@ cmSourceFileLocation const& cmSourceFile::GetLocation() const
   return this->Location;
 }
 
-std::string const& cmSourceFile::ResolveFullPath(std::string* error)
+std::string const& cmSourceFile::ResolveFullPath(std::string* error,
+                                                 std::string* cmp0115Warning)
 {
   if (this->FullPath.empty()) {
-    if (this->FindFullPath(error)) {
+    if (this->FindFullPath(error, cmp0115Warning)) {
       this->CheckExtension();
     }
   }
@@ -108,7 +110,8 @@ std::string const& cmSourceFile::GetFullPath() const
   return this->FullPath;
 }
 
-bool cmSourceFile::FindFullPath(std::string* error)
+bool cmSourceFile::FindFullPath(std::string* error,
+                                std::string* cmp0115Warning)
 {
   // If the file is generated compute the location without checking on disk.
   if (this->GetIsGenerated()) {
@@ -131,9 +134,11 @@ bool cmSourceFile::FindFullPath(std::string* error)
   // List of extension lists
   std::vector<std::string> exts =
     makefile->GetCMakeInstance()->GetAllExtensions();
+  auto cmp0115 = makefile->GetPolicyStatus(cmPolicies::CMP0115);
 
   // Tries to find the file in a given directory
-  auto findInDir = [this, &exts, &lPath](std::string const& dir) -> bool {
+  auto findInDir = [this, &exts, &lPath, cmp0115, cmp0115Warning,
+                    makefile](std::string const& dir) -> bool {
     // Compute full path
     std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir);
     // Try full path
@@ -141,13 +146,29 @@ bool cmSourceFile::FindFullPath(std::string* error)
       this->FullPath = fullPath;
       return true;
     }
-    // Try full path with extension
-    for (std::string const& ext : exts) {
-      if (!ext.empty()) {
-        std::string extPath = cmStrCat(fullPath, '.', ext);
-        if (cmSystemTools::FileExists(extPath)) {
-          this->FullPath = extPath;
-          return true;
+    // This has to be an if statement due to a bug in Oracle Developer Studio.
+    // See https://community.oracle.com/tech/developers/discussion/4476246/
+    // for details.
+    if (cmp0115 == cmPolicies::OLD || cmp0115 == cmPolicies::WARN) {
+      // Try full path with extension
+      for (std::string const& ext : exts) {
+        if (!ext.empty()) {
+          std::string extPath = cmStrCat(fullPath, '.', ext);
+          if (cmSystemTools::FileExists(extPath)) {
+            this->FullPath = extPath;
+            if (cmp0115 == cmPolicies::WARN) {
+              std::string warning =
+                cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0115),
+                         "\nFile:\n  ", extPath);
+              if (cmp0115Warning) {
+                *cmp0115Warning = std::move(warning);
+              } else {
+                makefile->GetCMakeInstance()->IssueMessage(
+                  MessageType::AUTHOR_WARNING, warning);
+              }
+            }
+            return true;
+          }
         }
       }
     }
@@ -168,11 +189,19 @@ bool cmSourceFile::FindFullPath(std::string* error)
   }
 
   // Compose error
-  std::string err =
-    cmStrCat("Cannot find source file:\n  ", lPath, "\nTried extensions");
-  for (std::string const& ext : exts) {
-    err += " .";
-    err += ext;
+  std::string err = cmStrCat("Cannot find source file:\n  ", lPath);
+  switch (cmp0115) {
+    case cmPolicies::OLD:
+    case cmPolicies::WARN:
+      err = cmStrCat(err, "\nTried extensions");
+      for (auto const& ext : exts) {
+        err = cmStrCat(err, " .", ext);
+      }
+      break;
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::NEW:
+      break;
   }
   if (error != nullptr) {
     *error = std::move(err);

+ 3 - 2
Source/cmSourceFile.h

@@ -77,7 +77,8 @@ public:
    * Resolves the full path to the file.  Attempts to locate the file on disk
    * and finalizes its location.
    */
-  std::string const& ResolveFullPath(std::string* error = nullptr);
+  std::string const& ResolveFullPath(std::string* error = nullptr,
+                                     std::string* cmp0115Warning = nullptr);
 
   /**
    * The resolved full path to the file.  The returned file name might be empty
@@ -138,7 +139,7 @@ private:
   bool FindFullPathFailed = false;
   bool IsGenerated = false;
 
-  bool FindFullPath(std::string* error);
+  bool FindFullPath(std::string* error, std::string* cmp0115Warning);
   void CheckExtension();
   void CheckLanguage(std::string const& ext);
 

+ 1 - 0
Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt

@@ -0,0 +1 @@
+1

+ 17 - 0
Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt

@@ -0,0 +1,17 @@
+^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Cannot find source file:
+
+    main
+Call Stack \(most recent call first\):
+  CMP0115-NEW\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+  CMP0115-NEW\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$

+ 1 - 0
Tests/RunCMake/CMP0115/CMP0115-NEW.cmake

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

+ 1 - 0
Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt

@@ -0,0 +1 @@
+1

+ 22 - 0
Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt

@@ -0,0 +1,22 @@
+^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Cannot find source file:
+
+    noexist
+
+  Tried extensions [^
+]*
+  [^
+]*
+Call Stack \(most recent call first\):
+  CMP0115-OLD\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+  CMP0115-OLD\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$

+ 1 - 0
Tests/RunCMake/CMP0115/CMP0115-OLD.cmake

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

+ 1 - 0
Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt

@@ -0,0 +1 @@
+1

+ 36 - 0
Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt

@@ -0,0 +1,36 @@
+^CMake Warning \(dev\) at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Policy CMP0115 is not set: Source file extensions must be explicit\.  Run
+  "cmake --help-policy CMP0115" for policy details\.  Use the cmake_policy
+  command to set the policy and suppress this warning\.
+
+  File:
+
+    [^
+]*/Tests/RunCMake/CMP0115/main\.c
+Call Stack \(most recent call first\):
+  CMP0115-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Cannot find source file:
+
+    noexist
+
+  Tried extensions [^
+]*
+  [^
+]*
+Call Stack \(most recent call first\):
+  CMP0115-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+  CMP0115-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$

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

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

+ 3 - 0
Tests/RunCMake/CMP0115/CMP0115.cmake

@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_executable(exe main noexist)

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

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

+ 12 - 0
Tests/RunCMake/CMP0115/RunCMakeTest.cmake

@@ -0,0 +1,12 @@
+include(RunCMake)
+
+function(run_cmp0115 status)
+  if(NOT status STREQUAL "WARN")
+    set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0115=${status})
+  endif()
+  run_cmake(CMP0115-${status})
+endfunction()
+
+run_cmp0115(OLD)
+run_cmp0115(WARN)
+run_cmp0115(NEW)

+ 4 - 0
Tests/RunCMake/CMP0115/main.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -125,6 +125,7 @@ if(CMake_TEST_CUDA)
 endif()
 add_RunCMake_test(CMP0106)
 add_RunCMake_test(CMP0111)
+add_RunCMake_test(CMP0115)
 
 # The test for Policy 65 requires the use of the
 # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode