From 36fb29f8f0317144a0074d7b6689912a4dc40325 Mon Sep 17 00:00:00 2001
From: Eelco Dolstra <e.dolstra@tudelft.nl>
Date: Mon, 2 May 2005 15:25:28 +0000
Subject: [PATCH] * Merge remaining stuff from the nix-make branch. * Add
 support for the creation of shared libraries to `compileC',   `link', and
 `makeLibrary'. * Enable the ATerm library to be made into a shared library.

---
 make/examples/aterm/aterm/default.nix         | 34 +++++++++
 make/examples/aterm/default.nix               |  1 +
 make/examples/aterm/test/default.nix          | 18 +++++
 make/examples/default.nix                     |  6 ++
 .../not-so-simple-header-auto/bar/hello.h     |  1 +
 .../not-so-simple-header-auto/default.nix     | 11 +++
 .../foo/fnord/indirect.h                      |  3 +
 .../not-so-simple-header-auto/foo/hello.c     |  9 +++
 .../examples/not-so-simple-header/bar/hello.h |  1 +
 .../examples/not-so-simple-header/default.nix | 14 ++++
 .../not-so-simple-header/foo/fnord/indirect.h |  3 +
 .../examples/not-so-simple-header/foo/hello.c |  9 +++
 make/examples/simple-header/default.nix       | 11 +++
 make/examples/simple-header/hello.c           |  9 +++
 make/examples/simple-header/hello.h           |  1 +
 make/examples/trivial/default.nix             |  8 ++
 make/examples/trivial/hello.c                 |  7 ++
 make/lib/compile-c.sh                         | 73 +++++++++++++++++++
 make/lib/default.nix                          | 59 +++++++++++++++
 make/lib/find-includes.sh                     | 20 +++++
 make/lib/link.sh                              | 21 ++++++
 make/lib/make-library.sh                      | 28 +++++++
 22 files changed, 347 insertions(+)
 create mode 100644 make/examples/aterm/aterm/default.nix
 create mode 100644 make/examples/aterm/default.nix
 create mode 100644 make/examples/aterm/test/default.nix
 create mode 100644 make/examples/default.nix
 create mode 100644 make/examples/not-so-simple-header-auto/bar/hello.h
 create mode 100644 make/examples/not-so-simple-header-auto/default.nix
 create mode 100644 make/examples/not-so-simple-header-auto/foo/fnord/indirect.h
 create mode 100644 make/examples/not-so-simple-header-auto/foo/hello.c
 create mode 100644 make/examples/not-so-simple-header/bar/hello.h
 create mode 100644 make/examples/not-so-simple-header/default.nix
 create mode 100644 make/examples/not-so-simple-header/foo/fnord/indirect.h
 create mode 100644 make/examples/not-so-simple-header/foo/hello.c
 create mode 100644 make/examples/simple-header/default.nix
 create mode 100644 make/examples/simple-header/hello.c
 create mode 100644 make/examples/simple-header/hello.h
 create mode 100644 make/examples/trivial/default.nix
 create mode 100644 make/examples/trivial/hello.c
 create mode 100644 make/lib/compile-c.sh
 create mode 100644 make/lib/default.nix
 create mode 100644 make/lib/find-includes.sh
 create mode 100644 make/lib/link.sh
 create mode 100644 make/lib/make-library.sh

diff --git a/make/examples/aterm/aterm/default.nix b/make/examples/aterm/aterm/default.nix
new file mode 100644
index 000000000..8b139219e
--- /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 000000000..edaac40aa
--- /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 000000000..b7a9dd361
--- /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 000000000..8b5b8bca5
--- /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 000000000..4595fad98
--- /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 000000000..9e84b0c28
--- /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 000000000..2fde1e26c
--- /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 000000000..7d5b402ce
--- /dev/null
+++ b/make/examples/not-so-simple-header-auto/foo/hello.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#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 000000000..4595fad98
--- /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 000000000..61ded57c8
--- /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 000000000..2fde1e26c
--- /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 000000000..7d5b402ce
--- /dev/null
+++ b/make/examples/not-so-simple-header/foo/hello.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#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 000000000..e943471aa
--- /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 000000000..15f1ac714
--- /dev/null
+++ b/make/examples/simple-header/hello.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#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 000000000..4595fad98
--- /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 000000000..132245e58
--- /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 000000000..237ad8ffe
--- /dev/null
+++ b/make/examples/trivial/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+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 000000000..3558dd89e
--- /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 000000000..a5059252d
--- /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 000000000..4824207c2
--- /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 000000000..a48f750f4
--- /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 000000000..a486a7bf7
--- /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    
+
+    
-- 
GitLab