This page is an attempt to create a Rocky Linux 10 for 32bit i686/i586.
Note: This is just a technical challenge. It is insanely impractical to deploy Rocky Linux/AlmaLinux/CentOS Stream 10 on sub-GHz CPUs in any way.
It works fairly well on Pentium M 1.8GHz. KDE Plasma 6 is somewhat sluggish, but works.
Some figures deployed on Pentium 120MHz:
$Keywords: Rocky Linux 10, AlmaLinux 10, CentOS Linux 10, 32bit, el10.i686, el10.i586, installation media respin, anaconda, Pentium, CMOV emulation, SSE emulation, SSE2 emulation, QtWebEngine without SSE $
$Id: i686.html,v 1.13 2026-06-19 08:47:16+09 kabe Exp kabe $ (2026/06)
You need enough memory to fit the
unexpanded (115MB) and expanded (~202MB) initrd of
anaconda installer,
plus kernel itself (29MB uncompressed), plus the work memory.
640MB was not enough.
anaconda installer is written in Python, which
inherently hogs a lot of memory.
BTW x86_64 needs at least 1280MB of memory to invoke the installer. 8 byte pointers do take much memory.
X.org support was dropped in RHEL 10.
Xorg bundled on this site is a recompile of it in Fedora 43.
Non-DRM videocard (such as S3 Virge)
is unfortunately out of scope.
You could still install with Remote Desktop mode
by giving inst.graphical inst.rdp kernel option.
You could then additionally install Xorg
for legacy hardware.
Compiling for .i586.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
mount -a to mount them all.
The goal is to prepare enough 32bit packages into /chroot/i686/
to run rpmbuild(8).
Drop-in ix86-vega.repo as /chroot/i686/etc/yum.repos.d/ix86-vega.repo .
base$ sudo mkdir -p /chroot/i686/etc/yum.repos.d/ base$ sudo cp ix86-vega.repo /chroot/i686/etc/yum.repos.d/ix86-vega.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=10 \
--disablerepo=\* \
--enablerepo=ix86repo\* \
--verbose install rpm-build sudo
Pull in other packages needed for rpmbuild:
base$ sudo setarch i386 \
dnf --installroot=/chroot/i686 --releasever=10 \
--disablerepo=\* \
--enablerepo=ix86repo\* \
--verbose install dnf gcc make vi util-linux
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 rocky10.five.ten 6.12.0-124.52.1.el10_1.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Apr 23 13:41:41 UTC 2026 x86_64 GNU/Linux base$ sudo setarch i686 chroot /chroot/i686 su - $LOGNAME i686$ uname -a Linux rocky10.five.ten 6.12.0-124.52.1.el10_1.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Apr 23 13:41:41 UTC 2026 i686 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,
mkdir a dedicated directory for the package compile.
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 ~/r10builds/coreutils-r10/ for coreutils package build.
base$ sudo setarch i686 chroot /chroot/i686 su - $LOGNAME user@i686$ cd user@i686$ mkdir -p r10builds/coreutils-r10 user@i686$ cd r10builds/coreutils-r10 user@i686$ pwd /home/user/r10builds/coreutils-r10
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=.el10
binary:
uname -a > log
CPPFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -fcf-protection=none" \
./rpmbuild --target=i586 -v -bb --noclean \
-D 'dist $(DIST)' \
SPECS/$(PKG).spec 2>&1 | \
while IFS="" read line; do echo `date '+%Y-%m-%d %T'` "$$line"; done | \
tee -a log
src:
./rpmbuild --target=i586 -v -bs --noclean \
-D 'dist $(DIST)' \
SPECS/$(PKG).spec
EOF
fi
This 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 download site.
For example, source RPM for coreutils package is at
https://ftp.iij.ad.jp/pub/linux/rocky/10.1/BaseOS/source/tree/Packages/c/coreutils-9.5-6.el10.src.rpm
.
Download it:
user@i686$ curl -R -O https://ftp.iij.ad.jp/pub/linux/rocky/10.1/BaseOS/source/tree/Packages/c/coreutils-9.5-6.el10.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-9.5-6.el10.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.
Change the DIST=.el10 part according to the package.
DIST=.el10 to the package suffix.
Some packages have .el10_1 suffix.
For example binutils-2.41-58.el10_1.2.src.rpm has .el10_1 .
rpmbuild to build the binary RPMYou have made a Makefile, so invoke
[kabe@i686 coreutils-r10]$ make uname -a > log LANG=C.utf-8 \ CPPFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -fcf-protection=none" \ ./rpmbuild --target=i586 -v -bb --noclean \ -D 'dist .el10' \ SPECS/coreutils.spec 2>&1 | \ while IFS="" read line; do echo `date '+%Y-%m-%d %T'` "$line"; done | \ tee -a log 2026-05-25 12:30:09 Building target platforms: i586 2026-05-25 12:30:09 Building for target i586 2026-05-25 12:30:09 setting SOURCE_DATE_EPOCH=1732579200 2026-05-25 12:30:09 error: Failed build dependencies: 2026-05-25 12:30:09 acl is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 autoconf is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 automake is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 gdb is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 gettext-devel is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 glibc-langpack-en is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 glibc-langpack-fr is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 glibc-langpack-ko is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 glibc-langpack-sv is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 gmp-devel is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 gnupg2 is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 hostname is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 libacl-devel is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 libattr-devel is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 libcap-devel is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 libselinux-devel is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 libselinux-utils is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 openssl-devel is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 perl(FileHandle) is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 perl-interpreter is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 strace is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 texinfo is needed by coreutils-9.5-6.el10.i586 2026-05-25 12:30:09 valgrind is needed by coreutils-9.5-6.el10.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 aclRepeat recursive build, install and make until binary RPMs are built.
The first package you will compile will begcc, to obtainlibgcc.so. Next will beglibc. Both is already available from this site.
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: 4408415 nopl: 0 fcomi: 0 fucomi: 68 fcmov: 0 sse: 55453 sse2: 1178191 sse3: 10 endbr32: 234098
Patch for emulating SSE2 by kernel Is available. Dig into Source RPMs for latest patches.
Patch for QtWebEngine to avoid SSE2 dependency, is available. Dig into Source RPMs for latest patches. Note that you still need SSE emulation kernel, since V8 JavaScript engine REQUIRES %xmm SSE registers.
From 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 Plasma 6 is provided via EPEL, but since it provides only x86_64 binaries, every KDE 6 components had to be recompiled for 32bit.
Collect .noarch 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 download site.
For KDE Plasma 6 desktop, additional EPEL source packages must be compiled.
Inspect the SPECS/*.spec file.
%build begins with %configure or %mesonJust passing
CPPFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -fcf-protection=none"
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 , or direct %make_buildYou must modify *.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
+
%cmake
and 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 ../r10builds/coreutils-r10/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_cFirst, browse in the Rocky Linux x86_64 binary repository
repodata/ for comps.xml file.
If your favorite mirror is located at
https://download.rockylinux.org/pub/rocky/10.1/BaseOS/x86_64/os/
,
the comps.xml file may be at
https://download.rockylinux.org/pub/rocky/10.1/BaseOS/x86_64/os/repodata/6babe543df2338047594fa6732cdc979774319195f01aaefeff4d99f0ae383f9-comps-BaseOS.x86_64.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.
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
If you are invoking lorax on base x86_64 machine, you must patch lorax, and patch python3-productmd, beforehand.
loraxPrepare a separate directory for boot image assembling. Begin with a pristine directory to store the boot.iso file:
base$ cd base$ mkdir r10lorax base$ cd r10lorax base$ rm -fr ./img10
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 10.1 -r 10.1 \ -s `pwd`/../ix86.repo/BaseOS \ -s `pwd`/../ix86.repo/AppStream \ -s `pwd`/../ix86.repo/CRB \ --add-template `pwd`/add_template.tmpl \ --buildarch=i686 --nomacboot \ `pwd`/img10This takes a about 15 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, ./img10/ will be populated with installer boot files, notably ./img10/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 ./img10 base$ chmod -R +w ./img10
The generated
./img10/images/boot.iso
of about 768MB 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 ./img10/ .
base$ sudo chown -R $LOGNAME ./img10
base$ rm -fr ./img10/Packages ./img10/SPackages ./img10/repodata
base$ rm -fr ./img10/{BaseOS,AppStream,CRB,devel,epel}
base$ cp -rpl ../ix86.repo/{BaseOS,AppStream,CRB,devel,epel} ./img10/
Optionally, if the target machine is slow, append the
kernel boot line with inst.xtimeout=600
(wait for 600 seconds for Wayland to start; default 60 secs)
base$ sed -i -e 's/^\([ ]linux .*\) quiet$/\1 inst.xtimeout=600 inst.disklabel=mbr/' ./img10/boot/grub2/grub.cfg
The ./img10/.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.12/site-packages/productmd/treeinfo.py .
Download productmd-treeinfo.py file, and invoke as:
base$ if [ ! -e ./img10/.treeinfo.lorax ]; then cp -p ./img10/.treeinfo ./img10/.treeinfo.lorax; fi base$ python3 ./productmd-treeinfo.py ./img10/.treeinfo.lorax > ./img10/.treeinfo
Now you can respin the DVD media image.
base$ rsync -avH /usr/lib/grub/i386-pc ./img10/boot/grub2/ base$ xorrisofs -o ./DVD1.iso \ -R -J \ -V "Rocky-Linux-10-1-i386" \ --grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img \ -partition_offset 16 -appended_part_as_gpt \ -b images/eltorito.img -c images/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ --grub2-boot-info -eltorito-alt-boot \ -v \ -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 \ ./img10 base$ implantisomd5 ./DVD1.iso
The volume label (-V "Rocky-Linux-10-1-i386") should match with kernel option in img10/boot/grub2/grub.cfg ,inst.stage2=hd:LABEL=Rocky-Linux-10-1-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 5.7GB.
Burn the DVD1.iso and try it out on your target machine.
You need to adjust xorrisofs -m [packages-to-exclude]
to fit them onto 4.7GB DVD-RW.
From RHEL 10, Xorg is deprecated and Wayland is the default graphics engine. If your target machine does not properly support Wayland, that is, when booting by the media results in
inst.graphical inst.rdp
to the kernel options.
When the anaconda installer starts, it will prompt you for
RDP username and password of a choice.
This means you need a wired network card installed on the target machine; anaconda installer is not aware of a wireless network.