Merge topic 'dev/strict-mode'

dd2f814 Merge branch 'dev/add_test-working-directory' into dev/strict-mode
949d32c Unwatch manual variables upon removal in cmake-gui
3939032 Unwatch manual variables upon removal in ccmake
8354413 Add method to unwatch a manual variable
8ed3c85 Give a better message for unused variables
729db48 Fix ArgumentExpansion test expected results
89c2544 Checking for a definition is a usage
5625dee Don't output to stderr in the GUI
ad25a96 Merge branch 'ImprovedDotSupport2' into dev/strict-mode
c128abe Merge branch 'AddCMAKE_CURRENT_LIST_DIR' into dev/strict-mode
9bcaff0 Merge branch 'cmake-guiRememberAdvancedCheckbox' into dev/strict-mode
544d0c3 Fix expected output for WarnUninitialized test
4e3bea4 Update expected messages to new format
8e8c9e4 Don't check at destruction for usage
668e005 Use cmake::IssueMessage for warnings
88cd4c1 Use 'CMake Warning' versus 'warning' for CDash
3c3b98d Initialize the class before setting warn flags
cf8b15a Ignore files under the CMakeFiles directory
fd50f06 Don't check for unused vars at configure time
447a04c Don't warn during configure when doing everything
b97ee21 Check for unused variables at the end of generate
c18c977 When checking for variables, specify a reason
3f1121f Use a long int since Line is a long as well
2507f93 Change the failure case string to 'Unexpected'
fe390a2 Add 'ArgumentExpansion' test
8dbb209 Wrong boolean value for CLI warnings
d4ee998 Hard-code the --no-warn-unused-cli flag
a267b99 Fix line lengths
82ed104 Flag that the directories have been set
5aa535b Add argument to arg parsing to not set directories
367e5c3 Revert "Revert "When calling CMake, set the args and the cache""
ab5d4e4 Revert "When calling CMake, set the args and the cache"
9b90040 When calling CMake, set the args and the cache
fe56002 Fix long lines for KWStyle
5d30cfc Set a watch on variables added through the gui
33c63b1 Add a method to put a watch for variables
535253f Initialize the warning variables earlier
cbb286c Fix the path detection to work for top-level
62be1f7 Initialize the usage stack earlier
c6e7fab Factor out the checks for unused variables
5e41ba8 When using the API, check for Add vs. Remove
dee1976 Fix typo in VariableUnusedViaUnset test
f231ce5 Remove old false positive avoidance code
a117e02 Revert "Add test for unused warnings at the end of scope"
2c82f2b Exempt CMAKE(CURRENT|PARENT)_LIST_FILE from usage
6d7d449 Ignore CLI warnings for ABI determination
7740a73 Only return local keys that are defined
bef3aee Use the API so that warnings can be tracked
05cb0f4 Check for unused variables in the dtor
91c4c99 Add test for unused warnings at the end of scope
ca90f67 Fix detection of unused variables when setting
f7438ca Add test for unused detection via setting it
995cfb0 Don't warn if the variable wasn't defined
aefc91d Add test for usage checks via unset
a8e97f8 Remove VarRemoved code since it's been superceded
59463ef Rework CheckVariableForUnused usage
f117423 Fix line lengths to be no more than 78
e49a935 Improve unused warning logic
e01e40c Mark ARGC, ARGV*, and ARGN as used
a17aff7 Ignore CMAKE_MATCH_* variables for usage
02a114d Add method to allow variables to be marked as used
a0b0d23 CMAKE_DO_TRY_COMPILE is no longer used
ae3eff3 Fix the path used for ignoring system warnings
056b441 Fix missing case for usage of a variable
980e048 Factor out checks for unused variables
83acb0a Remove now unused variables
3801463 Use built-ins for readability and maintainability
8b52015 Push the initialize and unused states when copying
439877f Be consistent with single and double quotes
4cf1706 Add documentation for check-system-vars
b74777f Fix the spelling of the flag for warn-unused-vars
b948120 Change logic of flag to turn off cli unused checks
f047a17 Add test for uninitialized variables
75bda38 Add tests for unused command line variables
300fc15 Fix detection of system files
d784e6a Run the unused variables check on the final pass
9efc057 VariableWatch is not available when bootstrapping
2e78224 Add a missing comma to the warning message
7499700 Add a flag to warn about system files
fff9f6d Rename flags again and use variablewatch for cli
786e269 Add warn-unused to the Qt interface
636e6c4 Default to marking things as used
4ff0340 Rename find-unused to warn-unused
d7999e9 Rename strict-mode to warn-uninitialized
e141bc9 Detect unused variables
d3e8eb5 Add flags to detect unused variables
f332e14 Complete strict-mode checks for uninitialized vars
52f9637 Add method to get the local scope variables
f794d58 Make --strict-mode option, and integrate with cmake-gui
48b5b85 Add a warning when variables are used uninitialized.
cd626ea For macros make sure the FilePath points to a valid pointer in the args.
This commit is contained in:
Brad King 2011-01-27 15:34:07 -05:00 committed by CMake Topic Stage
commit 182eb7c7ef
27 changed files with 621 additions and 18 deletions

View File

