List.iter (fun s -> require (compiled s)) sources;
let objects = List.map (change_file_extension "o") sources in
- sh "cc %s -o %s" (String.concat " " objects) program
+ sh "cd $builddir && cc %s -o %s" (String.concat " " objects) program
(* Goal: Make sure a C file is compiled (to an object file). *)
and compiled c_file =
let o_file = change_file_extension "o" c_file in
target (more_recent [o_file] [c_file]);
require (file_exists c_file);
- sh "cc -c %s -o %s" c_file o_file
+ sh "cd $builddir && cc -c %s -o %s" c_file o_file
(* XXX IMPLICIT *)
let () =
unlink tmp;
r
+(* Create a temporary directory. It is *not* deleted on exit. *)
+let tmpdir () =
+ let chan = open_in "/dev/urandom" in
+ let data = String.create 16 in
+ really_input chan data 0 (String.length data);
+ close_in chan;
+ let data = Digest.to_hex (Digest.string data) in
+ let dir = Filename.temp_dir_name // sprintf "goaljobstmp%s" data in
+ mkdir dir 0o700;
+ dir
+
+(* Recursively remove directory. *)
+let rm_rf dir =
+ let cmd = sprintf "rm -rf %s" (quote dir) in
+ ignore (Sys.command cmd)
+
+let shell = ref "/bin/sh"
+
+(* Used by sh, shout etc. Create a temporary directory and a
+ * 'script.sh' inside it containing the script to run. Returns the
+ * temporary directory and command to run.
+ *)
+let create_script script =
+ let dir = tmpdir () in
+ let script_file = dir // "script.sh" in
+ let chan = open_out script_file in
+ fprintf chan "#!%s\n" !shell;
+ fprintf chan "set -e\n"; (* so that job exits on error *)
+ fprintf chan "set -x\n"; (* echo commands (must be last) *)
+ fprintf chan "\n";
+ output_string chan script;
+ close_out chan;
+ chmod script_file 0o700;
+ let cmd = sprintf "cd %s && exec %s" (quote dir) (quote script_file) in
+ dir, cmd
let sh fs =
- let do_sh cmd =
- let cmd = "set -e\nset -x\n\n" ^ cmd in
+ let do_sh script =
+ let dir, cmd = create_script script in
let r = Sys.command cmd in
+ rm_rf dir;
if r <> 0 then (
let msg = sprintf "external command failed with code %d" r in
goal_failed msg
in
ksprintf do_sh fs
-let do_shlines cmd =
- let cmd = "set -e\nset -x\n\n" ^ cmd in
+let do_shlines script =
+ let dir, cmd = create_script script in
let chan = open_process_in cmd in
let lines = ref [] in
let rec loop () =
in
(try loop () with End_of_file -> ());
let r = close_process_in chan in
+ rm_rf dir;
match r with
| WEXITED 0 -> List.rev !lines
| WEXITED i ->
goal_failed msg
let shlines fs = ksprintf do_shlines fs
-let do_shout cmd =
- let lines = do_shlines cmd in
+let do_shout script =
+ let lines = do_shlines script in
String.concat "\n" lines
let shout fs = ksprintf do_shout fs
(*
-val shell : string ref
-*)
-
-(*
val replace_substring : string -> string -> string -> string
*)
let prog = Sys.executable_name in
let prog = Filename.basename prog in
+ (* Save the current working directory when the program started. *)
+ putenv "builddir" (getcwd ());
+
let args = ref [] in
let display_version () =
let o_file = change_file_extension "o" c_file in
target (more_recent [o_file] [c_file]);
- sh "cc -c %s -o %s" c_file o_file
+ sh "cd $builddir && cc -c %s -o %s" c_file o_file
}
In the second example, the rule requires that several files
require (compiled source);
let object = change_file_extension "o" source in
- sh "cc %s -o %s" object program
+ sh "cd $builddir && cc %s -o %s" object program
}
*)
{v command ||: }
to ignore the result of a command.
- Each shell runs in a new temporary directory. The temporary directory
- and all its contents is deleted after the shell exits. If you
- want to save any data, [cd] somewhere. For example you could start
- the command sequence with:
- {v cd $HOME/data/ }
+ Each shell runs in a new temporary directory. The temporary
+ directory and all its contents is deleted after the shell exits.
+ If you want to save any data, [cd] somewhere. The environment
+ variable [$builddir] is exported to the script. This is the
+ current directory when the goaljobs program was started.
+
+ For example you could start the command sequence with
+ [cd $HOME/data/] or [cd $builddir].
*)
val sh : ('a, unit, string, unit) format4 -> 'a
Any lines printed to stdout is returned as a list of strings.
Trailing [\n] characters are not returned. *)
-(*
val shell : string ref
(** Set this variable to override the default shell ([/bin/sh]). *)
-*)
(** {2 String functions}