How Update-Alternatives Manages Multiple Versions of Python, Node.js, and other Open Source Packages
After a friend installed Python 3.9 side-by-side with Python 3.6, he asked, “I noticed that the newer version, Python 3.9, became the default on my IBM i system. How did the default version get set?” We explained how IBM used the update-alternatives program to set the default version of Python and other open source software packages.
Update-alternatives helps organize multiple versions of open source packages, whether different versions of the same tool (like Python) or different implementations of the same standard (like a mailer or C compiler). Update-alternatives has long been the standard way to manage parallel versions on Linux systems, and now it’s used on IBM i, too.
Packages that support update-alternatives will use it when adding and removing alternative package versions. When packages are enrolled into the alternatives system (and possibly becomes default), you’ll see messages like these:
1 2 |
update-alternatives: using /QOpenSys/pkgs/bin/python3.9 to provide /QOpenSys/pkgs/bin/python3 (python3) in auto mode update-alternatives: using /QOpenSys/pkgs/bin/python3.9 to provide /QOpenSys/pkgs/bin/python (python) in auto mode |
To list packages that can be managed, run update-alternatives
from a PASE shell and pass the --get-selections
flag:
1 2 3 4 5 6 7 8 |
$ update-alternatives --get-selections libpgtypes auto /QOpenSys/pkgs/lib/postgresql12/lib/libpgtypes.so.3 libpq auto /QOpenSys/pkgs/lib/postgresql12/lib/libpq.so.5 mta auto /QOpenSys/pkgs/bin/msmtp node auto /QOpenSys/pkgs/lib/nodejs12/bin/node postgresql-devel auto /QOpenSys/pkgs/lib/postgresql12/bin/pg_config python auto /QOpenSys/pkgs/bin/python3.9 python3 auto /QOpenSys/pkgs/bin/python3.9 |
To see all available versions of a specific package, or to change the defaults, run update-alternatives
--config
with the package name you’re interested in. The following example retrieves all versions of python:
1 2 3 4 5 6 7 8 9 10 11 |
$ update-alternatives --config python There are 3 choices for the alternative python (providing /QOpenSys/pkgs/bin/python). Selection Path Priority Status ------------------------------------------------------------ * 0 /QOpenSys/pkgs/bin/python3.9 309 auto mode 1 /QOpenSys/pkgs/bin/python2.7 207 manual mode 2 /QOpenSys/pkgs/bin/python3.6 306 manual mode 3 /QOpenSys/pkgs/bin/python3.9 309 manual mode Press to keep the current choice[*], or type selection number: |
Note the values for Priority
; in automatic mode, the package having the highest priority when enrolled becomes the preferred alternative automatically. In the example above, the highest priority is 309, making python3.9 the default version.
Not all packages provide support for update-alternatives; this is usually due to limitations in package management. For packages that aren’t managed through update-alternatives, you can run multiple versions in parallel by installing them in chroot containers.
When you use this for node, how do you get matching versions of npm and pm2?
The npm link gets changed as well:
$ update-alternatives –display node
node – manual mode
link best version is /QOpenSys/pkgs/lib/nodejs18/bin/node
link currently points to /QOpenSys/pkgs/lib/nodejs18/bin/node
link node is /QOpenSys/pkgs/bin/node
slave npm is /QOpenSys/pkgs/bin/npm
slave npx is /QOpenSys/pkgs/bin/npx
/QOpenSys/pkgs/lib/nodejs12/bin/node – priority 12
slave npm: /QOpenSys/pkgs/lib/nodejs12/bin/npm
slave npx: /QOpenSys/pkgs/lib/nodejs12/bin/npx
/QOpenSys/pkgs/lib/nodejs14/bin/node – priority 14
slave npm: /QOpenSys/pkgs/lib/nodejs14/bin/npm
slave npx: /QOpenSys/pkgs/lib/nodejs14/bin/npx
/QOpenSys/pkgs/lib/nodejs16/bin/node – priority 16
slave npm: /QOpenSys/pkgs/lib/nodejs16/bin/npm
slave npx: /QOpenSys/pkgs/lib/nodejs16/bin/npx
/QOpenSys/pkgs/lib/nodejs18/bin/node – priority 18
slave npm: /QOpenSys/pkgs/lib/nodejs18/bin/npm
slave npx: /QOpenSys/pkgs/lib/nodejs18/bin/npx
As for things you install globally, those should be installed in the node version’s directory (i.e. /QOpenSys/pkgs/lib/nodejs18). I don’t recommend installing things globally though, because it can be really confusing to deal with for you and rpm. Best to install in the project’s directory, IMHO.