@ -24,10 +24,18 @@ FUNCTION(CMAKE_DETERMINE_COMPILER_ABI lang src)
# Compile the ABI identification source.
SET(BIN "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeDetermineCompilerABI_${lang}.bin")
SET(CMAKE_FLAGS )
IF(DEFINED CMAKE_${lang}_VERBOSE_FLAG)
SET(CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_${lang}_VERBOSE_FLAG}")
ENDIF()
TRY_COMPILE(CMAKE_DETERMINE_${lang}_ABI_COMPILED
${CMAKE_BINARY_DIR} ${src}
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_${lang}_VERBOSE_FLAG}"
CMAKE_FLAGS "${CMAKE_FLAGS}"
"-DCMAKE_${lang}_STANDARD_LIBRARIES="
# We need ignore these warnings because some platforms need
# CMAKE_${lang}_STANDARD_LIBRARIES to link properly and we
# don't care when we are just determining the ABI.
"--no-warn-unused-cli"
OUTPUT_VARIABLE OUTPUT
COPY_FILE "${BIN}"
)
@ -58,10 +66,16 @@ FUNCTION(CMAKE_DETERMINE_COMPILER_ABI lang src)
# Parse implicit linker information for this language, if available.
SET(implicit_dirs "")
SET(implicit_libs "")
SET(MULTI_ARCH FALSE)
IF(DEFINED CMAKE_OSX_ARCHITECTURES)
IF( "${CMAKE_OSX_ARCHITECTURES}" MATCHES ";" )
SET(MULTI_ARCH TRUE)
ENDIF()
ENDIF()
IF(CMAKE_${lang}_VERBOSE_FLAG
# Implicit link information cannot be used explicitly for
# multiple OS X architectures, so we skip it.
AND NOT "${CMAKE_OSX_ARCHITECTURES}" MATCHES ";"
AND NOT MULTI_ARCH
# Skip this with Xcode for now.
AND NOT "${CMAKE_GENERATOR}" MATCHES Xcode)
CMAKE_PARSE_IMPLICIT_LINK_INFO("${OUTPUT}" implicit_libs implicit_dirs log

View File

@ -243,7 +243,9 @@ FUNCTION(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
# ENDIF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface")
ENDIF(NOT CMAKE_EXECUTABLE_FORMAT)
IF(NOT DEFINED CMAKE_EXECUTABLE_FORMAT)
SET(CMAKE_EXECUTABLE_FORMAT)
ENDIF()
# Return the information extracted.
SET(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
SET(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)

View File

@ -789,6 +789,7 @@ void cmCursesMainForm::RemoveEntry(const char* value)
const char* val = (*it)->GetValue();
if ( val && !strcmp(value, val) )
{
this->CMakeInstance->UnwatchUnusedCli(value);
this->Entries->erase(it);
break;
}

View File

@ -118,8 +118,15 @@ CMakeSetupDialog::CMakeSetupDialog()
this, SLOT(doInstallForCommandLine()));
#endif
QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));
this->SuppressDevWarningsAction = OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)"));
this->SuppressDevWarningsAction =
OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)"));
this->SuppressDevWarningsAction->setCheckable(true);
this->WarnUninitializedAction =
OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)"));
this->WarnUninitializedAction->setCheckable(true);
this->WarnUnusedAction =
OptionsMenu->addAction(tr("&Warn Unused (--warn-unused-vars)"));
this->WarnUnusedAction->setCheckable(true);
QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
debugAction->setCheckable(true);
@ -247,6 +254,13 @@ void CMakeSetupDialog::initialize()
QObject::connect(this->SuppressDevWarningsAction, SIGNAL(triggered(bool)),
this->CMakeThread->cmakeInstance(), SLOT(setSuppressDevWarnings(bool)));
QObject::connect(this->WarnUninitializedAction, SIGNAL(triggered(bool)),
this->CMakeThread->cmakeInstance(),
SLOT(setWarnUninitializedMode(bool)));
QObject::connect(this->WarnUnusedAction, SIGNAL(triggered(bool)),
this->CMakeThread->cmakeInstance(),
SLOT(setWarnUnusedMode(bool)));
if(!this->SourceDirectory->text().isEmpty() ||
!this->BinaryDirectory->lineEdit()->text().isEmpty())
{

View File

@ -97,6 +97,8 @@ protected:
QAction* ConfigureAction;
QAction* GenerateAction;
QAction* SuppressDevWarningsAction;
QAction* WarnUninitializedAction;
QAction* WarnUnusedAction;
QAction* InstallForCommandLineAction;
State CurrentState;

View File

@ -28,6 +28,8 @@ QCMake::QCMake(QObject* p)
: QObject(p)
{
this->SuppressDevWarnings = false;
this->WarnUninitializedMode = false;
this->WarnUnusedMode = false;
qRegisterMetaType<QCMakeProperty>();
qRegisterMetaType<QCMakePropertyList>();
@ -164,6 +166,8 @@ void QCMake::configure()
this->CMakeInstance->CreateGlobalGenerator(this->Generator.toAscii().data()));
this->CMakeInstance->LoadCache();
this->CMakeInstance->SetSuppressDevWarnings(this->SuppressDevWarnings);
this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
this->CMakeInstance->SetWarnUnused(this->WarnUnusedMode);
this->CMakeInstance->PreLoadCMakeFiles();
cmSystemTools::ResetErrorOccuredFlag();
@ -238,12 +242,16 @@ void QCMake::setProperties(const QCMakePropertyList& newProps)
// remove some properites
foreach(QString s, toremove)
{
this->CMakeInstance->UnwatchUnusedCli(s.toAscii().data());
cachem->RemoveCacheEntry(s.toAscii().data());
}
// add some new properites
foreach(QCMakeProperty s, props)
{
this->CMakeInstance->WatchUnusedCli(s.Key.toAscii().data());
if(s.Type == QCMakeProperty::BOOL)
{
this->CMakeInstance->AddCacheEntry(s.Key.toAscii().data(),
@ -417,3 +425,13 @@ void QCMake::setSuppressDevWarnings(bool value)
{
this->SuppressDevWarnings = value;
}
void QCMake::setWarnUninitializedMode(bool value)
{
this->WarnUninitializedMode = value;
}
void QCMake::setWarnUnusedMode(bool value)
{
this->WarnUnusedMode = value;
}

View File

@ -88,6 +88,10 @@ public slots:
void setDebugOutput(bool);
/// set whether to do suppress dev warnings
void setSuppressDevWarnings(bool value);
/// set whether to run cmake with warnings about uninitialized variables
void setWarnUninitializedMode(bool value);
/// set whether to run cmake with warnings about unused variables
void setWarnUnusedMode(bool value);
public:
/// get the list of cache properties
@ -133,6 +137,9 @@ protected:
static void errorCallback(const char* msg, const char* title,
bool&, void* cd);
bool SuppressDevWarnings;
bool WarnUninitializedMode;
bool WarnUnusedMode;
bool WarnUnusedAllMode;
QString SourceDirectory;
QString BinaryDirectory;
QString Generator;

View File

@ -20,6 +20,8 @@ int cmCommandArgument_yyparse( yyscan_t yyscanner );
//
cmCommandArgumentParserHelper::cmCommandArgumentParserHelper()
{
this->WarnUninitialized = false;
this->CheckSystemVars = false;
this->FileLine = -1;
this->FileName = 0;
this->RemoveEmpty = true;
@ -119,10 +121,32 @@ char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
cmOStringStream ostr;
ostr << this->FileLine;
return this->AddString(ostr.str().c_str());
}
}
const char* value = this->Makefile->GetDefinition(var);
if(!value && !this->RemoveEmpty)
{
// check to see if we need to print a warning
// if strict mode is on and the variable has
// not been "cleared"/initialized with a set(foo ) call
if(this->WarnUninitialized && !this->Makefile->VariableInitialized(var))
{
if (this->CheckSystemVars ||
cmSystemTools::IsSubDirectory(this->FileName,
this->Makefile->GetHomeDirectory()) ||
cmSystemTools::IsSubDirectory(this->FileName,
this->Makefile->GetHomeOutputDirectory()))
{
cmOStringStream msg;
cmListFileBacktrace bt;
cmListFileContext lfc;
lfc.FilePath = this->FileName;
lfc.Line = this->FileLine;
bt.push_back(lfc);
msg << "uninitialized variable \'" << var << "\'";
this->Makefile->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING,
msg.str().c_str(), bt);
}
}
return 0;
}
if (this->EscapeQuotes && value)
@ -319,6 +343,8 @@ void cmCommandArgumentParserHelper::Error(const char* str)
void cmCommandArgumentParserHelper::SetMakefile(const cmMakefile* mf)
{
this->Makefile = mf;
this->WarnUninitialized = mf->GetCMakeInstance()->GetWarnUninitialized();
this->CheckSystemVars = mf->GetCMakeInstance()->GetCheckSystemVars();
}
void cmCommandArgumentParserHelper::SetResult(const char* value)

View File

@ -96,6 +96,8 @@ private:
const cmMakefile* Makefile;
std::string Result;
const char* FileName;
bool WarnUninitialized;
bool CheckSystemVars;
long FileLine;
bool EscapeQuotes;
std::string ErrorString;

View File

@ -251,10 +251,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
CMAKE_TRY_COMPILE_OSX_ARCHITECTURE first to i386 and then to ppc to
have the tests run for each specific architecture. Since
cmLocalGenerator doesn't allow building for "the other"
architecture only via CMAKE_OSX_ARCHITECTURES,use to CMAKE_DO_TRY_COMPILE
to enforce it for this case here.
architecture only via CMAKE_OSX_ARCHITECTURES.
*/
cmakeFlags.push_back("-DCMAKE_DO_TRY_COMPILE=TRUE");
if(this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_OSX_ARCHITECTURES")!=0)
{
std::string flag="-DCMAKE_OSX_ARCHITECTURES=";

View File

@ -84,6 +84,22 @@ const char* cmDefinitions::Set(const char* key, const char* value)
return def.Exists? def.c_str() : 0;
}
//----------------------------------------------------------------------------
std::set<cmStdString> cmDefinitions::LocalKeys() const
{
std::set<cmStdString> keys;
// Consider local definitions.
for(MapType::const_iterator mi = this->Map.begin();
mi != this->Map.end(); ++mi)
{
if (mi->second.Exists)
{
keys.insert(mi->first);
}
}
return keys;
}
//----------------------------------------------------------------------------
cmDefinitions cmDefinitions::Closure() const
{

View File

@ -40,6 +40,9 @@ public:
/** Set (or unset if null) a value associated with a key. */
const char* Set(const char* key, const char* value);
/** Get the set of all local keys. */
std::set<cmStdString> LocalKeys() const;
/** Compute the closure of all defined keys with values.
This flattens the scope. The result has no parent. */
cmDefinitions Closure() const;

View File

@ -113,6 +113,7 @@ bool cmFunctionHelperCommand::InvokeInitialPass
cmOStringStream strStream;
strStream << expandedArgs.size();
this->Makefile->AddDefinition("ARGC",strStream.str().c_str());
this->Makefile->MarkVariableAsUsed("ARGC");
// set the values for ARGV0 ARGV1 ...
for (unsigned int t = 0; t < expandedArgs.size(); ++t)
@ -121,6 +122,7 @@ bool cmFunctionHelperCommand::InvokeInitialPass
tmpStream << "ARGV" << t;
this->Makefile->AddDefinition(tmpStream.str().c_str(),
expandedArgs[t].c_str());
this->Makefile->MarkVariableAsUsed(tmpStream.str().c_str());
}
// define the formal arguments
@ -153,7 +155,9 @@ bool cmFunctionHelperCommand::InvokeInitialPass
cnt ++;
}
this->Makefile->AddDefinition("ARGV", argvDef.c_str());
this->Makefile->MarkVariableAsUsed("ARGV");
this->Makefile->AddDefinition("ARGN", argnDef.c_str());
this->Makefile->MarkVariableAsUsed("ARGN");
// Invoke all the functions that were collected in the block.
// for each function

View File

@ -903,6 +903,8 @@ void cmGlobalGenerator::Generate()
}
this->CMakeInstance->UpdateProgress("Generating done", -1);
this->CMakeInstance->RunCheckForUnusedVariables("generation");
}
//----------------------------------------------------------------------------

