diff --git a/util/LLgen/build.lua b/util/LLgen/build.lua
index ea7cdf122..8e5bd4ca7 100644
--- a/util/LLgen/build.lua
+++ b/util/LLgen/build.lua
@@ -1,6 +1,13 @@
 clibrary {
 	name = "headers",
-	hdrs = { "./src/*.h" } -- rm alloc.h
+	hdrs = {
+		"./src/cclass.h",
+		"./src/extern.h",
+		"./src/io.h",
+		"./src/Lpars.h",
+		"./src/sets.h",
+		"./src/types.h",
+	}
 }
 
 cprogram {
@@ -10,11 +17,28 @@ cprogram {
 	-- tokens.c. If LLgen.g or tokens.g gets updated, they need
 	-- rebuilding. Use the bootstrap target to do this.
 
-	srcs = { "./src/*.c" },
+	srcs = {
+		"./src/LLgen.c",
+		"./src/Lpars.c",
+		"./src/alloc.c",
+		"./src/cclass.c",
+		"./src/check.c",
+		"./src/compute.c",
+		"./src/gencode.c",
+		"./src/global.c",
+		"./src/machdep.c",
+		"./src/main.c",
+		"./src/name.c",
+		"./src/reach.c",
+		"./src/savegram.c",
+		"./src/sets.c",
+		"./src/tokens.c",
+		"./src/utils.c",
+	},
 	deps = { "+headers" },
 	vars = {
 		["+cflags"] = {
-			"-DLIBDIR=\\\""..posix.getcwd().."/"..cwd().."/lib\\\"",
+			"-DLIBDIR=\\\""..cwd().."/lib\\\"",
 			"-DNON_CORRECTING"
 		},
 	}
@@ -55,8 +79,11 @@ definerule("llgen",
 				"util/LLgen+llgen",
 				e.srcs,
 			},
+			vars = {
+				srcs = e.srcs
+			},
 			commands = {
-				"cd %{dir} && rm -f %{outs} && %{abspath(ins)}"
+				"rm -f %{outs} && %{ins[1]} -o%{dirname(outs[1])} %{srcs}"
 			}
 		}
 	end
diff --git a/util/LLgen/doc/LLgen.1 b/util/LLgen/doc/LLgen.1
index 0436ffa30..a50b900b3 100644
--- a/util/LLgen/doc/LLgen.1
+++ b/util/LLgen/doc/LLgen.1
@@ -76,6 +76,9 @@ If the flag is given more than once,
 will be more "verbose".
 If it is given three times, a complete description of the
 grammar will be supplied.
+.IP \fB\-o\fP
+Specifies the location of the output files. If not set, they
+are placed in the current directory.
 .IP \fB\-x\fP
 the sets that are computed are extended with the nonterminal
 symbols and these extended sets are also included in the
diff --git a/util/LLgen/src/extern.h b/util/LLgen/src/extern.h
index d3b3b89d6..82d861dba 100644
--- a/util/LLgen/src/extern.h
+++ b/util/LLgen/src/extern.h
@@ -97,37 +97,40 @@ extern int	strip_grammar;
 extern int	in_production;
 
 /* LLgen.g */
-void LLparse(void);
+extern void LLparse(void);
 
 /* check.c */
-void conflchecks(void);
+extern void conflchecks(void);
 
 /* compute.c */
-void do_compute(void);
-int empty(p_gram);
-int t_safety(int, int, int, int);
-int t_after(int, int, int);
+extern void do_compute(void);
+extern int empty(p_gram);
+extern int t_safety(int, int, int, int);
+extern int t_after(int, int, int);
 
 /* gencode.c */
-void gencode(int);
+extern void gencode(int);
 
 /* machdep.c */
-void TMPNAM(string);
-string libpath(string);
+extern string maketempfile(void);
+extern string libpath(string);
 
 /* main.c */
-void error(int lineno,string s,string t);
-void warning(int lineno,string s,string t);
-void fatal(int lineno,string s,string t);
-void copyfile(string);
-void install(string, string);
+extern void error(int lineno,string s,string t);
+extern void warning(int lineno,string s,string t);
+extern void fatal(int lineno,string s,string t);
+extern void copyfile(string);
+extern void install(string, string);
 
 /* name.c */
-void name_init(void);
-string store(string);
-p_gram search(int, string, int);
+extern void name_init(void);
+extern string store(string);
+extern p_gram search(int, string, int);
 
 /* reach.c */
-void co_reach(void);
+extern void co_reach(void);
+
+/* utils.c */
+extern string aprintf(const char* fmt, ...);
 
 #endif /* EXTERN_H_ */
diff --git a/util/LLgen/src/global.c b/util/LLgen/src/global.c
index e2fcc8599..8333f3684 100644
--- a/util/LLgen/src/global.c
+++ b/util/LLgen/src/global.c
@@ -45,15 +45,16 @@ FILE	*fout;
 FILE	*fpars;
 FILE	*finput;
 FILE	*fact;
-char	f_pars[L_tmpnam+sizeof(char)]; /* Add one more character for NULL, just in case of buggy implementations. */
-char	f_temp[L_tmpnam+sizeof(char)];
+string	f_dir;
+string	f_pars;
+string	f_temp;
 #ifdef NON_CORRECTING
-char	f_nc[20];
+string	f_nc;
 #endif
-char	f_out[20];
+string	f_out;
 string	f_input;
-char	f_include[20];
-char	f_rec[20];
+string	f_include;
+string	f_rec;
 string	e_noopen = "Cannot open %s";
 int	verbose;
 int	wflag;
diff --git a/util/LLgen/src/io.h b/util/LLgen/src/io.h
index fdfe0d630..8b4d68e1a 100644
--- a/util/LLgen/src/io.h
+++ b/util/LLgen/src/io.h
@@ -20,22 +20,23 @@
 
 /* FILES */
 
-# define OUTFILE	"%s.output"	/* -v option */
-# define HFILE		"%spars.h"	/* file for "#define's " */
-# define RFILE		"%spars.c"	/* Error recovery */
+# define OUTFILE	"%s/%s.output"	/* -v option */
+# define HFILE		"%s/%spars.h"	/* file for "#define's " */
+# define RFILE		"%s/%spars.c"	/* Error recovery */
 #ifdef NON_CORRECTING
-# define NCFILE		"%sncor.c"	/* Non-corrcting error recovery */
+# define NCFILE		"%s/%sncor.c"	/* Non-corrcting error recovery */
 #endif
 extern FILE *finput;
 extern FILE *fpars;
 extern FILE *fact;
 extern FILE *fout;
-extern char	f_pars[];
-extern char	f_temp[];
-extern char	f_out[];
-extern string	f_input;
-extern char	f_include[];
-extern char	f_rec[];
+extern string f_dir;
+extern string f_pars;
+extern string f_temp;
+extern string f_out;
+extern string f_input;
+extern string f_include;
+extern string f_rec;
 #ifdef NON_CORRECTING
-extern char	f_nc[];
+extern string f_nc;
 #endif
diff --git a/util/LLgen/src/machdep.c b/util/LLgen/src/machdep.c
index cf43119d4..34df65332 100644
--- a/util/LLgen/src/machdep.c
+++ b/util/LLgen/src/machdep.c
@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 # include "extern.h"
 # include "types.h"
 
@@ -39,18 +40,20 @@ string libpath(string s)
 	char* libdir = getenv("LLGEN_LIB_DIR");
 	if (!libdir)
 		libdir = LIBDIR;
-	length = strlen(libdir) + strlen(s) + 2;
-	p = (string) alloc(length);
-	strcpy(p,libdir);
-	strcat(p,"/");
-	strcat(p,s);
-	return p;
+	return aprintf("%s/%s", libdir, s);
 }
 
