This page is an attempt to create a Rocky Linux 9 for 32bit i686/i586.
Warning: This doesn't work on MMX-only processors. Processors with MMX but no SSE will execute some SSE instructions as MMX instruction, which lacks #UD exception for emulating it.
Note: This is just a technical challenge. It is insanely impractical to deploy Rocky Linux/AlmaLinux/CentOS Stream 9 on sub-GHz CPUs in any way.
It works fairly well on Pentium M 1.8GHz. KDE 5 is somewhat sluggish, but works.
Some figures deployed on Pentium 120MHz:
$Keywords: Rocky Linux 9, AlmaLinux 9, CentOS Linux 9, 32bit, el9.i686, el9.i586, installation media respin, anaconda, Pentium, CMOV emulation, SSE emulation, SSE2 emulation, QtWebEngine without SSE2 $
Former info for Rocky Linux 9.2 i586 is also archived.
$Id$ (2023/05)
Your CPU has capability of | |||||
cmov
| mmx
| sse
| sse2
| works? | Example CPUs |
---|---|---|---|---|---|
yes | plain Pentium | ||||
mmx | no | Pentium MMX, K6-2, WinChip | |||
cmov | mmx | no | Pentium II, Cyrix MII | ||
cmov | mmx | sse | no | Pentium III, Athlon XP | |
cmov | mmx | sse | sse2 | yes | Pentium M, Pentium 4 |
The reason for all this fuss is that not all binaries are re-compiled. RHEL provided userland .i686 RPMs includes CMOV and SSE2 instructions which needs emulation, but MMX/SSE only processors cannot emulate them properly.
But worth a try on your machine; it seems that when compiling enough packages for installer to work, seems to make SSE/SSE2 codepath away at least for anaconda installer to complete.
You need enough memory to fit the
unexpanded (70MB) and expanded (~220MB) initrd of
anaconda
installer,
plus kernel itself (20MB uncompressed), plus the work memory.
512MB was not enough.
anaconda
installer is written in Python, which
inherently hogs a lot of memory.
Compiled kernel's
/lib/modules/5.14.0-*/bls.conf
"title" label
will be taken from the work machine's /etc/os-release
, so
using the same distribution for work machine and target is recommended.
Compiling for .i686.rpm packages should be done in
setarch i686
'ed chroot environment.
Many packages just doesn't cross-compile properly in x86_64 environment.
On the work machine, make SELinux permissive.
This is a lorax
(1) requirement.
You need a reboot for this.
Build of sed
package fails if SELinux is totally disabled.
Suppose you are prepring a chroot environment in
/chroot/i686/
of the work machine.
After sudo mkdir -p /chroot/i686/,
add the following entries in /etc/fstab :
# /chroot/i686 /proc /chroot/i686/proc none auto,bind 0 0 /dev /chroot/i686/dev none auto,bind 0 0 /dev/pts /chroot/i686/dev/pts none auto,bind 0 0 tmpfs /chroot/i686/dev/shm tmpfs auto,nosuid,nodev 0 0 sysfs /chroot/i686/sys sysfs auto,rw,nosuid,nodev,noexec 0 0 /sys/fs/cgroup /chroot/i686/sys/fs/cgroup none auto,bind 0 0 ## to let systemd build test see a /sys/fs/cgroup/systemd fs_type /sys/fs/cgroup/systemd /chroot/i686/sys/fs/cgroup/systemd none auto,bind 0 0 ## to let systemd build test see /run/systemd/session/<#> /run /chroot/i686/run none auto,bind 0 0 ## to let sed build test see selinux selinuxfs /chroot/i686/sys/fs/selinux selinuxfs auto 0 0 /home /chroot/i686/home none auto,bind 0 0
Do:
base$ sudo mkdir -p /chroot/i686/{proc,dev,sys,run} /chroot/i686/home
Then, manually mount the entries above, or just reboot to mount them all.
The goal is to prepare enough 32bit packages into /chroot/i686/
to run rpmbuild
(8).
Drop-in ix86-r9.repo as /chroot/i686/etc/yum.repos.d/ix86-r9.repo .
base$ sudo mkdir -p /chroot/i686/etc/yum.repos.d/ base$ sudo cp ix86-r9.repo /chroot/i686/etc/yum.repos.d/ix86-r9.repo base$ sudo cp -p /etc/resolv.conf /chroot/i686/etc/ base$ sudo cp -p /etc/passwd /etc/shadow /etc/group /chroot/i686/etc/
Install rpm-build
package and mass dependencies
using dnf --installroot
.
Use precompiled packages provided by this site for bootstrapping.
base$ sudo setarch i686 \ dnf --installroot=/chroot/i686 --releasever=9 \ --disablerepo=\* \ --enablerepo=ix86repo\* \ --verbose install rpm-build sudo
Pull in other packages needed for rpmbuild:
base$ sudo setarch i386 \ dnf --installroot=/chroot/i686 --releasever=9 \ --disablerepo=\* \ --enablerepo=ix86repo\* \ --verbose install dnf gcc make vi
With bash
(1) installed in the chroot,
it should be able to chroot inside.
Check uname -a
to see if it is an i686 environment.
base$ uname -a Linux rocky9.five.ten 5.14.0-168.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Sep 23 11:43:25 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux base$ sudo setarch i686 chroot /chroot/i686 su - $LOGNAME i686$ uname -a Linux rocky9.five.ten 5.14.0-168.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Sep 23 11:43:25 UTC 2022 i686 i686 i386 GNU/Linux i686$This is tedious, so you want to add the following to
~/.bashrc
in the work machine's base x86_64 system:
if [ `uname -m` != i686 ]; then alias i686env="sudo setarch i686 chroot /chroot/i686 su - $LOGNAME" else PS1="[\u@i686 \W]\$ " fi
Now, you would compile the individual packages.
To compile a package,
rpmbuild
to build the binary RPMs.
rpmbuild
will tell you about the missing packages
needed for build.
Build and install the needed dependency, or
invoke dnf to download from this site.
Repeat above until the package compiles.
Since you are mass-building various packages, directly building under ~/rpmbuild/ is not recommended. The example below uses ~/r9builds/coreutils-r9/ for coreutils package build.
base$ sudo setarch i686 chroot /chroot/i686 su - $LOGNAME user@i686$ cd user@i686$ mkdir -p r9builds/coreutils-r9 user@i686$ cd r9builds/coreutils-r9 user@i686$ pwd /home/user/r9builds/coreutils-r9
You would like to run a following mkrpmdir
shellscript
inside the directory:
#!/bin/sh ### mkdir for d in SPECS SOURCES; do mkdir -p $d; done ### ./rpmbin cat > ./rpmbin << 'EOF' #!/bin/sh D=${0%/*} ## bash builtin "pwd" will return virtual path when ## symlink involves in the path. Avoid it. ## Otherwise /usr/lib/rpm/debugedit will be screwed. test x"$D" = x"." && D="`/bin/pwd`" #--target=i586 exec ${0##*/} -D "_topdir $D" "$@" EOF chmod +x ./rpmbin ### symlink ./rpmbuild, ./rpm -> rpmbin for i in rpmbuild rpm; do rm -f ./$i; ln -s rpmbin ./$i; done ### Makefile if [ ! -e ./Makefile ]; then cat > ./Makefile << 'EOF' PKG=$(shell ls SPECS/*.spec | sed -ne 's:SPECS/\(.*\)\.spec$$:\1:p') DIST=.el9 binary: CPPFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64" \ ./rpmbuild --target=i586 -v -bb \ -D 'dist $(DIST)' \ SPECS/$(PKG).spec 2>&1 | \ while IFS="" read line; do echo `date '+%Y-%m-%d %T'` "$$line"; done | \ tee log src: ./rpmbuild --target=i586 -v -bs \ -D 'dist $(DIST)' \ SPECS/$(PKG).spec EOF fiThis script prepares
./rpm
, ./rpmbuild
and
sample ./Makefile
to install/compile the package.
Source RPMs are available under
repo/Source/, or if not, under
Rocky Linux mirror.
For example, source RPM for coreutils
package is at
https://download.rockylinux.org/pub/rocky/9.4/BaseOS/source/tree/Packages/c/coreutils-8.32-35.el9.src.rpm
.
Download it:
user@i686$ curl -R -O https://download.rockylinux.org/pub/rocky/9.4/BaseOS/source/tree/Packages/c/coreutils-8.32-35.el9.src.rpmYou would like to take note what directory the package goes eventually:
user@i686$ echo BaseOS > reponame
"Install" the source rpm in the current directory. You do not need a root privilege for source installation and compile.
user@i686$ ./rpm -ivh coreutils-8.32-34.el9.src.rpmNote that you use
./rpm
. It installs the source RPM
in current directory and populates ./SPECS/ and ./SOURCE/ .
rpmbuild
to build the binary RPMYou will invoke ./rpmbuild
multiple times until it compiles,
so ./Makefile
template is provided by above
mkrpmdir
script.
PKG=$(shell ls SPECS/*.spec | sed -ne 's:SPECS/\(.*\)\.spec$$:\1:p') DIST=.el9 binary: CPPFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64" \ ./rpmbuild --target=i586 -v -bb \ -D 'dist $(DIST)' \ SPECS/$(PKG).spec 2>&1 | \ while IFS="" read line; do echo `date '+%Y-%m-%d %T'` "$$line"; done | \ tee log src: ./rpmbuild --target=i586 -v -bs \ -D 'dist $(DIST)' \ SPECS/$(PKG).specChange the emphasized part according to the package.
DIST=.el9
to the package suffix.
Some packages have .el9_0
, .el9_1
suffix.
For example systemd-250-6.el9_0.src.rpm
has .el9_0
.
rpmbuild
to build the binary RPMYou have made a Makefile, so invoke
[kabe@i686 coreutils-r9]$ make CPPFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64" \ ./rpmbuild --target=i586 -v -bb \ -D 'dist .el9' \ SPECS/coreutils.spec 2>&1 | \ while IFS="" read line; do echo `date '+%Y-%m-%d %T'` "$line"; done | \ tee log 2023-03-29 11:10:18 Building target platforms: i586 2023-03-29 11:10:18 Building for target i586 2023-03-29 11:10:18 setting SOURCE_DATE_EPOCH=1646092800 2023-03-29 11:10:18 error: Failed build dependencies: 2023-03-29 11:10:18 attr is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 autoconf is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 automake is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 gettext-devel is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 glibc-langpack-en is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 glibc-langpack-fr is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 glibc-langpack-ko is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 gmp-devel is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 hostname is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 libacl-devel is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 libattr-devel is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 libcap-devel is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 libselinux-devel is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 libselinux-utils is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 openssl-devel is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 perl(FileHandle) is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 strace is needed by coreutils-8.32-32.el9.i586 2023-03-29 11:10:18 texinfo is needed by coreutils-8.32-32.el9.i586Log will be logged in
./log
file.
You will normally have dependencies like above to resolve
for building packages.
Recursively build and install them, or install from this site:
i686# dnf --disablerepo=\* --enablerepo=ix86repo-\* install autoconfRepeat recursive build, install and make until binary RPMs are built.
Although the not hardest to compile for 32bit, kernel package has the most patches.
rpm
refuses so)
Patched for slower machine deployment.
Refer Source directory for other modified packages.
Note: QtWebEngine (Chromium) is about 20 times heavier than KHTML even after eliminating SSE2. Konqueror provided on this page is patched to use KHTML by default. (EPEL Konqueror defaults to QtWebEngine)
The kernel has CMOV, NOPL, FCOMI, FCMOVcc opcode emulation, and
some SSE2 emulation enough to run compiler-generated
(-mfpmath=sse
)
SSE2 instructions.
This will let .i686 binaries run on i586 CPUs, which lacks
cmov
and sse2
capability.
Note: opcode emulation is very slow in nature. Recompile for .i586 whenever possible.
Counts of emulated opcodes will be available under /proc/emulated_ops
:
$ cat /proc/emulated_ops cmov: 3750123 nopl: 0 fcomi: 0 fucomi: 0 fcmov: 0 sse: 32682918 sse2: 1489899
On RHEL 9, for desktop environment, only GNOME 3 is provided, but on slow machines I strongly recommend KDE. GNOME3 had become too heavyweight for sub-GHz, single-thread processor. KDE 5 is provided via EPEL, but since it provides only x86_64 binaries, every KDE 5 components had to be recompiled for 32bit.
Collect .i686 packages listed in
rocky-packages.txt
from your favorite
Rocky Linux x86_64 repository or mirror.
For downloading,
dnf download --downloadonly --downloaddir=`pwd` package
will download it in the current directory, but timestamp is not preserved.
Recommend downloading by
wget
or curl -R -O
.
Compile source packages listed in compile-packages.txt .
These packages needs to be compiled because either
Use Source RPMs in Source directory if available. If there wasn't, use Source RPMs from Rocky Linux downloads or mirror.
Following packages may not have corresponding source RPM in Rocky Linux mirror. You may have to pick them up from Rocky Linux Koji, Fedora 39 mirror or CentOS Stream buildsystem .
aspell-en
gtest
hidapi
mm-common
ncompress
passt
psutils
python3-mallard-ducktype
rapidjson
spirv-headers
umockdev
unicode-emoji
xorg-x11-font-utils
For KDE 5 desktop, additional EPEL source packages must be compiled.
Inspect the SPECS/*.spec
file.
%build
begins with %configure
Just passing
CPPFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64"
as environment value to rpmbuild
is often enough.
%build
begins with %{qmake_qt5}
./rpmbuild
:
./rpmbuild --target=i586 -v -bb \ -D "_qt5_cflags -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -fcf-protection=none" \ -D "_qt5_cxxflags -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -fcf-protection=none" \ -D 'dist $(DIST)'
%build
begins with %cmake
, %meson
, or direct %make_build
You must fiddle *.spec with CFLAGS
before invocation, as:
+%bcond_with use_time_bits64 ... %build + +%if %{with use_time_bits64} +export CFLAGS="${CFLAGS:-%{build_cflags}} -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64" +export CXXFLAGS="${CXXFLAGS:-%{build_cxxflags}} -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64" +%endif +%ifarch i586 +export CFLAGS="${CFLAGS:-%{build_cflags}} -fcf-protection=none" +export CXXFLAGS="${CXXFLAGS:-%{build_cxxflags}} -fcf-protection=none" +%endif + %mesonand invoke
rpmbuild
with --with use_time_bits64
option.
You need to collect the downloaded/compiled RPMs and
assemble them as a repository,
which lorax
(1) requires.
Prepare another directory for a repository:
user@i686$ cd user@i686$ mkdir ix86.repo user@i686$ cd ix86.repo user@i686$ mkdir -p BaseOS/Packages AppStream/Packages CRB/Packages devel/Packages epel/Packages
Then, collect the downloaded/compiled binary RPMs into the above directories. You don't have to strictly follow the location of the directory as published in Rocky/RHEL; if you are lazy, just cramming everything into BaseOS/Packages/ may work.
user@i686$ find ../r9builds/coreutils-r9/RPMS/ -name '*.rpm' | egrep -v -- '-debuginfo-|-debugsource-' | xargs ln -t BaseOS/PackagesYou would like to take advantage of "reponame" file made earlier for automatic sieving.
createrepo_c
First, browse in the Rocky Linux x86_64 binary repository for comps.xml file. If your favorite mirror is located at https://download.rockylinux.org/pub/rocky/9.4/BaseOS/x86_64/os/ , the comps.xml file may be at https://download.rockylinux.org/pub/rocky/9.4/BaseOS/x86_64/os/repodata/2fa35db0-5c08-498f-b22f-785550ee82cb-GROUPS.xml . Copy it as ./comps-BaseOS.x86_64.xml (for later use).
Then, invoke createrepo_c
against the RPM collection directory:
user@i686$ mkdir -p ./BaseOS/repodata/ user@i686$ cp -p comps-BaseOS.x86_64.xml ./BaseOS/repodata/comps.xml user@i686$ createrepo_c -v --groupfile repodata/comps.xml ./BaseOSDo the same thing against ./AppStream/ , ./CRB/ , ./devel/ and ./epel/ directory.
Since the compiled RPMs are not "modularized", there are no module info in the repository and anaconda installation will fail. Install a repo2module program.
user@i686$ dnf --enablerepo=ix86\* modulemd-toolsAdd module information to the repository:
user@i686$ cd user@i686$ cd ix86.repo user@i686$ repo2module --module-name=BaseOS --module-stream=stable ./BaseOS modules.yaml ## ./modules.yaml will be created. No need to edit for current purpose user@i686$ modifyrepo_c --mdtype=modules modules.yaml BaseOS/repodataDo the same thing against ./AppStream/ and ./CRB/ .
After you had made the repository,
it's the time to use lorax
(1) to assemble the
anaconda installer.
Install lorax
package
from official repository or media.
$ sudo dnf --disablerepo=\* --enablerepo=media\* install lorax
lorax
Prepare a separate directory for boot image assembling. Begin with a pristine directory to store the boot.iso file:
base$ cd base$ mkdir r9lorax base$ cd r9lorax base$ rm -fr ./img9
Download add_template.tmpl file. You need this if the target machine is a slow machine.
Then, invoke the lorax
with some options.
Below assumes that assembled repository resides in
../ix86.repo/ .
base$ LANG=C sudo lorax -p "Rocky Linux" -v 9.4 -r 9.4 \ -s `pwd`/../ix86.repo/BaseOS \ -s `pwd`/../ix86.repo/AppStream \ -s `pwd`/../ix86.repo/CRB \ --installpkgs=systemd-devel \ --add-template `pwd`/add_template.tmpl \ --buildarch=i686 --nomacboot \ `pwd`/img9This takes a about 20 minutes on 3GHz-4thread machine. Logfiles are automatically created as ./lorax.log, ./pylorax.log, ./program.log .
lorax
use a loopback filesystem.
-s repopath
should be absolute path.
As a result, ./img9/ will be populated with installer boot files, notably ./img9/images/boot.iso .
Scratch directories, owned by root, may be lying around in
/var/tmp/lorax/
directory. You can safely delete them.
The created files are owned by root, so you would like to
base$ sudo chown -R $LOGNAME ./img9 base$ chmod -R +w ./img9
The generated
./img9/images/boot.iso
of about 968MB should boot as a network installer.
You would like to try it out on target machine
to see if the anaconda installer would work.
(from RHEL 8.5, even the network installer does not fit on a CD.)
lorax
does not use the native files
of the work machine to build the installer;
it unpacks files from the *.rpm in the
-s path
directory.
Thus the work host doesn't have to be i686; working on x86_64 should be okay.
Copy (hardlink) over your repository contents to ./img9/ .
base$ sudo chown -R $LOGNAME ./img9 base$ rm -fr ./img9/Packages ./img9/SPackages ./img9/repodata base$ rm -fr ./img9/{BaseOS,AppStream,CRB,devel,epel} base$ cp -rpl ../ix86.repo/{BaseOS,AppStream,CRB,devel,epel} ./img9/
Optionally, if the target machine is slow, append the
kernel boot line with inst.xtimeout=600
(wait for 600 seconds for Xorg to start; default 60 secs)
base$ sed -i -e 's/ quiet$/ inst.xtimeout=600&/' ./img9/isolinux/isolinux.cfg
The ./img9/.treeinfo generated by lorax doesn't mention BaseOS/, AppStream/ et al directives. You must recreate it.
You need to install python3-productmd
package beforehand.
If the work host is not Fedora, RHEL or CentOS, you have to
patch
/usr/lib/python3.9/site-packages/productmd/treeinfo.py
.
Download productmd-treeinfo.py file, and invoke as:
base$ if [ ! -e ./img9/.treeinfo.lorax ]; then cp -p ./img9/.treeinfo ./img9/.treeinfo.lorax; fi base$ python3 ./productmd-treeinfo.py ./img9/.treeinfo.lorax > ./img9/.treeinfo
Now you can respin the DVD media image.
base$ xorriso -o ./DVD1.iso \ -b isolinux/isolinux.bin -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -R -T -J \ -v \ -V "Rocky-Linux-9-4-i386" \ -m upgrade.img -m boot.iso \ -m 'texlive-*' \ -m 'mingw*' -m 'gcc-toolset-12-*' -m 'gcc-toolset-13-*' \ -m 'java-11-openjdk-src-*' \ -m 'java-11-openjdk-*-devel-*' \ -m 'java-11-openjdk-*-slowdebug-*' \ -no-pad -iso-level 3 -D --hardlinks -joliet-long \ ./img9 base$ implantisomd5 ./DVD1.iso
The volume label (-V "Rocky-Linux-9-4-i386"
) should match with kernel option in ./img9/isolinux/isolinux.cfg,inst.stage2=hd:LABEL=Rocky-Linux-9-4-i386
.
Excluding boot.iso (~800MB) and texlive-* (~480MB) is for lowering size of the final DVD1.iso .
This will create a DVD1.iso image around 4.6GB. Burn the DVD1.iso and try it out on your target machine.
anaconda
started to depend on
skopeo
(container build environment)
which in turn needs golang
to build.
golang
is NOT Y2038 compliant, as it doesn't use glibc
but calls syscall(2) directly.
Major surgery
is needed on golang.
anaconda
provided on this page has removed
skopeo
dependency;
it seems to install the OS without problems.
systemd
does not
reset the time to
"epoch" (systemd build date)
even the RTC time was set beyond year 2038.
gcc-toolset-13
is needed to compile LLVM-17.