1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
|
# encoding: utf-8
"""
The ``yade.libVersions`` module tracks versions of all libraries it was compiled with. Example usage is as follows::
from yade.libVersions import *
if(getVersion('cgal') > (4,9,0)):
…
else:
…
To obtain a list of all libraries use the function :yref:`yade.libVersions.printAllVersions`.
All libraries listed in :ref:`prerequisites<prerequisites>` are detected by this module.
.. note:: If we need a version of some library not listed in :ref:`prerequisites<prerequisites>`, then it must also be added to :ysrc:`that list<doc/sphinx/installation.rst>`.
When adding a new version please have a look at these three files:
1. :ysrc:`py/_libVersions.cpp`: detection of versions from ``#include`` files by C++.
2. :ysrc:`py/libVersions.py.in`: python module which is constructed by cmake during compilation. All ``*.in`` files are processed by cmake.
3. :ysrc:`cMake/FindMissingVersions.cmake`: forced detection of library with undetectable version.
.. hint:: The safest way to compare versions is to use builtin python tuple comparison e.g. ``if(cgalVer > (4,9,0) and cgalVer < (5,1,1)):``.
"""
# all C++ functions are accessible now:
from yade._libVersions import *
import yade.config
def getArchitecture():
"""
:return: string containing processor architecture name, as reported by ``uname -m`` call or from ``CMAKE_HOST_SYSTEM_PROCESSOR`` cmake variable.
"""
return '${ARCHITECTURE}'
def getLinuxVersion():
"""
:return: string containing linux release and version, preferably the value of ``PRETTY_NAME`` from file ``/etc/os-release``.
"""
ret=""
try:
import os
listDir = os.listdir("/etc")
once = ("os-release" in listDir)
for f in listDir:
if((once and f=="os-release") or ((not once) and f.endswith("elease"))):
with open(os.path.join("/etc", f), 'r') as fin:
lines=""
for line in fin:
if(line.startswith("PRETTY_NAME")):
try:
ret=(line.split('"')[1])
except Exception as e:
ret=(line)
break
lines+=line
if(ret==""): ret=("\n"+lines)
except Exception as e:
print("Error: cannot find file /etc/os-release. Caught exception:",e)
if(ret==""): ret="Unknown"
return ret
def getVersion(libName):
"""
This function returns the tuple ``(major, minor, patchlevel)`` with library version number. The ``yade --test`` in file :ysrc:`py/tests/libVersions.py` tests that this
version is the same as detected by cmake and C++. If only one of those could detect the library version, then this number is used.
:param string libName: the name of the library
:return: tuple in format ``(major, minor, patchlevel)`` if ``libName`` exists. Otherwise it returns ``None``.
.. note:: library openblas has no properly defined version in header files, this function will return ``(0,0,0)`` for openblas. Parsing the version string would be unreliable. The mpi version detected by cmake sometimes is different than version detected by C++, this needs further investigation.
"""
cppVer = getAllVersionsCpp()
cmakeVer = getAllVersionsCmake()
if(libName == 'openblas'):
print("Warning: openblas has no properly defined version in header files, the obtained version is ",cppVer[libName])
if((libName == 'mpi' ) and (cppVer[libName][0] != cmakeVer[libName][0])):
print('\033[91m'+" Warning: mpi versions are different. Can you help with file py/libVersions.py.in?"+'\033[0m')
print("C++ is: " , cppVer[libName], " and cmake is: ",cmakeVer[libName], ", will return the C++ one.")
if((libName in cppVer) and (len(cppVer[libName])==2)):
return cppVer[libName][0]
if((libName in cmakeVer) and (len(cmakeVer[libName])==2)):
return cmakeVer[libName][0]
#raise RuntimeError("Could not find library version of ",libName)
return None
def getAllVersionsCmake():
"""
This function returns library versions as provided by cmake during compilation.
:return: dictionary in following format: ``{ "libName" : [ (major, minor, patchlevel) , "versionString" ] }``
As an example the dict below reflects what libraries this documentation was compiled with (here are only those detected by `CMAKE <https://cmake.org>`_):
.. ipython::
In [1]: from yade.libVersions import *
In [1]: getAllVersionsCmake()
.. note:: Please add here detection of other libraries when yade starts using them or if you discover how to extract from cmake a version which I didn't add here.
"""
ret={}
def addVer(name,v1,v2,v3,ver):
try:
ret.update({ name : [ ( int(v1) , int(v2) , int(v3) ) , ver ]})
except:
pass
# 0.cmake
addVer("cmake",'${CMAKE_MAJOR_VERSION}','${CMAKE_MINOR_VERSION}','${CMAKE_PATCH_VERSION}','${CMAKE_VERSION}')
# 1. compiler
try:
addVer('compiler' ,'${CMAKE_CXX_COMPILER_VERSION}'.split('.')[0],'${CMAKE_CXX_COMPILER_VERSION}'.split('.')[1],'${CMAKE_CXX_COMPILER_VERSION}'.split('.')[2],'${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_VERSION}')
except:
pass
addVer("clang",'${CLANG_VERSION_MAJOR}','${CLANG_VERSION_MINOR}','${CLANG_VERSION_PATCHLEVEL}','${CLANG_VERSION}')
# 2. boost
addVer("boost",'${Boost_MAJOR_VERSION}','${Boost_MINOR_VERSION}','${Boost_SUBMINOR_VERSION}','${Boost_VERSION}')
# 3. qt
addVer("qt" ,'${Used_QT_VERSION_MAJOR}','${Used_QT_VERSION_MINOR}','${Used_QT_VERSION_PATCH}','${Used_QT_VERSION_MAJOR}.${Used_QT_VERSION_MINOR}.${Used_QT_VERSION_PATCH}')
# 4. freeglut
addVer("freeglut" ,'${FREEGLUT_VERSION_MAJOR}','${FREEGLUT_VERSION_MINOR}','${FREEGLUT_VERSION_PATCH}','${FREEGLUT_VERSION_STR}')
try:
glutVerStr='${GLUT_VERSION}'
glutVerNum=glutVerStr.split('.')
addVer("glut", glutVerNum[0] , glutVerNum[1] , glutVerNum[2] , glutVerStr )
except:
pass
# 5. qglviewer - I don't know how to detect it
# 6. python
addVer("python",'${PYTHON_VERSION_MAJOR}','${PYTHON_VERSION_MINOR}','${PYTHON_VERSION_PATCH}','${PYTHON_VERSION_STRING}')
# 7. matplotlib
addVer("matplotlib" ,'${MATPLOTLIB_VERSION_MAJOR}','${MATPLOTLIB_VERSION_MINOR}','${MATPLOTLIB_VERSION_PATCH}', '${MATPLOTLIB_VERSION}')
# 8. eigen
addVer("eigen" ,'${EIGEN3_WORLD_VERSION}','${EIGEN3_MAJOR_VERSION}','${EIGEN3_MINOR_VERSION}','${EIGEN3_VERSION}')
# 9. gdb - I don't know how to detect it
# 10. sqlite3 - I don't know how to detect it
# 11. loki - I don't know how to detect it
# 12. vtk
addVer("vtk" ,'${VTK_MAJOR_VERSION}','${VTK_MINOR_VERSION}','${VTK_BUILD_VERSION}','${VTK_VERSION}')
# 13. cgal
addVer("cgal" ,'${CGAL_MAJOR_VERSION}','${CGAL_MINOR_VERSION}','${CGAL_BUGFIX_VERSION}','${CGAL_VERSION}')
# 14. suitesparse
addVer("suitesparse",'${SUITESPARSE_MAIN_VERSION}','${SUITESPARSE_SUB_VERSION}','${SUITESPARSE_SUBSUB_VERSION}','${SUITESPARSE_VERSION}')
# 15. openblas - I don't know how to detect it
# 16. metis - I don't know how to detect it
# 17. mpi - This one is based on https://cmake.org/cmake/help/v3.10/module/FindMPI.html
addVer("mpi" ,'${MPI_CXX_VERSION_MAJOR}','${MPI_CXX_VERSION_MINOR}','0', '${MPI_CXX_VERSION}')
# 18. numpy
addVer("numpy" ,'${NUMPY_VERSION_MAJOR}','${NUMPY_VERSION_MINOR}','${NUMPY_VERSION_PATCH}', '${NUMPY_VERSION}')
# Note: these below are getting the version currently installed, not the one with which yade was compiled. Maybe this will need to be changed.
# 19. ipython
addVer("ipython" ,'${IPYTHON_VERSION_MAJOR}','${IPYTHON_VERSION_MINOR}','${IPYTHON_VERSION_PATCH}', '${IPYTHON_VERSION}')
# 20. sphinx,
addVer("sphinx" ,'${SPHINX_VERSION_MAJOR}','${SPHINX_VERSION_MINOR}','${SPHINX_VERSION_PATCH}', '${SPHINX_VERSION}')
# 21. clp
# Note: this can be fixed in the same way as forced detection of freeglut, with file cMake/FindMissingVersions.cmake
addVer("clp",'${CLP_WORLD_VERSION}','${CLP_MAJOR_VERSION}','${CLP_MINOR_VERSION}','${CLP_VERSION}')
addVer("coinutils",'${COINUTILS_WORLD_VERSION}','${COINUTILS_MAJOR_VERSION}','${COINUTILS_MINOR_VERSION}','${COINUTILS_VERSION}')
# 22. PyMPI
addVer("mpi4py" ,'${MPI4PY_VERSION_MAJOR}','${MPI4PY_VERSION_MINOR}','${MPI4PY_VERSION_PATCH}', '${MPI4PY_VERSION}')
# 23. MPFR
addVer("mpfr",'${MPFR_MAJOR_VERSION}','${MPFR_MINOR_VERSION}','${MPFR_PATCHLEVEL_VERSION}','${MPFR_VERSION}')
addVer("mpc",'${MPC_MAJOR_VERSION}','${MPC_MINOR_VERSION}','${MPC_PATCHLEVEL_VERSION}','${MPC_VERSION}')
# 24. mpmath
# a simple check of mpmath is a following python command:
# import mpmath ; mpmath.mp.dps=50 ; mpmath.acos(0)
try:
addVer("mpmath",'${MPMATH_VERSION}'.split('.')[0],'${MPMATH_VERSION}'.split('.')[1],'${MPMATH_VERSION}'.split('.')[2],'${MPMATH_VERSION}')
except:
pass
# 25. tkinter
addVer("tkinter" ,'${TKINTER_VERSION_MAJOR}','${TKINTER_VERSION_MINOR}','${TKINTER_VERSION_PATCH}', '${TKINTER_VERSION}')
# 26. pygraphviz
addVer("pygraphviz" ,'${PYGRAPHVIZ_VERSION_MAJOR}','${PYGRAPHVIZ_VERSION_MINOR}','${PYGRAPHVIZ_VERSION_PATCH}', '${PYGRAPHVIZ_VERSION}')
# 27. Xlib
addVer("Xlib" ,'${XLIB_VERSION_MAJOR}','${XLIB_VERSION_MINOR}','${XLIB_VERSION_PATCH}', '${XLIB_VERSION}')
return ret
def printAllVersions(rstFormat=False):
"""
This function prints a nicely formatted table with library versions.
:param bool rstFormat: whether to print table using the reStructuredText formatting. Defaults to ``False`` and prints using `Gitlab markdown rules <https://gitlab.com/help/user/markdown>`_ so that it is easy to paste into gitlab discussions.
As an example the table below actually reflects with what libraries this documentation was compiled:
.. ipython::
In [1]: printAllVersions()
.. note:: For convenience at startup ``from yade.libVersions import printAllVersions`` is executed, so that this function is readily accessible.
"""
# there will be three columns: library , cmake , C++
headers = ["library","cmake","C++"]
longest = [None,None,None]
cmakeVer = getAllVersionsCmake()
cppVer = getAllVersionsCpp()
namesSet = set()
for i in range(3): longest[i] = len(headers[i])
for key,val in cmakeVer.items():
longest[0] = max(longest[0],len(key))
if(len(val)==2):
namesSet.add(key)
longest[1] = max(longest[1],len(val[1]))
for key,val in cppVer.items():
longest[0] = max(longest[0],len(key))
if(len(val)==2):
namesSet.add(key)
longest[2] = max(longest[2],len(val[1]))
for i in range(3): longest[i]+=2
sep = '| '+'-'*longest[0]+' | '+'-'*longest[1]+' | '+'-'*longest[2]+' |\n'
lines="|"
if(rstFormat):
sep = '+-'+'-'*longest[0]+'-+-'+'-'*longest[1]+'-+-'+'-'*longest[2]+'-+'
lines = sep+'\n|'
# nice python formatting guide: https://pyformat.info/
for i in range(3):
lines +=" "+(('{:'+str(longest[i])+'}').format(headers[i]))+" |"
lines+='\n'
if(rstFormat):
lines += sep.replace('-','=')+'\n'
else:
lines += sep
for libName in sorted(namesSet):
lines+="| "+(('{:'+str(longest[0])+'}').format(libName))+" |"
if (libName in cmakeVer) and (len(cmakeVer[libName])==2):
lines+=" "+(('{:'+str(longest[1])+'}').format(cmakeVer[libName][1]))+" |"
else:
lines+=" "+(('{:'+str(longest[1])+'}').format(' ' ))+" |"
if (libName in cppVer) and (len(cppVer[libName])==2):
lines+=" "+(('{:'+str(longest[2])+'}').format(cppVer[libName][1] ))+" |"
else:
lines+=" "+(('{:'+str(longest[2])+'}').format(' ' ))+" |"
lines+='\n'
if(rstFormat):
lines+= sep+'\n'
if(rstFormat==False): print("\n```")
#print("Yade revision : ",yade.config.revision)
print("Yade version : ",yade.config.version)
#print("Yade prefix : ",yade.config.prefix)
#print("Yade suffix : ",yade.config.suffix)
feats = ""
for f in yade.config.features: feats+=" "+f
print("Yade features :",feats)
# print yade config dir relative to ${HOME}
confD = yade.config.confDir
try:
import os
confD = "~/"+os.path.relpath(yade.config.confDir,os.environ['HOME'])
except Exception as e:
pass
print("Yade config dir: ",confD)
print("Yade precision : "+str(yade.math.getDigits2(1))+" bits, "+str(yade.math.getDigits10(1))+" decimal places, with"+("" if yade.config.highPrecisionMpmath else "out")+" mpmath, "+yade.config.highPrecisionName)
if(len(yade.math.getRealHPCppDigits10()) > 1):
print("Yade RealHP<…> : "+str(yade.math.getRealHPCppDigits10())+" decimal digits in C++, "+str(yade.math.getRealHPPythonDigits10())+" decimal digits accessible from python")
if(rstFormat==False): print("```")
print("\nLibraries used :\n")
print(lines)
if(rstFormat==False): print("```")
print("Linux version : "+str(getLinuxVersion()))
print("Architecture : "+str(getArchitecture()))
try:
print("Little endian : "+str(yade.math.isThisSystemLittleEndian()))
except Exception as e:
print("Little endian : unknown")
if(rstFormat==False): print("```")
print("")
def getAllVersions(rstFormat=False):
"""
:return: ``str`` - this function returns the result of :yref:`printAllVersions(rstFormat)<yade.libVersions.printAllVersions>` call inside a string variable.
"""
import sys,io
origStdOut = sys.stdout
newStdOut = io.StringIO()
sys.stdout = newStdOut
printAllVersions(rstFormat)
sys.stdout = origStdOut
return newStdOut.getvalue()
"""
GITLAB format:
| header 1 | header 2 |
| -------- | -------- |
| cell 1 | cell 2 |
| cell 3 | cell 4 |
reStructuredText format:
+----------+----------+
| header 1 | header 2 |
+==========+==========+
| cell 1 | cell 2 |
+----------+----------+
| cell 3 | cell 4 |
+----------+----------+
"""
|