-1

I'm trying to write an ocamlbuild plugin. The goal is to build Qt apps (without OCaml code for the time being). To handle the final linking phase, I have written the list of objs, mocs, uis and rcs in a .qtobjs file (like a .itarget), and the list of Qt libs in a .qtpackages file. The rule that applies to these files parses these lists and dynamically builds the objects, mocs and so on before linking everything.

The problem is that I would like not to dynamically build the targets that have not changed. See the rule below:

rule "Link a c++ executable that uses Qt."
  ~deps:["%.qtobjs"; "%.qtpackages"]
  ~prod:"%.cxxnative"
  (fun env build ->
     let dir = Pathname.dirname (env "%.qtobjs") in
     let output = env "%.cxxnative" in
     let objlist = pwd / (env "%.qtobjs") in
     let liblist = pwd / (env "%.qtpackages") in
     let packages = read_lines liblist in
     let lflags = List.map (fun p -> "-l"^p) packages
                  @ find_all "lflags" in
     let objs = List.map (fun o -> dir / o) (read_lines objlist) in



     (* Here, I would like to forget the targets that have not changed *)
     let objs_to_build = List.filter 
         (fun target -> 
            (* something to tell if "target" has to be rebuilt *))
         objs in



     (* This is where I build the dependencies : *)
     let success_builds = build 
         (List.map (fun o -> [o]) 
         objs_to_build) in


     let objects = filter_map
         (function
           | Outcome.Good x when get_extension x = "opp" ->
             Some (pwd / "_build" / (update_extension "o" x))
           | Outcome.Good _ -> None 
             (* Because I don't want to link the ui.h file generated by uic *)
           | Outcome.Bad exn -> raise exn)
         success_builds in
     let tags_objs = tags_of_pathname (env "%.qtobjs") ++ "link" in
     let tags_packs = tags_of_pathname (env "%.qtpackages") in
     Cmd (S [A (find_one "cxx"); T tags_objs; T tags_packs; Command.atomize lflags;
             A "-o"; P output; Command.atomize objects]));

I would like not to call "build" when it's not necessary.

NB: a function

newer_than: Pathname.t -> Pathname.t -> bool

could solve my problem.

Cœur
  • 37,241
  • 25
  • 195
  • 267

1 Answers1

0

Problem solved.

For those who are interested, the problem was in the COMPILING rule : because the ".o" rule was already used by ocamlbuild, I registered it to officially produce ".opp" files but the command actually wrote .o files. So when recompiling, ocamlbuild had no clue that the object file was already present.

Three options:

  • replace the default ".o" rule (I don't even know if it is possible ?),
  • produce ".opp" files (but it's less standard),
  • or alter the compiling rule to do Nop if the .o file exists:

    if Pathname.exists (env "%.o") then Nop
    else Cmd (S [A ("c++");
                 A "-c";
                 A "-o"; P (env "%.o"); P (env "%.cpp")]));