Building tensorflow 2.2.0 pip wheel file, for use in CentOS system (older libc) - docker

Introduction:
I have to create a pip wheel of Tensorflow 2.2.0 with cuda libraries dynamically linked(specifically cudart.so). To accomplish this i am currently using the tensorflow-dev docker image.
I am able to build the tf wheel file, an able to install and use it while inside the build container.
Issue:
The issue is that importing the generated wheel file in a CentOS server, i get the following error:
ImportError: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /home1/private/mavridis/Vineyard/tensorflowshared/test/lib64/python3.6/site-packages/tensorflow/python/_pywrap_tensorflow_internal.so)
Having looked around, the issue is caused by the build container using a newer libc:
ldd --version
ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27
Compared to CentOS older version:
ldd --version
ldd (GNU libc) 2.17
Expected behavior:
Having already tried the 'vanilla' tenorflow 2.2.0 version with no issues, installed using pip:
pip install tensorflow==2.2.0
I expected my own build to also work.
So i assume there is some configuration option or docker configuration to allow me to use the docker built wheel file, in a CentOS setup, just like the pip installed version. As this wheel file is intended to be deployed to setups beyond my control, solutions involving alternate OSes and/or libc replacement are not applicable.
Build configuration:
During build i use the following configuration/ command line:
export TF_NEED_CUDA=1
export TF_USE_XLA=0
export TF_SET_ANDROID_WORKSPACE=0
export TF_NEED_OPENCL_SYCL=0
export TF_NEED_ROCM=0
bazel build --config=opt --config=cuda --output_filter=DONT_MATCH_ANYTHING --linkopt=-L/usr/local/cuda/lib64 --linkopt=-lcudart --linkopt=-static-libstdc++ //tensorflow/tools/pip_package:build_pip_package
Regarding options used:
--output_filter=DONT_MATCH_ANYTHING : Silence warnings
--linkopt=-L/usr/local/cuda/lib64 --linkopt=-lcudart : Dynamic linking of cudart.so
--linkopt=-static-libstdc++ : Static link libstc++ as libstc++ also caused the libc error, this however is not possible for libm

