Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parsing cmake variables values of bool #25

Open
zerothi opened this issue Mar 2, 2023 · 5 comments
Open

parsing cmake variables values of bool #25

zerothi opened this issue Mar 2, 2023 · 5 comments

Comments

@zerothi
Copy link

zerothi commented Mar 2, 2023

Using fypp to parse cmake options are really great, but I generally have a problem parsing WITH_* arguments.

I would rather not do:

#:if defined("WITH_OPT")
.. option ON
#:endif

but rather something like:

#:if bool("WITH_OPT")
... option ON
#:endif

I can of course define a function that parses this, but I think this could be very generally useful? The truth/false values could optionally be set by some global FYPP_BOOL_TRUE/FALSE variables?

@zerothi
Copy link
Author

zerothi commented Mar 2, 2023

Along these lines it is difficult for me to expand a variable from a name, can this be achieved (i.e. I tried to implement the bool function).

# I kind of not expected this to work... but...
#:def expand(var)
${var}$
#:enddef

#:def bool(variable, default="True")
#:if defined(variable)
#: stop "Trying to see if I can double expand: {}={}".format(variable, expand(variable))
#: if variable.lower() in ["true", "on", "1", "yes", "y"]
True
#: elif variable.lower() in ["false", "off", "0", "no", "n"] or variable == ''
False
#: else
#: stop "Wrong boolean value: {}={}".format(variable, expand(variable))
#: endif
#:else
${default}
#:endif
#:enddef

I just can't seem to get it working

@zerothi
Copy link
Author

zerothi commented Mar 2, 2023

A small update, the way I am doing it now is:

#:def bool(variable, default="True")
#: if variable.lower() in ["true", "on", "1", "yes", "y"]
#: stop "Returning true == {}".format(variable)
True
#: elif variable.lower() in ["false", "off", "0", "no", "n"] or variable == ''
False
#: stop "Returning false == {}".format(variable)
#: else
#: stop "Wrong boolean value: {}".format(variable)
#: endif
#:enddef


#:if bool(getvar("WITH_OPTION", "True"))
...
#:endif

I would, however, still prefer to be able to loop variable names.

@zerothi
Copy link
Author

zerothi commented Mar 2, 2023

I can now also loop variable names, I encountered some spurious error messages, but finally got my head around it.
I now do something like the below to get variable names from variables and parse them on the fly.

#:def set_constant(name, value=None, default=0)
#:if value == None
$:"#:set {} = {}".format(name, getvar(name, default))
#:else
$:"#:set {} = {}".format(name, value)
#:endif
#:enddef
#!
$:set_constant("FDICT_VERSION", "'{}.{}.{}'".format(PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH))
$:set_constant("FDICT_MAJOR", PROJECT_VERSION_MAJOR)
$:set_constant("FDICT_MINOR", PROJECT_VERSION_MINOR)
$:set_constant("FDICT_PATCH", PROJECT_VERSION_PATCH)
#:for v in ["ISO_C", "ISO_ENV", &
	& "REAL80", "REAL128", &
	& "INT8", "INT16", &
	& "LOG8", "LOG16", "LOG64"]
$:set_constant("WITH_{}".format(v))
#:endfor
$:set_constant("MAXRANK", default=5)
#:for v in ["INT", "REAL", "CMPLX", "LOG", "ISO_C"]
$:set_constant("MAXRANK_{}".format(v))
#:endfor

@aradi
Copy link
Owner

aradi commented Mar 3, 2023

Nice solution. The only problem I see is, that with this approach you first create (by using fypp) a file, which must be processed once more by fypp to turn the CMake values into Python-logicals.

Inspired by your comments above, I could come up with a solution, which turns the CMake values into Python bools within one preprocessing step. It uses the global variable mechanism to manipulate global variables from within a function.

#:def cmake_to_python(var, nonevalue=False)
  #:mute
    #:if not defined(var)
      $:globalvar(var)
      $:setvar(var, False)
    #:else
      $:globalvar(var)
      $:setvar("value", getvar(var))
      #:if value is None
        $:setvar(var, nonevalue)
      #:elif isinstance(value, str)
        $:setvar(var, value.lower() in ["yes", "on", "1", "true", "y"])
      #:else
        $:setvar(var, bool(value))
      #:endif
    #:endif
  #:endmute
#:enddef

#! Testing the cmake_to_python function

#:set DEFINE_SUFFIXES = ["ISO_C", "ISO_ENV", "REAL80", "REAL128", "INT8", "INT16"]
#:set DEFINES = ["WITH_" + suffix for suffix in DEFINE_SUFFIXES]

#:for define in DEFINES
  $:cmake_to_python(define, nonevalue=True)
#:endfor

#:for define in DEFINES
The value of variable "${define}$" is ${getvar(define)}$
#:endfor

#! Note that WITH_* are now well defined variables with Python True/False values
Value of WITH_ISO_C is ${WITH_ISO_C}$

@zerothi
Copy link
Author

zerothi commented Mar 23, 2023

Thanks Balint.
Actually I wanted the two step process.
Details:

  • my project is a library which should be used in other codes
  • different types may have different dimensions as specified above
  • different types may be supported (on/off)

Of course it would be best if projects determine this from the configuration files of the build it-self (i.e. through cmake variables defined in the shipped project details.

However, in some cases you just want to limit your project's capabilities by following the library. In this case you want to ship a fypp settings file that can be used.

Hope this clarifies.

This was my intent. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants