diff --git a/configure.ac b/configure.ac index 54db203171..cc7db29c81 100644 --- a/configure.ac +++ b/configure.ac @@ -28,11 +28,11 @@ AC_CONFIG_FILES([Makefile src/Makefile src/boost/Makefile src/boost/format/Makefile + src/libutil/Makefile src/libnix/Makefile src/libmain/Makefile src/nix/Makefile src/nix-hash/Makefile - src/fix/Makefile src/fix-ng/Makefile scripts/Makefile corepkgs/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 57af4dbc8f..e62c29d7ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1 +1 @@ -SUBDIRS = boost libnix libmain nix nix-hash fix fix-ng +SUBDIRS = boost libutil libnix libmain nix nix-hash fix-ng diff --git a/src/fix-ng/Makefile.am b/src/fix-ng/Makefile.am index 359e39c46c..cf85493297 100644 --- a/src/fix-ng/Makefile.am +++ b/src/fix-ng/Makefile.am @@ -1,11 +1,12 @@ bin_PROGRAMS = fix-ng fix_ng_SOURCES = fix-expr.cc parser.cc eval.cc primops.cc fix.cc -fix_ng_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../boost/format/libformat.a \ - -L../../externals/inst/lib -ldb_cxx -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm +fix_ng_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../libutil/libutil.a \ + ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \ + -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm AM_CXXFLAGS = \ - -I.. -I../../externals/inst/include -I../libnix -I../libmain + -I.. -I../../externals/inst/include -I../libutil -I../libnix -I../libmain # Parse table generation. diff --git a/src/fix/Makefile.am b/src/fix/Makefile.am deleted file mode 100644 index 4786db54c3..0000000000 --- a/src/fix/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -bin_PROGRAMS = fix - -fix_SOURCES = fix.cc -fix_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../boost/format/libformat.a \ - -L../../externals/inst/lib -ldb_cxx -lATerm - -AM_CXXFLAGS = \ - -I.. -I../../externals/inst/include -I../libnix -I../libmain diff --git a/src/fix/fix.cc b/src/fix/fix.cc deleted file mode 100644 index 8b8441050d..0000000000 --- a/src/fix/fix.cc +++ /dev/null @@ -1,489 +0,0 @@ -#include -#include - -#include "globals.hh" -#include "normalise.hh" -#include "shared.hh" - - -typedef ATerm Expr; - -typedef map NormalForms; -typedef map PkgPaths; -typedef map PkgHashes; - -struct EvalState -{ - Paths searchDirs; - NormalForms normalForms; - PkgPaths pkgPaths; - PkgHashes pkgHashes; /* normalised package hashes */ - Expr blackHole; - - EvalState() - { - blackHole = ATmake("BlackHole()"); - if (!blackHole) throw Error("cannot build black hole"); - } -}; - - -static Expr evalFile(EvalState & state, const Path & path); -static Expr evalExpr(EvalState & state, Expr e); - - -static Path searchPath(const Paths & searchDirs, const Path & relPath) -{ - if (string(relPath, 0, 1) == "/") return relPath; - - for (Paths::const_iterator i = searchDirs.begin(); - i != searchDirs.end(); i++) - { - Path path = *i + "/" + relPath; - if (pathExists(path)) return path; - } - - throw Error( - format("path `%1%' not found in any of the search directories") - % relPath); -} - - -static Expr substExpr(string x, Expr rep, Expr e) -{ - char * s; - Expr e2; - - if (ATmatch(e, "Var()", &s)) - if (x == s) - return rep; - else - return e; - - ATermList formals; - if (ATmatch(e, "Function([], )", &formals, &e2)) { - while (!ATisEmpty(formals)) { - if (!ATmatch(ATgetFirst(formals), "", &s)) - throw badTerm("not a list of formals", (ATerm) formals); - if (x == (string) s) - return e; - formals = ATgetNext(formals); - } - } - - /* Generically substitute in subterms. */ - - if (ATgetType(e) == AT_APPL) { - AFun fun = ATgetAFun(e); - int arity = ATgetArity(fun); - ATermList args = ATempty; - - for (int i = arity - 1; i >= 0; i--) - args = ATinsert(args, substExpr(x, rep, ATgetArgument(e, i))); - - return (ATerm) ATmakeApplList(fun, args); - } - - if (ATgetType(e) == AT_LIST) { - ATermList in = (ATermList) e; - ATermList out = ATempty; - - while (!ATisEmpty(in)) { - out = ATinsert(out, substExpr(x, rep, ATgetFirst(in))); - in = ATgetNext(in); - } - - return (ATerm) ATreverse(out); - } - - throw badTerm("do not know how to substitute", e); -} - - -static Expr substExprMany(ATermList formals, ATermList args, Expr body) -{ - char * s; - Expr e; - - /* !!! check args against formals */ - - while (!ATisEmpty(args)) { - ATerm tup = ATgetFirst(args); - if (!ATmatch(tup, "(, )", &s, &e)) - throw badTerm("expected an argument tuple", tup); - - body = substExpr(s, e, body); - - args = ATgetNext(args); - } - - return body; -} - - -static PathSet nixExprRootsCached(EvalState & state, const Path & nePath) -{ - PkgPaths::iterator i = state.pkgPaths.find(nePath); - if (i != state.pkgPaths.end()) - return i->second; - else { - PathSet paths = nixExprRoots(nePath); - state.pkgPaths[nePath] = paths; - return paths; - } -} - - -static Hash hashPackage(EvalState & state, NixExpr ne) -{ - if (ne.type == NixExpr::neDerivation) { - PathSet inputs2; - for (PathSet::iterator i = ne.derivation.inputs.begin(); - i != ne.derivation.inputs.end(); i++) - { - PkgHashes::iterator j = state.pkgHashes.find(*i); - if (j == state.pkgHashes.end()) - throw Error(format("don't know expression `%1%'") % (string) *i); - inputs2.insert(j->second); - } - ne.derivation.inputs = inputs2; - } - return hashTerm(unparseNixExpr(ne)); -} - - -static string processBinding(EvalState & state, Expr e, NixExpr & ne) -{ - char * s1; - - if (ATmatch(e, "NixExpr()", &s1)) { - Path nePath(s1); - PathSet paths = nixExprRootsCached(state, nePath); - if (paths.size() != 1) abort(); - Path path = *(paths.begin()); - ne.derivation.inputs.insert(nePath); - return path; - } - - if (ATmatch(e, "", &s1)) - return s1; - - if (ATmatch(e, "True")) return "1"; - - if (ATmatch(e, "False")) return ""; - - ATermList l; - if (ATmatch(e, "[]", &l)) { - string s; - bool first = true; - while (!ATisEmpty(l)) { - if (!first) s = s + " "; else first = false; - s += processBinding(state, evalExpr(state, ATgetFirst(l)), ne); - l = ATgetNext(l); - } - return s; - } - - throw badTerm("invalid package binding", e); -} - - -static Expr evalExpr2(EvalState & state, Expr e) -{ - char * s1; - Expr e1, e2, e3, e4; - ATermList bnds; - - /* Normal forms. */ - if (ATmatch(e, "", &s1) || - ATmatch(e, "[]", &e1) || - ATmatch(e, "True") || - ATmatch(e, "False") || - ATmatch(e, "Function([], )", &e1, &e2) || - ATmatch(e, "NixExpr()", &s1)) - return e; - - try { - Hash pkgHash = hashPackage(state, parseNixExpr(e)); - Path pkgPath = writeTerm(e, ""); - state.pkgHashes[pkgPath] = pkgHash; - return ATmake("NixExpr()", pkgPath.c_str()); - } catch (...) { /* !!! catch parse errors only */ - } - - /* Application. */ - if (ATmatch(e, "Call(, [])", &e1, &e2) || - ATmatch(e, "App(, [])", &e1, &e2)) { - e1 = evalExpr(state, e1); - if (!ATmatch(e1, "Function([], )", &e3, &e4)) - throw badTerm("expecting a function", e1); - return evalExpr(state, - substExprMany((ATermList) e3, (ATermList) e2, e4)); - } - - /* Conditional. */ - if (ATmatch(e, "If(, , )", &e1, &e2, &e3)) { - e1 = evalExpr(state, e1); - Expr x; - if (ATmatch(e1, "True")) x = e2; - else if (ATmatch(e1, "False")) x = e3; - else throw badTerm("expecting a boolean", e1); - return evalExpr(state, x); - } - - /* Ad-hoc function for string matching. */ - if (ATmatch(e, "HasSubstr(, )", &e1, &e2)) { - e1 = evalExpr(state, e1); - e2 = evalExpr(state, e2); - - char * s1, * s2; - if (!ATmatch(e1, "", &s1)) - throw badTerm("expecting a string", e1); - if (!ATmatch(e2, "", &s2)) - throw badTerm("expecting a string", e2); - - return - string(s1).find(string(s2)) != string::npos ? - ATmake("True") : ATmake("False"); - } - - /* Platform constant. */ - if (ATmatch(e, "Platform")) { - return ATmake("", thisSystem.c_str()); - } - - /* Fix inclusion. */ - if (ATmatch(e, "IncludeFix()", &s1)) { - Path fileName(s1); - return evalFile(state, s1); - } - - /* Relative files. */ - if (ATmatch(e, "Relative()", &s1)) { - Path srcPath = searchPath(state.searchDirs, s1); - Path dstPath = addToStore(srcPath); - - ClosureElem elem; - NixExpr ne; - ne.type = NixExpr::neClosure; - ne.closure.roots.insert(dstPath); - ne.closure.elems[dstPath] = elem; - - Hash pkgHash = hashPackage(state, ne); - Path pkgPath = writeTerm(unparseNixExpr(ne), ""); - state.pkgHashes[pkgPath] = pkgHash; - - printMsg(lvlChatty, format("copied `%1%' -> closure `%2%'") - % srcPath % pkgPath); - - return ATmake("NixExpr()", pkgPath.c_str()); - } - - /* Packages are transformed into Nix derivation expressions. */ - if (ATmatch(e, "Package([])", &bnds)) { - - /* Evaluate the bindings and put them in a map. */ - map bndMap; - bndMap["platform"] = ATmake("", thisSystem.c_str()); - while (!ATisEmpty(bnds)) { - ATerm bnd = ATgetFirst(bnds); - if (!ATmatch(bnd, "(, )", &s1, &e1)) - throw badTerm("binding expected", bnd); - bndMap[s1] = evalExpr(state, e1); - bnds = ATgetNext(bnds); - } - - /* Gather information for building the derivation - expression. */ - NixExpr ne; - ne.type = NixExpr::neDerivation; - ne.derivation.platform = thisSystem; - string name; - Path outPath; - Hash outHash; - bool outHashGiven = false; - bnds = ATempty; - - for (map::iterator it = bndMap.begin(); - it != bndMap.end(); it++) - { - string key = it->first; - ATerm value = it->second; - - if (key == "args") { - ATermList args; - if (!ATmatch(value, "[]", &args)) - throw badTerm("list expected", value); - - while (!ATisEmpty(args)) { - Expr arg = evalExpr(state, ATgetFirst(args)); - ne.derivation.args.push_back(processBinding(state, arg, ne)); - args = ATgetNext(args); - } - } - - else { - string s = processBinding(state, value, ne); - ne.derivation.env[key] = s; - - if (key == "build") ne.derivation.builder = s; - if (key == "name") name = s; - if (key == "outPath") outPath = s; - if (key == "id") { - outHash = parseHash(s); - outHashGiven = true; - } - } - - bnds = ATinsert(bnds, - ATmake("(, )", key.c_str(), value)); - } - - if (ne.derivation.builder == "") - throw badTerm("no builder specified", e); - - if (name == "") - throw badTerm("no package name specified", e); - - /* Determine the output path. */ - if (!outHashGiven) outHash = hashPackage(state, ne); - if (outPath == "") - /* Hash the Nix expression with no outputs to produce a - unique but deterministic path name for this package. */ - outPath = - canonPath(nixStore + "/" + ((string) outHash).c_str() + "-" + name); - ne.derivation.env["out"] = outPath; - ne.derivation.outputs.insert(outPath); - - /* Write the resulting term into the Nix store directory. */ - Hash pkgHash = outHashGiven - ? hashString((string) outHash + outPath) - : hashPackage(state, ne); - Path pkgPath = writeTerm(unparseNixExpr(ne), "-d-" + name); - state.pkgHashes[pkgPath] = pkgHash; - - printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") - % name % pkgPath); - - return ATmake("NixExpr()", pkgPath.c_str()); - } - - /* BaseName primitive function. */ - if (ATmatch(e, "BaseName()", &e1)) { - e1 = evalExpr(state, e1); - if (!ATmatch(e1, "", &s1)) - throw badTerm("string expected", e1); - return ATmake("", baseNameOf(s1).c_str()); - } - - /* Barf. */ - throw badTerm("invalid expression", e); -} - - -static Expr evalExpr(EvalState & state, Expr e) -{ - startNest(nest, lvlVomit, - format("evaluating expression: %1%") % e); - - /* Consult the memo table to quickly get the normal form of - previously evaluated expressions. */ - NormalForms::iterator i = state.normalForms.find(e); - if (i != state.normalForms.end()) { - if (i->second == state.blackHole) - throw badTerm("infinite recursion", e); - return i->second; - } - - /* Otherwise, evaluate and memoize. */ - state.normalForms[e] = state.blackHole; - Expr nf = evalExpr2(state, e); - state.normalForms[e] = nf; - return nf; -} - - -static Expr evalFile(EvalState & state, const Path & relPath) -{ - Path path = searchPath(state.searchDirs, relPath); - startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); - Expr e = ATreadFromNamedFile(path.c_str()); - if (!e) - throw Error(format("unable to read a term from `%1%'") % path); - return evalExpr(state, e); -} - - -static Expr evalStdin(EvalState & state) -{ - startNest(nest, lvlTalkative, format("evaluating standard input")); - Expr e = ATreadFromFile(stdin); - if (!e) - throw Error(format("unable to read a term from stdin")); - return evalExpr(state, e); -} - - -static void printNixExpr(EvalState & state, Expr e) -{ - ATermList es; - char * s; - if (ATmatch(e, "NixExpr()", &s)) { - cout << format("%1%\n") % s; - } - else if (ATmatch(e, "[]", &es)) { - while (!ATisEmpty(es)) { - printNixExpr(state, evalExpr(state, ATgetFirst(es))); - es = ATgetNext(es); - } - } - else throw badTerm("top level does not evaluate to a (list of) Nix expression(s)", e); -} - - -void run(Strings args) -{ - EvalState state; - Strings files; - bool readStdin = false; - - state.searchDirs.push_back("."); - state.searchDirs.push_back(nixDataDir + "/fix"); - - for (Strings::iterator it = args.begin(); - it != args.end(); ) - { - string arg = *it++; - - if (arg == "--includedir" || arg == "-I") { - if (it == args.end()) - throw UsageError(format("argument required in `%1%'") % arg); - state.searchDirs.push_back(*it++); - } - else if (arg == "--verbose" || arg == "-v") - verbosity = (Verbosity) ((int) verbosity + 1); - else if (arg == "-") - readStdin = true; - else if (arg[0] == '-') - throw UsageError(format("unknown flag `%1%`") % arg); - else - files.push_back(arg); - } - - openDB(); - - if (readStdin) { - Expr e = evalStdin(state); - printNixExpr(state, e); - } - - for (Strings::iterator it = files.begin(); - it != files.end(); it++) - { - Expr e = evalFile(state, *it); - printNixExpr(state, e); - } -} - - -string programId = "fix"; diff --git a/src/libmain/Makefile.am b/src/libmain/Makefile.am index aebb1286e7..edd6685450 100644 --- a/src/libmain/Makefile.am +++ b/src/libmain/Makefile.am @@ -7,6 +7,6 @@ AM_CXXFLAGS = \ -DNIX_DATA_DIR=\"$(datadir)\" \ -DNIX_STATE_DIR=\"$(localstatedir)/nix\" \ -DNIX_LOG_DIR=\"$(localstatedir)/log/nix\" \ - -I.. -I../../externals/inst/include -I../libnix + -I.. -I../../externals/inst/include -I../libutil -I../libnix EXTRA_DIST = *.hh diff --git a/src/libnix/Makefile.am b/src/libnix/Makefile.am index 7671b1613d..055ef1af7b 100644 --- a/src/libnix/Makefile.am +++ b/src/libnix/Makefile.am @@ -1,10 +1,11 @@ noinst_LIBRARIES = libnix.a -libnix_a_SOURCES = util.cc hash.cc archive.cc md5.c \ +libnix_a_SOURCES = \ store.cc expr.cc normalise.cc exec.cc \ - globals.cc db.cc references.cc pathlocks.cc aterm.cc + globals.cc db.cc references.cc pathlocks.cc -AM_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall -I.. -I../../externals/inst/include +AM_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall \ + -I.. -I../../externals/inst/include -I../libutil EXTRA_DIST = *.hh *.h test-builder-*.sh diff --git a/src/libutil/Makefile.am b/src/libutil/Makefile.am new file mode 100644 index 0000000000..46f0a048fe --- /dev/null +++ b/src/libutil/Makefile.am @@ -0,0 +1,14 @@ +noinst_LIBRARIES = libutil.a + +libutil_a_SOURCES = util.cc hash.cc archive.cc md5.c aterm.cc + +AM_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall -I.. -I../../externals/inst/include + +EXTRA_DIST = *.hh *.h + +check_PROGRAMS = test-aterm + +test_aterm_SOURCES = test-aterm.cc +test_aterm_LDADD = libnix.a $(LDADD) ../boost/format/libformat.a \ + -L../../externals/inst/lib -ldb_cxx -lATerm + diff --git a/src/libnix/archive.cc b/src/libutil/archive.cc similarity index 100% rename from src/libnix/archive.cc rename to src/libutil/archive.cc diff --git a/src/libnix/archive.hh b/src/libutil/archive.hh similarity index 100% rename from src/libnix/archive.hh rename to src/libutil/archive.hh diff --git a/src/libnix/aterm.cc b/src/libutil/aterm.cc similarity index 100% rename from src/libnix/aterm.cc rename to src/libutil/aterm.cc diff --git a/src/libnix/aterm.hh b/src/libutil/aterm.hh similarity index 100% rename from src/libnix/aterm.hh rename to src/libutil/aterm.hh diff --git a/src/libnix/hash.cc b/src/libutil/hash.cc similarity index 100% rename from src/libnix/hash.cc rename to src/libutil/hash.cc diff --git a/src/libnix/hash.hh b/src/libutil/hash.hh similarity index 100% rename from src/libnix/hash.hh rename to src/libutil/hash.hh diff --git a/src/libnix/md5.c b/src/libutil/md5.c similarity index 100% rename from src/libnix/md5.c rename to src/libutil/md5.c diff --git a/src/libnix/md5.h b/src/libutil/md5.h similarity index 100% rename from src/libnix/md5.h rename to src/libutil/md5.h diff --git a/src/libnix/test-aterm.cc b/src/libutil/test-aterm.cc similarity index 100% rename from src/libnix/test-aterm.cc rename to src/libutil/test-aterm.cc diff --git a/src/libnix/util.cc b/src/libutil/util.cc similarity index 100% rename from src/libnix/util.cc rename to src/libutil/util.cc diff --git a/src/libnix/util.hh b/src/libutil/util.hh similarity index 100% rename from src/libnix/util.hh rename to src/libutil/util.hh diff --git a/src/nix-hash/Makefile.am b/src/nix-hash/Makefile.am index 7fb428a29f..7377a62e7c 100644 --- a/src/nix-hash/Makefile.am +++ b/src/nix-hash/Makefile.am @@ -1,8 +1,8 @@ bin_PROGRAMS = nix-hash nix_hash_SOURCES = nix-hash.cc -nix_hash_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../boost/format/libformat.a \ - -L../../externals/inst/lib -ldb_cxx -lATerm +nix_hash_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../libutil/libutil.a \ + ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx -lATerm AM_CXXFLAGS = \ - -I.. -I../../externals/inst/include -I../libnix -I../libmain + -I.. -I../../externals/inst/include -I../libutil -I../libnix -I../libmain diff --git a/src/nix/Makefile.am b/src/nix/Makefile.am index 37415976b3..c4368a37c6 100644 --- a/src/nix/Makefile.am +++ b/src/nix/Makefile.am @@ -1,8 +1,8 @@ bin_PROGRAMS = nix nix_SOURCES = nix.cc dotgraph.cc -nix_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../boost/format/libformat.a \ - -L../../externals/inst/lib -ldb_cxx -lATerm +nix_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../libutil/libutil.a \ + ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx -lATerm nix.o: nix-help.txt.hh @@ -12,7 +12,7 @@ nix.o: nix-help.txt.hh echo '"' >> $@ AM_CXXFLAGS = \ - -I.. -I../../externals/inst/include -I../libnix -I../libmain + -I.. -I../../externals/inst/include -I../libutil -I../libnix -I../libmain install-data-local: $(INSTALL) -d $(localstatedir)/nix