View File

@ -31,6 +31,7 @@ public:
// we must copy when we clone
newC->Args = this->Args;
newC->Functions = this->Functions;
newC->FilePath = this->FilePath;
newC->Policies = this->Policies;
return newC;
}
@ -78,6 +79,7 @@ public:
std::vector<std::string> Args;
std::vector<cmListFileFunction> Functions;
cmPolicies::PolicyMap Policies;
std::string FilePath;
};
@ -121,7 +123,10 @@ bool cmMacroHelperCommand::InvokeInitialPass
std::string argnDef;
bool argnDefInitialized = false;
bool argvDefInitialized = false;
if( this->Functions.size())
{
this->FilePath = this->Functions[0].FilePath;
}
// Invoke all the functions that were collected in the block.
cmListFileFunction newLFF;
// for each function
@ -135,10 +140,13 @@ bool cmMacroHelperCommand::InvokeInitialPass
newLFF.Line = this->Functions[c].Line;
// for each argument of the current function
for (std::vector<cmListFileArgument>::const_iterator k =
for (std::vector<cmListFileArgument>::iterator k =
this->Functions[c].Arguments.begin();
k != this->Functions[c].Arguments.end(); ++k)
{
// Set the FilePath on the arguments to match the function since it is
// not stored and the original values may be freed
k->FilePath = this->FilePath.c_str();
tmps = k->Value;
// replace formal arguments
for (unsigned int j = 1; j < this->Args.size(); ++j)

View File

@ -112,7 +112,6 @@ public:
"policies inside macros."
;
}
cmTypeMacro(cmMacroCommand, cmCommand);
};

