Welcome to little lamb

Code » comain » commit 70154f3

Bunch of changes to the whole system..

author Olivier Brunel
2023-03-31 13:40:14 UTC
committer Olivier Brunel
2023-03-31 13:40:14 UTC
parent 0c59daae2b512782455e69cb5586d589eee1b03d

Bunch of changes to the whole system..

..yeah, a big fat commit isn't ideal, but we didn't do it right, and I'm
too lazy to split that into self-contained commits. :|

So amongst other things are :

- make everything built into build/
- drop the meta/{libs,bins}/files to (manually) define objects for each
  library/binary. Instead source code is organized into a tree:
  src/foo : means source files -> objects for binary "foo"
  src/libbar : means the same for library "bar"
  Note that it is possible to include objects from another things through
  the use of symlinks. Then objects stay in their "primary" dest, are
  only compiled once but re-used.
- empty files +foobar will mean a dependency to foobar, so the proper
  -lfoobar needs be added to objects' lists.
  In order to get dependencies/librairies in the right order, one must
  define it in the meta/deps through a directory after containing empty
  files. Note that it might have been more logical to have it the other
  way around, e.g. to need to have meta/deps/foo/before/bar instead of
  meta/deps/bar/after/foo; but that way makes things (much) easier.
  Also, foo being after bar refers to the order on the command line, so
  e.g. it means to specify "-lbar -lfoo" in that order
- headers have moved into src/include; where config.h is generated
- public headers (for libraries) are expected to be into src/libxxx/include
  and for each src/libxxx there's a -isystem src/libxxx/include added
  for all, there's no per-binary/library things (for now)
- documentation is now moved into src/doc, and generated through mkdoc
  into build/doc. src/doc can have subdirs, build/doc is flattened.
  mkdoc is mainly cp but supports lines ~ "<inc file.md>" that are to be
  replaced by the content of src/doc/include/file.md
- use options to specify optimizations & warnings flags. Also support
  so-called "invisible" options, either by empty desc or an extra file
  invisible, to mean they're not listed on configure's --help
  An invisible option with a description will still be listed when set.
- options also support an after/ dir to have them ordered amngst each
  others.
- options have a file default which must contain 0 or 1. Their default
  values are set in a 2-pass system, first that default file, then - and
  if there wasn't one - through running the isdefault script. Which can
  make use of env vars to know if other options have been set or not.
  Note that is pretty limited, in that it will only be known for options
  that were user-set on configure's command-line, or that comes before
  the current option. But that still allows some nice stuff.
- dependencies found as internal are automatically set for static linking
  (no more need for a "static" file). Also if there's a "configure" file
  in their meta/deps folder, it's content will be passed to their
  ./configure when running "make deps" (to build all such internal deps)
- I'm sure I'm forgetting a bunch of (important) things, all apologies.

common.mk +74 -49
configure +278 -163
getdeps +3 -3
init +6 -6
libcomain +103 -18
meta/deps.tpl/limb/configure +1 -0
meta/deps.tpl/limb/incdir +1 -0
meta/deps.tpl/{limb/static => skalibs/after/limb} +0 -0
meta/deps.tpl/skalibs/configure +1 -0
meta/options/debug/{disabled => after/optimize} +0 -0
meta/options/debug/default +1 -0
meta/options/optimize/cflags +1 -0
meta/options/optimize/default +1 -0
meta/options/optimize/desc +1 -0
meta/options/optimizeOff/cflags +1 -0
meta/options/optimizeOff/desc +1 -0
meta/options/optimizeOff/invisible +0 -0
meta/options/optimizeOff/isdefault +5 -0
meta/options/warnings/cflags +1 -0
meta/options/warnings/default +1 -0
meta/options/warnings/desc +1 -0
mkbuild +11 -0
mkdoc +8 -0
mkreadme +1 -1
mktarball +4 -4
project.mk.tpl +2 -2

diff --git a/common.mk b/common.mk
index 45780a8..573683c 100644
--- a/common.mk
+++ b/common.mk
@@ -3,56 +3,73 @@
 
 # init some variables
 DEBUG =
+CPPFLAGS=
 CFLAGS =
 LDFLAGS =
 
-# basic warnings, create .d dependency files
-COMMON_CPPFLAGS  = -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
-COMMON_CPPFLAGS += -iquote include
-COMMON_CFLAGS    = -pipe -Wall -O3
-COMMON_CFLAGS   += -MMD -MP
-COMMON_LDFLAGS   = -Wl,--sort-section=alignment -Wl,--sort-common
-CFLAGS_SHARED    = -fPIC
-LDFLAGS_SHARED   = -shared -Wl,--hash-style=gnu
-
-SRCS  = $(wildcard src/*.c src/*/*.c)
-ASMS  = $(wildcard src/*.S src/*/*.S)
-OBJS  = $(SRCS:src/%.c=obj/%.o) $(ASMS:src/%.S=obj/%.o)
-OBJS += $(SRCS:src/%.c=obj/%.lo)
-DEPS  = $(OBJS:%=%.d)
-BINS  =
-LIBS  =
-TOOLS =
-SHARED_LIBS = $(patsubst %,lib%.so,$(LIBS))
-STATIC_LIBS = $(patsubst %,lib%.a,$(LIBS))
-SRCS_DOCS = $(wildcard doc/*.md)
-DOCS = README COPYING $(SRCS_DOCS:doc/%=%)
+# basic flags, create .d dependency files
+COMMON_CPPFLAGS         = -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
+COMMON_CPPFLAGS        += -iquote src/include
+COMMON_CFLAGS           = -pipe
+COMMON_CFLAGS          += -MMD -MP
+COMMON_LDFLAGS          =
+COMMON_CPPFLAGS_SHARED  =
+COMMON_CFLAGS_SHARED    = -shared
+COMMON_LDFLAGS_SHARED   =
+
+BLD_DOCS =
+BLD_SHARED_LIBS =
+BLD_STATIC_LIBS =
+BLD_BINS =
+# this isn't ideal, since it's limited to a depth of 2. However, that'll be
+# enough (for now), as 1 is binary/library level, 2 is header within library,
+# and we don't expect to go any deeper than that.
+DEPS = $(wildcard build/*/*.d) $(wildcard build/*/*/*.d)
+LIBS =
+STATIC_LIBS = $(LIBS:%=lib%.a)
+SHARED_LIBS = $(LIBS:%=lib%.so)
+BINS =
+PRIV_LIBS =
+PRIV_STATIC_LIBS = $(PRIV_LIBS:%=lib%.a)
+PRIV_SHARED_LIBS = $(PRIV_LIBS:%=lib%.so)
+PRIV_BINS =
+DOCS = README COPYING $(BLD_DOCS:build/doc/%=md/%)
 DATA =
 
 # to be removed upon `make clean`
