- How to compile a 32-bit binary on a 64-bit linux machine with gcc/cmake
- 7 Answers 7
- How to compile 32-bit executable on 64 bit system
- How do I run 32-bit programs on a 64-bit Debian/Ubuntu?
- 3 Answers 3
- For current releases
- For old releases
- Schroot
- Introduction
- Set up schroot
- Install the new distribution
- Services in the chroot
- Populate the new system
- Going further
- Virtual machine
- How to Compile 32-bit Apps on 64-bit Ubuntu?
- 3 Answers 3
How to compile a 32-bit binary on a 64-bit linux machine with gcc/cmake
Is it possible to compile a project in 32-bit with cmake and gcc on a 64-bit system? It probably is, but how do I do it? When I tried it the «ignorant» way, without setting any parameters/flags/etc, just setting LD_LIBRARY_PATH to find the linked libraries in ~/tools/lib it seems to ignore it and only look in subdirectories named lib64.
7 Answers 7
It should do. You could also modify the cmake script to create a 32 bit target — it would just add -m32 to the CFLAGS , probably by setting CMAKE_REQUIRED_FLAGS .
Well, the problem is that this is of course not necessarily enough. You may need to tweak the linker, too!
What does export mean? Where does it belong? Te header files? The makefile ? Nope, totally not an answer for me as a beginner.
@TomášZato: At the shell prompt, before invoking cmake (however in your case, if you have a Makefile, then you would be using make instead).
$ gcc test.c -o testc $ file testc testc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped $ ldd testc linux-vdso.so.1 => (0x00007fff227ff000) libc.so.6 => /lib64/libc.so.6 (0x000000391f000000) /lib64/ld-linux-x86-64.so.2 (0x000000391ec00000) $ gcc -m32 test.c -o testc $ file testc testc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped $ ldd testc linux-gate.so.1 => (0x009aa000) libc.so.6 => /lib/libc.so.6 (0x00780000) /lib/ld-linux.so.2 (0x0075b000)
In short: use the -m32 flag to compile a 32-bit binary.
Also, make sure that you have the 32-bit versions of all required libraries installed (in my case all I needed on Fedora was glibc-devel.i386)
In later versions of CMake, one way to do it on each target is:
set_target_properties(MyTarget PROPERTIES COMPILE_FLAGS «-m32» LINK_FLAGS «-m32»)
I don’t know of a way to do it globally.
+1. I’m trying to build 32-bit taglib(developer.kde.org/~wheeler/taglib.html) on a 64-bit snow leopard. This works for me.
How to compile 32-bit executable on 64 bit system
Note: I looked through some of the suggested «similar questions» and didn’t find anything that looked conclusive. Plus, it seems most of them are 6 years old (from 2014), so I’m hoping for something more up-to-date (and more likely to «just work»). I have a 64 bit Ubuntu system that works fine. I would like to be able to build a 32 bit version of, say, «hello, world». This is mostly an academic pursuit, but it would be convenient to get it working. It would be nice if compiling with «-m32» would «just work», but it doesn’t. Worse, my memory is that this used to «just work» (in an older version of 64 bit Linux), but no longer works. Observe:
$ cat hello.c #include int main() < puts("hello, world"); return 0; >$ gcc -m32 hello.c In file included from hello.c:1:0: /usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory #include ^~~~~~~~~~~~~~~~~~~~~~~~~~ compilation terminated. $
apt-get install libc6-dev-i386-x32-cross
The following NEW packages will be installed: libc6-dev-i386-x32-cross libc6-dev-x32-cross libc6-i386-x32-cross libc6-x32-cross linux-libc-dev-x32-cross
After that, with a little bit of fudging, I was able to get it to compile, but not link. The link phase gives these error msgs:
/usr/bin/ld: cannot find Scrt1.o: No such file or directory /usr/bin/ld: cannot find crti.o: No such file or directory /usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/7/libgcc.a when searching for -lgcc /usr/bin/ld: cannot find -lgcc /usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/7/libgcc.a when searching for -lgcc /usr/bin/ld: cannot find -lgcc collect2: error: ld returned 1 exit status
How do I run 32-bit programs on a 64-bit Debian/Ubuntu?
I have a 64-bit (amd64 a.k.a. x86_64) Debian or Ubuntu installation. I need to run 32-bit (i386/i686) programs occasionally, or to compile programs for a 32-bit system. How can I do this with a minimum of fuss? Bonus: what if I want to run or test with an older or newer release of the distribution?
3 Answers 3
For current releases
Current Debian and Ubuntu have multiarch support: You can mix x86_32 (i386) and x86_64 (amd64) packages on the same system in a straightforward way. This is known as multiarch support — see Ubuntu or Debian wiki more information.
See warl0ck’s answer for a simple, up-to-date answer.
For old releases
In older releases, Debian and Ubuntu ship with a number of 32-bit libraries on amd64. Install the ia32-libs package to have a basic set of 32-bit libraries, and possibly other packages that depend on this one. Your 32-bit executables should simply run if you have all the required libraries. For development, install gcc-multilib , and again possibly other packages that depend on it such as g++-multilib . You may find binutils-multiarch useful as well, and ia32-libs-dev on Debian. Pass the -m32 option to gcc to compile for ix86.
Note that uname -m will still show x64_64 if you’re running a 64-bit kernel, regardless of what 32-bit user mode components you have installed. Schroot described below takes care of this.
Schroot
This section is a guide to installing a Debian-like distribution “inside” another Linux distribution. It is worded in terms of installing a 32-bit Ubuntu inside a 64-bit Ubuntu, but should apply with minor modifications to other situations, such as installing Debian unstable inside Debian stable or vice versa.
Introduction
The idea is to install an alternate distribution in a subtree and run from that. You can install a 32-bit system on a 64-bit system that way, or a different release of your distribution, or a testing environment with different sets of packages installed.
The chroot command and system call starts a process with a view of the filesystem that’s restricted to a subtree of the directory tree. Debian and Ubuntu ship schroot, a utility that wraps around this feature to create a more usable sub-environment.
Install the schroot package (Debian) and the debootstrap package (Debian). Debootstrap is only needed for the installation of the alternate distribution and can be removed afterwards.
Set up schroot
This example describes how to set up a 32-bit Ubuntu 10.04LTS (lucid lynx) alternate environment. A similar setup should work with other releases of Debian and Ubuntu. Create a file /etc/schroot/chroot.d/lucid32 with the following contents:
[lucid32] description=Ubuntu 10.04LTS 32-bit directory=/32 type=directory personality=linux32 users=yourusername groups=users,admin
The line directory=/32 tells schroot where we’ll put the files of the 32-bit installation. The line username=yourusername says the user yourusername will be allowed to use the schroot. The line groups=users,admin says that users in either group will be allowed to use the schroot; you can also put a users=… directive.
Install the new distribution
Create the directory and start populating it with debootstrap. Debootstrap downloads and installs a core set of packages for the specified distribution and architecture.
mkdir /32 debootstrap --arch i386 lucid /32 http://archive.ubuntu.com/ubuntu
You almost have a working system already; what follows is minor enhancements. Schroot automatically overwrites several files in /32/etc when you run it, in particular the DNS configuration in /etc/resolv.conf and the user database in /etc/passwd and other files (this can be overridden, see the documentation). There are a few more files you may want to copy manually once and for all:
cp -p /etc/apt/apt.conf /32/etc/apt/ # for proxy settings cp -p /etc/apt/sources.list /32/etc/apt/ # for universe, security, etc cp -p /etc/environment /32/etc/ # for proxy and locale settings cp -p /etc/sudoers /32/etc/ # for custom sudo settings
There won’t be a file /etc/mtab or /etc/fstab in the chroot. I don’t recommend using the mount command manually in the chroot, do it from outside. But do create a good-enough /etc/mtab to make commands such as df work reasonably.
ln -s /proc/mounts /32/etc/mtab
With the directory type, schroot will perform bind mounts of a number of directories, i.e. those directories will be shared with the parent installation: /proc , /dev , /home , /tmp .
Services in the chroot
As described here, a schroot is not suitable for running daemons. Programs in the schroot will be killed when you exit the schroot. Use a “plain” schroot instead of a “directory” schroot if you want it to be more permanent, and set up permanent bind mounts in /etc/fstab on the parent installation.
On Debian and Ubuntu, services start automatically on installation. To avoid this (which could disrupt the services running outside the chroot, in particular because network ports are shared), establish a policy of not running services in the chroot. Put the following script as /32/usr/sbin/policy-rc.d and make it executable ( chmod a+rx /32/usr/sbin/policy-rc.d ).
#!/bin/sh ## Don't start any service if running in a chroot. ## See /usr/share/doc/sysv-rc/README.policy-rc.d.gz if [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]; then exit 101 fi
Populate the new system
Now we can start using the chroot. You’ll want to install a few more packages at this point.
schroot -c lucid32 sudo apt-get update apt-get install lsb-core nano .
You may need to generate a few locales, e.g.
locale-gen en_US en_US.utf8
If the schroot is for an older release of Ubuntu such as 8.04 (hardy), note that the package ubuntu-standard pulls in an MTA. Select nullmailer instead of the default postfix (you may want your chroot to send mail but you definitely don’t want it to receive any).
Going further
For more information, see the schroot manual, the schroot FAQ and the schroot.conf manual. Schroot is part of the Debian autobuilder (buildd) project. There may be additional useful tips on the Ubuntu community page about debootstrap.
Virtual machine
If you need complete isolation of the alternate environment, use a virtual machine such as KVM (qemu-kvm ) or VirtualBox.
How to Compile 32-bit Apps on 64-bit Ubuntu?
I’m trying to compile a 32-bit C application on Ubuntu Server 12.04 LTS 64-bit using gcc 4.8. I’m getting linker error messages about incompatible libraries and skipping -lgcc . What do I need to do to get 32 bit apps compiled and linked?
3 Answers 3
This is known to work on Ubuntu 16.04 through 22.04:
sudo apt install gcc-multilib g++-multilib
Then a minimal hello world:
compiles without warning with:
gcc -m32 -ggdb3 -O0 -pedantic-errors -std=c89 \ -Wall -Wextra -pedantic -o main.out main.c
main.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=87c87a83878ce7e7d23b6236e4286bf1daf59033, not stripped
but fails on an x86_64 executable with:
./main.out: Invalid ELF image for this architecture
It is a shame that this package conflicts with the cross compilers like gcc-arm-linux-gnueabihf https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
Running versions of the question:
We are able to run 32-bit programs directly on 64-bit Ubuntu because the Ubuntu kernel is configured with:
grep CONFIG_IA32_EMULATION "/boot/config-$(uname -r)"
Include code to run legacy 32-bit programs under a 64-bit kernel. You should likely turn this on, unless you're 100% sure that you don't have any 32-bit programs left.
This is in turn possible because x86 64 bit CPUs have a mode to run 32-bit programs that the Linux kernel uses.
TODO: what options does gcc-multilib get compiled differently than gcc ?
Doesn’t work in podman/docker container with Ubuntu 18.04. As a matter of fact, I don’t see why would it ever work, because the mentioned gcc-multilib packages barely has any files, and certainly it has no libraries in them.
So, what helped for me in a docker/podman container with Ubuntu, is to install lib32gcc-10-dev (worth noting, the 10 version in my case is from PPA; without PPA it would be a lower version).
To get Ubuntu Server 12.04 LTS 64-bit to compile gcc 4.8 32-bit programs, you’ll need to do two things.
- Make sure all the 32-bit gcc 4.8 development tools are completely installed: sudo apt-get install lib32gcc-4.8-dev
- Compile programs using the -m32 flag gcc pgm.c -m32 -o pgm
Note that the -m32 flag is specific to 32-bit x86. You need different flags to compile for 32-bit ARM, RISC-V, etc.
Multiarch installation is supported by adding the architecture information to the package names you want to install (instead of installing these packages using alternative names, which might or might not be available).
See this answer for more information on (modern) multiarch installations.
In your case you’d be better off installing the 32bit gcc and libc:
sudo apt-get install libc6-dev:i386 gcc:i386
It will install the 32-bit libc development and gcc packages, and all depending packages (all 32bit versions), next to your 64-bit installation without breaking it.