File: test_build_debug.ml

package info (click to toggle)
ocaml-obuild 0.2.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,456 kB
  • sloc: ml: 14,491; sh: 211; ansic: 34; makefile: 11
file content (210 lines) | stat: -rw-r--r-- 9,681 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
open Test_build_helpers

(** Debug version of failing tests with verbose output *)

(** Test: ML change and incremental rebuild - with debug output *)
let test_ml_incremental_debug () =
  with_temp_build_project
    ~name:"ml_incremental_debug"
    ~files:[
      ("src/foo.ml", "let x = 42\n");
      ("src/bar.ml", "let y = Foo.x + 1\n");
      ("src/baz.ml", "let z = Bar.y * 2\n");
    ]
    ~obuild_content:"name: incremental-test\nversion: 1.0\nobuild-ver: 1\n\nlibrary test\n  modules: Foo, Bar, Baz\n  src-dir: src\n"
    ~test_fn:(fun dir ->
      Printf.printf "Project directory: %s\n" dir;

      (* Initial build *)
      Printf.printf "\n=== Initial Configure ===\n";
      let (success, output) = run_obuild_command ~project_dir:dir ~command:"configure" ~args:[] in
      if not success then failwith ("Configure failed: " ^ output);
      Printf.printf "%s\n" output;

      Printf.printf "\n=== Initial Build ===\n";
      let (success, output) = run_obuild_command ~project_dir:dir ~command:"build" ~args:[] in
      if not success then failwith ("Initial build failed: " ^ output);
      Printf.printf "%s\n" output;

      (* Get initial mtimes *)
      let foo_cmo = dir ^ "/dist/build/lib-test/foo.cmo" in
      let bar_cmo = dir ^ "/dist/build/lib-test/bar.cmo" in
      let baz_cmo = dir ^ "/dist/build/lib-test/baz.cmo" in

      let foo_mtime1 = get_mtime foo_cmo in
      let bar_mtime1 = get_mtime bar_cmo in
      let baz_mtime1 = get_mtime baz_cmo in

      Printf.printf "\n=== Initial Mtimes ===\n";
      Printf.printf "foo.cmo: %s\n" (match foo_mtime1 with Some t -> string_of_float t | None -> "missing");
      Printf.printf "bar.cmo: %s\n" (match bar_mtime1 with Some t -> string_of_float t | None -> "missing");
      Printf.printf "baz.cmo: %s\n" (match baz_mtime1 with Some t -> string_of_float t | None -> "missing");

      Printf.printf "\nSleeping 1.1 seconds...\n";
      short_sleep ();

      (* Modify only foo.ml (no interface change) *)
      Printf.printf "\n=== Modifying foo.ml ===\n";
      write_file_with_dirs (dir ^ "/src/foo.ml") "let x = 99\n";
      Printf.printf "Changed foo.ml from 'let x = 42' to 'let x = 99'\n";

      (* Rebuild with verbose output *)
      Printf.printf "\n=== Rebuild ===\n";
      let (success, output) = run_obuild_command ~project_dir:dir ~command:"build" ~args:[] in
      if not success then failwith ("Rebuild failed: " ^ output);
      Printf.printf "%s\n" output;

      (* Get new mtimes *)
      let foo_mtime2 = get_mtime foo_cmo in
      let bar_mtime2 = get_mtime bar_cmo in
      let baz_mtime2 = get_mtime baz_cmo in

      Printf.printf "\n=== New Mtimes ===\n";
      Printf.printf "foo.cmo: %s\n" (match foo_mtime2 with Some t -> string_of_float t | None -> "missing");
      Printf.printf "bar.cmo: %s\n" (match bar_mtime2 with Some t -> string_of_float t | None -> "missing");
      Printf.printf "baz.cmo: %s\n" (match baz_mtime2 with Some t -> string_of_float t | None -> "missing");

      Printf.printf "\n=== Mtime Changes ===\n";
      (match (foo_mtime1, foo_mtime2) with
       | (Some t1, Some t2) -> Printf.printf "foo.cmo: %s (%.2f seconds)\n"
           (if t2 > t1 then "REBUILT" else "unchanged") (t2 -. t1)
       | _ -> Printf.printf "foo.cmo: error getting mtimes\n");

      (match (bar_mtime1, bar_mtime2) with
       | (Some t1, Some t2) -> Printf.printf "bar.cmo: %s (%.2f seconds)\n"
           (if t2 > t1 then "REBUILT" else "unchanged") (t2 -. t1)
       | _ -> Printf.printf "bar.cmo: error getting mtimes\n");

      (match (baz_mtime1, baz_mtime2) with
       | (Some t1, Some t2) -> Printf.printf "baz.cmo: %s (%.2f seconds)\n"
           (if t2 > t1 then "REBUILT" else "unchanged") (t2 -. t1)
       | _ -> Printf.printf "baz.cmo: error getting mtimes\n");

      Printf.printf "\n=== Analysis ===\n";
      Printf.printf "Expected: foo.cmo REBUILT, bar.cmo unchanged, baz.cmo unchanged\n";
      Printf.printf "Reason: foo.ml implementation changed, but interface did not change\n";
      Printf.printf "bar.ml depends on Foo's interface, not implementation\n";
    )