-CLEAN = $(BINS) $(TOOLS) $(STATIC_LIBS) $(SHARED_LIBS) $(OBJS) $(DEPS)
+CLEAN = $(BLD_STATIC_LIBS) $(BLD_SHARED_LIBS) $(BLD_BINS)
 
-obj: comain
-	$(_DIR) comain/mkdirobj
+build: comain
+	$(_DIR) comain/mkbuild
 
-obj/%.o: src/%.c Makefile common.mk config.mk project.mk | obj
-	$(_CC) $(COMMON_CPPFLAGS) $(CPPFLAGS) $(COMMON_CFLAGS) $(CFLAGS_$(<:src/%.c=%)) $(CFLAGS) -o $@ -c $<
-	@mv $(@:%.o=%.d) $(@:%.o=%.o.d)
+build/doc/%.md: | build
+	$(_DOC) comain/mkdoc $< $@
 
-obj/%.o: src/%.S Makefile common.mk config.mk project.mk | obj
-	$(_CC) $(COMMON_CPPFLAGS) $(CPPFLAGS) $(COMMON_CFLAGS) $(CFLAGS_$(<:src/%.c=%)) $(CFLAGS) -o $@ -c $<
-	@mv $(@:%.o=%.d) $(@:%.o=%.o.d)
+build/%.o: src/%.c Makefile common.mk config.mk project.mk | build
+	$(_CC) $(COMMON_CPPFLAGS) $(CPPFLAGS) \
+		$(COMMON_CFLAGS) $(CFLAGS_$(<:src/%.c=%)) $(CFLAGS) \
+		-o $@ -c $<
+	@test -e $(@:%.o=%.d) && mv $(@:%.o=%.d) $(@:%.o=%.o.d)
 
-obj/%.lo: src/%.c Makefile common.mk config.mk project.mk | obj
-	$(_CC) $(COMMON_CPPFLAGS) $(CPPFLAGS) $(COMMON_CFLAGS) $(CFLAGS_$(<:src/%.c=%)) $(CFLAGS) $(CFLAGS_SHARED) -o $@ -c $<
-	@mv $(@:%.lo=%.d) $(@:%.lo=%.lo.d)
+build/%.o: src/%.S Makefile common.mk config.mk project.mk | build
+	$(_CC) $(COMMON_CPPFLAGS) $(CPPFLAGS) \
+		$(COMMON_CFLAGS) $(CFLAGS_$(<:src/%.c=%)) $(CFLAGS) \
+		-o $@ -c $<
+	@test -e $(@:%.o=%.d) && mv $(@:%.o=%.d) $(@:%.o=%.o.d)
+
+build/%.lo: src/%.c Makefile common.mk config.mk project.mk | build
+	$(_CC) $(COMMON_CPPFLAGS) $(COMMON_CPPFLAGS_SHARED) $(CPPFLAGS) \
+		$(COMMON_CFLAGS) $(COMMON_CFLAGS_SHARED) $(CFLAGS_$(<:src/%.c=%)) $(CFLAGS) \
+		-o $@ -c $<
+	@test -e $(@:%.lo=%.d) && mv $(@:%.lo=%.d) $(@:%.lo=%.lo.d)
 
 lib%.a:
 	$(_AR) $(AR) rc $@ $^
 	$(_RANLIB) $(RANLIB) $@
 
 lib%.so:
-	$(_CC) -o $@ $(COMMON_CFLAGS) $(CFLAGS) $(CFLAGS_SHARED) $(LDFLAGS_SHARED) \
+	$(_CC) -o $@ $(COMMON_CFLAGS) $(COMMON_CFLAGS_SHARED) $(CFLAGS) \
+		$(COMMON_LDFLAGS) $(COMMON_LDFLAGS_SHARED) $(LDFLAGS) \
 		-Wl,-soname,$@.0 $^
 
 # dependencies to try and make automatically
@@ -68,7 +85,7 @@ include project.mk
 -include $(DEPS)
 
 # binary-specific deps
-DEPS += $(BINS:%=%.d)
+DEPS += $(BLD_BINS:%=%.d)
 
 # install binaries
 $(DESTDIR)$(BINDIR)/%: %
@@ -95,11 +112,11 @@ $(DESTDIR)$(SHAREDIR)/doc/$(PROJECT_NAME)/%: %
 	$(_INST) install -D -m 644 $< $@
 
 # install *.md documentation
-$(DESTDIR)$(SHAREDIR)/doc/$(PROJECT_NAME)/%.md: doc/%.md | dummy%
+$(DESTDIR)$(SHAREDIR)/doc/$(PROJECT_NAME)/md/%.md: build/doc/%.md | dummy%
 	$(_INST) install -D -m 644 $< $@
 
 # dummy rule, so "install doc" takes precedence over "install *.md doc" whenver
-# there is an *.md file in the root. E.g. whenit has been /generated from/ the
+# there is an *.md file in the root. E.g. when it has been /generated from/ the
 # doc/*.md source file
 dummy%:
 	@:
@@ -111,30 +128,34 @@ $(DESTDIR)$(SHAREDIR)/$(PROJECT_NAME)/%: %
 
 install-bins: $(BINS:%=$(DESTDIR)$(BINDIR)/%)
 
-install-libs: $(SHARED_LIBS:%=$(DESTDIR)$(LIBDIR)/%) \
-	$(STATIC_LIBS:%=$(DESTDIR)$(LIBDIR)/$(PROJECT_NAME)/%)
+install-libs: $(STATIC_LIBS:%=$(DESTDIR)$(LIBDIR)/%) \
+	$(SHARED_LIBS:%=$(DESTDIR)$(LIBDIR)/%)
+
+install-priv: $(PRIV_STATIC_LIBS:%=$(DESTDIR)$(LIBDIR)/$(PROJECT_NAME)/%) \
+	$(PRIV_SHARED_LIBS:%=$(DESTDIR)$(LIBDIR)/$(PROJECT_NAME)/%) \
+	$(PRIV_BINS:%=$(DESTDIR)$(LIBDIR)/$(PROJECT_NAME)/%)
 
 install-docs: $(DOCS:%=$(DESTDIR)$(SHAREDIR)/doc/$(PROJECT_NAME)/%)
 
 install-data: $(DATA:%=$(DESTDIR)$(SHAREDIR)/$(PROJECT_NAME)/%)
 
-install: install-bins install-libs install-docs install-data
+install: install-bins install-libs install-priv install-docs install-data
 
 clean:
-	$(_CLEAN) rm -f $(CLEAN)
-	@rm -rf obj
+	$(_CLEAN) rm -rf build ; rm -f $(CLEAN)
 
 cleandeps:
 	$(_CLEAN) rm -f $(BUILD_DEPS)
 	$(foreach file,$(BUILD_DEPS),@make -C $(subst .built,,$(file)) clean)
 
 distclean: clean cleandeps
