Compiling C code with dietlibc and tcc

by Martin Monperrus

Tcc (aka Tiny C Compiler, or tinycc) is a very lightweight C compiler. Dietlibc is lighweight libc (as opposed to GNU libc). Using a tiny C compiler and a tiny libc is a kind of software minimalism.

First download tcc and install dietlibc (apt-get install dietlibc-dev). Then compile tcc as follows.

Preparing tcc

Modify configure and set the following variables.

  tcc_sysincludepaths="./"
  tcc_libpaths="./"
  tcc_crtprefix="./"

Then run:

  ./configure

Set CONFIG_TCCDIR in config.mak:

  CFLAGS=-Wall -g -O2 -DCONFIG_TCCDIR="\"./\""

In libtcc.c, remove the forced dependencies to crt1.o and crti.o:

  //      if (output_type != TCC_OUTPUT_DLL)
  //          tcc_add_crt(s, "crt1.o");
  //      tcc_add_crt(s, "crti.o");
          tcc_add_crt(s, "crt0.o");

In tccelf.c, remove the dependency to crtn.o:

  //if (s1->output_type != TCC_OUTPUT_MEMORY)
  //   tcc_add_crt(s1, "crtn.o");

And the run $ make.

This produces tcc that is free of any assumption with respect to the libc that is used, it only requires one crt0.o for implementing function _start (see below) . The

  $ ./tcc -vv
  tcc version 0.9.26 (i386 Linux)
  install: /usr/local/lib/tcc/
  crt:
     ./
  libraries:
    ./
  include:
    ./
  elfinterp:
    /lib/ld-linux.so.2

Compiling with tcc

You now need a startup crt file crt0.o that would provide function "_start". There are several ones (see http://www.monperrus.net/martin/compiling-where-is-_start). The one of dietlibc is in a file called start.o. We copy it to crt0.o (since this name is hard coded in tcc, see above):

  cp /usr/lib/diet/lib/start.o crt0.o

And now you can compile against dietlibc:

  ./tcc -L. -L/usr/lib/diet/lib/ -I /usr/lib/diet/include/ -o foo foo.c

I got lua to be compiled this way.

This enables one to compile C code on machines with no compilation support at all. Basically, to compile C code, you only need tcc, libtcc1.a, libc.a, libm.a, and the dietlibc headers (one single self-contained folder).

Side notes

It is not possible to do the same thing with newlib because newlib heavily depends on the kernel and gcc headers (see https://sourceware.org/ml/newlib/2005/msg00723.html). On the contrary, dietlibc is self-contained.

Tagged as: