[CMake] Weird behaviour of mark_as_advanced(), find_program() and the cache
Alexander Neundorf
a.neundorf-work at gmx.net
Tue Mar 2 16:31:50 EST 2010
Hi,
attached is a short CMakeLists.txt which shows a strange behaviour of
mark_as_advanced(), find_program() and the cache.
What it does is the following: it sets a variable FOO to "foo", then marks it
as advanced (although it is not in the cache), then does a find_program() on
the variable, and after that find_program() FOO is suddenly empty.
I.e. the output is:
...
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- FOO = "foo"
-- FOO = "foo"
-- FOO = "foo"
-- FOO = ""
-- Configuring done
I tested this with current HEAD (or master) and CMake 2.6.2. Both give the
same result.
FOO is then also in the cache with value "".
What happens is this:
first set() sets the value, but not in the cache.
Then there comes the mark_as_advanced(), which creates a cache entry, but with
empty value:
bool cmMarkAsAdvancedCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
{
...
for(; i < args.size(); ++i)
{
std::string variable = args[i];
cmCacheManager* manager = this->Makefile->GetCacheManager();
cmCacheManager::CacheIterator it =
manager->GetCacheIterator(variable.c_str());
if ( it.IsAtEnd() )
{
this->Makefile->GetCacheManager()
->AddCacheEntry(variable.c_str(), 0, 0,
cmCacheManager::UNINITIALIZED);
overwrite = true;
}
Now this variable is kind-of in the cache. Then comes find_program():
bool cmFindProgramCommand
::InitialPass(std::vector<std::string> const& argsIn, cmExecutionStatus &)
{
this->VariableDocumentation = "Path to a program.";
this->CMakePathName = "PROGRAM";
// call cmFindBase::ParseArguments
if(!this->ParseArguments(argsIn))
{
return false;
}
if(this->AlreadyInCache)
{
// If the user specifies the entry on the command line without a
// type we should add the type and docstring but keep the original
// value.
if(this->AlreadyInCacheWithoutMetaInfo)
{
this->Makefile->GetDefinition(this->VariableName.c_str()));
this->Makefile->AddCacheDefinition(this->VariableName.c_str(), "",
this->VariableDocumentation.c_str(),
cmCacheManager::FILEPATH);
}
return true;
}
This sees the variable is already in the cache, but without meta info and adds
it using AddCacheDefinition().
After this call, makefile->GetDefinition("FOO") returns an empty string,
before this call it still returns "foo".
I didn't figure out the correct way how to improve this.
Making mark_as_advanced() put it in the cache with the current value has the
effect that find_program() also hits the same branch, but after the
AddCacheDefinition() FOO has the value
of "/home/alex/src/CMake/tests/find-cache-var-test/bH/foo", which is due to
the type FILEPATH, which, when set, causes AddCacheDefinition to expand the
value to a full path. If it is set simply as "STRING" in the cache, it
stays "FOO".
I think it should end up in the cache as "foo" with the type "FILEPATH", but I
didn't figure out how to achieve this.
Alex
-------------- next part --------------
cmake_minimum_required(VERSION 2.6)
macro(print var)
message(STATUS "${var} = \"${${var}}\"")
endmacro(print)
set(FOO foo)
print(FOO) # gives "foo"
find_program(FOO ls) # this line doesn't affect the result at all
print(FOO)
mark_as_advanced(FOO) # without this line FOO is still "foo" after the next find_program()
# with this line it is empty
print(FOO) # gives "foo"
find_program(FOO ls) # does nothing, since FOO is already valid
print(FOO) # gives ""
More information about the CMake
mailing list