-	$(_CLEAN) rm -f config.mk include/config.h
+	$(_CLEAN) rm -f config.mk src/include/config.h
 
 repoclean: distclean
 	$(_CLEAN) rm -f configure common.mk
 
 _DIR = $(if $(V),,$(call say," DIR  ")$@;)
+_DOC = $(if $(V),,$(call say," DOC  ")$@;)
 _CP = $(if $(V),,$(call say,"  CP  ")$@;)
 _CC = $(if $(V),$(CC),$(call say,"  CC  ")$@;$(CC))
 _GEN = $(if $(V),,$(call say," GEN  ")$@;)
@@ -146,19 +167,23 @@ _INST = $(if $(V),,$(call say," INST ")$@;)
 
 
 $(BUILD_DEPS): Makefile common.mk
-	$(_MAKE) cd $(subst .built,,$@) && ln -sf ../comain \
-		&& test -e configure || ( make || true ) \
+	$(_MAKE) cd $(subst .built,,$@) \
 		&& ./configure --bindir=$(BINDIR) --libdir=$(LIBDIR) \
 		--incdir=$(INCDIR) --sharedir=$(SHAREDIR) \
+		$$(cd .. && cat meta/deps/$(subst .built,,$@)/configure) \
 		&& make
 	@touch $@
 
-$(BINS) $(SHARED_LIBS) $(STATIC_LIBS) $(OBJS): | $(BUILD_DEPS)
+$(BLD_STATIC_LIBS) $(BLD_SHARED_LIBS) $(BLD_BINS): | $(BUILD_DEPS)
+
+all: doc $(BLD_STATIC_LIBS) $(BLD_SHARED_LIBS) $(BLD_BINS)
+
+deps: $(BUILD_DEPS)
 
-all: $(BINS) $(SHARED_LIBS) $(STATIC_LIBS) $(BUILD_DEPS)
+doc: $(BLD_DOCS)
 
-$(BINS) $(TOOLS):
+$(BLD_BINS):
 	$(_CC) -o $@ $(COMMON_CFLAGS) $(CFLAGS) $(COMMON_LDFLAGS) $(LDFLAGS) $^
 
-.PHONY: install-bins install-libs install-docs install-data install \
+.PHONY: install-bins install-libs install-priv install-docs install-data install \
 	clean cleandeps distclean repoclean
diff --git a/configure b/configure
index 701d65a..eebfe3e 100755
--- a/configure
+++ b/configure
@@ -4,20 +4,25 @@
 
 usageoptions()
 {
-    local name=$1
+    local name=$2
     local desc
     local disabled
-    eval desc=\$optdesc$name
-    eval disabled=\$optdisabled$name
-    # FIXME space alignment isn't right here, unless $name resolves to 5 chars
-    echon "      --with-$name                  Enable $desc"
-    if test $disabled -eq 0; then
+    local invisible
+    local i
+    eval desc="\$optdesc$name"
+    eval disabled="\$optdisabled$name"
+    eval invisible="\$optinvisible$name"
+    if test $invisible -ne 0; then return; fi
+    i=$((23 - ${#name}))
+    printf "      --with-$name%${i}sEnable $desc"
+    if test "$disabled" -eq 0; then
         echo " [default]"
     else
         echo ""
     fi
-    echon "      --without-$name               Disable $desc"
-    if test $disabled -eq 1; then
+    i=$(($i - 3))
+    printf "      --without-$name%${i}sDisable $desc"
+    if test "$disabled" -eq 1; then
         echo " [default]"
     else
         echo ""
@@ -43,10 +48,15 @@ usage: $0 [OPTION..]
       --incdir=DIR                  Set include directory to DIR [PREFIX/include]
       --sharedir=DIR                Set share directory to DIR [PREFIX/share]
 $s
+
+      --no-shared                   Don't build shared libraries
+      --no-static                   Don't build static librairies
+
       --prefer-shared               Prefer to link shared libraires [default]
       --prefer-static               Prefer to link static libraires
       --set-shared=DEP              Use shared linking for dependency DEP
       --set-static=DEP              Use static linking for dependency DEP
+
 EOF
     foreach optname $nb_options usageoptions
         cat <<EOF
@@ -72,6 +82,8 @@ has_skalibs=0
 if test -d meta/deps/skalibs; then has_skalibs=1; fi
 sysdeps=
 prefer=shared
+noshared=0
+nostatic=0
 
 CVARS=
 CPPFLAGS=
@@ -80,6 +92,9 @@ LDFLAGS=
 COMMON_CPPFLAGS=
 COMMON_CFLAGS=
 COMMON_LDFLAGS=
+COMMON_CPPFLAGS_SHARED=
+COMMON_CFLAGS_SHARED=
+COMMON_LDFLAGS_SHARED=
 VPATHS="# this will handle prefer or set shared/static"
 BUILD_DEPS=
 
@@ -105,7 +120,9 @@ for arg ; do
 
         --sysdeps=*) if test $has_skalibs -eq 1; then sysdeps=${arg#*=};
         else error 1 "invalid option '$arg'"; fi;;
-        --prefer-shared) ;;
+        --no-shared) noshared=1 ;;
+        --no-static) nostatic=1 ;;
+        --prefer-shared) prefer=shared ;;
         --prefer-static) prefer=static ;;
         --set-shared=*) eval "link${arg#*=}=1" ;;
         --set-static=*) eval "link${arg#*=}=2" ;;
@@ -133,7 +150,10 @@ incdir="$(echo $incdir | sed 's/\/\+/\//g')"
 sharedir="$(echo $sharedir | sed 's/\/\+/\//g')"
 sysdeps="$(echo $sysdeps | sed 's/\/\+/\//g')"
 
+# pass 2, to be able to use state of other options as selection
+setoptionsdefault
 