I expected my own build to also work.
That expectation is (obviously) incorrect. The symbols your program or library requires from GLIBC depend on exactly which functions you call.
Consider the following program:
int main() { exit(0); }
When compiled/linked on a GLIBC-2.30 system, this program only depends on GLIBC_2.2.5 (because it doesn't call any newer symbols).
Now change the program slightly:
int main() { gettid(); exit(0); }
Compile/link it again, and all of a sudden this program now requires GLIBC_2.30 (because that's where gettid() was added to GLIBC), and will not work on any system which has older GLIBC.
So i assume there is some configuration option or docker configuration
Sure: your Docker image must have GLIBC that is not newer than what your target system have, i.e. GLIBC-2.17. Your current image contains GLIBC-2.27 (or newer).
You need a different Docker image, and you'll likely have to build it yourself, since GLIBC-2.17 is over 7 years old, and predates TensorFlow by many years.
Update:
What i don't understand is how come the pip tensorflow package (which i assumed was build with the docker image i am using) works with CentOS?
It works by accident, just like my first program would work on CentOS, but the second one wouldn't.
In short i wanted to generate a pip package that would work on 'any' linux/libc version
That is an impossible goal: Linux predates GLIBC, and it is impossible to build a single package that will work on a Linux distribution which didn't include GLIBC and on a distribution that did.
You have to draw a line somewhere. The developers of tensorflow-dev docker image drew a line at GLIBC-2.27. Packages built on this image should work on any system with 2.27 or later, and might (but are not at all guaranteed to) work on older systems.
just like the pip installed version.
You claim that the pip installed version has no "only GLIBC-xx or later" requirement, but that is not true. I am 99.9% sure that it requires at least GLIBC-2.14.
To find which GLIBC versions that package requires, run this command:
readelf -WV _pywrap_tensorflow_internal.so | grep GLIBC_
I assumed, the pip installed version was built using the publicly available tensorflow-devel docker image.
That is quite likely. And like I said, it happens to work on CentOS, but minute changes may make it not work anymore.
Update 2:
So running the readelf command as you suggested, does show the most recent required versions to be: - pip version: GLIBC_2.12 - mine : GLIBC_2.27 So from what i understand the pip version uses an older version even from CentOS, which explains why it works.
It doesn't "use" older version, it uses whatever version is available.
It requires a minimum version 2.12, while your build requires a minimum version 2.27.
How do they achieve this? Do they use a different image that has an older libc? If so, where can i get it? Or do they use the public image, but build with some bazel flag, that 'limits' symbols to the ones contained up to libc 2.12?
You are still not getting it.
The version that your program requires depends on exactly which functions you call. In my example program, if I only call exit, my program requires vesion 2.2.5, but if I also call gettid, then my program requires version 2.30. Note: these two programs are built on the same system with the same flags.
So no: they (most likely) didn't use a different Docker image, and didn't use "magic" bazel flags. They just happened to not call any functions which require GLIBC version > 2.12, and you did.
P.S. You can find which symbol(s) are causing "bad" dependency in your build like so:
readelf -Ws _pywrap_tensorflow_internal.so | egrep 'GLIBC_2.2[0-9]'
readelf -Ws _pywrap_tensorflow_internal.so | egrep 'GLIBC_2.1[89]'
This would produce output similar to (using my second program):
readelf -Ws a.out | egrep 'GLIBC_2.[23][0-9]'
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gettid#GLIBC_2.30 (2)
48: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gettid##GLIBC_2.30
The output above shows that the only symbol my binary requires from GLIBC 2.20 or above is gettid.

To make a counter point to what Employed Russian wrote:
The version that your program requires depends on exactly which functions you call. In my example program, if I only call exit, my program requires vesion 2.2.5, but if I also call gettid, then my program requires version 2.30. Note: these two programs are built on the same system with the same flags.
I don't think that's quite accurate. My understanding, which is corroborated by https://github.com/wheybags/glibc_version_header, is that things work like so (quoting that project, emphasis mine):
Glibc uses something called symbol versioning. This means that when you use e.g., malloc in your program, the symbol the linker will actually link against is malloc#GLIBC_YOUR_INSTALLED_VERSION (actually, it will link to malloc from the most recent version of glibc that changed the implementaton of malloc, but you get the idea).
So my guess (I have not checked) would be that the Tensorflow releases are built against an older glibc (perhaps by way of being built on an older release of their target Linux distro).

Related

octave: add gdal support for mapping package

I am trying to run some old matlab code with octave. Unfortunately this code contains a geotiffread function and I think I should change this function with rasterread (package mapping).
However, when I try to install the mapping package I get this warning:
octave:7> pkg install mapping-1.4.0.tar.gz
configure: WARNING: GDAL library not found. Reading of raster files will be disabled.
For information about changes from previous versions of the mapping package, run 'news mapping'.
I tried to run octave (5.2.0 version) within:
a Debian Buster distribution (snap and flatpak package)
a docker container (MacOS 10.15 host, installed from the mtmiller/octave image).
online with the octave-online service, running this code:
pkg load mapping;
[bands, info] = rasterread ('mexutm250.tiff');
With this output:
octave:3> source("my_script.m")
error: gdalread: reading of raster file with GDAL was disabled during installation
error: called from
rasterread at line 56 column 26
my_script at line 2 column 15
No attempt was successful.
EDIT 2: I know that my octave installations are without GDAL support. I would like to use octave with full mapping package, and GDAL support, without recompile it. There is a way to do it (e.g. update a library path within the docker installation to add the libgdal library)?
If there is no way to add GDAL support without recompile octave, there is a guide to do it with minimal effort?
EDIT 3: I already installed the gdal dependencies:
$ sudo aptitude search gdal |grep ^i
[sudo] password for virtuser:
i gdal-bin - Geospatial Data Abstraction Library - programmi di utilità
i A gdal-data - libreria Geospatial Data Abstraction Library - file di dati
i libgdal-dev - libreria Geospatial Data Abstraction Library - file di sviluppo
i libgdal20 - libreria Geospatial Data Abstraction Library
Thank you.
I got octave with GDAL integration when I installed the octave package from the debian repository. I needed octave 5.2, so I switched to Ubuntu 20.04.
as suggested in one of the comments, checking
>> news mapping
(also at https://octave.sourceforge.io/mapping/NEWS.html)
looking at mapping 1.2.1 where rasterread was introduced, it states:
** New features
Reading GIS raster data: A first go is provided using
functions rasterread.m and rasterinfo.m. Both invoke binary
function gdalread() of which an initial version was provided
by Shashank Khare. rasterread.m and rasterinfo.m can read
and return info on any raster data type that the underlying
GDAL library can read. As such, separate functions for e.g.,
GeoTIFF and ArcGrid etc. are not required.
To make use of these functions the GDAL library must be
present on your system => GDAL is a suggested dependency.
You should be able to install the GDAL library in Debian using your preferred installation method.
Unsure whether or not you'll need to uninstall/reinstall the mapping package afterward, but if an unload/reload doesn't get rid of the message, try that and see if mapping is able to see the library.

Build dkms module for specific kernel versions only

How do you define dkms.conf such that a DKMS module will only be built for specific kernel version or range of versions?
Background:
A buggy driver is present in the the current kernels we are using (eg 4.4) but fixed in 4.10. I produced as dkms package with the 4.10 source code in it, which all works fine on kernel 4.4. But as we update to later OS releases (or HWE releases) with later kernel releases - eg 4.15 - I want to avoid rebuilding the (now possibly older) 4.10 kernel driver when the kernel version is 4.10 or higher.
Here's my base dkms.conf file
PACKAGE_NAME="cp210x"
PACKAGE_VERSION="#MODULE_VERSION#"
BUILT_MODULE_NAME[0]="$PACKAGE_NAME"
DEST_MODULE_LOCATION[0]="/updates/dkms"
AUTOINSTALL="YES"
REMAKE_INITRD="YES"
I tried BUILD_EXCLUSIVE_KERNEL matching to 4.N kernel versions
BUILD_EXCLUSIVE_KERNEL="^4\.[0-9]\.*"
Expected behaviour - will not install the kernel module for kernel 4.15.0-43-generic. Actual behaviour - installs as normal
My reading suggests an alternate might work (for this test I'm just matching my current kernel version) to change the compile rule to be a no-op.
MAKE_MATCH[1]="^4\.15\.*"
MAKE[1]=":"
I'm on Debian/Ubuntu platforms if that makes any difference.
Ok - the problem was between keyboard and chair - my BUILD_EXCLUSIVE_KERNEL regexp had an error in it - the .* suffix got mixed with the \. number separator. But I'll document a working example here since google didn't find any good examples before I posted here:
Firstly I wasn't sure what regexp dialect I needed to be using (grep, pcre, etc,..) especially since there is shell escaping mixed in, so thought perhaps the mismatch was there.
Turns out dkms is a bash script and so uses [[ $ver =~ $match_regexp ]]. So to test the matching this worked:
re="^(3\.[0-9]+\.|4\.[0-9]\.)" ; [[ "4.15.0-43-generic" =~ $re ]] && echo true
# but this didn't
[[ "4.15.0-43-generic" =~ "^(3\.[0-9]+\.|4\.[0-9]\.)" ]] && echo true
Here's the config file I ended up using:
PACKAGE_NAME="cp210x"
PACKAGE_VERSION="#MODULE_VERSION#"
BUILT_MODULE_NAME[0]="$PACKAGE_NAME"
DEST_MODULE_LOCATION[0]="/updates/dkms"
AUTOINSTALL="YES"
REMAKE_INITRD="YES"
# Since this code comes from 4.10 only update kernels 4.9 and earlier
BUILD_EXCLUSIVE_KERNEL="^(3\.[0-9]+\.|4\.[0-9]\.)"
Which looks like this when installed via dpkg.
First Installation: checking all kernels...
Building only for 4.15.0-43-generic
Building initial module for 4.15.0-43-generic
Error! The dkms.conf for this module includes a BUILD_EXCLUSIVE directive which
does not match this kernel/arch. This indicates that it should not be built.
Skipped.
But installs correctly against lower kernel versions.
Additionally the wording of the BUILD_EXCLUSIVE_KERNEL documentation suggests it is an error if the kernel mismatches which might not be desirable, however if you check the output above you'll see that the "Error" does not cause a package installation failure, just marked as skipped.

How to compile PyPy for OpenWrt?

I'm trying to compile PyPy for use on an OpenWrt configuration, but I am having a really hard time doing it.
My main problems are:
Each time I change the Makefile I am forced to start the translating process of PyPy again. Is there a way to avoid this?
Would copying just the compiled pypy-c and lib*.so binaries do it, or would I have to copy everything from the compiled files of PyPy?
Here is the directory structure after running make on the files.
How do I specify the version of GCC to use? I've tried to do this without success.
How would I get the interpreter to run after installing it on OpenWrt?
One can also compile PyPy using PyPy itself, which gives a .tar file with a different structure (no Makefile, pypy executable etc). Can I use that instead of building it from the source?
Here is my Makefile.
include $(TOPDIR)/rules.mk
PKG_NAME:=PyPy
PKG_VERSION:=5.8.0
PKG_RELEASE:=1
PKG_MD5SUM:=504c2d522595baf8775ae1045a217a2b120732537861d31b889d47c340b58bd5
PKG_SOURCE_NAME:=pypy2
PKG_SOURCE_URL:=https://bitbucket.org/pypy/pypy/downloads/
PKG_SOURCE:=$(PKG_SOURCE_NAME)-v$(PKG_VERSION)-src.tar.bz2
PKG_BUILD_DEPENDS:=python
PKG_CAT:=bzcat
PKG_BUILD_DIR:=$(BUILD_DIR)/$(BUILD_VARIANT)$(PKG_SOURCE_NAME)-v$(PKG_VERSION)-src
include $(INCLUDE_DIR)/package.mk
$(call include_mk, python-package.mk)
define Package/PyPy
SECTION:=utils
CATEGORY:=Utilities
TITLE:=PyPy
URL:=https://pypy.org/index.html
DEPENDS:=+libffi +libexpat +libunwind
endef
define Package/PyPy/description
PyPy is an alternate implementation of the Python programming language written in Python.
This distribution is for Linux architecture, using Python 2.
endef
define Package/PyPy/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/pypy-c $(1)/usr/bin
$(CP) (PKG_BUILD_DIR)/*.so $(1)/usr/lib
$(INSTALL_BIN) $(PKG_BUILD_DIR)/pypy/bin/* $(1)/usr/bin
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)
endef
$(eval $(call BuildPackage,PyPy))
I would need to see the entire process: the part of the Makefile above, the other pieces such as rules.mk, package.mk, command line arguments and environmental variables in order to understand what is not working
The Makefile in question is not supported, the developers do not use it, and as you discovered it does not work well. As described in the build page, building PyPy from source is a four part process, and the Makefile mashes three of those stages together so any changes currently require restarting from 0. Note that the underlying build process uses PYPY_USESSION_DIR, PYPY_USESSION_BASENAME, and a numbering system to ensure that each time the first stage (translation from RPython to C) puts the results in a new, clean directory. For this reason if you restart the process you will lose your previous work.
Python is both a binary interpreter and a stdlib of "battery included" modules. If you wish to use the binary interpreter, you need to install the binary and the stdlib support files together since they work as a unit. That is why we specify a fourth step in the build page, packaging. Please read that section carefully for methods of using the interpreter+stdlib
PyPy does not really support cross compiling, one method that used to work is described in the documentation of RPython. PyPy does support native gcc and/or clang. What compiler are you trying to use on what hardware?
Run the interpreter as you would any python interpreter; specify the path to the executable file, which (as stated above) needs to know how to find the support files such as the stdlib and the site-packages directory of third-party modules installed specifically for PyPy.
Using PyPy to build PyPy should be no different than using CPython to build PyPy, except it will be much faster. The differences you see must be an artifact of how you are building.
I would recommend you NOT use the unsupported Makefile until you understand the build, compile, package, install process, and then once you have a working installation help the PyPy project improve the process until it can be automated into a Makefile
If you are running OpenWRT on supported hardware and operating system, you would be much happier using a binary distribution and not compiling from source. In this case your Makefile should download a binary distribution and simply install it.
If you are using a different CPU, chances are PyPy will not work out-of-the-box on your hardware, you will have to run tests to make sure the JIT will actually make things faster.

How to change the version of python that pyscripter uses

I am a newb with python and just learning what to do.
I am using pyscripter and have been for a while whilst learning.
I am now going through an online course which is taught in 2.6, yet my pyscripter uses the latest.
I need to know how to change it to use an older version, I have seen replies about changing the PATH variable but not where it is or how to do it.
I have 3 versions of python on my machine, 25,26 and 33.
I don't know if this is the best way to do it, but those are the two ways I did it:
WAY 1 (The best of two)
Go to PyScripter>>Tools>>Options...>>Custom Parameters... and add the following values
1. PythonDir = C:\Program Files\CustomPythonInstallation
2. PythonExe = C:\Program Files\CustomPythonInstallation\python.exe
3. PythonVer = 3.3.3
Note: Adapt the Name = Value pairs above to your case.
And close the window with OK button.
Now select PyScripter>>Run>>Python Engine>>Remote and your are ready to go.
WAY 2 (The more temporary solution)
Go to PyScripter>>Run>>Configure External Run...
set the "Application:" field to your python.exe file
Close the window with OK button.
Make sure you run your scripts with PyScripter>>Run>>External Run (Alt+F9)
I hope this helped, good luck.
The easiest way I know (on Windows) is, having used the installer executable, I select from the Start menu's PyScripter folder whichever version of Python I want to run.
You can modify the PYTHONPATH (under Pyscripter>>Tools, for instance)
You can modify your External Python Interpreter with Pyscripter>>Modify Tools>>Python &Interpreter>>Modify
You can modify the default Python engine used with Pyscripter>>Options>>IDE Options>>Python Interpreter>>Python Engine Type
You can simply redirect Pyscripter to see the environment of a different Python distribution.
In Windows, do this by assigning PYTHONDLLPATH in the Pyscripter shortcut. You can r-click on the shortcut, access its properties and then set the target to:
[Pyscripter executable dir] --PYTHONDLLPATH [Python distribution dir]
See this image to help you out:
setting a shortcut target
For example, in my Win10 64-bit computer I have a Python 2.7.8 installation back from when I installed ArcGIS, which is automatically recognized by my 32-bit Pyscripter installation.
In the same computer, I also have Anaconda installed with two environments that feature two 64-bit Python distributions:
2.7.14 in "C:\ProgramData\Anaconda2"
3.6 in "C:\Users\bouzi\AppData\Local\conda\conda\envs\py3"
When I installed a 64-bit version of Pyscripter, that Pyscripter version couldn't even open, as it couldn't find the conda distributions. I had to point them to it by replacing the shortcut target to:
"C:\Program Files\PyScripterx64\PyScripter.exe" --PYTHONDLLPATH "C:\ProgramData\Anaconda2"
You can create three Pyscripter shortcuts that point to these different installations of Python within your system. It's probably not the optimal way to deal with this but it works, and allows you to combine Anaconda environments with Pyscripter.
You can also read more on opening non-standard python distributions with PyScripter from this link.
Run->Python Versions -> setup Python Versions -> Add... select folder
p.s.
python 3.7.3 - ok,
still python 3.10.5 could not be identified by PyScripter in such a way (actually works with WAY_1 Solution in this thread but pip install under such env. not succeed afterwards)

what is the standard ada include path

Im using gnat4.6 on Ubuntu installed using apt-get. I need to know where to install downloaded libraries like APQ. What should I set my ADA_INCLUDE_PATH and ADA_OBJECTS_PATH to?
The beauty of Ada support in Debian (on which Ubuntu is based) is that you don't need to mess with ADA_INCLUDE_PATH and friends; supported libraries are installed where the GNAT Project Manager expects to find them. Say gnatls -v to see the default values.
To use the system as intended, you will find it much simpler to use the GNAT Project Manager; you'd say, in your my_project.gpr file,
with "apq";
project My_Project is
...
and build with
$ gnatmake -P my_project
There's online documentation for GPR, but I wouldn't call it particularly user-friendly. There's a set of Youtube videos (I haven't looked at them in any detail; their stated interest is large systems, but hang in there).
I use gnatmake to build; how do I cite my build paths in a correct way?
The relevant options are shown in 6.2 Switches for gnatmake: Source and library search path switches.
Addendum: The development package is libapq3.2.0-dev.
The manual is in /usr/share/doc/libapq3.2.0-dev/manual.pdf.gz
An example and corresponding .gpr file are in /usr/share/doc/libapq3.2.0-dev/examples. As #Simon suggested, the .gpr file begins:
with "apq.gpr";
project APQ.Samples is
The Ada include files are in /usr/share/ada/adainclude/apq.
The libraries are in /usr/lib.
$ dpkg -L libapq3.2.0-dev
/.
/usr
/usr/share
/usr/share/ada
/usr/share/ada/adainclude
/usr/share/ada/adainclude/apq
/usr/share/ada/adainclude/apq/apq_helper.ads
/usr/share/ada/adainclude/apq/apq_helper.adb
/usr/share/ada/adainclude/apq/apq.adb
/usr/share/ada/adainclude/apq/apq.ads
/usr/share/ada/adainclude/apq.gpr
/usr/share/doc
/usr/share/doc/libapq3.2.0-dev
/usr/share/doc/libapq3.2.0-dev/copyright
/usr/share/doc/libapq3.2.0-dev/manual.pdf.gz
/usr/share/doc/libapq3.2.0-dev/examples
/usr/share/doc/libapq3.2.0-dev/examples/apq-samples.adb
/usr/share/doc/libapq3.2.0-dev/examples/apq-samples.ads
/usr/share/doc/libapq3.2.0-dev/examples/apq-samples.gpr
/usr/lib
/usr/lib/libapq.a
/usr/lib/ada
/usr/lib/ada/adalib
/usr/lib/ada/adalib/apq
/usr/lib/ada/adalib/apq/apq_helper.ali
/usr/lib/ada/adalib/apq/apq.ali
/usr/share/doc/libapq3.2.0-dev/changelog.Debian.gz
/usr/lib/libapq.so

Resources