>>> On 23/02/2012 02:00, Jean-Christophe Fillion-Robin wrote:
Hi François,

Would the use of function be helpful ?

See http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:function
and http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set

"If PARENT_SCOPE is present, the variable will be set in the scope above
the current scope. Each new directory or function creates a new scope.
This command will set the value of a variable into the parent directory
or calling function (whichever is applicable to the case at hand)."

I created a small example showing that variable set within a function
don't interfere with the parent scope if not explicitly required.

git clone git://gist.github.com/1888836.git
<http://gist.github.com/1888836.git>
cmake -P 1888836/cmake-illustrate-function-scope.cmake


Hi JC

I've also played around with functions vs macros to check for scoping features and I have basically written the same test script for my own learning. I agree that SET coupled with the PARENT_SCOPE directive can solve some scope issues within function, preserving the very useful ability to have "pure" local variables and still making possible for a given variable to be visible ONE scope level up. The problem is when you need to invoke several find_package commands from a thread of nested function/macros, eventually with some recursive pattern. AFAIU, a find_package() command implies to be invoked from a macro, and not a function, to preserve the global scoping of the xxx_LIBRARIES and xxx_INCLUDE_DIRS variables set from a FindXxx.cmake or xxx-config.cmake file, and thus make them visible at the top-level CMakeLists.txt file for example. May be I'm wrong and I miss something but it seems other people, trying to setup a set of homemade macros/functions to traverse automatically a dependency tree, have also faced this kind of scoping issue.

Because I have to build some complex applications and libraries from
a large set of "low-level" dedicated home-made libraries that have dependency links between them (not cyclic of course, but possibly diamond shaped), I've implemented a basic CMake dependency driver that uses a simple lists of dependency rules for any new home-made library (let's call it 'xxx') that depends on some other libraries I have at hand.

from the xxx's top-level CMakeLists.txt,  I just have to set:
{{{
SET( xxx_deprules "GSL:>=1.12;Python:>=2.6:<=2.7.3;foo:>=2.1;bar:=3.2" )
}}}
which means I want to check and use:
- GSL libs with ver >=1.12
- Python (interp+libs) with ver in [2.6-2.7.3]
- my home-made foo lib with ver >=2.1
- my home-made bar with ver==3.2
and then automatically build some xxx_INCLUDE_DIRS and xxx_LIBRARIES from these rules.

There is a special set of macros that are given the "xxx_deprules" list and are supposed to invoke the 'find_package (...)' command to check if the dependencies in the list are fulfilled. Then the macros collect/aggregate the various [GSL|Python|foo|bar]_INCLUDE_DIRS and [GSL|Python|foo|bar]_LIBRARIES variables. Note that packages like GSL and Python or Boost use typically the so-called 'Module' find_package mode (FindGSL, FindPythonInterp, FindBoost...)
while my foo and bar package uses the 'Config' mode through
well-formatted foo-config.cmake and bar-config.cmake files.
Note also that because the FindXxx.cmake files provided with the CMake distribution does not follow a strict pattern and standard (variable names...), I have to wrap the find Module within some dedicated macros to standardize the output (examples: Boost_VERSION gives "104700" and not "1.47.0", argh ! ).

So far, so good. Now assume that the "foo" lib depends also on external libs, say : 'john' and 'doe'. because they are also home-made libraries, I also provide some 'john-config.cmake' and 'doe-config.cmake' files for both.

The dependency check for the 'xxx' lib is implemented in the following way:
0) From the xxx Top-level CmakeLists.txt file, I loop on the list of dependecy rules (gsl, python, foo...)
1 ) Example for "foo:>=2.1" : invoke
{{{
find_package (foo 2.1 REQUIRED NO_MODULE HINT ...)
}}}
  this loads the 'foo-config.cmake' file with all
  its exported DLL targets : here the john DLL and the doe DLL
2) because foo has been build with john==1.2 and doe==3.1.4, the foo-config.cmake calls explicitely :
{{{
   find_package (john 1.2 EXACT REQUIRED NO_MODULE HINT ...)
}}}
and
{{{
   find_package (doe 3.1.4 EXACT REQUIRED NO_MODULE HINT ...)
}}}
with the consequence that both john-config.cmake and doe-config.cmake
will be sourced with their own exported targets.
3) again if john also depends on other libs (exported targets), the process recurses down to the leaf dependency

the result is that, given a simple dependency rule
in the top-level cmake file :
  "GSL:>=1.12 ; Python:>=2.6:<=2.7.3 ; foo:>=2.1 ; bar:=3.2"
