Skip to content

Updating libc

Andrew Kelley edited this page Dec 16, 2021 · 34 revisions

Here's how to update the libc files that Zig bundles.

glibc

Make sure these dependencies are installed. If the scripts below fail, I'm not aware of a way to make them resume; each command deletes everything and starts over.

  • python3
  • subversion
  • gawk
  • autotools
  • flex
  • bison
  • build-essential
  • texinfo

Next, git clone glibc.

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.34 # the tag of the version to update to

Assuming the path of that is ~/glibc, make a new directory and go to it. Then run the Python commands, each of which uses all CPU cores and takes a long time. If any of them fail, look at the logs to find out why, correct it, and then start the command again. Unfortunately each command will delete its own previous progress and start over.

mkdir multi
cd multi
python3 ~/glibc/scripts/build-many-glibcs.py . checkout
cd src/glibc
git checkout glibc-2.34 # the tag of the version to update to
cd -
python3 ~/glibc/scripts/build-many-glibcs.py . host-libraries
python3 ~/glibc/scripts/build-many-glibcs.py . compilers # takes upwards of 12 hours with 16 CPU cores, might want to run overnight
python3 ~/glibc/scripts/build-many-glibcs.py . glibcs # took 7 hours for me with 8 CPU cores

Next, make sure that the list of architectures in tools/process_headers.zig is complete in that it lists all of the glibc targets and maps them to Zig targets. Any additional targets you add, add to the libcs_available variable in src/stage1/target.cpp, as well as available_libcs in src/target.zig.

Next, from the "build" directory of zig git source, use tools/process_headers.zig:

./zig build-exe ../tools/process_headers.zig
./process_headers --search-path ~/glibc/multi/install/glibcs --out hdrs --abi glibc

Inspect the hdrs directory that the tool just created. If it looks good, then:

