2020-01-29 21:58:43 +02:00
|
|
|
[Graphs::] Build Graphs.
|
|
|
|
|
|
|
|
Graphs in which vertices correspond to files or copies, and arrows to
|
|
|
|
dependencies between them.
|
|
|
|
|
|
|
|
@h Build graphs.
|
|
|
|
These are directed acyclic graphs which show what depends on what in the
|
|
|
|
building process. If an arrow leads from A to B, then B must be built before
|
|
|
|
A can be built.
|
|
|
|
|
|
|
|
There can be two sorts of vertex in such a graph: copy vertices, each of which
|
|
|
|
belongs to a single copy, and internal vertices, each of which represents
|
|
|
|
a different file inside the copy.
|
|
|
|
|
|
|
|
=
|
|
|
|
typedef struct build_graph {
|
|
|
|
struct inbuild_copy *buildable_if_copy;
|
|
|
|
struct filename *buildable_if_internal_file;
|
|
|
|
struct linked_list *arrows; /* of pointers to other |build_graph| nodes */
|
|
|
|
struct build_script *script;
|
|
|
|
time_t timestamp;
|
|
|
|
MEMORY_MANAGEMENT
|
|
|
|
} build_graph;
|
|
|
|
|
|
|
|
build_graph *Graphs::internal_vertex(filename *F) {
|
|
|
|
build_graph *G = CREATE(build_graph);
|
|
|
|
G->buildable_if_copy = NULL;
|
|
|
|
G->buildable_if_internal_file = F;
|
|
|
|
G->arrows = NEW_LINKED_LIST(build_graph);
|
|
|
|
G->timestamp = (time_t) 0;
|
|
|
|
G->script = BuildSteps::new_script();
|
|
|
|
return G;
|
|
|
|
}
|
|
|
|
|
|
|
|
build_graph *Graphs::copy_vertex(inbuild_copy *C) {
|
|
|
|
if (C == NULL) internal_error("no copy");
|
|
|
|
if (C->graph == NULL) {
|
|
|
|
C->graph = Graphs::internal_vertex(NULL);
|
|
|
|
C->graph->buildable_if_copy = C;
|
|
|
|
}
|
|
|
|
return C->graph;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphs::arrow(build_graph *from, build_graph *to) {
|
|
|
|
if (from == NULL) internal_error("no from");
|
|
|
|
if (to == NULL) internal_error("no to");
|
|
|
|
if (from == to) internal_error("graph node depends on itself");
|
|
|
|
build_graph *G;
|
|
|
|
LOOP_OVER_LINKED_LIST(G, build_graph, from->arrows)
|
|
|
|
if (G == to) return;
|
|
|
|
ADD_TO_LINKED_LIST(to, build_graph, from->arrows);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphs::describe(OUTPUT_STREAM, build_graph *G, int recurse) {
|
|
|
|
Graphs::describe_r(OUT, 0, G, recurse);
|
|
|
|
}
|
|
|
|
void Graphs::describe_r(OUTPUT_STREAM, int depth, build_graph *V, int recurse) {
|
|
|
|
for (int i=0; i<depth; i++) WRITE(" ");
|
|
|
|
if (V->buildable_if_copy) {
|
|
|
|
WRITE("[copy%d] ", V->allocation_id);
|
2020-01-31 02:13:50 +02:00
|
|
|
Model::write_copy(OUT, V->buildable_if_copy);
|
2020-01-29 21:58:43 +02:00
|
|
|
WRITE("\n");
|
|
|
|
} else {
|
|
|
|
Graphs::update_timestamp(V);
|
|
|
|
WRITE("[int%d] %f", V->allocation_id, V->buildable_if_internal_file);
|
|
|
|
if (V->timestamp != (time_t) 0) WRITE(" %s", ctime(&(V->timestamp)));
|
|
|
|
else WRITE("\n");
|
|
|
|
}
|
|
|
|
if (recurse) {
|
|
|
|
build_graph *W;
|
|
|
|
LOOP_OVER_LINKED_LIST(W, build_graph, V->arrows)
|
|
|
|
Graphs::describe_r(OUT, depth+1, W, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphs::update_timestamp(build_graph *V) {
|
|
|
|
if (V == NULL) return;
|
|
|
|
if (V->buildable_if_internal_file == NULL) return;
|
|
|
|
char transcoded_pathname[4*MAX_FILENAME_LENGTH];
|
|
|
|
TEMPORARY_TEXT(FN);
|
|
|
|
WRITE_TO(FN, "%f", V->buildable_if_internal_file);
|
|
|
|
Str::copy_to_locale_string(transcoded_pathname, FN, 4*MAX_FILENAME_LENGTH);
|
|
|
|
DISCARD_TEXT(FN);
|
|
|
|
struct stat filestat;
|
|
|
|
if (stat(transcoded_pathname, &filestat) == -1) { V->timestamp = (time_t) 0; return; }
|
|
|
|
V->timestamp = filestat.st_mtime;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Graphs::build(build_graph *G, build_methodology *meth) {
|
|
|
|
Graphs::build_r(FALSE, G, meth);
|
|
|
|
}
|
|
|
|
void Graphs::rebuild(build_graph *G, build_methodology *meth) {
|
|
|
|
Graphs::build_r(TRUE, G, meth);
|
|
|
|
}
|
|
|
|
void Graphs::build_r(int forcing_build, build_graph *V, build_methodology *meth) {
|
|
|
|
int needs_building = forcing_build;
|
|
|
|
if (V->buildable_if_internal_file)
|
|
|
|
if (TextFiles::exists(V->buildable_if_internal_file) == FALSE)
|
|
|
|
needs_building = TRUE;
|
|
|
|
build_graph *W;
|
|
|
|
LOOP_OVER_LINKED_LIST(W, build_graph, V->arrows)
|
|
|
|
Graphs::build_r(forcing_build, W, meth);
|
|
|
|
if (needs_building == FALSE) {
|
|
|
|
Graphs::update_timestamp(V);
|
|
|
|
LOOP_OVER_LINKED_LIST(W, build_graph, V->arrows) {
|
|
|
|
Graphs::update_timestamp(W);
|
|
|
|
double since = difftime(V->timestamp, W->timestamp);
|
|
|
|
if (since < 0) { needs_building = TRUE; break; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (needs_building) BuildSteps::execute(V->script, meth);
|
|
|
|
}
|