File: libVersions.py.in

package info (click to toggle)
yade 2025.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 33,308 kB
  • sloc: cpp: 93,298; python: 50,409; sh: 577; makefile: 162
file content (312 lines) | stat: -rw-r--r-- 13,320 bytes parent folder | download | duplicates (2)
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   |
+----------+----------+
"""