feat: add tinycc

This commit is contained in:
Jake Hamilton 2024-06-06 17:13:22 -07:00
parent 5032b8772b
commit 560078707c
Signed by: jakehamilton
GPG key ID: 9762169A1B35EA68
10 changed files with 765 additions and 1 deletions

View file

@ -9,6 +9,8 @@ in {
includes = [
./nyacc
./mes
./ln-boot
./tinycc
];
config = {
@ -17,6 +19,12 @@ in {
stage1-nyacc = stage1.nyacc.package;
stage1-mes = stage1.mes.compiler.package;
stage1-mes-libs = stage1.mes.libs.package;
stage1-ln-boot = stage1.ln-boot.package;
stage1-mes-libc = stage1.mes.libc.package;
stage1-tinycc-boot = stage1.tinycc.boot.compiler.package;
stage1-tinycc-boot-libs = stage1.tinycc.boot.libs.package;
stage1-tinycc-mes = stage1.tinycc.mes.compiler.package;
stage1-tinycc-mes-libs = stage1.tinycc.mes.libs.package;
};
extras = {
@ -27,6 +35,15 @@ in {
prefix = stage1.mes.libs.prefix;
};
};
tinycc = {
boot = {
src = stage1.tinycc.boot.src;
tarball = builtins.fetchurl {
url = "https://gitlab.com/janneke/tinycc/-/archive/${stage1.tinycc.boot.revision}/tinycc-${stage1.tinycc.boot.revision}.tar.gz";
sha256 = "1a0cw9a62qc76qqn5sjmp3xrbbvsz2dxrw21lrnx9q0s74mwaxbq";
};
};
};
};
};
};

View file

@ -0,0 +1,64 @@
{
lib,
config,
}: let
cfg = config.aux.foundation.stages.stage1.ln-boot;
builders = config.aux.foundation.builders;
stage0 = config.aux.foundation.stages.stage0;
stage1 = config.aux.foundation.stages.stage1;
in {
options.aux.foundation.stages.stage1.ln-boot = {
package = lib.options.create {
type = lib.types.package;
description = "The package to use for ln-boot.";
};
meta = {
description = lib.options.create {
type = lib.types.string;
description = "Description for the package.";
default.value = "A basic program to create symlinks.";
};
homepage = lib.options.create {
type = lib.types.string;
description = "Homepage for the package.";
default.value = "https://github.com/auxolotl/labs";
};
license = lib.options.create {
# TODO: Add a proper type for licenses.
type = lib.types.attrs.any;
description = "License for the package.";
default.value = lib.licenses.mit;
};
platforms = lib.options.create {
type = lib.types.list.of lib.types.string;
description = "Platforms the package supports.";
default.value = ["x86_64-linux" "aarch64-linux" "i686-linux"];
};
};
};
config = {
aux.foundation.stages.stage1.ln-boot = {
package = builders.kaem.build {
name = "ln-boot";
meta = cfg.meta;
script = ''
mkdir -p ''${out}/bin
${stage1.mes.compiler.package}/bin/mes --no-auto-compile -e main ${stage1.mes.libs.src.bin}/bin/mescc.scm -- \
-L ${stage1.mes.libs.package}/lib \
-lc+tcc \
-o ''${out}/bin/ln \
${./main.c}
'';
};
};
};
}

View file

@ -0,0 +1,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv) {
if (argc != 4 || strcmp(argv[1], "-s")) {
fputs("Usage: ", stdout);
fputs(argv[0], stdout);
fputs(" -s TARGET LINK_NAME\n", stdout);
exit(EXIT_FAILURE);
}
symlink(argv[2], argv[3]);
exit(EXIT_SUCCESS);
}

View file

