diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 45efaa5fa2..1a94eb9f5d 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -22,6 +22,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmRange.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -35,7 +36,6 @@ void TopLevelCMakeVarCondSet(cmMakefile& mf, std::string const& name, struct ProjectArguments : ArgumentParser::ParseResult { - cm::optional ProjectName; cm::optional Version; cm::optional CompatVersion; cm::optional Description; @@ -66,7 +66,6 @@ bool cmProjectCommand(std::vector const& args, ProjectArgumentParser parser; parser.BindKeywordMissingValue(missingValueKeywords) .BindParsedKeywords(parsedKeywords) - .Bind(0, prArgs.ProjectName) .Bind("VERSION"_s, prArgs.Version) .Bind("DESCRIPTION"_s, prArgs.Description) .Bind("HOMEPAGE_URL"_s, prArgs.HomepageURL) @@ -80,13 +79,24 @@ bool cmProjectCommand(std::vector const& args, parser.Bind("COMPAT_VERSION"_s, prArgs.CompatVersion); } - parser.Parse(args, &unparsedArgs, 0); - - if (!prArgs.ProjectName) { + if (args.empty()) { status.SetError("PROJECT called with incorrect number of arguments"); return false; } + std::string const& projectName = args[0]; + if (parser.HasKeyword(projectName)) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat( + "project() called with '", projectName, + "' as first argument. The first parameter should be the project name, " + "not a keyword argument. See the cmake-commands(7) manual for correct " + "usage of the project() command.")); + } + + parser.Parse(cmMakeRange(args).advance(1), &unparsedArgs, 1); + if (mf.IsRootMakefile() && !mf.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) { mf.IssueMessage( @@ -100,16 +110,16 @@ bool cmProjectCommand(std::vector const& args, return false; } - if (!IncludeByVariable( - status, "CMAKE_PROJECT_" + *prArgs.ProjectName + "_INCLUDE_BEFORE")) { + if (!IncludeByVariable(status, + "CMAKE_PROJECT_" + projectName + "_INCLUDE_BEFORE")) { return false; } - mf.SetProjectName(*prArgs.ProjectName); + mf.SetProjectName(projectName); cmPolicies::PolicyStatus cmp0180 = mf.GetPolicyStatus(cmPolicies::CMP0180); - std::string varName = cmStrCat(*prArgs.ProjectName, "_BINARY_DIR"_s); + std::string varName = cmStrCat(projectName, "_BINARY_DIR"_s); bool nonCacheVarAlreadySet = mf.IsNormalDefinitionSet(varName); mf.AddCacheDefinition(varName, mf.GetCurrentBinaryDirectory(), "Value Computed by CMake", cmStateEnums::STATIC); @@ -117,7 +127,7 @@ bool cmProjectCommand(std::vector const& args, mf.AddDefinition(varName, mf.GetCurrentBinaryDirectory()); } - varName = cmStrCat(*prArgs.ProjectName, "_SOURCE_DIR"_s); + varName = cmStrCat(projectName, "_SOURCE_DIR"_s); nonCacheVarAlreadySet = mf.IsNormalDefinitionSet(varName); mf.AddCacheDefinition(varName, mf.GetCurrentSourceDirectory(), "Value Computed by CMake", cmStateEnums::STATIC); @@ -128,11 +138,11 @@ bool cmProjectCommand(std::vector const& args, mf.AddDefinition("PROJECT_BINARY_DIR", mf.GetCurrentBinaryDirectory()); mf.AddDefinition("PROJECT_SOURCE_DIR", mf.GetCurrentSourceDirectory()); - mf.AddDefinition("PROJECT_NAME", *prArgs.ProjectName); + mf.AddDefinition("PROJECT_NAME", projectName); mf.AddDefinitionBool("PROJECT_IS_TOP_LEVEL", mf.IsRootMakefile()); - varName = cmStrCat(*prArgs.ProjectName, "_IS_TOP_LEVEL"_s); + varName = cmStrCat(projectName, "_IS_TOP_LEVEL"_s); nonCacheVarAlreadySet = mf.IsNormalDefinitionSet(varName); mf.AddCacheDefinition(varName, mf.IsRootMakefile() ? "ON" : "OFF", "Value Computed by CMake", cmStateEnums::STATIC); @@ -140,7 +150,7 @@ bool cmProjectCommand(std::vector const& args, mf.AddDefinition(varName, mf.IsRootMakefile() ? "ON" : "OFF"); } - TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_NAME", *prArgs.ProjectName); + TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_NAME", projectName); std::set seenKeywords; for (cm::string_view keyword : parsedKeywords) { @@ -253,7 +263,7 @@ bool cmProjectCommand(std::vector const& args, auto createVariables = [&](cm::string_view var, std::string const& val) { mf.AddDefinition(cmStrCat("PROJECT_"_s, var), val); - mf.AddDefinition(cmStrCat(*prArgs.ProjectName, "_"_s, var), val); + mf.AddDefinition(cmStrCat(projectName, "_"_s, var), val); TopLevelCMakeVarCondSet(mf, cmStrCat("CMAKE_PROJECT_"_s, var), val); }; @@ -282,8 +292,8 @@ bool cmProjectCommand(std::vector const& args, return false; } - if (!IncludeByVariable( - status, "CMAKE_PROJECT_" + *prArgs.ProjectName + "_INCLUDE")) { + if (!IncludeByVariable(status, + "CMAKE_PROJECT_" + projectName + "_INCLUDE")) { return false; } diff --git a/Tests/RunCMake/project/KeywordProjectName-stderr.txt b/Tests/RunCMake/project/KeywordProjectName-stderr.txt new file mode 100644 index 0000000000..a96ac320b7 --- /dev/null +++ b/Tests/RunCMake/project/KeywordProjectName-stderr.txt @@ -0,0 +1,31 @@ +CMake Warning \(dev\) at KeywordProjectName\.cmake:[0-9]+ \(project\): + project\(\) called with 'LANGUAGES' as first argument\. The first parameter + should be the project name, not a keyword argument\. See the + cmake-commands\(7\) manual for correct usage of the project\(\) command\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. + +CMake Warning \(dev\) at KeywordProjectName\.cmake:[0-9]+ \(project\): + project\(\) called with 'VERSION' as first argument\. The first parameter + should be the project name, not a keyword argument\. See the + cmake-commands\(7\) manual for correct usage of the project\(\) command\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. + +CMake Warning \(dev\) at KeywordProjectName\.cmake:[0-9]+ \(project\): + project\(\) called with 'DESCRIPTION' as first argument\. The first parameter + should be the project name, not a keyword argument\. See the + cmake-commands\(7\) manual for correct usage of the project\(\) command\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. + +CMake Warning \(dev\) at KeywordProjectName\.cmake:[0-9]+ \(project\): + project\(\) called with 'HOMEPAGE_URL' as first argument\. The first + parameter should be the project name, not a keyword argument\. See the + cmake-commands\(7\) manual for correct usage of the project\(\) command\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. diff --git a/Tests/RunCMake/project/KeywordProjectName.cmake b/Tests/RunCMake/project/KeywordProjectName.cmake new file mode 100644 index 0000000000..07a075782b --- /dev/null +++ b/Tests/RunCMake/project/KeywordProjectName.cmake @@ -0,0 +1,9 @@ +project(LANGUAGES) +project(VERSION) +project(DESCRIPTION) +project(HOMEPAGE_URL) + +# CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO=b80be207-778e-46ba-8080-b23bba22639e +# Enable these when Package Info is no longer experimental +# project(COMPAT_VERSION) +# project(SPDX_LICENSE) diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake index 8ffc645f95..92b6de593c 100644 --- a/Tests/RunCMake/project/RunCMakeTest.cmake +++ b/Tests/RunCMake/project/RunCMakeTest.cmake @@ -21,6 +21,8 @@ if(CMake_TEST_RESOURCES) run_cmake(ExplicitRC) endif() +run_cmake(KeywordProjectName) + set(RunCMake_DEFAULT_stderr .) run_cmake(LanguagesDuplicate) unset(RunCMake_DEFAULT_stderr)