C build tool of the 21st century
at main 140 lines 4.3 kB view raw
1open Types 2 3type t = { 4 env : Eio_posix.stdenv; 5 hidden : bool; 6 source : path; 7 build : path; 8 compiler_index : (string, Compiler.t) Hashtbl.t; 9 compilers : Compiler.Set.t; 10 linker : Linker.t option; 11 script : string option; 12 after : string option; 13 depends_on : string list; 14 name : string; 15 pkgconf : string list; 16 ignore : Re.t list; 17 output : path option; 18 disable_cache : bool; 19 mtime : float; 20 parallel : bool; 21 log_level : Util.log_level; 22 mutable files : Re.t list; 23 mutable headers : Re.t list; 24 mutable flags : Flags.t; 25 mutable compiler_flags : (string, Flags.t) Hashtbl.t; 26} 27 28module External = struct 29 type nonrec t = { path : string; target : string; build : t } 30end 31 32let add_compile_flags t = Flags.add_compile_flags t.flags 33let add_link_flags t = Flags.add_link_flags t.flags 34let obj_path t = Eio.Path.(t.build / "obj" / t.name) 35 36let v ?build ?(parallel = true) ?(hidden = false) ?mtime ?(pkgconf = []) ?script 37 ?after ?(depends_on = []) ?flags ?linker ?compilers ?(compiler_flags = []) 38 ?(files = []) ?(headers = []) ?(ignore = []) ?(disable_cache = false) 39 ?(log_level = `Quiet) ?output ~source ~name env = 40 let compilers = 41 match compilers with 42 | None -> Compiler.Set.default 43 | Some compilers -> 44 Compiler.Set.union Compiler.Set.default 45 @@ Compiler.Set.of_list compilers 46 in 47 let build = 48 match build with 49 | None -> Eio.Path.(env#cwd / "zenon-build") 50 | Some path -> path 51 in 52 Eio.Path.mkdirs ~exists_ok:true build ~perm:0o755; 53 let compiler_flags = Hashtbl.of_seq (List.to_seq compiler_flags) in 54 let compiler_index = Hashtbl.create 8 in 55 Compiler.Set.iter 56 (fun c -> 57 String_set.iter (fun ext -> Hashtbl.replace compiler_index ext c) c.ext) 58 compilers; 59 { 60 parallel; 61 pkgconf; 62 env; 63 source; 64 build; 65 compiler_index; 66 compilers; 67 linker; 68 files = List.map Util.glob files; 69 headers = List.map Util.glob headers; 70 script; 71 after; 72 depends_on; 73 flags = Option.value ~default:(Flags.v ()) flags; 74 output; 75 ignore; 76 name; 77 compiler_flags; 78 disable_cache; 79 mtime = Option.value ~default:(Unix.gettimeofday ()) mtime; 80 hidden; 81 log_level; 82 } 83 84let special_dirs = String_set.of_list [ "zenon-build"; ".git"; ".jj" ] 85let is_special_dir name = String_set.mem name special_dirs 86 87let rec collect_all count check_ignore root path = 88 let entries = Eio.Path.read_dir path |> List.to_seq in 89 Seq.concat_map 90 (fun name -> 91 incr count; 92 let full_path = Eio.Path.(path / name) in 93 if Eio.Path.is_directory full_path then 94 let rel_path = Util.relative_to root full_path in 95 if (not (is_special_dir name)) && check_ignore rel_path then 96 collect_all count check_ignore root full_path 97 else Seq.empty 98 else Seq.return full_path) 99 entries 100 101let locate_files t = function 102 | [] -> Seq.empty 103 | patterns -> 104 let ignore_re = Re.alt t.ignore |> Re.compile in 105 let check_ignore f = 106 match t.ignore with [] -> true | _ -> not (Re.execp ignore_re f) 107 in 108 let count = ref 0 in 109 let all_files = collect_all count check_ignore t.source t.source |> List.of_seq in 110 let seen = Hashtbl.create (List.length all_files) in 111 List.concat_map 112 (fun pattern -> 113 let re = Re.compile pattern in 114 List.filter_map 115 (fun path -> 116 let path_str = Eio.Path.native_exn path in 117 if Hashtbl.mem seen path_str then None 118 else 119 let rel_path = Util.relative_to t.source path in 120 if Re.execp re rel_path then ( 121 Hashtbl.add seen path_str true; 122 Some path) 123 else None) 124 all_files) 125 patterns 126 |> List.to_seq 127 128let locate_source_files t : Source_file.t Seq.t = 129 locate_files t t.files 130 |> Seq.map (fun path -> Source_file.v ~root:t.source path) 131 132let locate_headers t : path Seq.t = locate_files t t.headers 133let add_source_file t path = t.files <- t.files @ [ Util.glob path ] 134 135let add_source_files t ?(reset = false) files = 136 if reset then t.files <- []; 137 t.files <- t.files @ List.map Util.glob files 138 139let clean t = Eio.Path.rmtree ~missing_ok:true t.build 140let clean_obj t = Eio.Path.rmtree ~missing_ok:true (obj_path t)