From ac0e58dcfbf17dec84b7bd848f6df0175f7d516b Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 11 Feb 2008 13:35:39 -0500 Subject: [PATCH] ENH: Enforce global target name uniqueness. - Error if imported target is involved in conflict - Error for non-imported target conflict unless CMAKE_BACKWARDS_COMPATIBILITY <= 2.4 - Include OUTPUT_NAME property in error message - Update add_executable and add_library command documentation --- Source/cmAddCustomTargetCommand.cxx | 8 +++++ Source/cmAddExecutableCommand.cxx | 24 +++++-------- Source/cmAddExecutableCommand.h | 55 +++++++++++++++-------------- Source/cmAddLibraryCommand.cxx | 24 +++++-------- Source/cmAddLibraryCommand.h | 45 +++++++++++++++++------ Source/cmMakefile.cxx | 39 ++++++++++++++++++++ Source/cmMakefile.h | 5 +++ Source/cmTarget.cxx | 19 +++++++--- 8 files changed, 146 insertions(+), 73 deletions(-) diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index dfb9b0ce4..085a80d48 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -158,6 +158,14 @@ bool cmAddCustomTargetCommand currentLine.clear(); } + // Enforce name uniqueness. + std::string msg; + if(!this->Makefile->EnforceUniqueName(args[0], msg)) + { + this->SetError(msg.c_str()); + return false; + } + // Add the utility target to the makefile. bool escapeOldStyle = !verbatim; this->Makefile->AddUtilityCommand(args[0].c_str(), excludeFromAll, diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index cea12bc34..744506969 100644 --- a/Source/cmAddExecutableCommand.cxx +++ b/Source/cmAddExecutableCommand.cxx @@ -82,12 +82,11 @@ bool cmAddExecutableCommand return false; } - // Check for an existing target with this name. - cmTarget* existing = this->Makefile->FindTargetToUse(exename.c_str()); + // Handle imported target creation. if(importTarget) { // Make sure the target does not already exist. - if(existing) + if(this->Makefile->FindTargetToUse(exename.c_str())) { cmOStringStream e; e << "cannot create imported target \"" << exename @@ -100,20 +99,13 @@ bool cmAddExecutableCommand this->Makefile->AddImportedTarget(exename.c_str(), cmTarget::EXECUTABLE); return true; } - else + + // Enforce name uniqueness. + std::string msg; + if(!this->Makefile->EnforceUniqueName(exename, msg)) { - // Make sure the target does not conflict with an imported target. - // This should really enforce global name uniqueness for targets - // built within the project too, but that may break compatiblity - // with projects in which it was accidentally working. - if(existing && existing->IsImported()) - { - cmOStringStream e; - e << "cannot create target \"" << exename - << "\" because an imported target with the same name already exists."; - this->SetError(e.str().c_str()); - return false; - } + this->SetError(msg.c_str()); + return false; } if (s == args.end()) diff --git a/Source/cmAddExecutableCommand.h b/Source/cmAddExecutableCommand.h index 4ac11cc50..7492a6edb 100644 --- a/Source/cmAddExecutableCommand.h +++ b/Source/cmAddExecutableCommand.h @@ -63,33 +63,36 @@ public: virtual const char* GetFullDocumentation() { return - " add_executable(exename [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL]\n" + " add_executable( [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL]\n" " source1 source2 ... sourceN)\n" - "This command adds an executable target to the current directory. " - "The executable will be built from the list of source files " - "specified.\n" - "After specifying the executable name, WIN32 and/or MACOSX_BUNDLE can " - "be specified. WIN32 indicates that the executable (when compiled on " - "windows) is a windows app (using WinMain) not a console app " - "(using main). The variable CMAKE_MFC_FLAG be used if the windows app " - "uses MFC. This variable can be set to the following values:\n" - " 0: Use Standard Windows Libraries\n" - " 1: Use MFC in a Static Library\n" - " 2: Use MFC in a Shared DLL\n" - "MACOSX_BUNDLE indicates that when build on Mac OSX, executable should " - "be in the bundle form. The MACOSX_BUNDLE also allows several " - "variables to be specified:\n" - " MACOSX_BUNDLE_INFO_STRING\n" - " MACOSX_BUNDLE_ICON_FILE\n" - " MACOSX_BUNDLE_GUI_IDENTIFIER\n" - " MACOSX_BUNDLE_LONG_VERSION_STRING\n" - " MACOSX_BUNDLE_BUNDLE_NAME\n" - " MACOSX_BUNDLE_SHORT_VERSION_STRING\n" - " MACOSX_BUNDLE_BUNDLE_VERSION\n" - " MACOSX_BUNDLE_COPYRIGHT\n" - "If EXCLUDE_FROM_ALL is given the target will not be built by default. " - "It will be built only if the user explicitly builds the target or " - "another target that requires the target depends on it." + "Adds an executable target called to be built from the " + "source files listed in the command invocation. " + "The corresponds to the logical target name and must be " + "globally unique within a project. " + "The actual file name of the executable built is constructed based on " + "conventions of the native platform " + "(such as .exe or just ). " + "\n" + "By default the executable file will be created in the build tree " + "directory corresponding to the source tree directory in which " + "the command was invoked. " + "See documentation of the RUNTIME_OUTPUT_DIRECTORY " + "target property to change this location. " + "See documentation of the OUTPUT_NAME target property to change " + "the part of the final file name. " + "\n" + "If WIN32 is given the property WIN32_EXECUTABLE will be set on the " + "target created. " + "See documentation of that target property for details." + "\n" + "If MACOSX_BUNDLE is given the corresponding property will be " + "set on the created target. " + "See documentation of the MACOSX_BUNDLE target property for details." + "\n" + "If EXCLUDE_FROM_ALL is given the corresponding property will be " + "set on the created target. " + "See documentation of the EXCLUDE_FROM_ALL target property for " + "details." "\n" "The add_executable command can also create IMPORTED executable " "targets using this signature:\n" diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 9406a3584..389672243 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -109,12 +109,11 @@ bool cmAddLibraryCommand return false; } - // Check for an existing target with this name. - cmTarget* existing = this->Makefile->FindTargetToUse(libName.c_str()); + // Handle imported target creation. if(importTarget) { // Make sure the target does not already exist. - if(existing) + if(this->Makefile->FindTargetToUse(libName.c_str())) { cmOStringStream e; e << "cannot create imported target \"" << libName @@ -127,20 +126,13 @@ bool cmAddLibraryCommand this->Makefile->AddImportedTarget(libName.c_str(), type); return true; } - else + + // Enforce name uniqueness. + std::string msg; + if(!this->Makefile->EnforceUniqueName(libName, msg)) { - // Make sure the target does not conflict with an imported target. - // This should really enforce global name uniqueness for targets - // built within the project too, but that may break compatiblity - // with projects in which it was accidentally working. - if(existing && existing->IsImported()) - { - cmOStringStream e; - e << "cannot create target \"" << libName - << "\" because an imported target with the same name already exists."; - this->SetError(e.str().c_str()); - return false; - } + this->SetError(msg.c_str()); + return false; } if (s == args.end()) diff --git a/Source/cmAddLibraryCommand.h b/Source/cmAddLibraryCommand.h index 9b95b86ff..ad23ffc5b 100644 --- a/Source/cmAddLibraryCommand.h +++ b/Source/cmAddLibraryCommand.h @@ -62,18 +62,41 @@ public: virtual const char* GetFullDocumentation() { return - " add_library(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL]\n" + " add_library( [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL]\n" " source1 source2 ... sourceN)\n" - "Adds a library target. SHARED, STATIC or MODULE keywords are used " - "to set the library type. If the keyword MODULE appears, the library " - "type is set to MH_BUNDLE on systems which use dyld. On systems " - "without dyld, MODULE is treated like SHARED. If no keywords appear " - " as the second argument, the type defaults to the current value of " - "BUILD_SHARED_LIBS. If this variable is not set, the type defaults " - "to STATIC.\n" - "If EXCLUDE_FROM_ALL is given the target will not be built by default. " - "It will be built only if the user explicitly builds the target or " - "another target that requires the target depends on it." + "Adds a library target called to be built from the " + "source files listed in the command invocation. " + "The corresponds to the logical target name and must be " + "globally unique within a project. " + "The actual file name of the library built is constructed based on " + "conventions of the native platform " + "(such as lib.a or .lib)." + "\n" + "STATIC, SHARED, or MODULE may be given to specify the type of library " + "to be created. " + "STATIC libraries are archives of object files for use when linking " + "other targets. " + "SHARED libraries are linked dynamically and loaded at runtime. " + "MODULE libraries are plugins that are not linked into other targets " + "but may be loaded dynamically at runtime using dlopen-like " + "functionality. " + "If no type is given explicitly the type is STATIC or SHARED based " + "on whether the current value of the variable BUILD_SHARED_LIBS is " + "true." + "\n" + "By default the library file will be created in the build tree " + "directory corresponding to the source tree directory in which " + "the command was invoked. " + "See documentation of the ARCHIVE_OUTPUT_DIRECTORY, " + "LIBRARY_OUTPUT_DIRECTORY, and RUNTIME_OUTPUT_DIRECTORY " + "target properties to change this location. " + "See documentation of the OUTPUT_NAME target property to change " + "the part of the final file name. " + "\n" + "If EXCLUDE_FROM_ALL is given the corresponding property will be " + "set on the created target. " + "See documentation of the EXCLUDE_FROM_ALL target property for " + "details." "\n" "The add_library command can also create IMPORTED library " "targets using this signature:\n" diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 5e22b15ca..1f8c60257 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3138,3 +3138,42 @@ cmTarget* cmMakefile::FindTargetToUse(const char* name) // Look for a target built in this project. return this->LocalGenerator->GetGlobalGenerator()->FindTarget(0, name); } + +//---------------------------------------------------------------------------- +bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg) +{ + if(cmTarget* existing = this->FindTargetToUse(name.c_str())) + { + // The name given conflicts with an existing target. Produce an + // error in a compatible way. + if(existing->IsImported()) + { + // Imported targets were not supported in previous versions. + // This is new code, so we can make it an error. + cmOStringStream e; + e << "cannot create target \"" << name + << "\" because an imported target with the same name already exists."; + msg = e.str(); + return false; + } + 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. + cmOStringStream e; + e << "cannot create target \"" << name + << "\" because another target with the same name already exists. " + << "Logical target names must be globally unique. " + << "Consider using the OUTPUT_NAME target property to create " + << "two targets with the same physical name while keeping logical " + << "names distinct.\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(); + return false; + } + } + return true; +} diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 12545e979..f3714cb0d 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -129,6 +129,11 @@ public: unsigned int minor, unsigned int patch = 0xFFu); + /** + * Help enforce global target name uniqueness. + */ + bool EnforceUniqueName(std::string const& name, std::string& msg); + /** * Perform FinalPass, Library dependency analysis etc before output of the * makefile. diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ace3d6f04..c043eceb7 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -496,10 +496,21 @@ void cmTarget::DefineProperties(cmake *cm) cm->DefineProperty ("WIN32_EXECUTABLE", cmProperty::TARGET, - "Used to specify Windows executable with a WinMain entry point.", - "This can be set to indicate that a target is a Windows executable " - "in contrast to a console application for example. This changes " - "how the executable will be linked."); + "Build an executable with a WinMain entry point on windows.", + "When this property is set to true the executable when linked " + "on Windows will be created with a WinMain() entry point instead " + "of of just main()." + "This makes it a GUI executable instead of a console application. " + "See the CMAKE_MFC_FLAG variable documentation to configure use " + "of MFC for WinMain executables."); + + cm->DefineProperty + ("MACOSX_BUNDLE", cmProperty::TARGET, + "Build an executable as an application bundle on Mac OS X.", + "When this property is set to true the executable when built " + "on Mac OS X will be created as an application bundle. " + "This makes it a GUI executable that can be launched from " + "the Finder."); cm->DefineProperty ("ENABLE_EXPORTS", cmProperty::TARGET,