aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.md2
-rw-r--r--src/tomo.c45
2 files changed, 46 insertions, 1 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 1d3c2909..1fba98fc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,7 +18,7 @@
- Mutation of a collection during iteration was violating value semantics.
- `extend` statements weren't properly checking that the type name was valid.
- Lazy recompilation wasn't happening when `use ./foo.c` was used for local
- C/assembly files.
+ C/assembly files or their `#include`s.
## v0.2
diff --git a/src/tomo.c b/src/tomo.c
index 32acf8e6..0f131513 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -666,6 +666,46 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l
}
}
+time_t latest_c_modification_time(Path_t path)
+{
+ static Table_t c_modification_times = {};
+ const TypeInfo_t time_info = {.size=sizeof(time_t), .align=alignof(time_t), .tag=OpaqueInfo};
+ time_t *cached_latest = Table$get(c_modification_times, &path, Table$info(&Path$info, &time_info));
+ if (cached_latest) return *cached_latest;
+
+ struct stat s;
+ time_t latest = 0;
+ if (stat(Path$as_c_string(path), &s) == 0)
+ latest = s.st_mtime;
+ Table$set(&c_modification_times, &path, &latest, Table$info(&Path$info, &time_info));
+
+ OptionalClosure_t by_line = Path$by_line(path);
+ if (by_line.fn == NULL) return 0;
+ OptionalText_t (*next_line)(void*) = by_line.fn;
+ Path_t parent = Path$parent(path);
+ for (Text_t line; (line=next_line(by_line.userdata)).length >= 0; ) {
+ line = Text$trim(line, Text(" \t"), true, false);
+ if (!Text$starts_with(line, Text("#include")))
+ continue;
+
+ List_t tokens = Text$split_any(line, Text(" \t"));
+ if (tokens.length < 2 || !Text$equal_values(*(Text_t*)tokens.data, Text("#include")))
+ continue;
+
+ Text_t include = *(Text_t*)(tokens.data + tokens.stride);
+ if (!Text$starts_with(include, Text("\"")))
+ continue;
+
+ Path_t included_path = Path$resolved(Path$from_text(Text$trim(include, Text("\""), true, true)), parent);
+ time_t included_time = latest_c_modification_time(included_path);
+ if (included_time > latest) {
+ latest = included_time;
+ Table$set(&c_modification_times, &path, &latest, Table$info(&Path$info, &time_info));
+ }
+ }
+ return latest;
+}
+
bool is_stale(Path_t path, Path_t relative_to, bool ignore_missing)
{
struct stat target_stat;
@@ -680,6 +720,11 @@ bool is_stale(Path_t path, Path_t relative_to, bool ignore_missing)
return true;
#endif
+ if (Path$has_extension(relative_to, Text("c")) || Path$has_extension(relative_to, Text("h"))) {
+ time_t mtime = latest_c_modification_time(relative_to);
+ return target_stat.st_mtime < mtime;
+ }
+
struct stat relative_to_stat;
if (stat(Path$as_c_string(relative_to), &relative_to_stat) != 0) {
if (ignore_missing) return false;