rm -rf $(find ../lib/libc/include/ -name "*linux-gnu*")
rm -rf ../lib/libc/include/generic-glibc
mv hdrs/* ../lib/libc/include/

Inspect git status and make sure the changes look good. Make a commit with only the updated glibc headers in it.

Next, use glibc-abi-tool to update the lib/libc/glibc/abilists file. The instructions for how to do that are in the README.

Finally, update the rest of the files in lib/libc/glibc/ besides abilists, to match the new glibc version, using the tool:

./zig run ../tools/update_glibc.zig -- ~/Downloads/glibc ..

You definitely need to inspect the full diff and look for patches that Zig has on top of these files and put them back in place.

If you keep your glibc build artifacts, you can use it with zig build test -fqemu --glibc-runtimes /foo/glibc/multi/install/glibcs.

musl

git clone git://git.musl-libc.org/musl
git checkout v1.2.2 # the tag of the version to update to
rm -rf obj/ && make DESTDIR=build-all/aarch64   install-headers ARCH=aarch64   prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/arm       install-headers ARCH=arm       prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/i386      install-headers ARCH=i386      prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/mips      install-headers ARCH=mips      prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/mips64    install-headers ARCH=mips64    prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/powerpc   install-headers ARCH=powerpc   prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/powerpc64 install-headers ARCH=powerpc64 prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/riscv64   install-headers ARCH=riscv64   prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/s390x     install-headers ARCH=s390x     prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/x86_64    install-headers ARCH=x86_64    prefix=/usr/local/musl
rm -rf obj/ && make DESTDIR=build-all/m68k      install-headers ARCH=m68k      prefix=/usr/local/musl

Make sure the list of architectures in tools/process_headers.zig is complete in that it lists all of the musl targets which have corresponding Zig targets. Any additional targets you add, add to the libcs_available variable in target.cpp.

Next, use tools/process_headers.zig, with these parameters:

  • --abi musl
  • --search-path parameter will be the path to the build-all directory.
  • --out to a temporary directory if you want to inspect the output first, or lib/libc/include if you are confident in the output.

To update musl source code:

cd lib/libc/musl
rm -rf arch crt compat src include
cp -r ~/Downloads/musl/arch ./
cp -r ~/Downloads/musl/crt ./
cp -r ~/Downloads/musl/compat ./
cp -r ~/Downloads/musl/src ./
cp -r ~/Downloads/musl/include ./

Remove the non-supported architectures:

rm -rf arch/microblaze
rm -rf arch/mipsn32
rm -rf arch/or1k
rm -rf arch/sh
rm -rf arch/x32

Next, look at a git status and git diff and make sure everything looks OK. There are some chores to do below:

Update the contents of libc/musl/src/internal/version.h to the correct musl version number. This file will have been deleted by the above process and you will need to create it now (look at the git diff to see the contents).

Take note of the .mak files. These will show up in the "Untracked files" section, and should be deleted:

rm arch/arm/arch.mak
rm arch/i386/arch.mak
rm arch/mips/arch.mak
rm arch/powerpc/arch.mak

If there are any new ones not covered in this list, support needs to be added in link.cpp, where there is special handling for these. Look for time32_compat_arch_list.

Update src_files in src/musl.zig to be a complete list, e.g. with find musl/src -type f -name "*.c" -o -iname "*.s". Similarly, update compat_time32_files, e.g. with find musl/compat/time32 -type f -name "*.c" -o -iname "*.s".

If musl added any new architectures, add them to musl_arch_names in src/musl.zig. These can be found by ls arch/ in the musl source directory.

Updating the libc.S file

lib/libc/musl/libc.S contains stubs for all the dynamic symbols of musl's libc.so. It is generated from tools/gen_stubs.zig.

First, cross-compile musl for all the supported architectures:

echo -e '#!/bin/sh\nzig cc -target aarch64-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/aarch64"   --target=aarch64   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

# zig: error: clang frontend command failed with exit code 139 (use -v to see invocation)
echo -e '#!/bin/sh\nzig cc -target arm-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/arm"   --target=arm   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

echo -e '#!/bin/sh\nzig cc -target i386-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/i386"   --target=i386   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

echo -e '#!/bin/sh\nzig cc -target mips-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/mips"   --target=mips   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

# zig/lib/std/os/linux.zig:50:34: error: container 'std.os.linux.arch_bits' has no member called 'syscall3'
echo -e '#!/bin/sh\nzig cc -target mips64-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/mips64" --target=mips64   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

echo -e '#!/bin/sh\nzig cc -target powerpc-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/powerpc"   --target=powerpc   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

echo -e '#!/bin/sh\nzig cc -target powerpc64-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/powerpc64"   --target=powerpc64   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

echo -e '#!/bin/sh\nzig cc -target riscv64-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/riscv64"   --target=riscv64   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

# error: unknown target CPU 'generic'
# note: valid target CPU values are: arch8, z10, arch9, z196, arch10, zEC12, arch11, z13, arch12, z14, arch13, z15, arch14
echo -e '#!/bin/sh\nzig cc -target s390x-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/s390x"   --target=s390x   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

echo -e '#!/bin/sh\nzig cc -target x86_64-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/x86_64"   --target=x86_64   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

# checking whether C compiler works... no; compiler output follows:
# /home/andy/bin/zcc: line 2: 2622967 Segmentation fault      (core dumped) zig cc -target m68k-linux-musl $@
echo -e '#!/bin/sh\nzig cc -target m68k-linux-musl $@' > ~/bin/zcc && \
  make distclean && \
  PATH="$HOME/bin:$PATH" CC=zcc ./configure --prefix="$(pwd)/build-all/m68k"   --target=m68k   --disable-static && \
  PATH="$HOME/bin:$PATH" CC=zcc make -j$(nproc) install

Some of these didn't work last time I tried them, as you can see with the comments that contain error messages. These are bugs that should be fixed in zig or in clang. However, fixing those bugs is a separate issue that won't block the musl upgrade process. If any of them start working, then add the newly working architecture to the arches global variable in tools/gen_stubs.zig.

Anyway you should now have libc.so built for multiple architectures:

andy@ark ~/Downloads/musl ((v1.2.2))> find -name "libc.so"
./build-all/riscv64/lib/libc.so
./build-all/mips/lib/libc.so
./build-all/aarch64/lib/libc.so
./build-all/i386/lib/libc.so
./build-all/x86_64/lib/libc.so
./build-all/powerpc/lib/libc.so
./build-all/powerpc64/lib/libc.so

From the root of the zig source repository:

zig run tools/gen_stubs.zig >lib/libc/musl/libc.S

Pay attention to the stderr output of this command. It may reveal an issue has occurred that will require you to massage the data by editing gen_stubs.zig.

Check the git diff to make sure everything seems OK.

To verify that the stub libc.so matches the "real" musl libc.so first build a zig hello world that dynamically links musl:

zig build-exe -lc -dynamic -target x86_64-linux-musl hello.zig --verbose-link

Copy the path to the stub libc.so in the global cache from the link command logged and then run the following commands (with the proper paths):

objdump --dynamic-syms /home/ifreund/.cache/zig/o/94cd8ea1da001f912f2f7d259446424d/libc.so | sed -E -e 's/[0-9a-f]{16}//g' | sort > stubs.txt
objdump --dynamic-syms /path/to/musl/lib/libc.so | sed -E -e 's/[0-9a-f]{16}//g' | sort > musl.txt                                                
diff musl.txt stubs.txt

If all is well, the only output of the diff command should be the line containing the filename. For example:

1702c1702
< ../musl/lib/libc.so:     file format elf64-x86-64
---
> /home/ifreund/.cache/zig/o//libc.so:     file format elf64-x86-64

Linux

Obtain the latest master branch Linux code. Run the following commands:

make ARCH=alpha      INSTALL_HDR_PATH=dest/alpha      headers_install
make ARCH=arc        INSTALL_HDR_PATH=dest/arc        headers_install
make ARCH=arm        INSTALL_HDR_PATH=dest/arm        headers_install
make ARCH=arm64      INSTALL_HDR_PATH=dest/arm64      headers_install
make ARCH=csky       INSTALL_HDR_PATH=dest/csky       headers_install
make ARCH=h8300      INSTALL_HDR_PATH=dest/h8300      headers_install
make ARCH=hexagon    INSTALL_HDR_PATH=dest/hexagon    headers_install
make ARCH=ia64       INSTALL_HDR_PATH=dest/ia64       headers_install
make ARCH=m68k       INSTALL_HDR_PATH=dest/m68k       headers_install
make ARCH=microblaze INSTALL_HDR_PATH=dest/microblaze headers_install
make ARCH=mips       INSTALL_HDR_PATH=dest/mips       headers_install
make ARCH=nds32      INSTALL_HDR_PATH=dest/nds32      headers_install
make ARCH=nios2      INSTALL_HDR_PATH=dest/nios2      headers_install
make ARCH=openrisc   INSTALL_HDR_PATH=dest/openrisc   headers_install
make ARCH=parisc     INSTALL_HDR_PATH=dest/parisc     headers_install
make ARCH=powerpc    INSTALL_HDR_PATH=dest/powerpc    headers_install
make ARCH=riscv      INSTALL_HDR_PATH=dest/riscv      headers_install
make ARCH=s390       INSTALL_HDR_PATH=dest/s390       headers_install
make ARCH=sh         INSTALL_HDR_PATH=dest/sh         headers_install
make ARCH=sparc      INSTALL_HDR_PATH=dest/sparc      headers_install
make ARCH=um         INSTALL_HDR_PATH=dest/um         headers_install
make ARCH=x86        INSTALL_HDR_PATH=dest/x86        headers_install
make ARCH=xtensa     INSTALL_HDR_PATH=dest/xtensa     headers_install

Eyeball the linux_targets variable inside tools/update-linux-headers.zig.

rm -rf lib/libc/include/*-linux-any
zig run tools/update-linux-headers.zig -- --search-path ~/Downloads/linux/dest --out lib/libc/include

freebsd

TODO

openbsd

TODO

netbsd

TODO

macOS

For macOS, we only need to fetch the latest libc headers. The easiest way to achieve this is to use fetch-them-macos-headers utility. The only requirement is that you have to run it directly on the target (i.e., a native macOS installation).

git clone https://github.com/kubkon/fetch-them-macos-headers
cd fetch-them-macos-headers
zig build run

This will create a new dir x86_64-macos-gnu in cwd with all the required headers for macOS. Assuming that Zig source is in ~/zig, simply copy the dir over

rm -rf ~/zig/lib/libc/include/x86_64-macos-gnu
mv x86_64-macos-gnu ~/zig/lib/libc/include/.

mingw-w64 (Windows)

The process-headers tool is not needed for these headers because mingw-w64 headers are already multi-architecture.

git clone git://git.code.sf.net/p/mingw-w64/mingw-w64

Check out the latest release.

ZIGSRC=/path/to/zig/src/tree
rm -rf $ZIGSRC/lib/libc/include/any-windows-any
cd mingw-w64-headers
./configure --prefix=/tmp/prefix --with-default-win32-winnt=0x0603
make install
mv /tmp/prefix/include $ZIGSRC/lib/libc/include/any-windows-any

The above makes Windows 8.1 the minimum version. Once Windows 10 is the minimum supported version (on January 10, 2023), we can additionally pass --with-default-msvcrt=ucrt.

Next, update all the files in lib/libc/mingw/*.

Examine carefully the diff between v9.0.0 and the version that you are updating to, and consider if anything else needs to be done. Update the previous sentence in this wiki article to the version you updated to.