Compare commits

...

11 Commits

Author SHA1 Message Date
Eelco Dolstra f1ed34081e * ATerm library example. 2004-07-06 17:27:11 +00:00
Eelco Dolstra 17e20716c0 * A function to build libraries.
* The linker can link against libraries.
* C flags can be passed to the C compiler.
2004-07-06 17:25:10 +00:00
Eelco Dolstra 5d48dd6912 * A `map' primop. 2004-07-06 17:20:34 +00:00
Eelco Dolstra af54a60204 * Dirty interim hack to make header file dependency determination
reliable (if somewhat inefficient): make the current time an
  attribute of the derivation.  Thus, every call to `nix-build' will
  cause the find-includes derivation to be re-done (but not the actual
  compilations if that's not necessary!).  I added a `curTime' primop
  to do this.
2004-07-06 16:33:46 +00:00
Eelco Dolstra 7d386d5c29 * Automatically determine header file dependencies using the
`findIncludes' function.  The current implementation is impure and
  therefore not correct: it gathers header file dependencies only once
  for a specific path (due to caching).
2004-07-06 16:05:28 +00:00
Eelco Dolstra fa50c0849e * The `import' primop now accepts derivations. These are first
realised, and then the file at the derivation's output path is
  loaded as a Nix expression.
2004-07-06 15:57:39 +00:00
Eelco Dolstra 321be4649d * Linker accepts a name for the program.
* Better diagnostics.
2004-07-06 14:10:09 +00:00
Eelco Dolstra 0920fe3038 * Deal with directory components in header file references (e.g.,
`#include "foo/../bar/bla.h"') by building an appropriate tree of
  symlinks.
2004-07-06 13:45:14 +00:00
Eelco Dolstra 08de98f8b6 * Header files that are used by a compilation must be declared
explicitly.  If you forget a dependency, it's simply not visible to
  the compiler, and so the compilation fails.  This is a big plus over
  conventional Make.
2004-07-06 12:27:19 +00:00
Eelco Dolstra 15646244ba * Some trivial Nix Make examples. 2004-07-06 11:43:37 +00:00
Eelco Dolstra a2e33d200e * Branch for nix-make. So that all those ad-hoc extensions don't
pollute the mainline.
2004-07-06 09:57:40 +00:00
25 changed files with 393 additions and 4 deletions

View File

@ -0,0 +1,30 @@
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";
};
libATerm = makeLibrary {
libraryName = "ATerm";
objects = map {function = compile; list = sources;};
};
}

View File

@ -0,0 +1 @@
import test/default.nix

View File

@ -0,0 +1,16 @@
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;};
body = [fib];
}

6
examples/default.nix Normal file
View File

@ -0,0 +1,6 @@
[ (import ./trivial)
(import ./simple-header)
(import ./not-so-simple-header)
(import ./not-so-simple-header-auto)
(import ./aterm)
]

View File

@ -0,0 +1 @@
#define WHAT "World"

View File

@ -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];
}

View File

@ -0,0 +1,3 @@
#define HELLO "Hello"
#include "../../bar/hello.h"

View File

@ -0,0 +1,9 @@
#include <stdio.h>
#include "fnord/indirect.h"
int main(int argc, char * * argv)
{
printf(HELLO " " WHAT "\n");
return 0;
}

View File

@ -0,0 +1 @@
#define WHAT "World"

View File

@ -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];
}

View File

@ -0,0 +1,3 @@
#define HELLO "Hello"
#include "../../bar/hello.h"

View File

@ -0,0 +1,9 @@
#include <stdio.h>
#include "fnord/indirect.h"
int main(int argc, char * * argv)
{
printf(HELLO " " WHAT "\n");
return 0;
}

View File

@ -0,0 +1,11 @@
let {
inherit (import ../../lib) compileC link;
hello = link {objects = compileC {
main = ./hello.c;
localIncludes = [ [./hello.h "hello.h"] ];
};};
body = [hello];
}

View File

@ -0,0 +1,9 @@
#include <stdio.h>
#include "hello.h"
int main(int argc, char * * argv)
{
printf("Hello " WHAT "\n");
return 0;
}

View File

@ -0,0 +1 @@
#define WHAT "World"

View File

@ -0,0 +1,8 @@
let {
inherit (import ../../lib) compileC link;
hello = link {objects = compileC {main = ./hello.c;};};
body = [hello];
}

7
examples/trivial/hello.c Normal file
View File

@ -0,0 +1,7 @@
#include <stdio.h>
int main(int argc, char * * argv)
{
printf("Hello World\n");
return 0;
}

73
lib/compile-c.sh Normal file
View File

@ -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 -s $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

46
lib/default.nix Normal file
View File

@ -0,0 +1,46 @@
rec {
inherit (import /home/eelco/nixpkgs/pkgs/system/i686-linux.nix) stdenv;
compileC = {main, localIncludes ? [], cFlags ? ""}: stdenv.mkDerivation {
name = "compile-c";
builder = ./compile-c.sh;
localIncludes =
if localIncludes == "auto" then
import (findIncludes {
main = toString main;
hack = curTime;
inherit cFlags;
})
else
localIncludes;
inherit main cFlags;
};
/*
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 ? []}: stdenv.mkDerivation {
name = "library";
builder = ./make-library.sh;
inherit objects libraryName;
};
}

20
lib/find-includes.sh Normal file
View File

@ -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

19
lib/link.sh Normal file
View File

@ -0,0 +1,19 @@
. $stdenv/setup
objs=
for i in $objects; do
obj=$(echo $i/*.o)
objs="$objs $obj"
done
libs=
for i in $libraries; do
lib=$(echo $i/*.a)
name=$(echo $(basename $lib) | sed -e 's/^lib//' -e 's/.a$//')
libs="$libs -L$(dirname $lib) -l$name"
done
echo "linking object files into \`$programName'..."
mkdir $out
gcc -o $out/$programName $objs $libs

15
lib/make-library.sh Normal file
View File

@ -0,0 +1,15 @@
. $stdenv/setup
objs=
for i in $objects; do
obj=$(echo $i/*.o)
objs="$objs $obj"
done
echo "archiving object files into library \`$libraryName'..."
outPath=$out/lib${libraryName}.a
mkdir $out
ar crs $outPath $objs
ranlib $outPath

View File

@ -28,12 +28,14 @@ EvalState::EvalState()
addPrimOp0("true", primTrue);
addPrimOp0("false", primFalse);
addPrimOp0("null", primNull);
addPrimOp0("curTime", primCurTime);
addPrimOp1("import", primImport);
addPrimOp1("derivation", primDerivation);
addPrimOp1("baseNameOf", primBaseNameOf);
addPrimOp1("toString", primToString);
addPrimOp1("isNull", primIsNull);
addPrimOp1("map", primMap);
primOpsAll.add(primOps0);
primOpsAll.add(primOps1);

View File

@ -1,3 +1,5 @@
#include <time.h>
#include "primops.hh"
#include "normalise.hh"
#include "globals.hh"
@ -6,9 +8,35 @@
Expr primImport(EvalState & state, Expr arg)
{
ATMatcher m;
string path;
if (!(atMatch(m, arg) >> "Path" >> path))
throw Error("path expected");
ATermList es;
Path path;
arg = evalExpr(state, arg);
if (atMatch(m, arg) >> "Path" >> path)
;
else if (atMatch(m, arg) >> "Attrs" >> es) {
Expr a = queryAttr(arg, "type");
/* If it is a derivation, we have to realise it and load the
Nix expression created at the derivation's output path. */
if (a && evalString(state, a) == "derivation") {
a = queryAttr(arg, "drvPath");
if (!a) throw Error("bad derivation in import");
Path drvPath = evalPath(state, a);
realiseStoreExpr(drvPath);
a = queryAttr(arg, "outPath");
if (!a) throw Error("bad derivation in import");
path = evalPath(state, a);
}
}
if (path == "")
throw Error("path or derivation expected in import");
return evalFile(state, path);
}
@ -267,7 +295,7 @@ Expr primToString(EvalState & state, Expr arg)
atMatch(m, arg) >> "Path" >> s ||
atMatch(m, arg) >> "Uri" >> s)
return ATmake("Str(<str>)", s.c_str());
else throw Error("cannot coerce value to string");
throw Error("cannot coerce value to string");
}
@ -295,3 +323,41 @@ Expr primIsNull(EvalState & state, Expr arg)
ATMatcher m;
return makeBool(atMatch(m, arg) >> "Null");
}
Expr primCurTime(EvalState & state)
{
return ATmake("Int(<int>)", time(0));
}
Expr primMap(EvalState & state, Expr arg)
{
arg = evalExpr(state, arg);
ATMatcher m;
ATermList es;
if (!(atMatch(m, arg) >> "Attrs" >> es))
throw Error("function `map' expects an attribute set");
Expr function = queryAttr(arg, "function");
if (!function)
throw Error("function `map' expects an attribute `function'");
Expr list = queryAttr(arg, "list");
if (!list)
throw Error("function `map' expects an attribute `list'");
list = evalExpr(state, list);
ATermList es2;
if (!(atMatch(m, list) >> "List" >> es2))
throw Error("attribute `list' in call to `map' must be a list");
ATermList res = ATempty;
for (ATermIterator i(es2); i; ++i)
res = ATinsert(res,
ATmake("Call(<term>, <term>)", function, *i));
return ATmake("List(<term>)", ATreverse(res));
}

View File

@ -34,5 +34,13 @@ Expr primNull(EvalState & state);
/* Determine whether the argument is the null value. */
Expr primIsNull(EvalState & state, Expr arg);
/* Return the current time. !!! hack, impure - although due to
memoization of evaluation results this should always yield the same
value for a particular run of the program. */
Expr primCurTime(EvalState & state);
/* Apply a function to each element of a list. */
Expr primMap(EvalState & state, Expr arg);
#endif /* !__PRIMOPS_H */