View File

@ -44,12 +44,22 @@ class cmMakefile::Internals
{
public:
std::stack<cmDefinitions, std::list<cmDefinitions> > VarStack;
std::stack<std::set<cmStdString> > VarInitStack;
std::stack<std::set<cmStdString> > VarUsageStack;
};
// default is not to be building executables
cmMakefile::cmMakefile(): Internal(new Internals)
{
this->Internal->VarStack.push(cmDefinitions());
const cmDefinitions& defs = cmDefinitions();
const std::set<cmStdString> globalKeys = defs.LocalKeys();
this->Internal->VarStack.push(defs);
this->Internal->VarInitStack.push(globalKeys);
this->Internal->VarUsageStack.push(globalKeys);
// Initialize these first since AddDefaultDefinitions calls AddDefinition
this->WarnUnused = false;
this->CheckSystemVars = false;
// Setup the default include file regular expression (match everything).
this->IncludeFileRegularExpression = "^.*$";
@ -92,6 +102,8 @@ cmMakefile::cmMakefile(): Internal(new Internals)
cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals)
{
this->Internal->VarStack.push(mf.Internal->VarStack.top().Closure());
this->Internal->VarInitStack.push(mf.Internal->VarInitStack.top());
this->Internal->VarUsageStack.push(mf.Internal->VarUsageStack.top());
this->Prefix = mf.Prefix;
this->AuxSourceDirectories = mf.AuxSourceDirectories;
@ -129,8 +141,10 @@ cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals)
this->SubDirectoryOrder = mf.SubDirectoryOrder;
this->Properties = mf.Properties;
this->PreOrder = mf.PreOrder;
this->ListFileStack = mf.ListFileStack;
this->WarnUnused = mf.WarnUnused;
this->Initialize();
this->CheckSystemVars = mf.CheckSystemVars;
this->ListFileStack = mf.ListFileStack;
}
//----------------------------------------------------------------------------
@ -571,6 +585,7 @@ bool cmMakefile::ReadListFile(const char* filename_in,
std::string currentFile
= this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
this->AddDefinition("CMAKE_PARENT_LIST_FILE", filename_in);
this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
const char* external = 0;
std::string external_abs;
@ -611,8 +626,10 @@ bool cmMakefile::ReadListFile(const char* filename_in,
}
this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread);
this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
cmSystemTools::GetFilenamePath(filenametoread).c_str());
this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
// try to see if the list file is the top most
// list file for a project, and if it is, then it
@ -645,9 +662,12 @@ bool cmMakefile::ReadListFile(const char* filename_in,
*fullPath = "";
}
this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str());
this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str());
this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
cmSystemTools::GetFilenamePath(currentFile).c_str());
this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
return false;
}
// add this list file to the list of dependencies
@ -687,13 +707,19 @@ bool cmMakefile::ReadListFile(const char* filename_in,
}
this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str());
this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str());
this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
cmSystemTools::GetFilenamePath(currentFile).c_str());
this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
// pop the listfile off the stack
this->ListFileStack.pop_back();
// Check for unused variables
this->CheckForUnusedVariables();
return true;
}
@ -759,6 +785,8 @@ void cmMakefile::SetLocalGenerator(cmLocalGenerator* lg)
this->AddSourceGroup("Resources", "\\.plist$");
#endif
this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
}
bool cmMakefile::NeedBackwardsCompatibility(unsigned int major,
@ -1627,6 +1655,13 @@ void cmMakefile::AddDefinition(const char* name, const char* value)
#endif
this->Internal->VarStack.top().Set(name, value);
if (this->Internal->VarUsageStack.size() &&
this->VariableInitialized(name))
{
this->CheckForUnused("changing definition", name);
this->Internal->VarUsageStack.top().erase(name);
}
this->Internal->VarInitStack.top().insert(name);
#ifdef CMAKE_BUILD_WITH_CMAKE
cmVariableWatch* vv = this->GetVariableWatch();
@ -1691,6 +1726,13 @@ void cmMakefile::AddCacheDefinition(const char* name, const char* value,
void cmMakefile::AddDefinition(const char* name, bool value)
{
this->Internal->VarStack.top().Set(name, value? "ON" : "OFF");
if (this->Internal->VarUsageStack.size() &&
this->VariableInitialized(name))
{
this->CheckForUnused("changing definition", name);
this->Internal->VarUsageStack.top().erase(name);
}
this->Internal->VarInitStack.top().insert(name);
#ifdef CMAKE_BUILD_WITH_CMAKE
cmVariableWatch* vv = this->GetVariableWatch();
if ( vv )
@ -1701,9 +1743,90 @@ void cmMakefile::AddDefinition(const char* name, bool value)
#endif
}
void cmMakefile::CheckForUnusedVariables() const
{
const cmDefinitions& defs = this->Internal->VarStack.top();
const std::set<cmStdString>& locals = defs.LocalKeys();
std::set<cmStdString>::const_iterator it = locals.begin();
for (; it != locals.end(); ++it)
{
this->CheckForUnused("out of scope", it->c_str());
}
}
void cmMakefile::MarkVariableAsUsed(const char* var)
{
this->Internal->VarUsageStack.top().insert(var);
}
bool cmMakefile::VariableInitialized(const char* var) const
{
if(this->Internal->VarInitStack.top().find(var) !=
this->Internal->VarInitStack.top().end())
{
return true;
}
return false;
}
bool cmMakefile::VariableUsed(const char* var) const
{
if(this->Internal->VarUsageStack.top().find(var) !=
this->Internal->VarUsageStack.top().end())
{
return true;
}
return false;
}
void cmMakefile::CheckForUnused(const char* reason, const char* name) const
{
if (this->WarnUnused && !this->VariableUsed(name))
{
cmStdString path;
cmListFileBacktrace bt;
if (this->CallStack.size())
{
const cmListFileContext* file = this->CallStack.back().Context;
bt.push_back(*file);
path = file->FilePath.c_str();
}
else
{
path = this->GetStartDirectory();
path += "/CMakeLists.txt";
cmListFileContext lfc;
lfc.FilePath = path;
lfc.Line = 0;
bt.push_back(lfc);
}
if (this->CheckSystemVars ||
cmSystemTools::IsSubDirectory(path.c_str(),
this->GetHomeDirectory()) ||
(cmSystemTools::IsSubDirectory(path.c_str(),
this->GetHomeOutputDirectory()) &&
!cmSystemTools::IsSubDirectory(path.c_str(),
cmake::GetCMakeFilesDirectory())))
{
cmOStringStream msg;
msg << "unused variable (" << reason << ") \'" << name << "\'";
this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING,
msg.str().c_str(),
bt);
}
}
}
void cmMakefile::RemoveDefinition(const char* name)
{
this->Internal->VarStack.top().Set(name, 0);
if (this->Internal->VarUsageStack.size() &&
this->VariableInitialized(name))
{
this->CheckForUnused("unsetting", name);
this->Internal->VarUsageStack.top().erase(name);
}
this->Internal->VarInitStack.top().insert(name);
#ifdef CMAKE_BUILD_WITH_CMAKE
cmVariableWatch* vv = this->GetVariableWatch();
if ( vv )
@ -2055,6 +2178,7 @@ const char* cmMakefile::GetRequiredDefinition(const char* name) const
bool cmMakefile::IsDefinitionSet(const char* name) const
{
const char* def = this->Internal->VarStack.top().Get(name);
this->Internal->VarUsageStack.top().insert(name);
if(!def)
{
def = this->GetCacheManager()->GetCacheValue(name);
@ -2082,6 +2206,10 @@ const char* cmMakefile::GetDefinition(const char* name) const
RecordPropertyAccess(name,cmProperty::VARIABLE);
}
#endif
if (this->WarnUnused)
{
this->Internal->VarUsageStack.top().insert(name);
}
const char* def = this->Internal->VarStack.top().Get(name);
if(!def)
{
@ -2733,6 +2861,31 @@ int cmMakefile::TryCompile(const char *srcdir, const char *bindir,
// if cmake args were provided then pass them in
if (cmakeArgs)
{
// FIXME: Workaround to ignore unused CLI variables in try-compile.
//
// Ideally we should use SetArgs to honor options like --warn-unused-vars.
// However, there is a subtle problem when certain arguments are passed to
// a macro wrapping around try_compile or try_run that does not escape
// semicolons in its parameters but just passes ${ARGV} or ${ARGN}. In
// this case a list argument like "-DVAR=a;b" gets split into multiple
// cmake arguments "-DVAR=a" and "b". Currently SetCacheArgs ignores
// argument "b" and uses just "-DVAR=a", leading to a subtle bug in that
// the try_compile or try_run does not get the proper value of VAR. If we
// call SetArgs here then it would treat "b" as the source directory and
// cause an error such as "The source directory .../CMakeFiles/CMakeTmp/b
// does not exist", thus breaking the try_compile or try_run completely.
//
// Strictly speaking the bug is in the wrapper macro because the CMake
// language has always flattened nested lists and the macro should escape
// the semicolons in its arguments before forwarding them. However, this
// bug is so subtle that projects typically work anyway, usually because
// the value VAR=a is sufficient for the try_compile or try_run to get the
// correct result. Calling SetArgs here would break such projects that
// previously built. Instead we work around the issue by never reporting
// unused arguments and ignoring options such as --warn-unused-vars.
cm.SetWarnUnusedCli(false);
//cm.SetArgs(*cmakeArgs, true);
cm.SetCacheArgs(*cmakeArgs);
}
// to save time we pass the EnableLanguage info directly
@ -3416,12 +3569,48 @@ std::string cmMakefile::GetListFileStack()
void cmMakefile::PushScope()
{
cmDefinitions* parent = &this->Internal->VarStack.top();
const std::set<cmStdString>& init = this->Internal->VarInitStack.top();
const std::set<cmStdString>& usage = this->Internal->VarUsageStack.top();
this->Internal->VarStack.push(cmDefinitions(parent));
this->Internal->VarInitStack.push(init);
this->Internal->VarUsageStack.push(usage);
}
void cmMakefile::PopScope()
{
cmDefinitions* current = &this->Internal->VarStack.top();
std::set<cmStdString> init = this->Internal->VarInitStack.top();
std::set<cmStdString> usage = this->Internal->VarUsageStack.top();
const std::set<cmStdString>& locals = current->LocalKeys();
// Remove initialization and usage information for variables in the local
// scope.
std::set<cmStdString>::const_iterator it = locals.begin();
for (; it != locals.end(); ++it)
{
init.erase(*it);
if (!this->VariableUsed(it->c_str()))
{
this->CheckForUnused("out of scope", it->c_str());
}
else
{
usage.erase(*it);
}
}
this->Internal->VarStack.pop();
this->Internal->VarInitStack.pop();
this->Internal->VarUsageStack.pop();
// Push initialization and usage up to the parent scope.
it = init.begin();
for (; it != init.end(); ++it)
{
this->Internal->VarInitStack.top().insert(*it);
}
it = usage.begin();
for (; it != usage.end(); ++it)
{
this->Internal->VarUsageStack.top().insert(*it);
}
}
void cmMakefile::RaiseScope(const char *var, const char *varDef)
@ -3446,7 +3635,14 @@ void cmMakefile::RaiseScope(const char *var, const char *varDef)
// directory's scope was initialized by the closure of the parent
// scope, so we do not need to localize the definition first.
cmMakefile* parent = plg->GetMakefile();
parent->Internal->VarStack.top().Set(var, varDef);
if (varDef)
{
parent->AddDefinition(var, varDef);
}
else
{
parent->RemoveDefinition(var);
}
}
else
{

View File

@ -61,6 +61,14 @@ public:
unsigned int GetCacheMajorVersion();
unsigned int GetCacheMinorVersion();
/* Check for unused variables in this scope */
void CheckForUnusedVariables() const;
/* Mark a variable as used */
void MarkVariableAsUsed(const char* var);
/* return true if a variable has been initialized */
bool VariableInitialized(const char* ) const;
/* return true if a variable has been used */
bool VariableUsed(const char* ) const;
/** Return whether compatibility features needed for a version of
the cache or lower should be enabled. */
bool NeedCacheCompatibility(int major, int minor);
@ -836,7 +844,10 @@ public:
protected:
// add link libraries and directories to the target
void AddGlobalLinkInformation(const char* name, cmTarget& target);
// Check for a an unused variable
void CheckForUnused(const char* reason, const char* name) const;
std::string Prefix;
std::vector<std::string> AuxSourceDirectories; //
@ -929,6 +940,10 @@ private:
// should this makefile be processed before or after processing the parent
bool PreOrder;
// Unused variable flags
bool WarnUnused;
bool CheckSystemVars;
// stack of list files being read
std::deque<cmStdString> ListFileStack;

View File

@ -482,6 +482,7 @@ void cmStringCommand::ClearMatches(cmMakefile* mf)
char name[128];
sprintf(name, "CMAKE_MATCH_%d", i);
mf->AddDefinition(name, "");
mf->MarkVariableAsUsed(name);
}
}
@ -493,6 +494,7 @@ void cmStringCommand::StoreMatches(cmMakefile* mf,cmsys::RegularExpression& re)
char name[128];
sprintf(name, "CMAKE_MATCH_%d", i);
mf->AddDefinition(name, re.match(i).c_str());
mf->MarkVariableAsUsed(name);
}
}

View File

@ -138,9 +138,20 @@ void cmNeedBackwardsCompatibility(const std::string& variable,
#endif
}
void cmWarnUnusedCliWarning(const std::string& variable,
int, void* ctx, const char*, const cmMakefile*)
{
cmake* cm = reinterpret_cast<cmake*>(ctx);
cm->MarkCliAsUsed(variable);
}
cmake::cmake()
{
this->Trace = false;
this->WarnUninitialized = false;
this->WarnUnused = false;
this->WarnUnusedCli = true;
this->CheckSystemVars = false;
this->SuppressDevWarnings = false;
this->DoSuppressDevWarnings = false;
this->DebugOutput = false;
@ -367,6 +378,10 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
{
this->CacheManager->AddCacheEntry(var.c_str(), value.c_str(),
"No help, variable specified on the command line.", type);
if(this->WarnUnusedCli)
{
this->WatchUnusedCli(var.c_str());
}
}
else
{
@ -509,9 +524,10 @@ void cmake::ReadListFile(const char *path)
}
// Parse the args
void cmake::SetArgs(const std::vector<std::string>& args)
void cmake::SetArgs(const std::vector<std::string>& args,
bool directoriesSetBefore)
{
bool directoriesSet = false;
bool directoriesSet = directoriesSetBefore;
for(unsigned int i=1; i < args.size(); ++i)
{
std::string arg = args[i];
@ -613,6 +629,28 @@ void cmake::SetArgs(const std::vector<std::string>& args)
std::cout << "Running with trace output on.\n";
this->SetTrace(true);
}
else if(arg.find("--warn-uninitialized",0) == 0)
{
std::cout << "Warn about uninitialized values.\n";
this->SetWarnUninitialized(true);
}
else if(arg.find("--warn-unused-vars",0) == 0)
{
std::cout << "Finding unused variables.\n";
this->SetWarnUnused(true);
}
else if(arg.find("--no-warn-unused-cli",0) == 0)
{
std::cout << "Not searching for unused variables given on the " <<
"command line.\n";
this->SetWarnUnusedCli(false);
}
else if(arg.find("--check-system-vars",0) == 0)
{
std::cout << "Also check system files when warning about unused and " <<
"uninitialized variables.\n";
this->SetCheckSystemVars(true);
}
else if(arg.find("-G",0) == 0)
{
std::string value = arg.substr(2);
@ -2272,6 +2310,11 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
std::string oldstartoutputdir = this->GetStartOutputDirectory();
this->SetStartDirectory(this->GetHomeDirectory());
this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
const bool warncli = this->WarnUnusedCli;
if (!this->ScriptMode)
{
this->WarnUnusedCli = false;
}
int ret = this->Configure();
if (ret || this->ScriptMode)
{
@ -2293,6 +2336,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
#endif
return ret;
}
this->WarnUnusedCli = warncli;
ret = this->Generate();
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
@ -2835,6 +2879,10 @@ const char* cmake::GetCPackCommand()
return this->CPackCommand.c_str();
}
void cmake::MarkCliAsUsed(const std::string& variable)
{
this->UsedCliVariables[variable] = true;
}
void cmake::GenerateGraphViz(const char* fileName) const
{
@ -4255,3 +4303,40 @@ int cmake::Build(const std::string& dir,
config.c_str(), clean, false, 0, true,
0, nativeOptions);
}
void cmake::WatchUnusedCli(const char* var)
{
#ifdef CMAKE_BUILD_WITH_CMAKE
this->VariableWatch->AddWatch(var, cmWarnUnusedCliWarning, this);
this->UsedCliVariables[var] = false;
#endif
}
void cmake::UnwatchUnusedCli(const char* var)
{
#ifdef CMAKE_BUILD_WITH_CMAKE
this->VariableWatch->RemoveWatch(var, cmWarnUnusedCliWarning);
this->UsedCliVariables[var] = true;
#endif
}
void cmake::RunCheckForUnusedVariables(const std::string& reason) const
{
#ifdef CMAKE_BUILD_WITH_CMAKE
if(this->WarnUnusedCli)
{
std::map<std::string, bool>::const_iterator it;
for(it = this->UsedCliVariables.begin();
it != this->UsedCliVariables.end(); ++it)
{
if(!it->second)
{
std::string message = "CMake Warning: The variable, '" + it->first +
"', specified manually, was not used during the " + reason +
".";
cmSystemTools::Message(message.c_str());
}
}
}
#endif
}

View File

@ -214,7 +214,8 @@ class cmake
bool CommandExists(const char* name) const;
///! Parse command line arguments
void SetArgs(const std::vector<std::string>&);
void SetArgs(const std::vector<std::string>&,
bool directoriesSetBefore = false);
///! Is this cmake running as a result of a TRY_COMPILE command
bool GetIsInTryCompile() { return this->InTryCompile; }
@ -308,6 +309,17 @@ class cmake
// Do we want trace output during the cmake run.
bool GetTrace() { return this->Trace;}
void SetTrace(bool b) { this->Trace = b;}
bool GetWarnUninitialized() { return this->WarnUninitialized;}
void SetWarnUninitialized(bool b) { this->WarnUninitialized = b;}
bool GetWarnUnused() { return this->WarnUnused;}
void SetWarnUnused(bool b) { this->WarnUnused = b;}
bool GetWarnUnusedCli() { return this->WarnUnusedCli;}
void SetWarnUnusedCli(bool b) { this->WarnUnusedCli = b;}
bool GetCheckSystemVars() { return this->CheckSystemVars;}
void SetCheckSystemVars(bool b) { this->CheckSystemVars = b;}
void MarkCliAsUsed(const std::string& variable);
// Define a property
void DefineProperty(const char *name, cmProperty::ScopeType scope,
const char *ShortDescription,
@ -353,6 +365,10 @@ class cmake
const std::string& config,
const std::vector<std::string>& nativeOptions,
bool clean);
void UnwatchUnusedCli(const char* var);
void WatchUnusedCli(const char* var);
void RunCheckForUnusedVariables(const std::string& reason) const;
protected:
void InitializeProperties();
int HandleDeleteCacheVariables(const char* var);
@ -445,6 +461,11 @@ private:
bool ScriptMode;
bool DebugOutput;
bool Trace;
bool WarnUninitialized;
bool WarnUnused;
bool WarnUnusedCli;
bool CheckSystemVars;
std::map<std::string, bool> UsedCliVariables;
std::string CMakeEditCommand;
std::string CMakeCommand;
std::string CXXEnvironment;

View File

@ -120,6 +120,17 @@ static const char * cmDocumentationOptions[][3] =
{"--trace", "Put cmake in trace mode.",
"Print a trace of all calls made and from where with "
"message(send_error ) calls."},
{"--warn-uninitialized", "Warn about uninitialized values.",
"Print a warning when an uninitialized variable is used."},
{"--warn-unused-vars", "Warn about unused variables.",
"Find variables that are declared or set, but not used."},
{"--no-warn-unused-cli", "Don't warn about command line options.",
"Don't find variables that are declared on the command line, but not "
"used."},
{"--check-system-vars", "Find problems with variable usage in system "
"files.", "Normally, unused and uninitialized variables are searched for "
"only in CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR. This flag tells CMake to "
"warn about other files as well."},
{"--help-command cmd [file]", "Print help for a single command and exit.",
"Full documentation specific to the given command is displayed. "
"If a file is specified, the documentation is written into and the output "

View File

@ -0,0 +1,60 @@
cmake_minimum_required(VERSION 2.8)
project(ArgumentExpansion)
function (argument_tester expected expected_len)
list(LENGTH ARGN argn_len)
list(LENGTH ${expected} expected_received_len)
if (NOT ${expected_received_len} EQUAL ${expected_len})
message(STATUS "Unexpected: Expanding expected values isn't working")
endif (NOT ${expected_received_len} EQUAL ${expected_len})
if (${argn_len} EQUAL ${expected_len})
set(i 0)
while (i LESS ${argn_len})
list(GET ARGN ${i} argn_value)
list(GET ${expected} ${i} expected_value)
if (NOT "${argn_value}" STREQUAL "${expected_value}")
message(STATUS "Unexpected: Argument ${i} doesn't match")
message(STATUS " Expected: ${expected_value}")
message(STATUS " Received: ${argn_value}")
endif ()
math(EXPR i "${i} + 1")
endwhile (i LESS ${argn_len})
else (${argn_len} EQUAL ${expected_len})
message(STATUS "Unexpected: Lengths of arguments don't match")
message(STATUS " Expected: ${expected_len}")
message(STATUS " Received: ${argn_len}")
endif (${argn_len} EQUAL ${expected_len})
endfunction (argument_tester expected)
set(empty_test)
message(STATUS "Test: Empty arguments")
argument_tester(empty_test 0 ${empty_test})
set(single_arg_test
"single arg")
message(STATUS "Test: Single argument")
argument_tester(single_arg_test 1 ${single_arg_test})
set(multiple_arg_test
"first arg"
"second arg")
message(STATUS "Test: Multiple arguments")
argument_tester(multiple_arg_test 2 ${multiple_arg_test})
set(nested_list_arg_test
"${multiple_arg_test}"
"first arg"
"second arg")
message(STATUS "Test: Nested list argument flattens")
argument_tester(nested_list_arg_test 4 ${nested_list_arg_test})
set(semicolon_arg_test
"pre\;post")
set(semicolon_arg_test_flat "pre;post")
message(STATUS "Test: Semicolon argument flattens")
argument_tester(semicolon_arg_test_flat 2 ${semicolon_arg_test})

View File

@ -391,6 +391,19 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
)
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CustComDepend")
ADD_TEST(ArgumentExpansion ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/ArgumentExpansion"
"${CMake_BINARY_DIR}/Tests/ArgumentExpansion"
--build-generator ${CMAKE_TEST_GENERATOR}
--build-project ArgumentExpansion
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--build-exe-dir "${CMake_BINARY_DIR}/Tests/ArgumentExpansion/bin"
)
SET_TESTS_PROPERTIES(ArgumentExpansion PROPERTIES
FAIL_REGULAR_EXPRESSION "Unexpected: ")
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ArgumentExpansion")
ADD_TEST(CustomCommand ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/CustomCommand"
@ -1139,6 +1152,77 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleGeneratorTest")
ENDIF(APPLE AND CTEST_TEST_CPACK)
ADD_TEST(WarnUnusedUnusedViaSet ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/VariableUnusedViaSet"
"${CMake_BINARY_DIR}/Tests/WarnUnusedUnusedViaSet"
--build-generator ${CMAKE_TEST_GENERATOR}
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--build-noclean
--build-project WarnUnusedUnusedViaSet
--build-options "--warn-unused-vars")
SET_TESTS_PROPERTIES(WarnUnusedUnusedViaSet PROPERTIES
PASS_REGULAR_EXPRESSION "unused variable \\(changing definition\\) 'UNUSED_VARIABLE'")
SET_TESTS_PROPERTIES(WarnUnusedUnusedViaSet PROPERTIES
FAIL_REGULAR_EXPRESSION "unused variable \\(unsetting\\) 'UNUSED_VARIABLE'")
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedUnusedViaSet")
ADD_TEST(WarnUnusedUnusedViaUnset ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/VariableUnusedViaUnset"
"${CMake_BINARY_DIR}/Tests/WarnUnusedUnusedViaUnset"
--build-generator ${CMAKE_TEST_GENERATOR}
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--build-noclean
--build-project WarnUnusedUnusedViaUnset
--build-options "--warn-unused-vars")
SET_TESTS_PROPERTIES(WarnUnusedUnusedViaUnset PROPERTIES
PASS_REGULAR_EXPRESSION "CMake Warning .*:7 \\(set\\):")
SET_TESTS_PROPERTIES(WarnUnusedUnusedViaUnset PROPERTIES
FAIL_REGULAR_EXPRESSION "CMake Warning .*:5 \\(set\\):")
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedUnusedViaUnset")
ADD_TEST(WarnUnusedCliUnused ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/VariableUsage"
"${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused"
--build-generator ${CMAKE_TEST_GENERATOR}
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--build-noclean
--build-project WarnUnusedCliUnused
--build-options "-DUNUSED_CLI_VARIABLE=Unused")
SET_TESTS_PROPERTIES(WarnUnusedCliUnused PROPERTIES
PASS_REGULAR_EXPRESSION "CMake Warning: The variable, 'UNUSED_CLI_VARIABLE'")
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused")
ADD_TEST(WarnUnusedCliUsed ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/VariableUsage"
"${CMake_BINARY_DIR}/Tests/WarnUnusedCliUsed"
--build-generator ${CMAKE_TEST_GENERATOR}
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--build-noclean
--build-project WarnUnusedCliUsed
--build-options "-DUSED_VARIABLE=Usage proven")
SET_TESTS_PROPERTIES(WarnUnusedCliUsed PROPERTIES
PASS_REGULAR_EXPRESSION "Usage proven")
SET_TESTS_PROPERTIES(WarnUnusedCliUsed PROPERTIES
FAIL_REGULAR_EXPRESSION "CMake Warning: The variable, 'USED_VARIABLE'")
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUsed")
ADD_TEST(WarnUninitialized ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/VariableUsage"
"${CMake_BINARY_DIR}/Tests/WarnUninitialized"
--build-generator ${CMAKE_TEST_GENERATOR}
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--build-noclean
--build-project WarnUninitialized
--build-options "--warn-uninitialized")
SET_TESTS_PROPERTIES(WarnUninitialized PROPERTIES
PASS_REGULAR_EXPRESSION "uninitialized variable 'USED_VARIABLE'")
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUninitialized")
ADD_TEST(TestsWorkingDirectory ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/TestsWorkingDirectory"

View File

@ -0,0 +1,4 @@
set(UNUSED_VARIABLE)
# Warning should occur here
set(UNUSED_VARIABLE "Usage")
message(STATUS "${UNUSED_VARIABLE}")

View File

@ -0,0 +1,8 @@
# NOTE: Changing lines in here changes the test results since the first
# instance shouldn't warn, but the second should and they have the same message
# A warning should NOT be issued for this line:
set(UNUSED_VARIABLE)
# Warning should occur here:
set(UNUSED_VARIABLE)
message(STATUS "${UNUSED_VARIABLE}")

View File

@ -0,0 +1 @@
message(STATUS "${USED_VARIABLE}")