-void TMPNAM(string result)
+string maketempfile()
 {
-   if (tmpnam(result)==NULL)
-   {
+	string tmp = getenv("TMP");
+	if (!tmp)
+		tmp = "/tmp";
+
+	string filename = aprintf("%s/llgen-XXXXXX", tmp);
+	int fd = mkstemp(filename);
+	if (fd == -1)
 	   fatal(1, "Cannot create temporary file.", NULL);
-   }
+
+	close(fd);
+	return filename;
 }
diff --git a/util/LLgen/src/main.c b/util/LLgen/src/main.c
index 217214f68..8f2a814c3 100644
--- a/util/LLgen/src/main.c
+++ b/util/LLgen/src/main.c
@@ -37,8 +37,9 @@ int main(int argc, register string argv[])
 {
 	register string arg;
 
-	TMPNAM(f_temp);
-	TMPNAM(f_pars);
+	f_dir = ".";
+	f_temp = maketempfile();
+	f_pars = maketempfile();
 
 	/* Initialize */
 
@@ -116,6 +117,12 @@ int main(int argc, register string argv[])
 			case 'G':
 				strip_grammar = 1;
 				continue;
+
+			case 'o':
+			case 'O':
+				f_dir = ++arg;
+				break;
+
 			default:
 				fprintf(stderr, "illegal option : %c\n", *arg);
 				exit(1);
@@ -170,16 +177,16 @@ int main(int argc, register string argv[])
 	}
 	name_init();
 	readgrammar(argc, argv);