+cprefix=$(sanitize "$name")
 
 procneeddep()
 {
@@ -146,9 +166,10 @@ procneeddep()
 
 procdep()
 {
-    local dep="$1"
+    local idx=$1
+    local dep="$2"
     local depname="${dep##*/}"
-    local cpnt="$2"
+    local cpnt="$3"
     local link=0
     local needver="$(cat $dep/version 2>/dev/null)"
     local include="$depname"
@@ -169,16 +190,16 @@ procdep()
 
     if procneeddep "$depname"; then
         echo "  -> $type $depname not needed; SKipping"
-        nbdeps=$(($nbdeps+1))
-        eval dep$nbdeps=$depname
-        eval lib$depname=
+        eval idx$depname=$1
+        eval after$depname=0
         return
     fi
 
     if test -d "./$depname"; then
         found=1
         internal=1
-        if test -e "$dep/static"; then link=2; fi
+        # internal deps defaults to static linking
+        link=2
         path="include"
         if test -e "$dep/incdir"; then path="$(cat $dep/incdir)"; fi
         path="$depname/$path"
@@ -249,8 +270,9 @@ procdep()
     fi
 
     if test $cpnt -ne 1; then
-        nbdeps=$(($nbdeps+1))
-        eval dep$nbdeps=$depname
+        eval idx$depname=$1
+        eval after$depname=0
+        eval "library$depname=$library"
 
         case $link in
             0)
@@ -271,7 +293,6 @@ vpath lib$library.so $vpathso"
 vpath lib$library.a $vpatha"
                 ;;
         esac
-        eval lib$depname=-l$library
 
         if test $internal -ne 1; then
             path="$incdir/$include"
@@ -299,38 +320,29 @@ Configuring $name $version :
  => Checking requirements...
 EOF
 
-setoptionsflags()
-{
-    local name=$1
-    local cvar
-    local disabled
-    eval cvar=\$optcvar$name
-    eval disabled=\$optdisabled$name
-    if test $disabled -eq 1; then 
-    CVARS="$CVARS
-#undef $cvar"
-        return
-    fi
-    local cppflags
-    local cflags
-    local ldflags
-    eval cppflags=\"\$optcppflags$name\"
-    eval cflags=\"\$optcflags$name\"
-    eval ldflags=\"\$optldflags$name\"
-    CVARS="$CVARS
-#define $cvar 1"
-    if test -n "$cppflags"; then COMMON_CPPFLAGS="$COMMON_CPPFLAGS $cppflags"; fi
-    if test -n "$cflags"; then COMMON_CFLAGS="$COMMON_CFLAGS $cflags"; fi
-    if test -n "$ldflags"; then COMMON_LDFLAGS="$COMMON_LDFLAGS $ldflags"; fi
-}
-
 loaddeps
-foreach optname $nb_options setoptionsflags
-
-nbdeps=0
 foreach "cpnt" $nb_cpnt procdep 1
 foreach "deps" $nb_deps procdep 0
 
+setdepsafters()
+{
+    local dep
+    for dep in meta/deps/*/after; do
+        if test "$dep" = "meta/deps/*/after"; then break; fi
+        local depname="$(expr substr "$dep" 11 $((${#dep} - 16)))"
+        local depidx=$(($(eval echo \$idx$depname) + 0))
+        local after=$(($(eval echo \$after$depname) + 0))
+        local name
+        for name in meta/deps/$depname/after/*; do
+            name=${name##*/}
+            local idx=$(eval echo \$idx$name)
+            after=$(($after | (1 << ($idx - 1))))
+        done
+        eval "after$depname=$after"
+    done
+}
+setdepsafters
+
 if test -n "$fail"; then
     error 2 "Cannot continue: $fail"
 fi
@@ -363,12 +375,26 @@ tryflag()
     fi
 }
 
+tryldflag()
+{
+    echon "  -> Checking whether linker accepts $2.."
+    echo "typedef int x;" > "tmp.c"
+    if $CC $CPPFLAGS $CFLAGS $LDFLAGS -nostdlib "$2" -o "tmp.o" "tmp.c" > /dev/null 2>&1; then
+        echo ".. yes"
+        eval "$1=\"\${$1} \$2\""
+        eval "$1=\${$1# }"
+        return 0
+    else
+        echo ".. no"
+        return 1
+    fi
+}
+
 trap 'rm -f tmp.c tmp.o config.mk.tmp config.h.tmp' EXIT ABRT INT QUIT TERM HUP
 
 echo " => Checking compiler..."
 
 echon "  -> Looking for a C compiler.."
-trycmd CC "$CC"
 trycmd CC "gcc"
 trycmd CC "clang"
 trycmd CC "cc"
@@ -378,9 +404,7 @@ if test -z "$CC"; then
 else
     echo ".. $CC"
 fi
-trycmd AR "$AR"
 trycmd AR "ar"
-trycmd RANLIB "$RANLIB"
 trycmd RANLIB "ranlib"
 
 ENDIAN=0
@@ -414,17 +438,25 @@ if test $has_skalibs -eq 1; then
 fi
 
 echo " => Testing C compiler..."
-tryflag CFLAGS -std=c99
-tryflag CFLAGS -fomit-frame-pointer
-tryflag CFLAGS -fno-exceptions
-tryflag CFLAGS -fno-unwind-tables
-tryflag CFLAGS -fno-asynchronous-unwind-tables
-tryflag CPPFLAGS -Werror=implicit-function-declaration
-tryflag CPPFLAGS -Werror=implicit-int
-tryflag CPPFLAGS -Werror=pointer-sign
-tryflag CPPFLAGS -Werror=pointer-arith
-tryflag CFLAGS -ffunction-sections
-tryflag CFLAGS -fdata-sections
+tryflag COMMON_CFLAGS -std=c99
+tryflag COMMON_CFLAGS -fomit-frame-pointer
+tryflag COMMON_CFLAGS -fno-exceptions
+tryflag COMMON_CFLAGS -fno-unwind-tables
+tryflag COMMON_CFLAGS -fno-asynchronous-unwind-tables
+tryflag COMMON_CPPFLAGS -Werror=implicit-function-declaration
+tryflag COMMON_CPPFLAGS -Werror=implicit-int
+tryflag COMMON_CPPFLAGS -Werror=pointer-sign
+tryflag COMMON_CPPFLAGS -Werror=pointer-arith
+tryflag COMMON_CPPFLAGS -Wno-unused-value
+tryflag COMMON_CFLAGS -ffunction-sections
+tryflag COMMON_CFLAGS -fdata-sections
+tryldflag COMMON_LDFLAGS -Wl,--as-needed
+tryldflag COMMON_LDFLAGS -Wl,--sort-section=alignment
+tryldflag COMMON_LDFLAGS -Wl,--sort-common
+tryflag COMMON_CPPFLAGS_SHARED -fPIC
+tryldflag COMMON_LDFLAGS_SHARED -Wl,--hash-style=gnu
+tryldflag COMMON_LDFLAGS_SHARED -nostartfiles
+
 
 echo " => Paths :"
 cat <<EOF
@@ -434,26 +466,102 @@ cat <<EOF
   -> sharedir : $sharedir
 EOF
 
+excl=
 options=
+optleft=0
+
 showoption()
 {
-    local name=$1
+    local idx=$1
+    local name=$2
     local disabled
+    local invisible
+    local cvar
     eval disabled=\$optdisabled$name
-    if test $disabled -eq 0; then
+    eval invisible=\$optinvisible$name
+    eval cvar=\$optcvar$name
+    if test $disabled -eq 1; then
+        CVARS="$CVARS
+#undef ${cprefix}_$cvar"
+        if test -e meta/options/$name/objs; then
+            while IFS= read -r line; do
+                line="$(printf $line | sed -e 's/\//\\\//g')"
+                excl="-e s/build\\/$line//g $excl"
+                if test "$(expr substr "$line" $((${#line}-1)) 2)" = ".o"; then
+                    line="$(expr substr "$line" 1 $((${#line}-2))).lo"
+                    excl="-e s/build\\/$line//g $excl"
+                fi
+            done < meta/options/$name/objs
+        fi
+    else
+        CVARS="$CVARS
+#define ${cprefix}_$cvar 1"
+        optleft=$(($optleft | (1 << ($idx - 1))))
         local desc
         eval desc=\$optdesc$name
-        options="$options
+        if test -n "$desc"; then
+            options="$options
   -> $name : $desc"
+        fi
     fi
 }
