Browse Source

ENH: Add global property ALLOW_DUPLICATE_CUSTOM_TARGETS to help existing projects that depend on having duplicate custom targets. It is allowed only for Makefile generators. See bug#6348.

Brad King 17 years ago
parent
commit
1c0595c73f

+ 1 - 1
Source/cmAddCustomTargetCommand.cxx

@@ -161,7 +161,7 @@ bool cmAddCustomTargetCommand
   // Enforce name uniqueness.
   {
   std::string msg;
-  if(!this->Makefile->EnforceUniqueName(args[0], msg))
+  if(!this->Makefile->EnforceUniqueName(args[0], msg, true))
     {
     this->SetError(msg.c_str());
     return false;

+ 27 - 0
Source/cmGlobalGenerator.cxx

@@ -733,12 +733,39 @@ void cmGlobalGenerator::Configure()
     }
 }
 
+bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
+{
+  // If the property is not enabled then okay.
+  if(!this->CMakeInstance
+     ->GetPropertyAsBool("ALLOW_DUPLICATE_CUSTOM_TARGETS"))
+    {
+    return true;
+    }
+
+  // This generator does not support duplicate custom targets.
+  cmOStringStream e;
+  e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
+    << "global property.  "
+    << "The \"" << this->GetName() << "\" generator does not support "
+    << "duplicate custom targets.  "
+    << "Consider using a Makefiles generator or fix the project to not "
+    << "use duplicat target names.";
+  cmSystemTools::Error(e.str().c_str());
+  return false;
+}
+
 void cmGlobalGenerator::Generate()
 {
   // Some generators track files replaced during the Generate.
   // Start with an empty vector:
   this->FilesReplacedDuringGenerate.clear();
 
+  // Check whether this generator is allowed to run.
+  if(!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS())
+    {
+    return;
+    }
+
   // For each existing cmLocalGenerator
   unsigned int i;
 

+ 2 - 0
Source/cmGlobalGenerator.h

@@ -258,6 +258,8 @@ protected:
   void SetLanguageEnabledFlag(const char* l, cmMakefile* mf);
   void SetLanguageEnabledMaps(const char* l, cmMakefile* mf);
 
+  virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS();
+
   // Fill the ProjectMap, this must be called after LocalGenerators 
   // has been populated.
   void FillProjectMap();

+ 2 - 0
Source/cmGlobalUnixMakefileGenerator3.h

@@ -162,6 +162,8 @@ protected:
   virtual const char* GetRebuildCacheTargetName() { return "rebuild_cache"; }
   virtual const char* GetCleanTargetName()        { return "clean"; }
 
+  virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; }
+
   // Some make programs (Borland) do not keep a rule if there are no
   // dependencies or commands.  This is a problem for creating rules
   // that might not do anything but might have other dependencies

+ 69 - 13
Source/cmMakefile.cxx

@@ -3140,7 +3140,8 @@ cmTarget* cmMakefile::FindTargetToUse(const char* name)
 }
 
 //----------------------------------------------------------------------------
-bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg)
+bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
+                                   bool isCustom)
 {
   if(cmTarget* existing = this->FindTargetToUse(name.c_str()))
     {
@@ -3158,21 +3159,76 @@ bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg)
       }
     else if(!this->NeedBackwardsCompatibility(2, 4))
       {
-      // The conflict is with a non-imported target.  Produce an error
-      // that tells the user how to work around the problem.
+      // The conflict is with a non-imported target.
+      // Allow this if the user has requested support.
+      cmake* cm =
+        this->LocalGenerator->GetGlobalGenerator()->GetCMakeInstance();
+      if(isCustom && existing->GetType() == cmTarget::UTILITY &&
+         this != existing->GetMakefile() &&
+         cm->GetPropertyAsBool("ALLOW_DUPLICATE_CUSTOM_TARGETS"))
+        {
+        return true;
+        }
+
+      // Produce an error that tells the user how to work around the
+      // problem.
       cmOStringStream e;
       e << "cannot create target \"" << name
         << "\" because another target with the same name already exists.  "
-        << "Logical target names must be globally unique.  "
-        << "For executables and libraries, consider using the OUTPUT_NAME "
-        << "target property to create two targets with the same physical "
-        << "name while keeping logical names distinct.  "
-        << "Custom targets must simply have globally unique names.\n"
-        << "If you are building an older project it is possible that "
-        << "it violated this rule but was working accidentally.  "
-        << "Set CMAKE_BACKWARDS_COMPATIBILITY to 2.4 or lower to disable "
-        << "this error.";
-      msg = e.str();
+        << "The existing target is ";
+      switch(existing->GetType())
+        {
+        case cmTarget::EXECUTABLE:
+          e << "an executable ";
+          break;
+        case cmTarget::STATIC_LIBRARY:
+          e << "a static library ";
+          break;
+        case cmTarget::SHARED_LIBRARY:
+          e << "a shared library ";
+          break;
+        case cmTarget::MODULE_LIBRARY:
+          e << "a module library ";
+          break;
+        case cmTarget::UTILITY:
+          e << "a custom target ";
+          break;
+        default: break;
+        }
+      e << "created in source directory \""
+        << existing->GetMakefile()->GetCurrentDirectory() << "\".\n"
+        << "\n";
+      e <<
+        "Logical target names must be globally unique because:\n"
+        "  - Unique names may be referenced unambiguously both in CMake\n"
+        "    code and on make tool command lines.\n"
+        "  - Logical names are used by Xcode and VS IDE generators\n"
+        "    to produce meaningful project names for the targets.\n"
+        "The logical name of executable and library targets does not "
+        "have to correspond to the physical file names built.  "
+        "Consider using the OUTPUT_NAME target property to create two "
+        "targets with the same physical name while keeping logical "
+        "names distinct.  "
+        "Custom targets must simply have globally unique names.\n"
+        "\n"
+        "If you are building an older project it is possible that "
+        "it violated this rule but was working accidentally because "
+        "CMake did not previously diagnose this problem.  "
+        "Set CMAKE_BACKWARDS_COMPATIBILITY to 2.4 or lower to disable "
+        "this error.\n";
+      if(isCustom && existing->GetType() == cmTarget::UTILITY)
+        {
+        e <<
+          "\n"
+          "For projects that care only about Makefile generators and do "
+          "not wish to support Xcode or VS IDE generators, one may add\n"
+          "  set_property(GLOBAL PROPERTY ALLOW_DUPLICATE_CUSTOM_TARGETS 1)\n"
+          "to the top of the project to allow duplicate custom targets "
+          "(target names must still be unique within each directory).  "
+          "However, setting this property will cause non-Makefile generators "
+          "to produce an error and refuse to generate the project.";
+        }
+        msg = e.str();
       return false;
       }
     }

+ 2 - 1
Source/cmMakefile.h

@@ -132,7 +132,8 @@ public:
   /**
    * Help enforce global target name uniqueness.
    */
-  bool EnforceUniqueName(std::string const& name, std::string& msg);
+  bool EnforceUniqueName(std::string const& name, std::string& msg,
+                         bool isCustom = false);
 
   /**
    * Perform FinalPass, Library dependency analysis etc before output of the

+ 19 - 0
Source/cmake.cxx

@@ -3322,6 +3322,25 @@ void cmake::DefineProperties(cmake *cm)
     "at the beginning of native build system generation.  "
     "This property causes it to display details of its analysis to stderr.");
 
+  cm->DefineProperty(
+    "ALLOW_DUPLICATE_CUSTOM_TARGETS", cmProperty::GLOBAL,
+    "Allow duplicate custom targets to be created.",
+    "Normally CMake requires that all targets built in a project have "
+    "globally unique names.  "
+    "This is necessary to generate meaningful project file names in "
+    "Xcode and VS IDE generators.  "
+    "It also allows the target names to be referenced unambiguously.\n"
+    "Makefile generators are capable of supporting duplicate custom target "
+    "names.  "
+    "For projects that care only about Makefile generators and do "
+    "not wish to support Xcode or VS IDE generators, one may set this "
+    "property to true to allow duplicate custom targets.  "
+    "The property allows multiple add_custom_target command calls in "
+    "*different directories* to specify the same target name.  "
+    "However, setting this property will cause non-Makefile generators "
+    "to produce an error and refuse to generate the project."
+    );
+
   cm->DefineProperty
     ("IN_TRY_COMPILE", cmProperty::GLOBAL,
      "Read-only property that is true during a try-compile configuration.",