-	sprintf(f_out, OUTFILE, prefix ? prefix : "LL");
+	f_out = aprintf(OUTFILE, f_dir, prefix ? prefix : "LL");
 
 	/* for the following two filenames only one L is used; historical
 	 reasons ...
 	 */
-	sprintf(f_include, HFILE, prefix ? prefix : "L");
-	sprintf(f_rec, RFILE, prefix ? prefix : "L");
+	f_include = aprintf(HFILE, f_dir, prefix ? prefix : "L");
+	f_rec = aprintf(RFILE, f_dir, prefix ? prefix : "L");
 #ifdef NON_CORRECTING
 	if (non_corr)
-	sprintf(f_nc, NCFILE, prefix ? prefix : "L");
+		f_nc = aprintf(NCFILE, f_dir, prefix ? prefix : "L");
 #endif
 	setinit(ntneeded);
 	maxnt = &nonterms[nnonterms];
@@ -377,6 +384,7 @@ void install(string target, string source)
 	register int c1, c2;
 	register FILE *f1, *f2;
 	int cnt;
+	string realtarget = (target[0] != '/') ? aprintf("%s/%s", f_dir, target) : target;
 
 	/*
 	 * First open temporary, generated for source
@@ -388,10 +396,10 @@ void install(string target, string source)
 	/*
 	 * Now open target for reading
 	 */
-	if ((f2 = fopen(target, "r")) == NULL)
+	if ((f2 = fopen(realtarget, "r")) == NULL)
 	{
 		fclose(f1);
-		copyto(target, f_pars);
+		copyto(realtarget, f_pars);
 		return;
 	}
 	/*
@@ -420,6 +428,6 @@ void install(string target, string source)
 		{
 			fatal(0, "%s : not a file generated by LLgen", target);
 		}
-		copyto(target, f_pars);
+		copyto(realtarget, f_pars);
 	}
 }
diff --git a/util/LLgen/src/utils.c b/util/LLgen/src/utils.c
new file mode 100644
index 000000000..7da06e9fa
--- /dev/null
+++ b/util/LLgen/src/utils.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+const char* aprintf(const char* fmt, ...)
+{
+    int n;
+    char* p;
+    va_list ap;
+
+    va_start(ap, fmt);
+    n = vsnprintf(NULL, 0, fmt, ap) + 1;
+    va_end(ap);
+
+    p = malloc(n);
+    if (!p)
+        return NULL;
+
+    va_start(ap, fmt);
+    vsnprintf(p, n, fmt, ap);
+    va_end(ap);
+
+    return p;
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
+