[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