@ -10,6 +10,7 @@ in {
includes = [
./compiler.nix
./libs.nix
./libc.nix
];
options.aux.foundation.stages.stage1.mes = {

View file

@ -0,0 +1,95 @@
{
lib,
config,
}: let
cfg = config.aux.foundation.stages.stage1.mes.libc;
builders = config.aux.foundation.builders;
stage1 = config.aux.foundation.stages.stage1;
in {
options.aux.foundation.stages.stage1.mes.libc = {
package = lib.options.create {
type = lib.types.package;
description = "The package to use for mes-libc.";
};
meta = {
description = lib.options.create {
type = lib.types.string;
description = "Description for the package.";
default.value = "The Mes C Library";
};
homepage = lib.options.create {
type = lib.types.string;
description = "Homepage for the package.";
default.value = "https://gnu.org/software/mes";
};
license = lib.options.create {
# TODO: Add a proper type for licenses.
type = lib.types.attrs.any;
description = "License for the package.";
default.value = lib.licenses.gpl3Plus;
};
platforms = lib.options.create {
type = lib.types.list.of lib.types.string;
description = "Platforms the package supports.";
default.value = ["x86_64-linux" "aarch64-linux" "i686-linux"];
};
};
};
config = {
aux.foundation.stages.stage1.mes.libc = {
package = let
sources = import ./sources.nix;
libtcc1 = sources.x86.linux.gcc.libtcc1;
first = lib.lists.take 100 sources.x86.linux.gcc.libc_gnu;
last = lib.lists.drop 100 sources.x86.linux.gcc.libc_gnu;
in
builders.kaem.build {
name = "mes-libc-${stage1.mes.version}";
meta = cfg.meta;
deps.build.host = [
stage1.ln-boot.package
];
script = ''
cd ${stage1.mes.libs.prefix}
# mescc compiled libc.a
mkdir -p ''${out}/lib/x86-mes
# libc.c
catm ''${TMPDIR}/first.c ${builtins.concatStringsSep " " first}
catm ''${out}/lib/libc.c ''${TMPDIR}/first.c ${builtins.concatStringsSep " " last}
# crt{1,n,i}.c
cp lib/linux/x86-mes-gcc/crt1.c ''${out}/lib
cp lib/linux/x86-mes-gcc/crtn.c ''${out}/lib
cp lib/linux/x86-mes-gcc/crti.c ''${out}/lib
# libtcc1.c
catm ''${out}/lib/libtcc1.c ${builtins.concatStringsSep " " libtcc1}
# getopt.c
cp lib/posix/getopt.c ''${out}/lib/libgetopt.c
# Install headers
ln -s ${stage1.mes.libs.prefix}/include ''${out}/include
'';
extras = {
CFLAGS = "-DHAVE_CONFIG_H=1 -I${cfg.package}/include -I${cfg.package}/include/linux/x86";
};
};
};
};
}

View file

@ -199,7 +199,11 @@ in {
libc-mini = createLib "libc-mini" sources.x86.linux.mescc.libc_mini;
libmescc = createLib "libmescc" sources.x86.linux.mescc.libmescc;
libc = createLib "libc" sources.x86.linux.mescc.libc;
libc_tcc = createLib "libc+tcc" sources.x86.linux.mescc.libc_tcc;
libc_tcc = createLib "libc+tcc" (sources.x86.linux.mescc.libc_tcc
++ [
# We need `symlink` support for `ln-boot` to work.
"lib/linux/symlink.c"
]);
in
builders.kaem.build {
name = "mes-m2-libs-${stage1.mes.version}";

View file

@ -0,0 +1,194 @@
args @ {
lib,
config,
}: let
cfg = config.aux.foundation.stages.stage1.tinycc.boot;
builders = config.aux.foundation.builders;
stage1 = config.aux.foundation.stages.stage1;
pname = "tinycc-boot";
helpers = lib.fp.withDynamicArgs (import ./helpers.nix) args;
in {
options.aux.foundation.stages.stage1.tinycc.boot = {
compiler = {
package = lib.options.create {
type = lib.types.package;
description = "The package to use for the tinycc-boot compiler.";
};
};
libs = {
package = lib.options.create {
type = lib.types.package;
description = "The package to use for the tinycc-boot libs.";
};
};
meta = {
description = lib.options.create {
type = lib.types.string;
description = "Description for the package.";
default.value = "Tiny C Compiler's bootstrappable fork.";
};
homepage = lib.options.create {
type = lib.types.string;
description = "Homepage for the package.";
default.value = "https://repo.or.cz/w/tinycc.git";
};
license = lib.options.create {
# TODO: Add a proper type for licenses.
type = lib.types.attrs.any;
description = "License for the package.";
default.value = lib.licenses.lgpl21Only;
};
platforms = lib.options.create {
type = lib.types.list.of lib.types.string;
description = "Platforms the package supports.";
default.value = ["x86_64-linux" "i686-linux"];
};
};
src = lib.options.create {
type = lib.types.string;
description = "Source for the package.";
};
revision = lib.options.create {
type = lib.types.string;
description = "Revision of the package.";
};
};
config = {
aux.foundation.stages.stage1.tinycc.boot = let
tinycc-boot = let
tinycc-mes-bootstrappable = helpers.createBoot {
pname = "tinycc-mes-bootstrappable";
version = stage1.tinycc.version;
src = cfg.src;
};
tinycc-boot0 = helpers.createTinyccMes {
pname = "tinycc-boot0";
version = stage1.tinycc.version;
src = cfg.src;
args = [
"-D HAVE_LONG_LONG_STUB=1"
"-D HAVE_SETJMP=1"
];
lib.args = [
"-D HAVE_LONG_LONG_STUB=1"
];
boot = tinycc-mes-bootstrappable;
meta = cfg.meta;
};
tinycc-boot1 = helpers.createTinyccMes {
pname = "tinycc-boot1";
version = stage1.tinycc.version;
src = cfg.src;
args = [
"-D HAVE_BITFIELD=1"
"-D HAVE_LONG_LONG=1"
"-D HAVE_SETJMP=1"
];
lib.args = [
"-D HAVE_LONG_LONG=1"
];
boot = tinycc-boot0;
meta = cfg.meta;
};
tinycc-boot2 = helpers.createTinyccMes {
pname = "tinycc-boot2";
version = stage1.tinycc.version;
src = cfg.src;
args = [
"-D HAVE_BITFIELD=1"
"-D HAVE_FLOAT_STUB=1"
"-D HAVE_LONG_LONG=1"
"-D HAVE_SETJMP=1"
];
lib.args = [
"-D HAVE_FLOAT_STUB=1"
"-D HAVE_LONG_LONG=1"
];
boot = tinycc-boot1;
meta = cfg.meta;
};
tinycc-boot3 = helpers.createTinyccMes {
pname = "tinycc-boot3";
version = stage1.tinycc.version;
src = cfg.src;
args = [
"-D HAVE_BITFIELD=1"
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
"-D HAVE_SETJMP=1"
];
lib.args = [
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
];
boot = tinycc-boot2;
meta = cfg.meta;
};
in
helpers.createTinyccMes {
pname = "tinycc-boot";
version = stage1.tinycc.version;
src = cfg.src;
args = [
"-D HAVE_BITFIELD=1"
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
"-D HAVE_SETJMP=1"
];
lib.args = [
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
];
boot = tinycc-boot3;
meta = cfg.meta;
};
in {
revision = "80114c4da6b17fbaabb399cc29f427e368309bc8";
libs.package = tinycc-boot.libs;
compiler.package = tinycc-boot.compiler;
src = let
tarball = builtins.fetchurl {
url = "https://gitlab.com/janneke/tinycc/-/archive/${cfg.revision}/tinycc-${cfg.revision}.tar.gz";
sha256 = "1a0cw9a62qc76qqn5sjmp3xrbbvsz2dxrw21lrnx9q0s74mwaxbq";
};
patched = builders.kaem.build {
name = "${pname}-src";
meta = stage1.tinycc.meta;
script = ''
ungz --file ${tarball} --output tinycc.tar
mkdir -p ''${out}
cd ''${out}
untar --file ''${NIX_BUILD_TOP}/tinycc.tar
# Patch
cd tinycc-${cfg.revision}
# Static link by default
replace --file libtcc.c --output libtcc.c --match-on "s->ms_extensions = 1;" --replace-with "s->ms_extensions = 1; s->static_link = 1;"
'';
};
in "${patched}/tinycc-${cfg.revision}";
};
};
}

View file

@ -0,0 +1,55 @@
{
lib,
config,
}: let
cfg = config.aux.foundation.stages.stage1.tinycc;
builders = config.aux.foundation.builders;
stage1 = config.aux.foundation.stages.stage1;
in {
includes = [
./boot.nix
./mes.nix
];
options.aux.foundation.stages.stage1.tinycc = {
meta = {
description = lib.options.create {
type = lib.types.string;
description = "Description for the package.";
default.value = "Small, fast, embeddable C compiler and interpreter";
};
homepage = lib.options.create {
type = lib.types.string;
description = "Homepage for the package.";
default.value = "https://repo.or.cz/w/tinycc.git";
};
license = lib.options.create {
# TODO: Add a proper type for licenses.
type = lib.types.attrs.any;
description = "License for the package.";
default.value = lib.licenses.lgpl21Only;
};
platforms = lib.options.create {
type = lib.types.list.of lib.types.string;
description = "Platforms the package supports.";
default.value = ["x86_64-linux" "i686-linux"];
};
};
version = lib.options.create {
type = lib.types.string;
description = "Version of the package.";
};
};
config = {
aux.foundation.stages.stage1.tinycc = {
version = "unstable-2023-04-20";
};
};
}

View file

@ -0,0 +1,176 @@
{
lib,
config,
}: let
cfg = config.aux.foundation.stages.stage1.tinycc.boot;
builders = config.aux.foundation.builders;
stage1 = config.aux.foundation.stages.stage1;
cflags = stage1.mes.libc.package.extras.CFLAGS;
createBoot = {
pname,
version,
src,
}: let
compiler = builders.kaem.build {
name = "${pname}-${version}";
script = ''
catm config.h
${stage1.mes.compiler.package}/bin/mes --no-auto-compile -e main ${stage1.mes.libs.src.bin}/bin/mescc.scm -- \
-S \
-o tcc.s \
-I . \
-D BOOTSTRAP=1 \
-I ${src} \
-D TCC_TARGET_I386=1 \
-D inline= \
-D CONFIG_TCCDIR=\"\" \
-D CONFIG_SYSROOT=\"\" \
-D CONFIG_TCC_CRTPREFIX=\"{B}\" \
-D CONFIG_TCC_ELFINTERP=\"/mes/loader\" \
-D CONFIG_TCC_LIBPATHS=\"{B}\" \
-D CONFIG_TCC_SYSINCLUDEPATHS=\"${stage1.mes.libc.package}/include\" \
-D TCC_LIBGCC=\"${stage1.mes.libc.package}/lib/x86-mes/libc.a\" \
-D CONFIG_TCC_LIBTCC1_MES=0 \
-D CONFIG_TCCBOOT=1 \
-D CONFIG_TCC_STATIC=1 \
-D CONFIG_USE_LIBGCC=1 \
-D TCC_MES_LIBC=1 \
-D TCC_VERSION=\"${version}\" \
-D ONE_SOURCE=1 \
${src}/tcc.c
mkdir -p ''${out}/bin
${stage1.mes.compiler.package}/bin/mes --no-auto-compile -e main ${stage1.mes.libs.src.bin}/bin/mescc.scm -- \
-L ${stage1.mes.libs.package}/lib \
-l c+tcc \
-o ''${out}/bin/tcc \
tcc.s
'';
};
libs = createLibc {
inherit pname version;
src = stage1.mes.libc.package;
args = cflags;
tinycc = compiler;
};
in {inherit compiler libs;};
createTinyccMes = {
pname,
version,
src,
args,
boot,
lib ? {},
meta,
}: let
compiler = builders.kaem.build {
name = "${pname}-${version}";
inherit meta;
#
script = ''
catm config.h
mkdir -p ''${out}/bin
${boot.compiler}/bin/tcc \
-B ${boot.libs}/lib \
-g \
-v \
-o ''${out}/bin/tcc \
-D BOOTSTRAP=1 \
${builtins.concatStringsSep " " args} \
-I . \
-I ${src} \
-D TCC_TARGET_I386=1 \
-D CONFIG_TCCDIR=\"\" \
-D CONFIG_SYSROOT=\"\" \
-D CONFIG_TCC_CRTPREFIX=\"{B}\" \
-D CONFIG_TCC_ELFINTERP=\"\" \
-D CONFIG_TCC_LIBPATHS=\"{B}\" \
-D CONFIG_TCC_SYSINCLUDEPATHS=\"${stage1.mes.libc.package}/include\" \
-D TCC_LIBGCC=\"libc.a\" \
-D TCC_LIBTCC1=\"libtcc1.a\" \
-D CONFIG_TCCBOOT=1 \
-D CONFIG_TCC_STATIC=1 \
-D CONFIG_USE_LIBGCC=1 \
-D TCC_MES_LIBC=1 \
-D TCC_VERSION=\"${version}\" \
-D ONE_SOURCE=1 \
${src}/tcc.c
'';
};
libs = createLibc {
inherit pname version src;
args =
builtins.concatStringsSep
" "
(
["-c" "-D" "TCC_TARGET_I386=1"]
++ (lib.args or [])
);
tinycc = compiler;
};
in {
inherit compiler libs boot;
};
createLibc = {
pname,
version,
src,
args,
tinycc,
}: let
createLibrary = name: args: source:
builders.kaem.build {
name = "${name}.a";
script = ''
${tinycc}/bin/tcc ${args} -c -o ${name}.o ${source}
${tinycc}/bin/tcc -ar cr ''${out} ${name}.o
'';
};
crt = builders.kaem.build {
name = "crt";
script = ''
mkdir -p ''${out}/lib
${tinycc}/bin/tcc ${cflags} -c -o ''${out}/lib/crt1.o ${stage1.mes.libc.package}/lib/crt1.c
${tinycc}/bin/tcc ${cflags} -c -o ''${out}/lib/crtn.o ${stage1.mes.libc.package}/lib/crtn.c
${tinycc}/bin/tcc ${cflags} -c -o ''${out}/lib/crti.o ${stage1.mes.libc.package}/lib/crti.c
'';
};
libtcc1 = createLibrary "libtcc1" args "${src}/lib/libtcc1.c";
libc = createLibrary "libc" cflags "${stage1.mes.libc.package}/lib/libc.c";
libgetopt = createLibrary "libgetopt" cflags "${stage1.mes.libc.package}/lib/libgetopt.c";
in
builders.kaem.build {
name = "${pname}-libs-${version}";
script = ''
mkdir -p ''${out}/lib
cp ${crt}/lib/crt1.o ''${out}/lib
cp ${crt}/lib/crtn.o ''${out}/lib
cp ${crt}/lib/crti.o ''${out}/lib
cp ${libtcc1} ''${out}/lib/libtcc1.a
cp ${libc} ''${out}/lib/libc.a
cp ${libgetopt} ''${out}/lib/libgetopt.a
'';
};
in {
inherit
createBoot
createTinyccMes
createLibc
;
}

View file

@ -0,0 +1,142 @@
args @ {
lib,
config,
}: let
cfg = config.aux.foundation.stages.stage1.tinycc.mes;
builders = config.aux.foundation.builders;
stage1 = config.aux.foundation.stages.stage1;
pname = "tinycc-boot";
helpers = lib.fp.withDynamicArgs (import ./helpers.nix) args;
in {
options.aux.foundation.stages.stage1.tinycc.mes = {
compiler = {
package = lib.options.create {
type = lib.types.package;
description = "The package to use for the tinycc-mes compiler.";
};
};
libs = {
package = lib.options.create {
type = lib.types.package;
description = "The package to use for the tinycc-mes libs.";
};
};
src = lib.options.create {
type = lib.types.string;
description = "Source for the package.";
};
revision = lib.options.create {
type = lib.types.string;
description = "Revision of the package.";
};
};
config = {
aux.foundation.stages.stage1.tinycc.mes = let
tinycc-mes = let
tccdefs = builders.kaem.build {
name = "tccdefs-${stage1.tinycc.version}";
script = ''
mkdir ''${out}
${stage1.tinycc.boot.compiler.package}/bin/tcc \
-B ${stage1.tinycc.boot.libs.package}/lib \
-DC2STR \
-o c2str \
${cfg.src}/conftest.c
./c2str ${cfg.src}/include/tccdefs.h ''${out}/tccdefs_.h
'';
};
tinycc-mes-boot = helpers.createTinyccMes {
pname = "tinycc-mes-boot";
version = stage1.tinycc.version;
src = cfg.src;
args = [
"-D HAVE_BITFIELD=1"
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
"-D HAVE_SETJMP=1"
"-D CONFIG_TCC_PREDEFS=1"
"-I ${tccdefs}"
"-D CONFIG_TCC_SEMLOCK=0"
];
lib.args = [
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
"-D CONFIG_TCC_PREDEFS=1"
"-I ${tccdefs}"
"-D CONFIG_TCC_SEMLOCK=0"
];
boot = {
libs = stage1.tinycc.boot.libs.package;
compiler = stage1.tinycc.boot.compiler.package;
};
meta = stage1.tinycc.meta;
};
in
helpers.createTinyccMes {
pname = "tinycc-mes";
version = stage1.tinycc.version;
src = cfg.src;
args = [
"-std=c99"
"-D HAVE_BITFIELD=1"
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
"-D HAVE_SETJMP=1"
"-D CONFIG_TCC_PREDEFS=1"
"-I ${tccdefs}"
"-D CONFIG_TCC_SEMLOCK=0"
];
lib.args = [
"-D HAVE_FLOAT=1"
"-D HAVE_LONG_LONG=1"
"-D CONFIG_TCC_PREDEFS=1"
"-I ${tccdefs}"
"-D CONFIG_TCC_SEMLOCK=0"
];
boot = tinycc-mes-boot;
meta = stage1.tinycc.meta;
};
in {
revision = "86f3d8e33105435946383aee52487b5ddf918140";
libs.package = tinycc-mes.libs;
compiler.package = tinycc-mes.compiler;
src = let
tarball = builtins.fetchurl {
url = "https://repo.or.cz/tinycc.git/snapshot/${cfg.revision}.tar.gz";
sha256 = "11idrvbwfgj1d03crv994mpbbbyg63j1k64lw1gjy7mkiifw2xap";
};
patched = builders.kaem.build {
name = "${pname}-src";
meta = stage1.tinycc.meta;
script = ''
ungz --file ${tarball} --output tinycc.tar
mkdir -p ''${out}
cd ''${out}
untar --file ''${NIX_BUILD_TOP}/tinycc.tar
# Patch
cd tinycc-${builtins.substring 0 7 cfg.revision}
# Static link by default
replace --file libtcc.c --output libtcc.c --match-on "s->ms_extensions = 1;" --replace-with "s->ms_extensions = 1; s->static_link = 1;"
'';
};
in "${patched}/tinycc-${builtins.substring 0 7 cfg.revision}";
};
};
}