Source code for yade.libVersions

# 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

[docs] def getArchitecture(): """ :return: string containing processor architecture name, as reported by ``uname -m`` call or from ``CMAKE_HOST_SYSTEM_PROCESSOR`` cmake variable. """ return 'amd64'
[docs] 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
[docs] 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
[docs] 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",'3','28','3','3.28.3') # 1. compiler try: addVer('compiler' ,'13.2.0'.split('.')[0],'13.2.0'.split('.')[1],'13.2.0'.split('.')[2],'/usr/bin/c++ 13.2.0') except: pass addVer("clang",'','','','') # 2. boost addVer("boost",'1','83','0','108300') # 3. qt addVer("qt" ,'','','','..') # 4. freeglut addVer("freeglut" ,'3','0','0','3.0.0') try: glutVerStr='' 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",'3','12','3','3.12.3') # 7. matplotlib addVer("matplotlib" ,'3','6','3', '3.6.3') # 8. eigen addVer("eigen" ,'3','4','0','3.4.0') # 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" ,'9','1','0','9.1.0') # 13. cgal addVer("cgal" ,'','','','') # 14. suitesparse addVer("suitesparse",'7','6','1','7.6.1') # 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" ,'3','1','0', '3.1') # 18. numpy addVer("numpy" ,'1','26','4', '1.26.4') # 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" ,'8','20','0', '8.20.0') # 20. sphinx, addVer("sphinx" ,'7','2','6', '7.2.6') # 21. clp # Note: this can be fixed in the same way as forced detection of freeglut, with file cMake/FindMissingVersions.cmake addVer("clp",'1','17','9','1.17.9') addVer("coinutils",'2','11','4','2.11.4') # 22. PyMPI addVer("mpi4py" ,'3','1','5', '3.1.5') # 23. MPFR addVer("mpfr",'','','','') addVer("mpc",'','','','') # 24. mpmath # a simple check of mpmath is a following python command: # import mpmath ; mpmath.mp.dps=50 ; mpmath.acos(0) try: addVer("mpmath",'1.2.1'.split('.')[0],'1.2.1'.split('.')[1],'1.2.1'.split('.')[2],'1.2.1') except: pass # 25. tkinter addVer("tkinter" ,'8','6','0', '8.6') # 26. pygraphviz addVer("pygraphviz" ,'1','7','0', '1.7') # 27. Xlib addVer("Xlib" ,'0','33','0', '(0,33)') return ret
[docs] 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 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("")
[docs] 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 | +----------+----------+ """