diff --git a/make/examples/aterm/aterm/default.nix b/make/examples/aterm/aterm/default.nix new file mode 100644 index 0000000000..8b139219e9 --- /dev/null +++ b/make/examples/aterm/aterm/default.nix @@ -0,0 +1,34 @@ +{sharedLib ? true}: + +rec { + + inherit (import ../../../lib) compileC makeLibrary; + + sources = [ + ./afun.c + ./aterm.c + ./bafio.c + ./byteio.c + ./gc.c + ./hash.c + ./list.c + ./make.c + ./md5c.c + ./memory.c + ./tafio.c + ./version.c + ]; + + compile = fn: compileC { + main = fn; + localIncludes = "auto"; + forSharedLib = sharedLib; + }; + + libATerm = makeLibrary { + libraryName = "ATerm"; + objects = map compile sources; + inherit sharedLib; + }; + +} diff --git a/make/examples/aterm/default.nix b/make/examples/aterm/default.nix new file mode 100644 index 0000000000..edaac40aa4 --- /dev/null +++ b/make/examples/aterm/default.nix @@ -0,0 +1 @@ +import test/default.nix \ No newline at end of file diff --git a/make/examples/aterm/test/default.nix b/make/examples/aterm/test/default.nix new file mode 100644 index 0000000000..b7a9dd3619 --- /dev/null +++ b/make/examples/aterm/test/default.nix @@ -0,0 +1,18 @@ +let { + + inherit (import ../../../lib) compileC link; + + inherit (import ../aterm {}) libATerm; + + compile = fn: compileC { + main = fn; + localIncludes = "auto"; + cFlags = "-I../aterm"; + }; + + fib = link {objects = compile ./fib.c; libraries = libATerm;}; + + primes = link {objects = compile ./primes.c; libraries = libATerm;}; + + body = [fib primes]; +} diff --git a/make/examples/default.nix b/make/examples/default.nix new file mode 100644 index 0000000000..8b5b8bca5e --- /dev/null +++ b/make/examples/default.nix @@ -0,0 +1,6 @@ +[ (import ./trivial) + (import ./simple-header) + (import ./not-so-simple-header) + (import ./not-so-simple-header-auto) + (import ./aterm) +] \ No newline at end of file diff --git a/make/examples/not-so-simple-header-auto/bar/hello.h b/make/examples/not-so-simple-header-auto/bar/hello.h new file mode 100644 index 0000000000..4595fad98d --- /dev/null +++ b/make/examples/not-so-simple-header-auto/bar/hello.h @@ -0,0 +1 @@ +#define WHAT "World" diff --git a/make/examples/not-so-simple-header-auto/default.nix b/make/examples/not-so-simple-header-auto/default.nix new file mode 100644 index 0000000000..9e84b0c28a --- /dev/null +++ b/make/examples/not-so-simple-header-auto/default.nix @@ -0,0 +1,11 @@ +let { + + inherit (import ../../lib) compileC findIncludes link; + + hello = link {programName = "hello"; objects = compileC { + main = ./foo/hello.c; + localIncludes = "auto"; + };}; + + body = [hello]; +} diff --git a/make/examples/not-so-simple-header-auto/foo/fnord/indirect.h b/make/examples/not-so-simple-header-auto/foo/fnord/indirect.h new file mode 100644 index 0000000000..2fde1e26c1 --- /dev/null +++ b/make/examples/not-so-simple-header-auto/foo/fnord/indirect.h @@ -0,0 +1,3 @@ +#define HELLO "Hello" + +#include "../../bar/hello.h" diff --git a/make/examples/not-so-simple-header-auto/foo/hello.c b/make/examples/not-so-simple-header-auto/foo/hello.c new file mode 100644 index 0000000000..7d5b402ce5 --- /dev/null +++ b/make/examples/not-so-simple-header-auto/foo/hello.c @@ -0,0 +1,9 @@ +#include + +#include "fnord/indirect.h" + +int main(int argc, char * * argv) +{ + printf(HELLO " " WHAT "\n"); + return 0; +} diff --git a/make/examples/not-so-simple-header/bar/hello.h b/make/examples/not-so-simple-header/bar/hello.h new file mode 100644 index 0000000000..4595fad98d --- /dev/null +++ b/make/examples/not-so-simple-header/bar/hello.h @@ -0,0 +1 @@ +#define WHAT "World" diff --git a/make/examples/not-so-simple-header/default.nix b/make/examples/not-so-simple-header/default.nix new file mode 100644 index 0000000000..61ded57c82 --- /dev/null +++ b/make/examples/not-so-simple-header/default.nix @@ -0,0 +1,14 @@ +let { + + inherit (import ../../lib) compileC link; + + hello = link {programName = "hello"; objects = compileC { + main = ./foo/hello.c; + localIncludes = [ + [./foo/fnord/indirect.h "fnord/indirect.h"] + [./bar/hello.h "fnord/../../bar/hello.h"] + ]; + };}; + + body = [hello]; +} diff --git a/make/examples/not-so-simple-header/foo/fnord/indirect.h b/make/examples/not-so-simple-header/foo/fnord/indirect.h new file mode 100644 index 0000000000..2fde1e26c1 --- /dev/null +++ b/make/examples/not-so-simple-header/foo/fnord/indirect.h @@ -0,0 +1,3 @@ +#define HELLO "Hello" + +#include "../../bar/hello.h" diff --git a/make/examples/not-so-simple-header/foo/hello.c b/make/examples/not-so-simple-header/foo/hello.c new file mode 100644 index 0000000000..7d5b402ce5 --- /dev/null +++ b/make/examples/not-so-simple-header/foo/hello.c @@ -0,0 +1,9 @@ +#include + +#include "fnord/indirect.h" + +int main(int argc, char * * argv) +{ + printf(HELLO " " WHAT "\n"); + return 0; +} diff --git a/make/examples/simple-header/default.nix b/make/examples/simple-header/default.nix new file mode 100644 index 0000000000..e943471aaa --- /dev/null +++ b/make/examples/simple-header/default.nix @@ -0,0 +1,11 @@ +let { + + inherit (import ../../lib) compileC link; + + hello = link {objects = compileC { + main = ./hello.c; + localIncludes = [ [./hello.h "hello.h"] ]; + };}; + + body = [hello]; +} diff --git a/make/examples/simple-header/hello.c b/make/examples/simple-header/hello.c new file mode 100644 index 0000000000..15f1ac714e --- /dev/null +++ b/make/examples/simple-header/hello.c @@ -0,0 +1,9 @@ +#include + +#include "hello.h" + +int main(int argc, char * * argv) +{ + printf("Hello " WHAT "\n"); + return 0; +} diff --git a/make/examples/simple-header/hello.h b/make/examples/simple-header/hello.h new file mode 100644 index 0000000000..4595fad98d --- /dev/null +++ b/make/examples/simple-header/hello.h @@ -0,0 +1 @@ +#define WHAT "World" diff --git a/make/examples/trivial/default.nix b/make/examples/trivial/default.nix new file mode 100644 index 0000000000..132245e582 --- /dev/null +++ b/make/examples/trivial/default.nix @@ -0,0 +1,8 @@ +let { + + inherit (import ../../lib) compileC link; + + hello = link {objects = compileC {main = ./hello.c;};}; + + body = [hello]; +} diff --git a/make/examples/trivial/hello.c b/make/examples/trivial/hello.c new file mode 100644 index 0000000000..237ad8ffe7 --- /dev/null +++ b/make/examples/trivial/hello.c @@ -0,0 +1,7 @@ +#include + +int main(int argc, char * * argv) +{ + printf("Hello World\n"); + return 0; +} diff --git a/make/lib/compile-c.sh b/make/lib/compile-c.sh new file mode 100644 index 0000000000..3558dd89ea --- /dev/null +++ b/make/lib/compile-c.sh @@ -0,0 +1,73 @@ +. $stdenv/setup + +mainName=$(basename $main | cut -c34-) + +echo "compiling \`$mainName'..." + +# Turn $localIncludes into an array. +localIncludes=($localIncludes) + +# Determine how many `..' levels appear in the header file references. +# E.g., if there is some reference `../../foo.h', then we have to +# insert two extra levels in the directory structure, so that `a.c' is +# stored at `dotdot/dotdot/a.c', and a reference from it to +# `../../foo.h' resolves to `dotdot/dotdot/../../foo.h' == `foo.h'. +n=0 +maxDepth=0 +for ((n = 0; n < ${#localIncludes[*]}; n += 2)); do + target=${localIncludes[$((n + 1))]} + + # Split the target name into path components using some IFS magic. + savedIFS="$IFS" + IFS=/ + components=($target) + depth=0 + for ((m = 0; m < ${#components[*]}; m++)); do + c=${components[m]} + if test "$c" = ".."; then + depth=$((depth + 1)) + fi + done + IFS="$savedIFS" + + if test $depth -gt $maxDepth; then + maxDepth=$depth; + fi +done + +# Create the extra levels in the directory hierarchy. +prefix= +for ((n = 0; n < maxDepth; n++)); do + prefix="dotdot/$prefix" +done + +# Create symlinks to the header files. +for ((n = 0; n < ${#localIncludes[*]}; n += 2)); do + source=${localIncludes[n]} + target=${localIncludes[$((n + 1))]} + + # Create missing directories. We use IFS magic to split the path + # into path components. + savedIFS="$IFS" + IFS=/ + components=($prefix$target) + fullPath=(.) + for ((m = 0; m < ${#components[*]} - 1; m++)); do + fullPath=("${fullPath[@]}" ${components[m]}) + if ! test -d "${fullPath[*]}"; then + mkdir "${fullPath[*]}" + fi + done + IFS="$savedIFS" + + ln -sf $source $prefix$target +done + +# Create a symlink to the main file. +if ! test "$(readlink $prefix$mainName)" = $main; then + ln -s $main $prefix$mainName +fi + +mkdir $out +test "$prefix" && cd $prefix +gcc -Wall $cFlags -c $mainName -o $out/$mainName.o diff --git a/make/lib/default.nix b/make/lib/default.nix new file mode 100644 index 0000000000..a5059252da --- /dev/null +++ b/make/lib/default.nix @@ -0,0 +1,59 @@ +rec { + + # Should point at your Nixpkgs installation. + pkgPath = ./pkgs; + + pkgs = import (pkgPath + /system/all-packages.nix) {}; + + stdenv = pkgs.stdenv; + + + compileC = {main, localIncludes ? [], cFlags ? "", forSharedLib ? false}: + stdenv.mkDerivation { + name = "compile-c"; + builder = ./compile-c.sh; + localIncludes = + if localIncludes == "auto" then + import (findIncludes { + main = toString main; + hack = __currentTime; + inherit cFlags; + }) + else + localIncludes; + inherit main; + cFlags = [ + cFlags + (if forSharedLib then ["-fpic"] else []) + ]; + }; + + /* + runCommand = {command}: { + name = "run-command"; + builder = ./run-command.sh; + inherit command; + }; + */ + + findIncludes = {main, hack, cFlags ? ""}: stdenv.mkDerivation { + name = "find-includes"; + builder = ./find-includes.sh; + inherit main hack cFlags; + }; + + link = {objects, programName ? "program", libraries ? []}: stdenv.mkDerivation { + name = "link"; + builder = ./link.sh; + inherit objects programName libraries; + }; + + makeLibrary = {objects, libraryName ? [], sharedLib ? false}: + # assert sharedLib -> fold (obj: x: assert obj.sharedLib && x) false objects + stdenv.mkDerivation { + name = "library"; + builder = ./make-library.sh; + inherit objects libraryName sharedLib; + }; + +} diff --git a/make/lib/find-includes.sh b/make/lib/find-includes.sh new file mode 100644 index 0000000000..4824207c29 --- /dev/null +++ b/make/lib/find-includes.sh @@ -0,0 +1,20 @@ +. $stdenv/setup + +echo "finding includes of \`$(basename $main)'..." + +makefile=$NIX_BUILD_TOP/makefile + +mainDir=$(dirname $main) +(cd $mainDir && gcc $cFlags -MM $(basename $main) -MF $makefile) || false + +echo "[" >$out + +while read line; do + line=$(echo "$line" | sed 's/.*://') + for i in $line; do + fullPath=$(readlink -f $mainDir/$i) + echo " [ $fullPath \"$i\" ]" >>$out + done +done < $makefile + +echo "]" >>$out diff --git a/make/lib/link.sh b/make/lib/link.sh new file mode 100644 index 0000000000..a48f750f41 --- /dev/null +++ b/make/lib/link.sh @@ -0,0 +1,21 @@ +. $stdenv/setup + +shopt -s nullglob + +objs= +for i in $objects; do + obj=$(echo $i/*.o) + objs="$objs $obj" +done + +libs= +for i in $libraries; do + lib=$(echo $i/*.a; echo $i/*.so) + name=$(echo $(basename $lib) | sed -e 's/^lib//' -e 's/.a$//' -e 's/.so$//') + libs="$libs -L$(dirname $lib) -l$name" +done + +echo "linking object files into \`$programName'..." + +mkdir $out +gcc -o $out/$programName $objs $libs diff --git a/make/lib/make-library.sh b/make/lib/make-library.sh new file mode 100644 index 0000000000..a486a7bf74 --- /dev/null +++ b/make/lib/make-library.sh @@ -0,0 +1,28 @@ +. $stdenv/setup + +objs= +for i in $objects; do + obj=$(echo $i/*.o) + objs="$objs $obj" +done + +echo "archiving object files into library \`$libraryName'..." + +ensureDir $out + +if test -z "$sharedLib"; then + + outPath=$out/lib${libraryName}.a + + ar crs $outPath $objs + ranlib $outPath + +else + + outPath=$out/lib${libraryName}.so + + gcc -shared -o $outPath $objs + +fi + +