we can rebuild the full path of the
depencency tree, including hidden parent dependencies exported target, and store it in some global variables to be used
with the include_directories(...) and target_link_libraries(...) commands.
this system is based on a strict design pattern I use for my home-made library packages with a standard interface (names of the variables, location of various .cmake files...) and a set of smart *macros* that drive the recursion, preserving the global scope of all dependency-related variables and exported targets. The main issue comes from the fact that to write such macros and algos, one needs to use many temporary variables with dynamic naming such as :
{{{
foreach (depname ${depnames})
   set ( ${depname}_DIR ...)
...
}}}
within foreach loops or if/endif tests, also to tokenize some variables and locally parse directives stored in string variables. Without local scoping, this turns to be a mess when you meet a dependency recursion with at least two levels (variable names collision, corruption of variables in the parent scope due to reuse of a variable name in a daughter macro...).

Maybe there is another way in the CMake language to design such a
dep-driver without "local scoping". From my programing experience
with various languages such as C/C++/Java/Python/shell, local scoping
is a natural way to achieve this without significant issues. In short, it is a fundamental tool for most language. Here CMake lacks this feature and makes life harder (at least mine) !

Even if I've found a solution to workaround this Cmake behaviour, I'm still interested in this general question :
" Will Cmake implement some kind of "local scoping" in the future ? "

;-)

Apologize for this long thread, but I hope it will help you to figure out the pb I have faced.

cheers

frc
--

Hth
Jc

On Wed, Feb 22, 2012 at 7:07 PM, François Mauger
<mau...@lpccaen.in2p3.fr <mailto:mau...@lpccaen.in2p3.fr>> wrote:

    Hi CMakers,

    In november 2007, there was a long thread titled "lexical scoping".
    The discussion was really interesting and was suggesting that some
    "local scoping" features for variables could be implemented in CMake...
    particularly from macros, which are probably the practical case that
    causes most issues when users implement several nested levels of
    macro invocations with many intermediate temporary variables that
    unfortunately aggregate in the global scope. It is really easy to
    face such problem in a rather large project driven with Cmake (a
    dependency driver invoking the find_package command in a foreach
    loop must be done from a macro AFAIK).
    Unless I missed something in the jungle of CMake threads and doc,
    I'm afraid I was not able to find some satisfactory solution other
    than hacks (using very long variable names to "emulate" some pseudo
    local scopes). this is tedious and bug prone.

    Browsing the last 4 years of archives and some additionnal docs, I
    was not able to find a single trace of such new feature :
    implementing "local scoping" in CMake (whatever "local scoping"
    could rationally mean).

    What is the current situation on users' side ? Is there any pressure
    for "local scoping" ? Maybe too few people ask for it so CMake
    developpers do not consider it as a priority... or no clear definition
    of "local scoping" has been patterned ?
    more what is the view of the CMake devel team ? do they consider
    this idea as a good one or not ?

    Thanks a lot for hints and advices.

    Best regards
    frc
    --
    François Mauger
    LPC Caen-CNRS/IN2P3-UCBN-ENSICAEN
    Département de Physique -- Université de Caen Basse-Normandie

    --

    Powered by www.kitware.com <http://www.kitware.com>

    Visit other Kitware open-source projects at
    http://www.kitware.com/__opensource/opensource.html
    <http://www.kitware.com/opensource/opensource.html>

    Please keep messages on-topic and check the CMake FAQ at:
    http://www.cmake.org/Wiki/__CMake_FAQ
    <http://www.cmake.org/Wiki/CMake_FAQ>

    Follow this link to subscribe/unsubscribe:
    http://www.cmake.org/mailman/__listinfo/cmake
    <http://www.cmake.org/mailman/listinfo/cmake>




--
+1 919 869 8849



--
François Mauger
  Groupe "Interactions Fondamentales et Nature du Neutrino"
  NEMO-3/SuperNEMO Collaboration
LPC Caen-CNRS/IN2P3-UCBN-ENSICAEN
Département de Physique -- Université de Caen Basse-Normandie
Adresse/address:
  Laboratoire de Physique Corpusculaire de Caen (UMR 6534)
  ENSICAEN
  6, Boulevard du Marechal Juin
  14050 CAEN Cedex
  FRANCE
Courriel/e-mail: mau...@lpccaen.in2p3.fr
Tél./phone:      02 31 45 25 12 / (+33) 2 31 45 25 12
Fax:             02 31 45 25 49 / (+33) 2 31 45 25 49

--

Powered by www.kitware.com

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Follow this link to subscribe/unsubscribe:
http://www.cmake.org/mailman/listinfo/cmake

Reply via email to