diff --git a/bootstrap b/bootstrap index 3ba164e..0a9a1f7 100755 --- a/bootstrap +++ b/bootstrap @@ -1,6 +1,6 @@ #!/usr/bin/env bash -libs="unix.cmxa" +libs="unix.cmxa str.cmxa" OCAMLOPT="ocamlopt -g" # use faster ocamlopt, if available OCAMLOPT_OPT=`which ocamlopt.opt` @@ -8,7 +8,7 @@ if [[ $OCAMLOPT_OPT != "" ]] ; then OCAMLOPT="ocamlopt.opt -g" fi -extmodules="fugue filepath filesystem" +extmodules="bash fugue filepath filesystem" libmodules="types gconf filetype dag libname pp expr utils modname taskdep helper dagutils process findlibConf scheduler prog dependencies generators hier meta target dist project analyze configure prepare buildprogs build exception" mainmodules="sdist doc init help install path_generated main" diff --git a/ext/bash.ml b/ext/bash.ml new file mode 100644 index 0000000..d41cb3d --- /dev/null +++ b/ext/bash.ml @@ -0,0 +1,73 @@ +open Printf +open Sys + +let is_bash_enabled = ref false +let filename = ref "" +let lib_path = ref "" + +let create_bash fn = + let oc = open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_text] 0o740 !filename in + try + fprintf oc "#!/bin/bash\n"; + fprintf oc "# Automatically generated file.\n# EDIT AT YOUR OWN RISK !!\n\n"; + fprintf oc "# Find library path\n"; + fprintf oc "conf_path=$(ocamlfind printconf conf)\n"; + fprintf oc "lib_path=$(grep path ${conf_path} | sed 's/path=//' | sed 's/\"//g')\n\n"; + close_out oc + with e -> + close_out_noerr oc; + raise e + +let init_bash fn cmd stdlibPath = + is_bash_enabled := true; + lib_path := stdlibPath; + match fn with + | Some name -> (match cmd with + | "configure" -> (filename := name; create_bash name) + | "build" -> (filename := name; if Sys.file_exists name then () else create_bash name) + | _ -> failwith "--bash can only be used with build and configure options") + | None -> failwith "bash field is empty !!" + +let bash_write str = + if !is_bash_enabled then + begin + let oc = open_out_gen [Open_creat; Open_text; Open_append] 0o740 !filename in + try + fprintf oc "%s\n" str; + close_out oc; + with e -> + close_out_noerr oc; + raise e; + end + else () + +let bash_cmd args = + let bash_set_var str = bash_write (Str.global_replace (Str.regexp_string !lib_path) "${lib_path}" str) in + let cmd_tmp = List.hd args in + let cmd_len = String.length cmd_tmp in + try + let cmd_pos = (String.rindex cmd_tmp '/') + 1 in + let cmd = String.sub cmd_tmp cmd_pos (cmd_len - cmd_pos) in + bash_set_var (String.concat " " (cmd :: (List.tl args))) + with e -> match e with + | Not_found -> bash_set_var (String.concat " " args) + | _ -> raise e + +let bash_comment str = bash_write ("\n# " ^ str) + +let bash_mkdir str perm = bash_write ("mkdir -m " ^ (sprintf "%o" perm) ^ " " ^ str) + +let bash_symlink target link_name = bash_write ("ln -s " ^ target ^ " " ^ link_name) + +let bash_generateMlFile version file flags = + bash_write ("echo \"(* autogenerated file by obuild. do not modify *)\" >> " ^ file); + bash_write (sprintf "echo \"let project_version = \\\"%s\\\"\" >> %s" version file); + List.iter (fun (name, v) -> bash_write (sprintf "let project_flag_%s = %b >> %s" name v file)) flags + +let bash_generateCFile version file flags = + bash_write ("echo \"/* autogenerated file by obuild. do not modify */\" >> " ^ file); + bash_write (sprintf "echo \"#define PROJECT_VERSION \\\"%s\\\"\" >> %s" version file); + List.iter (fun (name, v) -> bash_write (sprintf "#define PROJECT_FLAG_%s %d >> %s" + (String.uppercase name) (if v then 1 else 0) file)) flags + + diff --git a/ext/filesystem.ml b/ext/filesystem.ml index cc2e0b7..a37a90d 100644 --- a/ext/filesystem.ml +++ b/ext/filesystem.ml @@ -1,6 +1,7 @@ open Printf open Fugue open Filepath +open Bash exception UnexpectedFileType of string exception WriteFailed @@ -96,7 +97,7 @@ let mkdirSafe path perm = then (if Sys.is_directory (fp_to_string path) then false else failwith ("directory " ^ (fp_to_string path) ^ " cannot be created: file already exists")) - else (Unix.mkdir (fp_to_string path) perm; true) + else (Unix.mkdir (fp_to_string path) perm; Bash.bash_mkdir (fp_to_string path) perm; true) let mkdirSafe_ path perm = let (_: bool) = mkdirSafe path perm in diff --git a/obuild.obuild b/obuild.obuild index a7eea0b..940c74a 100644 --- a/obuild.obuild +++ b/obuild.obuild @@ -47,26 +47,26 @@ extra-srcs: bootstrap library obuild modules: obuild - build-deps: unix, obuild.ext + build-deps: unix, str, obuild.ext library ext modules: ext - build-deps: unix + build-deps: unix, str # a comment executable obuild main-is: main.ml src-dir: src - build-deps: unix, obuild + build-deps: unix, str, obuild executable obuild-simple main-is: simple.ml src-dir: src - build-deps: unix, obuild + build-deps: unix, str, obuild executable obuild-from-oasis main-is: assimilate_oasis.ml src-dir: tools - build-deps: obuild, obuild.ext + build-deps: str, obuild, obuild.ext installable: false test dag diff --git a/obuild/build.ml b/obuild/build.ml index a496ac3..609b13a 100644 --- a/obuild/build.ml +++ b/obuild/build.ml @@ -1,5 +1,6 @@ open Ext.Fugue open Ext.Filepath +open Ext.Bash open Ext open Types open Helper @@ -129,6 +130,8 @@ let compile_c task_index task c_file bstate task_context dag = let (nb_step,nb_step_len) = get_nb_step dag in verbose Report "[%*d of %d] Compiling C %-30s%s\n%!" nb_step_len task_index nb_step (fn_to_string c_file) (if reason <> "" then " ( " ^ reason ^ " )" else ""); + bash_comment (sprintf "[%*d of %d] Compiling C %-30s%s%!" nb_step_len task_index nb_step (fn_to_string c_file) + (if reason <> "" then " ( " ^ reason ^ " )" else "")); let cflags = cbits.target_cflags in Scheduler.AddProcess (task, runCCompile bstate.bstate_config c_dir_spec cflags c_file) ) @@ -176,6 +179,7 @@ let compile_directory task_index task (h : Hier.t) task_context dag = if ops <> [] then ( let (nb_step,nb_step_len) = get_nb_step dag in verbose Report "[%*d of %d] Packing %-30s%s\n%!" nb_step_len task_index nb_step (Hier.to_string h) reason; + bash_comment (sprintf "[%*d of %d] Packing %-30s%s%!" nb_step_len task_index nb_step (Hier.to_string h) reason); Scheduler.AddTask (task, ops) ) else Scheduler.FinishTask task @@ -287,6 +291,8 @@ let compile_module task_index task is_intf h bstate task_context dag = let (nb_step, nb_step_len) = get_nb_step dag in verbose Report "[%*d of %d] %s %-30s%s\n%!" nb_step_len task_index nb_step verb (Hier.to_string h) (if reason <> "" then " ( " ^ reason ^ " )" else ""); + bash_comment (sprintf "[%*d of %d] %s %-30s%s%!" nb_step_len task_index nb_step verb (Hier.to_string h) + (if reason <> "" then " ( " ^ reason ^ " )" else "")); Scheduler.AddTask (task, all_fun_lists) let wait_for_files cdep_files = @@ -375,6 +381,8 @@ let link_ task_index bstate cstate pkgDeps target dag compiled useThreadLib ccli if is_lib target then LinkingLibrary else LinkingExecutable in verbose Report "[%*d of %d] Linking %s %s\n%!" nb_step_len task_index nb_step (if is_lib target then "library" else "executable") (fp_to_string dest); + bash_comment (sprintf "[%*d of %d] Linking %s %s%!" nb_step_len task_index nb_step + (if is_lib target then "library" else "executable") (fp_to_string dest)); [(fun () -> runOcamlLinking (linking_paths_of compileOpt) compiledType link_type compileOpt useThreadLib systhread cclibs buildDeps compiled dest)] ) else [] diff --git a/obuild/buildprogs.ml b/obuild/buildprogs.ml index 11a77d0..91cca02 100644 --- a/obuild/buildprogs.ml +++ b/obuild/buildprogs.ml @@ -2,6 +2,7 @@ open Types open Ext open Ext.Filepath open Ext.Fugue +open Ext.Bash open Process open Prepare open Gconf @@ -139,7 +140,7 @@ let runOcamlLinking includeDirs buildMode linkingMode compileType useThread syst let real = fp_to_string dest in let basename = Filename.basename real in if not (file_or_link_exists basename) - then Unix.symlink real basename) + then Unix.symlink real basename; bash_symlink real basename;) in let prog = match buildMode with | Native -> Prog.getOcamlOpt () diff --git a/obuild/configure.ml b/obuild/configure.ml index 0a2b482..f7e3dc6 100644 --- a/obuild/configure.ml +++ b/obuild/configure.ml @@ -1,5 +1,6 @@ open Ext.Fugue open Ext.Filepath +open Ext.Bash open Ext open Helper open Printf @@ -18,22 +19,26 @@ let getDigestKV () = [ ("obuild-digest", digest) ] let generateMlFile project file flags = - Utils.generateFile file (fun add -> - add "(* autogenerated file by obuild. do not modify *)\n"; - add (sprintf "let project_version = \"%s\"\n" project.Analyze.project_file.Project.version); - (* TODO escape name properly *) - List.iter (fun (name, v) -> add (sprintf "let project_flag_%s = %b\n" name v)) flags; - ) + let version = project.Analyze.project_file.Project.version in + Utils.generateFile file (fun add -> + add "(* autogenerated file by obuild. do not modify *)\n"; + add (sprintf "let project_version = \"%s\"\n" version); + (* TODO escape name properly *) + List.iter (fun (name, v) -> add (sprintf "let project_flag_%s = %b\n" name v)) flags; + ); + bash_generateMlFile version (fp_to_string file) flags let generateCFile project file flags = - Utils.generateFile file (fun add -> - add "/* autogenerated file by obuild. do not modify */\n"; - add (sprintf "#define PROJECT_VERSION \"%s\"\n" project.Analyze.project_file.Project.version); - (* TODO escape name properly *) - List.iter (fun (name, v) -> - add (sprintf "#define PROJECT_FLAG_%s %d\n" (String.uppercase name) (if v then 1 else 0)) - ) flags; - ) + let version = project.Analyze.project_file.Project.version in + Utils.generateFile file (fun add -> + add "/* autogenerated file by obuild. do not modify */\n"; + add (sprintf "#define PROJECT_VERSION \"%s\"\n" version); + (* TODO escape name properly *) + List.iter (fun (name, v) -> + add (sprintf "#define PROJECT_FLAG_%s %d\n" (String.uppercase name) (if v then 1 else 0)) + ) flags; + ); + bash_generateCFile version (fp_to_string file) flags let makeSetup digestKV project flags = hashtbl_fromList ( digestKV diff --git a/obuild/gconf.ml b/obuild/gconf.ml index 7b17cff..ebb063b 100644 --- a/obuild/gconf.ml +++ b/obuild/gconf.ml @@ -8,6 +8,7 @@ type t = { mutable parallel_jobs : int; mutable dump_dot : bool; mutable color : bool; + mutable bash : bool; mutable bin_annot : bool; mutable short_path : bool; mutable ocamlmklib : bool; @@ -18,7 +19,8 @@ exception UnknownOption of string let env_variables = [ "ocamlopt"; "ocamlc"; "ocaml"; "ocamldep"; "ocamldoc"; "ocamlyacc"; "ocamllex"; "ocamlmklib"; - "ocamlmktop"; "cc"; "ranlib"; "ar"; "ld"; "pkg-config"; "camlp4"; "findlib-path"; "atdgen" + "ocamlmktop"; "cc"; "ranlib"; "ar"; "ld"; "pkg-config"; "camlp4"; "findlib-path"; "atdgen"; + "bash" ] let env_ = @@ -77,6 +79,7 @@ let defaults = { parallel_jobs = 2; dump_dot = false; color = false; + bash = false; bin_annot = true; short_path = false; ocamlmklib = true; diff --git a/obuild/process.ml b/obuild/process.ml index daabc91..e9341df 100644 --- a/obuild/process.ml +++ b/obuild/process.ml @@ -1,5 +1,7 @@ open Helper open Gconf +open Ext.Bash +open Ext type output = { buf : Buffer.t; @@ -29,6 +31,7 @@ let make args = let _ = String.index s ' ' in "\"" ^ s ^ "\"" with Not_found -> s in verbose DebugPlus " [CMD]: %s\n%!" (String.concat " " (List.map escape args)); + bash_cmd args; let (r1,w1) = Unix.pipe () in let (r2,w2) = Unix.pipe () in let argv = Array.of_list args in diff --git a/src/main.ml b/src/main.ml index bd75d45..b330eb3 100644 --- a/src/main.ml +++ b/src/main.ml @@ -5,6 +5,7 @@ open Ext open Obuild.Types open Obuild.Helper open Obuild.Gconf +open Obuild.Analyze open Obuild let programName = "obuild" @@ -88,8 +89,9 @@ let mainBuild argv = | _ -> let targets = List.map Target.Name.of_string !anon in Dag.subset project.Analyze.project_targets_dag targets - in - Build.build_dag bstate proj_file dag + in ( + Build.build_dag bstate proj_file dag + ) let mainClean _ = if Filesystem.exists (Dist.get_path ()) @@ -226,6 +228,16 @@ let mainGet argv = | "name" -> printf "%s\n" proj_file.Project.name; | "version" -> printf "%s\n" proj_file.Project.version; | "license" -> printf "%s\n" proj_file.Project.license; + | "ocaml_extra_args" -> (match proj_file.Project.ocaml_extra_args with + | Some x -> List.iter (function y -> printf "%s\n" y) x + | None -> printf "None\n"); + | "configure_script" -> (match proj_file.Project.configure_script with + | Some x -> printf "%s\n" (fp_to_string (x)) + | None -> printf "None\n"); + | "extra_srcs" -> List.iter (function x -> printf "%s\n" (fp_to_string (x))) proj_file.Project.extra_srcs; + (*| "extra_args" -> match proj_file.Project.ocaml_extra_args with + | None -> printf "None\n"; + | Some v -> List.iter (function x -> printf "%s\n" x) v;*) | _ -> eprintf "error: unknown field %s\n" field; exit 1 ) | _ -> eprintf "usage: obuild get \n"; exit 1 @@ -272,6 +284,7 @@ let parseGlobalArgs () = | [] -> failwith (optName ^ " expect a parameter") | x::xs -> f x; xs in + let rec processGlobalArgs l = match l with | x::xs -> if String.length x > 0 && x.[0] = '-' @@ -288,6 +301,7 @@ let parseGlobalArgs () = | "-vvv" | "--debug+" | "--debug-with-cmd" -> gconf.verbosity <- DebugPlus; xs + | "--bash" -> expect_param1 x xs (fun p -> (gconf.bash <- true; Gconf.set_env "bash" p;)) | "-q" (* for quiet *) | "--silent" -> gconf.verbosity <- Silent; xs | "--strict" -> gconf.strict <- true; xs @@ -333,6 +347,19 @@ let defaultMain () = ); let cmd = List.hd args in + + let ocamlCfg = Prog.getOcamlConfig () in + if gconf.bash then + begin + FindlibConf.load (); + let stdlibPath = match FindlibConf.get_destdir () with + | None -> if gconf.bash then failwith "Cannot find dest_dir in with ocamlfind" else "" + | Some str -> fp_to_string (str) + in + Bash.init_bash (Gconf.get_env "bash") cmd stdlibPath; + end + else (); + try let mainF = List.assoc cmd knownCommands in mainF args