+
 if test $nb_options -gt 0; then
-    foreach optname $nb_options showoption
+    foreach "optname" $nb_options showoption
     if test -n "$options"; then
         echo " => Options :$options"
     fi
 fi
 
+setoptionflags()
+{
+    local name=$1
+    local cppflags
+    local cflags
+    local ldflags
+    eval cppflags=\"\$optcppflags$name\"
+    eval cflags=\"\$optcflags$name\"
+    eval ldflags=\"\$optldflags$name\"
+    if test -n "$cppflags"; then COMMON_CPPFLAGS="$COMMON_CPPFLAGS $cppflags"; fi
+    if test -n "$cflags"; then COMMON_CFLAGS="$COMMON_CFLAGS $cflags"; fi
+    if test -n "$ldflags"; then COMMON_LDFLAGS="$COMMON_LDFLAGS $ldflags"; fi
+}
+
+setoptionsflags()
+{
+    local i=1
+    while test $optleft -gt 0; do
+        local n=$((1 << ($i - 1)))
+        if test $(($optleft & $n)) -gt 0; then
+            local name="$(eval echo \$optname$i)"
+            local after=$((($(eval echo \$optafter$name) + 0) & $optleft))
+            eval "optafter$name=$after"
+            if test $after -eq 0; then
+                setoptionflags "$name"
+                optleft=$(($optleft & ~$n))
+            fi
+        fi
+        if test $i -eq $nb_options; then
+            i=1
+        else
+            i=$(($i + 1))
+        fi
+    done
+}
+
+setoptionsflags
+
+
+if test $(($noshared + $nostatic)) -gt 0; then
+    echo " => Librairies"
+    if test $noshared -eq 1; then
+        echo "  -> Don't build shared librairies"
+    fi
+    if test $nostatic -eq 1; then
+        echo "  -> Don't build static librairies"
+    fi
+fi
+
 echo " => Generating files..."
 
 echo "  -> Generating config.mk..."
@@ -483,103 +591,110 @@ else
 fi
 echo $VPATHS
 
-setdep()
-{
-    local depname="$1"
-    if test "$line" != "$depname"; then return; fi
-    line="$(eval "echo \$lib$depname")"
-}
-
 echo "# dependencies"
 echo ".SECONDEXPANSION:"