(** Test: C file rebuild - with debug output *)
let test_c_file_rebuild_debug () =
  with_temp_build_project
    ~name:"c_rebuild_debug"
    ~files:[
      ("src/cbits.c", "int add(int a, int b) { return a + b; }\n");
      ("src/cbits.h", "int add(int a, int b);\n");
      ("src/main.ml", "external add : int -> int -> int = \"add\"\nlet () = Printf.printf \"%d\\n\" (add 1 2)\n");
    ]
    ~obuild_content:"name: c-test\nversion: 1.0\nobuild-ver: 1\n\nexecutable ctest\n  main-is: main.ml\n  src-dir: src\n  c-sources: cbits.c\n  c-dir: src\n"
    ~test_fn:(fun dir ->
      Printf.printf "Project directory: %s\n" dir;

      (* Initial build *)
      Printf.printf "\n=== Initial Build ===\n";
      let (success, output) = run_obuild_command ~project_dir:dir ~command:"configure" ~args:[] in
      if not success then failwith ("Configure failed: " ^ output);

      let (success, output) = run_obuild_command ~project_dir:dir ~command:"build" ~args:[] in
      if not success then failwith ("Initial build failed: " ^ output);
      Printf.printf "%s\n" output;

      (* Find C object and executable *)
      Printf.printf "\n=== Finding Build Artifacts ===\n";
      let dist_contents = Sys.readdir (dir ^ "/dist/build") in
      Printf.printf "dist/build contents: %s\n" (String.concat ", " (Array.to_list dist_contents));

      (* List all files in ctest directory *)
      let ctest_dir = dir ^ "/dist/build/ctest" in
      if Sys.file_exists ctest_dir && Sys.is_directory ctest_dir then (
        let ctest_contents = Sys.readdir ctest_dir in
        Printf.printf "dist/build/ctest contents: %s\n"
          (String.concat ", " (Array.to_list ctest_contents));
      ) else (
        Printf.printf "dist/build/ctest: NOT FOUND\n";
      );

      (* Try different possible locations for C object *)
      let possible_c_obj_paths = [
        dir ^ "/dist/build/ctest/cbits.c.o";
        dir ^ "/dist/build/exe-ctest/cbits.c.o";
        dir ^ "/dist/build/lib-test/cbits.c.o";
      ] in

      let c_obj = Compat.SafeList.find_opt Sys.file_exists possible_c_obj_paths in
      let exe = dir ^ "/dist/build/ctest/ctest" in

      Printf.printf "\nC object file: %s\n"
        (match c_obj with Some p -> p ^ " (found)" | None -> "NOT FOUND");
      Printf.printf "Executable: %s\n" (if Sys.file_exists exe then exe ^ " (found)" else "NOT FOUND");

      (match c_obj with
       | None ->
           Printf.printf "\nERROR: Could not find C object file in any expected location\n";
           Printf.printf "Checked:\n";
           List.iter (fun p -> Printf.printf "  - %s\n" p) possible_c_obj_paths;
           failwith "C object file not found"
       | Some c_obj_path ->
           let obj_mtime1 = get_mtime c_obj_path in
           let exe_mtime1 = get_mtime exe in

           Printf.printf "\n=== Initial Mtimes ===\n";
           Printf.printf "C object: %s\n" (match obj_mtime1 with Some t -> string_of_float t | None -> "missing");
           Printf.printf "Executable: %s\n" (match exe_mtime1 with Some t -> string_of_float t | None -> "missing");

           Printf.printf "\nSleeping 1.1 seconds...\n";
           short_sleep ();

           (* Modify C file *)
           Printf.printf "\n=== Modifying C file ===\n";
           write_file_with_dirs (dir ^ "/src/cbits.c") "int add(int a, int b) { return a + b + 1; }\n";
           Printf.printf "Changed: return a + b; -> return a + b + 1;\n";

           (* Rebuild *)
           Printf.printf "\n=== Rebuild ===\n";
           let (success, output) = run_obuild_command ~project_dir:dir ~command:"build" ~args:[] in
           if not success then failwith ("Rebuild failed: " ^ output);
           Printf.printf "%s\n" output;

           (* Get new mtimes *)
           let obj_mtime2 = get_mtime c_obj_path in
           let exe_mtime2 = get_mtime exe in

           Printf.printf "\n=== New Mtimes ===\n";
           Printf.printf "C object: %s\n" (match obj_mtime2 with Some t -> string_of_float t | None -> "missing");
           Printf.printf "Executable: %s\n" (match exe_mtime2 with Some t -> string_of_float t | None -> "missing");

           Printf.printf "\n=== Mtime Changes ===\n";
           (match (obj_mtime1, obj_mtime2) with
            | (Some t1, Some t2) -> Printf.printf "C object: %s (%.2f seconds)\n"
                (if t2 > t1 then "REBUILT" else "unchanged") (t2 -. t1)
            | _ -> Printf.printf "C object: error getting mtimes\n");

           (match (exe_mtime1, exe_mtime2) with
            | (Some t1, Some t2) -> Printf.printf "Executable: %s (%.2f seconds)\n"
                (if t2 > t1 then "RELINKED" else "unchanged") (t2 -. t1)
            | _ -> Printf.printf "Executable: error getting mtimes\n");

           Printf.printf "\n=== Analysis ===\n";
           Printf.printf "Expected: C object REBUILT, Executable RELINKED\n";
      )
    )

let () =
  print_endline "";
  print_endline "Build Logic Debug Tests";
  print_endline "=======================";
  print_endline "";

  print_endline "=============================================================";
  print_endline "TEST 1: ML Incremental Rebuild";
  print_endline "=============================================================";
  test_ml_incremental_debug ();

  print_endline "";
  print_endline "=============================================================";
  print_endline "TEST 2: C File Rebuild";
  print_endline "=============================================================";
  test_c_file_rebuild_debug ();

  print_endline "";
  print_endline "Debug tests completed!";