PageRenderTime 30ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/sw/tools/gen_aircraft.ml

http://github.com/pchickey/paparazzi-linux-release
OCaml | 280 lines | 204 code | 39 blank | 37 comment | 13 complexity | bf1bee7dde7ddc1d65e9d29c696eef1b MD5 | raw file
Possible License(s): GPL-2.0
  1. (*
  2. * $Id: gen_aircraft.ml 4198 2009-09-23 19:15:40Z hecto $
  3. *
  4. * Call to Makefile.ac with the appropriate attributes from conf.xml
  5. *
  6. * Copyright (C) 2003-2009 Pascal Brisset, Antoine Drouin, ENAC
  7. *
  8. * This file is part of paparazzi.
  9. *
  10. * paparazzi is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2, or (at your option)
  13. * any later version.
  14. *
  15. * paparazzi is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with paparazzi; see the file COPYING. If not, write to
  22. * the Free Software Foundation, 59 Temple Place - Suite 330,
  23. * Boston, MA 02111-1307, USA.
  24. *
  25. *)
  26. open Printf
  27. module U = Unix
  28. let (//) = Filename.concat
  29. let paparazzi_conf = Env.paparazzi_home // "conf"
  30. let conf_xml = paparazzi_conf // "conf.xml"
  31. let modules_dir = paparazzi_conf // "modules"
  32. let mkdir = fun d ->
  33. assert (Sys.command (sprintf "mkdir -p %s" d) = 0)
  34. (** Raises a Failure if an ID or a NAME appears twice in the conf *)
  35. let check_unique_id_and_name = fun conf ->
  36. let ids = Hashtbl.create 5
  37. and names = Hashtbl.create 5 in
  38. List.iter
  39. (fun x ->
  40. if String.lowercase (Xml.tag x) = "aircraft" then
  41. let id = ExtXml.attrib x "ac_id"
  42. and name = ExtXml.attrib x "name" in
  43. if Hashtbl.mem ids id then begin
  44. let other_name = Hashtbl.find ids id in
  45. failwith (sprintf "Error: A/C Id '%s' duplicated in %s (%s and %s)" id conf_xml name other_name)
  46. end;
  47. if Hashtbl.mem names name then begin
  48. let other_id = Hashtbl.find names name in
  49. failwith (sprintf "Error: A/C name '%s' duplicated in %s (ids %s and %s)" name conf_xml id other_id)
  50. end;
  51. Hashtbl.add ids id name;
  52. Hashtbl.add names name id)
  53. (Xml.children conf)
  54. let pipe_regexp = Str.regexp "|"
  55. let targets_of_field = fun field ->
  56. try
  57. Str.split pipe_regexp (Xml.attrib field "target")
  58. with
  59. _ -> []
  60. let get_modules = fun dir m ->
  61. match String.lowercase (Xml.tag m) with
  62. "load" -> dir // ExtXml.attrib m "name"
  63. | tag -> failwith (sprintf "Warning: tag load is undefined; found '%s'" tag)
  64. (** Extracts the makefile section of an airframe file *)
  65. let extract_makefile = fun airframe_file makefile_ac ->
  66. let xml = Xml.parse_file airframe_file in
  67. let f = open_out makefile_ac in
  68. fprintf f "# This file has been generated from %s by %s\n" airframe_file Sys.argv.(0);
  69. fprintf f "# Please DO NOT EDIT\n";
  70. (** Search and dump the makefile sections *)
  71. List.iter (fun x ->
  72. if ExtXml.tag_is x "makefile" then begin
  73. begin try
  74. fprintf f "\n# makefile target '%s'\n" (Xml.attrib x "target")
  75. with _ -> () end;
  76. match Xml.children x with
  77. [Xml.PCData s] -> fprintf f "%s\n" s
  78. | _ -> failwith (sprintf "Warning: wrong makefile section in '%s': %s\n" airframe_file (Xml.to_string_fmt x))
  79. end)
  80. (Xml.children xml);
  81. (** Look for modules *)
  82. let modules_exist = ref [] in (* Targets requring modules *)
  83. let files = ref [] in
  84. List.iter (fun x ->
  85. if ExtXml.tag_is x "modules" then
  86. let modules_names =List.map (get_modules modules_dir) (Xml.children x) in
  87. List.iter (fun name -> files := name :: !files) modules_names;
  88. let modules_list = List.map Xml.parse_file modules_names in
  89. List.iter (fun modul ->
  90. let name = ExtXml.attrib modul "name" in
  91. let dir_name = (String.uppercase name)^"_DIR" in
  92. fprintf f "\n# makefile for module %s\n" name;
  93. fprintf f "%s = $(PAPARAZZI_SRC)/sw/airborne/modules/%s\n" dir_name name;
  94. List.iter (fun l ->
  95. if ExtXml.tag_is l "makefile" then begin
  96. let targets = targets_of_field l in
  97. List.iter (fun t ->
  98. if not (List.mem t !modules_exist) then begin
  99. fprintf f "%s.srcs += $(ACINCLUDE)/modules.c\n" t;
  100. modules_exist := t :: !modules_exist
  101. end;
  102. fprintf f "%s.CFLAGS += -I $(%s)\n" t dir_name
  103. ) targets;
  104. List.iter (fun field ->
  105. match String.lowercase (Xml.tag field) with
  106. "flag" ->
  107. List.iter
  108. (fun target ->
  109. let value = try "="^(Xml.attrib field "value") with _ -> ""
  110. and name = Xml.attrib field "name" in
  111. fprintf f "%s.CFLAGS += -D%s%s\n" target name value)
  112. targets
  113. | "file" ->
  114. let name = Xml.attrib field "name" in
  115. List.iter (fun target -> fprintf f "%s.srcs += $(%s)/%s\n" target dir_name name) targets
  116. | "define" ->
  117. let value = Xml.attrib field "value"
  118. and name = Xml.attrib field "name" in
  119. fprintf f "%s = %s\n" name value
  120. | "raw" ->
  121. begin match Xml.children field with
  122. [Xml.PCData s] -> fprintf f "%s\n" s
  123. | _ -> fprintf stderr "Warning: wrong makefile section in module '%s'\n" name
  124. end
  125. | _ -> ()
  126. )
  127. (Xml.children l)
  128. end)
  129. (Xml.children modul))
  130. modules_list)
  131. (Xml.children xml);
  132. close_out f;
  133. !files
  134. let is_older = fun target_file dep_files ->
  135. not (Sys.file_exists target_file) ||
  136. let target_file_time = (U.stat target_file).U.st_mtime in
  137. let rec loop = function
  138. [] -> false
  139. | f::fs ->
  140. target_file_time < (U.stat f).U.st_mtime ||
  141. loop fs in
  142. loop dep_files
  143. let make_element = fun t a c -> Xml.Element (t,a,c)
  144. (******************************* MAIN ****************************************)
  145. let () =
  146. try
  147. if Array.length Sys.argv <> 2 then
  148. failwith (sprintf "Usage: %s <A/C ident (conf.xml)>" Sys.argv.(0));
  149. let aircraft = Sys.argv.(1) in
  150. let conf = Xml.parse_file conf_xml in
  151. check_unique_id_and_name conf;
  152. let aircraft_xml =
  153. try
  154. ExtXml.child conf ~select:(fun x -> Xml.attrib x "name" = aircraft) "aircraft"
  155. with
  156. Not_found -> failwith (sprintf "Aircraft '%s' not found in '%s'" aircraft conf_xml)
  157. in
  158. let value = fun attrib -> ExtXml.attrib aircraft_xml attrib in
  159. let aircraft_dir = Env.paparazzi_home // "var" // aircraft in
  160. let aircraft_conf_dir = aircraft_dir // "conf" in
  161. mkdir (Env.paparazzi_home // "var");
  162. mkdir aircraft_dir;
  163. mkdir (aircraft_dir // "fbw");
  164. mkdir (aircraft_dir // "autopilot");
  165. mkdir (aircraft_dir // "sim");
  166. mkdir aircraft_conf_dir;
  167. mkdir (aircraft_conf_dir // "airframes");
  168. mkdir (aircraft_conf_dir // "flight_plans");
  169. mkdir (aircraft_conf_dir // "radios");
  170. mkdir (aircraft_conf_dir // "settings");
  171. mkdir (aircraft_conf_dir // "telemetry");
  172. let settings =
  173. try value "settings" with
  174. _ ->
  175. fprintf stderr "\nWARNING: No 'settings' attribute specified for A/C '%s', using 'settings/basic.xml'\n\n%!" aircraft;
  176. "settings/basic.xml" in
  177. (** Expands the configuration of the A/C into one single file *)
  178. let conf_aircraft = Env.expand_ac_xml aircraft_xml in
  179. let configuration =
  180. make_element
  181. "configuration"
  182. []
  183. [make_element "conf" [] [conf_aircraft]; Pprz.messages_xml ()] in
  184. let conf_aircraft_file = aircraft_conf_dir // "conf_aircraft.xml" in
  185. let f = open_out conf_aircraft_file in
  186. Printf.fprintf f "%s\n" (ExtXml.to_string_fmt configuration);
  187. close_out f;
  188. (** Computes and store a signature of the configuration *)
  189. let md5sum = Digest.to_hex (Digest.file conf_aircraft_file) in
  190. let md5sum_file = aircraft_conf_dir // "aircraft.md5" in
  191. (* Store only if different from previous one *)
  192. if not (Sys.file_exists md5sum_file
  193. && md5sum = input_line (open_in md5sum_file)) then begin
  194. let f = open_out md5sum_file in
  195. Printf.fprintf f "%s\n" md5sum;
  196. close_out f;
  197. (** Save the configuration for future use *)
  198. let d = U.localtime (U.gettimeofday ()) in
  199. let filename = sprintf "%02d_%02d_%02d__%02d_%02d_%02d_%s_%s.conf" (d.U.tm_year mod 100) (d.U.tm_mon+1) (d.U.tm_mday) (d.U.tm_hour) (d.U.tm_min) (d.U.tm_sec) md5sum aircraft in
  200. let d = Env.paparazzi_home // "var" // "conf" in
  201. mkdir d;
  202. let f = open_out (d // filename) in
  203. Printf.fprintf f "%s\n" (ExtXml.to_string_fmt configuration);
  204. close_out f end;
  205. let airframe_file = value "airframe" in
  206. let airframe_dir = Filename.dirname airframe_file in
  207. let var_airframe_dir = aircraft_conf_dir // airframe_dir in
  208. mkdir var_airframe_dir;
  209. assert (Sys.command (sprintf "cp %s %s" (paparazzi_conf // airframe_file) var_airframe_dir) = 0);
  210. (** Calls the Makefile with target and options *)
  211. let make = fun target options ->
  212. let c = sprintf "make -f Makefile.ac AIRCRAFT=%s AC_ID=%s AIRFRAME_XML=%s TELEMETRY=%s SETTINGS=\"%s\" MD5SUM=\"%s\" %s %s" aircraft (value "ac_id") airframe_file (value "telemetry") settings md5sum options target in
  213. begin (** Quiet is speficied in the Makefile *)
  214. try if Sys.getenv "Q" <> "@" then raise Not_found with
  215. Not_found -> prerr_endline c
  216. end;
  217. let returned_code = Sys.command c in
  218. if returned_code <> 0 then
  219. exit returned_code in
  220. (** Calls the makefile if the optional attribute is available *)
  221. let make_opt = fun target var attr ->
  222. try
  223. let value = Xml.attrib aircraft_xml attr in
  224. make target (sprintf "%s=%s" var value)
  225. with
  226. Xml.No_attribute _ -> () in
  227. let temp_makefile_ac = Filename.temp_file "Makefile.ac" "tmp" in
  228. let abs_airframe_file = paparazzi_conf // airframe_file in
  229. let modules_files = extract_makefile abs_airframe_file temp_makefile_ac in
  230. (* Create Makefile.ac only if needed *)
  231. let makefile_ac = aircraft_dir // "Makefile.ac" in
  232. if is_older makefile_ac (abs_airframe_file :: modules_files) then begin
  233. assert(Sys.command (sprintf "mv %s %s" temp_makefile_ac makefile_ac) = 0)
  234. end;
  235. make "all_ac_h" "";
  236. make_opt "radio_ac_h" "RADIO" "radio";
  237. make_opt "flight_plan_ac_h" "FLIGHT_PLAN" "flight_plan"
  238. with
  239. Failure f ->
  240. prerr_endline f;
  241. exit 1