-if test -d meta/libs; then
-    for file in meta/libs/*; do
-        exec 4<"$file"
-        depsA=
-        depsSO=
-        while IFS= read -r line <&4; do
-            # ignore comment
-            if test "$(expr substr "$line" 1 1)" = "#"; then continue; fi
-            # +name=obj means only add obj is option name is set
-            if test "$(expr substr "$line" 1 1)" = "+"; then
-                opt="$(echo $line | cut -d= -f1)"
-                opt="$(expr substr "$opt" 2 ${#opt})"
-                eval disabled=\$optdisabled$opt
-                # empty $disabled means an option that doesn't exist!
-                if test -z "$disabled"; then error 2 "Unknown option '$opt' in $line"; fi
-                if test $disabled -eq 1; then continue; fi
-                line="$(echo $line | cut -d= -f2)"
+BLD_STATIC_LIBS=
+BLD_SHARED_LIBS=
+BLD_BINS=
+BLD_DOCS=
+setupobjs()
+{
+    local docs_objs
+    local d
+    # FIXME find's -printf isn't POSIX
+    for d in src/*; do
+        local name="$(expr substr "$d" 5 ${#d})"
+        if test "$name" = "*" || test "$name" = "include"; then continue; fi
+        local objs
+        if test "$name" = "doc"; then
+            objs="$(find "$d" -type f -name '*.md')"
+            docs_objs="$(echo "$objs" \
+                | sed -e 's/^src\/doc\(.*\/\)\(.\+\.md\)$/build\/doc\/\2: src\/doc\1\2/g')"
+
+            objs="$(echo "$objs" \
+                | sed -e 's/^.\+\(\/.\+\.md\)$/build\/doc\1/g' \
+                | tr '\n' ' ')"
+            BLD_DOCS="$objs $BLD_DOCS"
+            continue
+        fi
+        objs="$(find "$d" -type f -name '*.[cS]' | sed -e s/^src/build/g \
+            -e s/\\.c$/.o/g -e s/\\.S/.o/g $excl | tr '\n' ' ')"
+        objs="$objs $(find "$d" -type l -printf "build/%l ")"
+
+        local libs=
+        local deps=0
+        local depname
+        local tmp=configure-$PPID-$$
+        mkfifo $tmp
+        find "$d" -type f -name '+*' > $tmp  &
+        while IFS= read -r depname; do
+            depname=${depname##*/+}
+            local idx=$(($(eval echo \$idx$depname) + 0))
+            deps=$(($deps | (1 << ($idx - 1))))
+        done < $tmp
+        rm -r $tmp
+        local i=1
+        while test $deps -gt 0; do
+            local n=$((1 << ($i - 1)))
+            if test $(($deps & $n)) -gt 0; then
+                depname=$(eval echo \$deps$i)
+                depname=${depname##*/}
+                local after=$((($(eval echo \$after$depname) + 0) & $deps))
+                if test $after -eq 0; then
+                    local library="$(eval echo \$library$depname)"
+                    libs="$libs -l$library"
+                    deps=$(($deps & ~$n))
+                fi
             fi
-            # replace depname by -llibdeb (e.g. skalibs by -lskarnet)
-            foreach "dep" $nbdeps setdep
-
-            offset=$((${#line}-1))
-            # if a variable - e.g. $$(FOO) - then use $$(FOO_so) for shared lib
-            if test "$(expr substr "$line" ${#line} 1)" = ")"; then
-                lineso="$(expr substr "$line" 1 $offset)_so)"
-            # if a .o then use .lo for shared lib
-            elif test "$(expr substr "$line" $offset 2)" = ".o"; then
-                lineso="$(expr substr "$line" 1 $(($offset-1))).lo"
+            if test $i -eq $nb_deps; then
+                i=1
             else
-                lineso=
+                i=$(($i + 1))
             fi
-            # if .O then use .o always (shared lib also)
-            if test "$(expr substr "$line" $offset 2)" = ".O"; then
-                line="$(expr substr "$line" 1 $(($offset-1))).o"
-            fi
-            # not special for shared lib, so use the same
-            if test -z "$lineso"; then
-                lineso="$line"
-            fi
-            depsA="$depsA $line"
-            depsSO="$depsSO $lineso"
         done
-        exec 4<&-
-        echo lib${file##*/}.a: $depsA
-        echo lib${file##*/}.so: $depsSO
-    done
-fi
 
-if test -d meta/bins; then
-    for file in meta/bins/*; do
-        exec 4<"$file"
-        deps=
-        while IFS= read -r line <&4; do
-            # ignore comment
-            if test "$(expr substr "$line" 1 1)" = "#"; then continue; fi
-            # +name=obj means only add obj is option name is set
-            if test "$(expr substr "$line" 1 1)" = "+"; then
-                opt="$(echo $line | cut -d= -f1)"
-                opt="$(expr substr "$opt" 2 ${#opt})"
-                eval disabled=\$optdisabled$opt
-                # empty $disabled means an option that doesn't exist!
-                if test -z "$disabled"; then error 2 "Unknown option '$opt' in $line"; fi
-                if test $disabled -eq 1; then continue; fi
-                line="$(echo $line | cut -d= -f2)"
+        if test "$(expr substr "$name" 1 3)" = "lib"; then
+            local l="$(expr substr "$name" 4 ${#name})"
+            COMMON_CPPFLAGS="-isystem src/$name/include $COMMON_CPPFLAGS"
+            if test $nostatic -eq 0; then
+                echo "$name.a: $objs"
+                BLD_STATIC_LIBS="$name.a $BLD_STATIC_LIBS"
             fi
-            # replace depname by -llibdeb (e.g. skalibs by -lskarnet)
-            foreach "dep" $nbdeps setdep
-
-            offset=$((${#line}-1))
-            # if .O then use .o always
-            if test "$(expr substr "$line" $offset 2)" = ".O"; then
-                line="$(expr substr "$line" 1 $(($offset-1))).o"
+            if test $noshared -eq 0; then
+                objs="$(find "$d" -type f -name '*.[cS]' | sed -e s/^src/build/g \
+                    -e s/\\.c$/.lo/g -e s/\\.S/.o/g $excl | tr '\n' ' ')"
+                objs="$objs $(find "$d" -type l -printf "build/%l " | sed -e s/\\.o/.lo/g)"
+                echo "$name.so: $objs $libs"
+                BLD_SHARED_LIBS="$name.so $BLD_SHARED_LIBS"
             fi
-            deps="$deps $line"
-        done
-        exec 4<&-
-        echo ${file##*/}: $deps
+        else
+            BLD_BINS="$name $BLD_BINS"
+            echo "$name: $objs $libs"
+        fi
     done
-fi
+    echo "# docs"
+    echo "$docs_objs"
+}
+setupobjs
 
 cat <<EOF
+
+# build targets
+BLD_DOCS = $BLD_DOCS
+BLD_STATIC_LIBS = $BLD_STATIC_LIBS
+BLD_SHARED_LIBS = $BLD_SHARED_LIBS
+BLD_BINS = $BLD_BINS
+
 # some flags
 COMMON_CPPFLAGS += $COMMON_CPPFLAGS
-COMMON_CFLAGS += $COMMON_CFLAGS
-COMMON_LDFLAGS += $COMMON_LDFLAGS
-CPPFLAGS = $CPPFLAGS
-CFLAGS = $CFLAGS
-LDFLAGS = $LDFLAGS
+COMMON_CFLAGS   += $COMMON_CFLAGS
+COMMON_LDFLAGS  += $COMMON_LDFLAGS
+COMMON_CPPFLAGS_SHARED += $COMMON_CPPFLAGS_SHARED
+COMMON_CFLAGS_SHARED   += $COMMON_CFLAGS_SHARED
+COMMON_LDFLAGS_SHARED  += $COMMON_LDFLAGS_SHARED
+CPPFLAGS += $CPPFLAGS
+CFLAGS   += $CFLAGS
+LDFLAGS  += $LDFLAGS
 
 # special dependencies we try to make automatically
 BUILD_DEPS = $BUILD_DEPS
@@ -600,7 +715,6 @@ mv -f config.mk.tmp config.mk
 
 
 echo "  -> Generating config.h..."
-prefix=$(sanitize "$name")
 
 url="$(cat meta/site 2>/dev/null)"
 if test -z "$url"; then url="https://lila.oss"; fi
@@ -611,27 +725,28 @@ cat <<EOF
  * $0 $@
  * Any changes you make in here will be lost on the next ./configure
  */
-#ifndef ${prefix}_CONFIG_H
-#define ${prefix}_CONFIG_H
-
-#define ${prefix}_CURYEAR   "$(date +%Y)"
-#define ${prefix}_AUTHOR    "Olivier Brunel"
-#define ${prefix}_VERSION   "$version"
-#define ${prefix}_URL       "$url"
-#define ${prefix}_LIBDIR    "$libdir/$name"
-#define ${prefix}_SHAREDIR  "$sharedir/$name"
+#ifndef ${cprefix}_CONFIG_H
+#define ${cprefix}_CONFIG_H
+
+#define ${cprefix}_CURYEAR   "$(date +%Y)"
+#define ${cprefix}_AUTHOR    "Olivier Brunel"
+#define ${cprefix}_VERSION   "$version"
+#define ${cprefix}_URL       "$url"
+#define ${cprefix}_LIBDIR    "$libdir/$name"
+#define ${cprefix}_SHAREDIR  "$sharedir/$name"
 $CVARS
 
-#define ${prefix}_LITTLE    1234
-#define ${prefix}_BIG       4321
-#define ${prefix}_PDP       3412
-#define ${prefix}_ENDIAN    ${prefix}_$ENDIAN
+#define ${cprefix}_LITTLE    1234
+#define ${cprefix}_BIG       4321
+#define ${cprefix}_PDP       3412
+#define ${cprefix}_ENDIAN    ${cprefix}_$ENDIAN
 
-#endif /* ${prefix}_CONFIG_H */
+#endif /* ${cprefix}_CONFIG_H */
 EOF
 
 exec 1>&5 5>&-
-mv -f config.h.tmp include/config.h
+if ! test -d src/include; then mkdir src/include; fi
+mv -f config.h.tmp src/include/config.h
 
 
 echo "done."
diff --git a/getdeps b/getdeps
index 11c33ea..1b2ecfd 100755
--- a/getdeps
+++ b/getdeps
@@ -26,7 +26,7 @@ EOF
 
 showdep()
 {
-    local dep=$1
+    local dep=$2
     local depname="${dep##*/}"
     local needed
     eval needed=\"\$need$depname\"
@@ -51,9 +51,9 @@ list()
 
 getdep()
 {
-    local dep=$1
+    local dep=$2
     local depname="${dep##*/}"
-    local intonly=$2
+    local intonly=$3
     if test $intonly -eq 1 && test ! -e "$dep/files"; then return; fi
     if test -e "$depname"; then
         warn "cannot clone $depname: file already exists"
diff --git a/init b/init
index 32958f5..6c7f0c4 100755
--- a/init
+++ b/init
@@ -18,7 +18,7 @@ fi
 
 run cp -n comain/Makefile Makefile
 run cp -n comain/project.mk.tpl project.mk
-run mkdir include src
+run mkdir src
 run cp -n comain/meta/README.git meta
 run echo https://lila.oss/$name > meta/site
 run echo git://lila.oss/$name.git > meta/git
@@ -33,7 +33,9 @@ run touch meta/deps/comain/cpnt
 run cp -n comain/meta/version meta/deps/comain/version
 run cp -n comain/meta/git meta/deps/comain/git
 run mkdir meta/options
-run ln -sf ../../comain/meta/options/debug meta/options
+for opt in comain/meta/options/*; do
+    run ln -s ../../$opt meta/options
+done
 run ln -sf meta/README.git README
 run ln -sf meta/AUTHORS
 run ln -sf meta/COPYING
@@ -44,10 +46,8 @@ run cat > .gitignore <<EOF
 /configure
 /common.mk
 /config.mk
-/include/config.h
-*.o
-*.lo
-*.d
+/src/include/config.h
+/build
 EOF
 if test -e .git; then error 2 "Already a git repo (.git exist)"; fi
 git init .
diff --git a/libcomain b/libcomain
index b5d50c4..1c461c5 100644
--- a/libcomain
+++ b/libcomain
@@ -28,7 +28,7 @@ error()
 
 warn()
 {
-    echo "$0: $@" >&2
+    echo "$0: warning: $@" >&2
 }
 
 upper()
@@ -72,11 +72,12 @@ foreach()
     local nb="$2"
     local fn="$3"
     shift 3
+    local i=1
     nb=$(($nb+0))
 
-    while test $nb -gt 0; do
-        "$fn" "$(eval "echo \$$name$nb")" "$@"
-        nb=$(($nb-1))
+    while test $i -le $nb; do
+        "$fn" $i "$(eval "echo \$$name$i")" "$@"
+        i=$(($i+1))
     done
 }
 
@@ -140,38 +141,122 @@ loadoptions()
     local cflags=
     local ldflags=
     local disabled=
+    local invisible=
     for name in meta/options/*; do
         name=${name##*/}
+        if test "$name" != "$(echo $name | tr -cd '[[:alnum:]]')"; then
+            warn "invalid option name: $name"
+            continue
+        fi
+        if test ! -r meta/options/$name/desc; then
+            warn "decription missing for option $name"
+            continue
+        fi
         desc="$(cat meta/options/$name/desc 2>/dev/null)"
-        if test -z "$desc"; then return 0; fi
+        if test -z "$desc" || test -e meta/options/$name/invisible; then
+            invisible=1
+        else
+            invisible=0
+        fi
         cvar="$(cat meta/options/$name/cvar 2>/dev/null)"
         if test -z "$cvar"; then cvar="WITH_$(sanitize $name)"; fi
         cflags="$(cat meta/options/$name/cflags 2>/dev/null)"
         ldflags="$(cat meta/options/$name/ldflags 2>/dev/null)"
-        disabled=0
-        if test -e meta/options/$name/disabled; then disabled=1; fi
+        disabled=-1
+        if test -e meta/options/$name/default; then
+            local s="$(cat meta/options/$name/default)"
+            if test "$s" = "0"; then
+                disabled=1
+            elif test "$s" = "1"; then
+                disabled=0
+            else
+                warn "invalid default value for option $name ($s)"
+            fi
+        fi
         dep="$(cat meta/options/$name/dep 2>/dev/null)"
 
         nb_options=$(($nb_options+1))
-        eval optname$nb_options=$name
-        eval optdesc$name=\"$desc\"
-        eval optcvar$name=\"$cvar\"
-        eval optcflags$name=\"$cflags\"
-        eval optldflags$name=\"$ldflags\"
-        eval optdisabled$name=$disabled
+        eval "optname$nb_options"="$name"
+        eval "optdesc$name"=\"$desc\"
+        eval "optcvar$name"=\"$cvar\"
+        eval "optcflags$name"=\"$cflags\"
+        eval "optldflags$name"=\"$ldflags\"
+        eval "optdisabled$name"=$disabled
+        eval "optinvisible$name"=$invisible
+        eval "optafter$name"=0
         local tmp
         eval tmp=\"\$need$dep\"
         if test -z "$tmp"; then
-            eval need$dep=$name
+            eval need$dep="$name"
         elif test "$tmp" = "1"; then
-            eval need$dep=$name
+            eval need$dep="$name"
         else
             eval need$dep=\"$\need$dep $name\"
         fi
     done
+    local opt=
+    for opt in meta/options/*/after; do
+        if test "$opt" = "meta/options/*/after"; then break; fi
+        opt=$(expr substr "$opt" 14 $((${#opt} - 19)))
+        if test "$opt" != "$(echo $opt | tr -cd '[[:alnum:]]')"; then
+            continue
+        fi
+        local after=0
+        for name in meta/options/$opt/after/*; do
+            if test "$name" = "meta/options/$opt/after/*"; then break; fi
+            name=${name##*/}
+            local idx=0
+            local n=$nb_options
+            while test $n -gt 0; do
+                if test "$(eval echo \$optname$n)" = "$name"; then
+                    idx=$n
+                    n=0
+                fi
+                n=$((n - 1))
+            done
+            if test $idx -eq 0; then continue; fi
+            n=$((1 << $idx - 1))
+            after=$(($after | $n))
+        done
+        eval "optafter$opt"=$after
+    done
     return 1
 }
 
+setoptenv()
+{
+    local name=$2
+    local disabled
+    eval disabled=\$optdisabled$name
+    if test $disabled -eq 1; then
+        vars="WITH_OPT_$name=0 $vars"
+    elif test $disabled -eq 0; then
+        vars="WITH_OPT_$name=1 $vars"
+    fi
+}
+
+setoptdef()
+{
+    local name=$2
+    local disabled
+    eval disabled=\$optdisabled$name
+    if test $disabled -eq -1; then
+        local vars=
+        foreach "optname" $nb_options setoptenv
+        if env $vars meta/options/$name/isdefault 2>/dev/null; then
+            disabled=0
+        else
+            disabled=1
+        fi
+        eval "optdisabled$name"=$disabled
+    fi
+}
+
+setoptionsdefault()
+{
+    foreach "optname" $nb_options setoptdef
+}
+
 optexist()
 {
     if test -e meta/options/"$1"; then echo 1; else echo 0; fi
@@ -179,9 +264,9 @@ optexist()
 
 setneeddep()
 {
-    local dep=$1
+    local dep=$2
     local depname="${dep##*/}"
-    local optname=$2
+    local optname=$3
     local tmp
     eval tmp=\"\$need$depname\"
     tmp="$(echo $tmp | sed s/$optname//)"
@@ -190,7 +275,7 @@ setneeddep()
 
 setoptionsdep()
 {
-    local name=$1
+    local name=$2
     local disabled
     eval disabled=\$optdisabled$name
     if test $disabled -eq 1; then
diff --git a/meta/deps.tpl/limb/configure b/meta/deps.tpl/limb/configure
index e69de29..4928a4a 100644
--- a/meta/deps.tpl/limb/configure
+++ b/meta/deps.tpl/limb/configure
@@ -0,0 +1 @@
+--no-shared
diff --git a/meta/deps.tpl/limb/incdir b/meta/deps.tpl/limb/incdir
new file mode 100644
index 0000000..30b990f
--- /dev/null
+++ b/meta/deps.tpl/limb/incdir
@@ -0,0 +1 @@
+src/liblimb/include
diff --git a/meta/deps.tpl/limb/static b/meta/deps.tpl/skalibs/after/limb
similarity index 100%
rename from meta/deps.tpl/limb/static
rename to meta/deps.tpl/skalibs/after/limb
diff --git a/meta/deps.tpl/skalibs/configure b/meta/deps.tpl/skalibs/configure
new file mode 100644
index 0000000..5d55893
--- /dev/null
+++ b/meta/deps.tpl/skalibs/configure
@@ -0,0 +1 @@
+--disable-shared
diff --git a/meta/options/debug/disabled b/meta/options/debug/after/optimize
similarity index 100%
rename from meta/options/debug/disabled
rename to meta/options/debug/after/optimize
diff --git a/meta/options/debug/default b/meta/options/debug/default
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/meta/options/debug/default
@@ -0,0 +1 @@
+0
diff --git a/meta/options/optimize/cflags b/meta/options/optimize/cflags
new file mode 100644
index 0000000..d15a710
--- /dev/null
+++ b/meta/options/optimize/cflags
@@ -0,0 +1 @@
+-O3
diff --git a/meta/options/optimize/default b/meta/options/optimize/default
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/meta/options/optimize/default
@@ -0,0 +1 @@
+1
diff --git a/meta/options/optimize/desc b/meta/options/optimize/desc
new file mode 100644
index 0000000..cade659
--- /dev/null
+++ b/meta/options/optimize/desc
@@ -0,0 +1 @@
+compilation optimizations
diff --git a/meta/options/optimizeOff/cflags b/meta/options/optimizeOff/cflags
new file mode 100644
index 0000000..e2571f8
--- /dev/null
+++ b/meta/options/optimizeOff/cflags
@@ -0,0 +1 @@
+-O0
diff --git a/meta/options/optimizeOff/desc b/meta/options/optimizeOff/desc
new file mode 100644
index 0000000..44bdaae
--- /dev/null
+++ b/meta/options/optimizeOff/desc
@@ -0,0 +1 @@
+disable compilation optimizations
diff --git a/meta/options/optimizeOff/invisible b/meta/options/optimizeOff/invisible
new file mode 100644
index 0000000..e69de29
diff --git a/meta/options/optimizeOff/isdefault b/meta/options/optimizeOff/isdefault
new file mode 100755
index 0000000..3570b06
--- /dev/null
+++ b/meta/options/optimizeOff/isdefault
@@ -0,0 +1,5 @@
+#!/bin/sh
+if test -n "$WITH_OPT_optimize" && test "$WITH_OPT_optimize" -eq 1; then
+    exit 1
+fi
+exit 0
diff --git a/meta/options/warnings/cflags b/meta/options/warnings/cflags
new file mode 100644
index 0000000..6492588
--- /dev/null
+++ b/meta/options/warnings/cflags
@@ -0,0 +1 @@
+-Wall -Wextra
diff --git a/meta/options/warnings/default b/meta/options/warnings/default
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/meta/options/warnings/default
@@ -0,0 +1 @@
+1
diff --git a/meta/options/warnings/desc b/meta/options/warnings/desc
new file mode 100644
index 0000000..7357b48
--- /dev/null
+++ b/meta/options/warnings/desc
@@ -0,0 +1 @@
+compilation warnings
diff --git a/mkbuild b/mkbuild
new file mode 100755
index 0000000..c0373c6
--- /dev/null
+++ b/mkbuild
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+if test ! -e build; then mkdir build; fi
+
+for dir in src/*; do
+    if test "$dir" = "src/*" || test "$dir" = "src/include"; then continue; fi
+    find "$dir" -name "include" -prune -o -type d | while read -r d; do
+        d="build/$(expr substr "$d" 5 ${#d})"
+        if test ! -d "$d"; then mkdir "$d"; fi
+    done
+done
diff --git a/mkdoc b/mkdoc
new file mode 100755
index 0000000..15d8d2d
--- /dev/null
+++ b/mkdoc
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+src="$1"
+dst="$2"
+
+awk 'BEGIN { FS="[ >]" }
+{ if ($0 ~ /^<inc (.+)>$/) { system("cat src/doc/include/"$2) }
+  else { print } } ' "$src" > "$dst"
diff --git a/mkreadme b/mkreadme
index ade7be5..63d686e 100755
--- a/mkreadme
+++ b/mkreadme
@@ -99,7 +99,7 @@ fi
 LINKS=
 echodep()
 {
-    local dep="$1"
+    local dep="$2"
     local depname="${dep##*/}"
     local name="$depname"
     local needed
diff --git a/mktarball b/mktarball
index c576b8a..f1dae03 100755
--- a/mktarball
+++ b/mktarball
@@ -13,9 +13,9 @@ run git worktree add $tb -b tarball master
 
 adddep()
 {
-    local dep=$1
+    local dep=$2
     local depname="${dep##*/}"
-    local intonly=$2
+    local intonly=$3
     if test $intonly -eq 1 && test ! -e "$dep/files"; then return; fi
 
     local ref="$(cat $dep/ref 2>/dev/null)"
@@ -45,9 +45,9 @@ run tar -cJp --owner=0 --group=0 --numeric-owner --exclude=".git"* -f $tb.tar.xz
 echo " => Clean up..."
 deldep()
 {
-    local dep=$1
+    local dep=$2
     local depname="${dep##*/}"
-    local intonly=$2
+    local intonly=$3
     if test $intonly -eq 1 && test ! -e "$dep/files"; then return; fi
 
     local ref="$(cat $dep/ref 2>/dev/null)"
diff --git a/project.mk.tpl b/project.mk.tpl
index cd9bd93..0d8c07b 100644
--- a/project.mk.tpl
+++ b/project.mk.tpl
@@ -1,7 +1,7 @@
 $(error You need to edit project.mk)
 
-# binaries: -- don't forget to set meta/bins/{bin1,bin2,...} with all deps & .o files
+# binaries
 BINS = 
 
-# librairies -- don't forget to set meta/libs{lib1,lib2,...} with all deps & .o files
+# librairies
 LIBS =