diff --git a/.gitignore b/.gitignore index fac4595f1..0d4bf66c0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .DS_Store gameinfo.dbg +gametext.txt makefile diff --git a/inbuild/Chapter 1/Main.w b/inbuild/Chapter 1/Main.w index dd695aaee..0217dcc5e 100644 --- a/inbuild/Chapter 1/Main.w +++ b/inbuild/Chapter 1/Main.w @@ -36,8 +36,8 @@ int main(int argc, char **argv) { path_to_inbuild = Pathnames::installation_path("INBUILD_PATH", I"inbuild"); build_methodology *BM; - if (path_to_tools) BM = BuildSteps::methodology(path_to_tools, FALSE); - else BM = BuildSteps::methodology(Pathnames::up(path_to_inbuild), TRUE); + if (path_to_tools) BM = BuildMethodology::new(path_to_tools, FALSE); + else BM = BuildMethodology::new(Pathnames::up(path_to_inbuild), TRUE); if (dry_run_mode == FALSE) BM->methodology = SHELL_METHODOLOGY; if (Str::len(unit_test) > 0) { BM->methodology = DRY_RUN_METHODOLOGY; @@ -63,9 +63,9 @@ int main(int argc, char **argv) { LOOP_OVER_LINKED_LIST(C, inbuild_copy, targets) { switch (inbuild_task) { case INSPECT_TTASK: Copies::inspect(STDOUT, C); break; - case GRAPH_TTASK: Graphs::describe(STDOUT, C->vertex, TRUE); break; - case BUILD_TTASK: Graphs::build(C->vertex, BM); break; - case REBUILD_TTASK: Graphs::rebuild(C->vertex, BM); break; + case GRAPH_TTASK: Copies::show_graph(STDOUT, C); break; + case BUILD_TTASK: Copies::build(STDOUT, C, BM); break; + case REBUILD_TTASK: Copies::rebuild(STDOUT, C, BM); break; case COPY_TO_TTASK: if (destination_nest) Nests::copy_to(C, destination_nest, FALSE, BM); break; case SYNC_TO_TTASK: if (destination_nest) Nests::copy_to(C, destination_nest, TRUE, BM); break; } diff --git a/inbuild/inbuild-module/Chapter 1/Inbuild Control.w b/inbuild/inbuild-module/Chapter 1/Inbuild Control.w index 92353bdd6..00ad6c96b 100644 --- a/inbuild/inbuild-module/Chapter 1/Inbuild Control.w +++ b/inbuild/inbuild-module/Chapter 1/Inbuild Control.w @@ -340,6 +340,7 @@ inform_project *Inbuild::create_shared_project(inbuild_copy *C) { if (C == NULL) C = ProjectFileManager::claim_file_as_copy(filename_of_i7_source); shared_project = ProjectFileManager::from_copy(C); } + @; @; if (shared_project) { pathname *P = (shared_materials_nest)?(shared_materials_nest->location):NULL; @@ -350,6 +351,21 @@ inform_project *Inbuild::create_shared_project(inbuild_copy *C) { return shared_project; } +@ = + inbuild_nest *E = shared_external_nest; + if (E == NULL) { + pathname *P = home_path; + char *subfolder_within = INFORM_FOLDER_RELATIVE_TO_HOME; + if (subfolder_within[0]) { + TEMPORARY_TEXT(SF); + WRITE_TO(SF, "%s", subfolder_within); + P = Pathnames::subfolder(home_path, SF); + DISCARD_TEXT(SF); + } + P = Pathnames::subfolder(P, I"Inform"); + E = Inbuild::add_nest(P, EXTERNAL_NEST_TAG); + } + @ = pathname *materials = NULL; if (pathname_of_bundle) { diff --git a/inbuild/inbuild-module/Chapter 2/Copies.w b/inbuild/inbuild-module/Chapter 2/Copies.w index 4959a19fb..0c5880991 100644 --- a/inbuild/inbuild-module/Chapter 2/Copies.w +++ b/inbuild/inbuild-module/Chapter 2/Copies.w @@ -67,6 +67,16 @@ void Copies::scan(inbuild_copy *C) { VMETHOD_CALL(C->edition->work->genre, GENRE_SCAN_COPY_MTID, C); } +void Copies::build(OUTPUT_STREAM, inbuild_copy *C, build_methodology *BM) { + VMETHOD_CALL(C->edition->work->genre, GENRE_BUILD_COPY_MTID, OUT, C, BM, FALSE, FALSE); +} +void Copies::rebuild(OUTPUT_STREAM, inbuild_copy *C, build_methodology *BM) { + VMETHOD_CALL(C->edition->work->genre, GENRE_BUILD_COPY_MTID, OUT, C, BM, TRUE, FALSE); +} +void Copies::show_graph(OUTPUT_STREAM, inbuild_copy *C) { + VMETHOD_CALL(C->edition->work->genre, GENRE_BUILD_COPY_MTID, OUT, C, NULL, FALSE, TRUE); +} + wording Copies::read_source_text_for(inbuild_copy *C) { if (C->source_text_read == FALSE) { C->source_text_read = TRUE; diff --git a/inbuild/inbuild-module/Chapter 2/Genres.w b/inbuild/inbuild-module/Chapter 2/Genres.w index 8be415ce1..d49776606 100644 --- a/inbuild/inbuild-module/Chapter 2/Genres.w +++ b/inbuild/inbuild-module/Chapter 2/Genres.w @@ -38,6 +38,7 @@ text_stream *Genres::name(inbuild_genre *G) { @e GENRE_COPY_TO_NEST_MTID @e GENRE_GO_OPERATIONAL_MTID @e GENRE_READ_SOURCE_TEXT_FOR_MTID +@e GENRE_BUILD_COPY_MTID = VMETHOD_TYPE(GENRE_WRITE_WORK_MTID, @@ -57,3 +58,6 @@ VMETHOD_TYPE(GENRE_GO_OPERATIONAL_MTID, inbuild_genre *gen, inbuild_copy *C) VMETHOD_TYPE(GENRE_READ_SOURCE_TEXT_FOR_MTID, inbuild_genre *gen, inbuild_copy *C) +VMETHOD_TYPE(GENRE_BUILD_COPY_MTID, + inbuild_genre *gen, text_stream *OUT, inbuild_copy *C, + build_methodology *BM, int rebuild, int describe_only) diff --git a/inbuild/inbuild-module/Chapter 3/Build Graphs.w b/inbuild/inbuild-module/Chapter 3/Build Graphs.w index f39979439..7d2ad5f5d 100644 --- a/inbuild/inbuild-module/Chapter 3/Build Graphs.w +++ b/inbuild/inbuild-module/Chapter 3/Build Graphs.w @@ -27,7 +27,6 @@ typedef struct build_vertex { struct linked_list *build_edges; /* of |build_vertex| */ struct linked_list *use_edges; /* of |build_vertex| */ struct build_script *script; - time_t timestamp; int last_described; int built; MEMORY_MANAGEMENT @@ -40,8 +39,7 @@ build_vertex *Graphs::file_vertex(filename *F) { V->buildable_if_internal_file = F; V->build_edges = NEW_LINKED_LIST(build_vertex); V->use_edges = NEW_LINKED_LIST(build_vertex); - V->timestamp = (time_t) 0; - V->script = BuildSteps::new_script(); + V->script = BuildScripts::new(); V->annotation = NULL; V->read_as = NULL; V->last_described = 0; @@ -114,13 +112,7 @@ void Graphs::describe_r(OUTPUT_STREAM, int depth, build_vertex *V, } DISCARD_TEXT(S); DISCARD_TEXT(T); - if (V->type == FILE_VERTEX) { - Graphs::update_timestamp(V); - if (V->timestamp != (time_t) 0) WRITE(" -- %s", ctime(&(V->timestamp))); - else WRITE(" -- no time stamp\n"); - } else { - WRITE("\n"); - } + WRITE("\n"); if (recurse) { if (V->buildable_if_copy) stem = V->buildable_if_copy->location_if_path; if (V->buildable_if_internal_file) @@ -142,17 +134,48 @@ void Graphs::describe_vertex(OUTPUT_STREAM, build_vertex *V) { } } -void Graphs::update_timestamp(build_vertex *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; +time_t Graphs::timestamp_for(build_vertex *V) { + time_t latest = (time_t) 0; + + if (V->buildable_if_internal_file) { + 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) latest = filestat.st_mtime; + } else { + latest = Graphs::time_of_most_recent_ingredient(V); + } + + return latest; +} + +time_t Graphs::time_of_most_recent_ingredient(build_vertex *V) { + time_t latest = (time_t) 0; + + build_vertex *W; + LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges) { + time_t inner = Graphs::timestamp_for(W); + if ((latest == (time_t) 0) || (difftime(inner, latest) > 0)) + latest = inner; + } + + return latest; +} + +time_t Graphs::time_of_most_recent_used_resource(build_vertex *V) { + time_t latest = (time_t) 0; + + build_vertex *W; + LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges) { + time_t inner = Graphs::timestamp_for(W); + if ((latest == (time_t) 0) || (difftime(inner, latest) > 0)) + latest = inner; + } + + return latest; } @ @@ -163,40 +186,61 @@ void Graphs::update_timestamp(build_vertex *V) { @d USE_GB 4 = -void Graphs::build(build_vertex *V, build_methodology *meth) { - Graphs::build_r(BUILD_GB, V, meth); +int Graphs::build(OUTPUT_STREAM, build_vertex *V, build_methodology *meth) { + return Graphs::build_r(OUT, BUILD_GB, V, meth); } -void Graphs::rebuild(build_vertex *V, build_methodology *meth) { - Graphs::build_r(BUILD_GB + FORCE_GB, V, meth); +int Graphs::rebuild(OUTPUT_STREAM, build_vertex *V, build_methodology *meth) { + return Graphs::build_r(OUT, BUILD_GB + FORCE_GB, V, meth); } -void Graphs::build_r(int gb, build_vertex *V, build_methodology *meth) { - int needs_building = FALSE; - if (gb & FORCE_GB) needs_building = TRUE; - else if (V->built) return; - if (V->buildable_if_internal_file) - if (TextFiles::exists(V->buildable_if_internal_file) == FALSE) - needs_building = TRUE; +int trace_ibg = FALSE; +int Graphs::build_r(OUTPUT_STREAM, int gb, build_vertex *V, build_methodology *meth) { + if (trace_ibg) { WRITE_TO(STDOUT, "Build: "); Graphs::describe(STDOUT, V, FALSE); } + + if (V->built) return TRUE; + + STREAM_INDENT(STDOUT); + int rv = TRUE; build_vertex *W; LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges) - Graphs::build_r(gb | USE_GB, W, meth); + if (rv) + rv = Graphs::build_r(OUT, gb | USE_GB, W, meth); if (gb & USE_GB) LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges) - Graphs::build_r(gb & (BUILD_GB + FORCE_GB), W, meth); - if (needs_building == FALSE) { - Graphs::update_timestamp(V); - LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges) { - Graphs::update_timestamp(W); - double since = difftime(V->timestamp, W->timestamp); - if (since < 0) { needs_building = TRUE; break; } + if (rv) + rv = Graphs::build_r(OUT, gb & (BUILD_GB + FORCE_GB), W, meth); + STREAM_OUTDENT(STDOUT); + if (rv) { + int needs_building = FALSE; + if (gb & FORCE_GB) needs_building = TRUE; + else @; + + if (needs_building) { + if (trace_ibg) { WRITE_TO(STDOUT, "Exec\n"); } + rv = BuildScripts::execute(V, V->script, meth); } - if (gb & USE_GB) - LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges) { - Graphs::update_timestamp(W); - double since = difftime(V->timestamp, W->timestamp); - if (since < 0) { needs_building = TRUE; break; } - } } - if (V->built) needs_building = FALSE; - if (needs_building) BuildSteps::execute(V, V->script, meth); - V->built = TRUE; + V->built = rv; + return rv; } + +@ = + time_t last_built_at = Graphs::timestamp_for(V); + if (trace_ibg) { WRITE_TO(STDOUT, "Last built at: %08x\n", last_built_at); } + if (last_built_at == (time_t) 0) + needs_building = TRUE; + else { + time_t time_of_most_recent = Graphs::time_of_most_recent_ingredient(V); + if (time_of_most_recent != (time_t) 0) { + if (trace_ibg) { WRITE_TO(STDOUT, "Most recent: %08x\n", time_of_most_recent); } + if (difftime(time_of_most_recent, last_built_at) > 0) + needs_building = TRUE; + } + if (gb & USE_GB) { + time_t time_of_most_recent_used = Graphs::time_of_most_recent_used_resource(V); + if (time_of_most_recent_used != (time_t) 0) { + if (trace_ibg) { WRITE_TO(STDOUT, "Most recent use: %08x\n", time_of_most_recent_used); } + if (difftime(time_of_most_recent_used, last_built_at) > 0) + needs_building = TRUE; + } + } + } diff --git a/inbuild/inbuild-module/Chapter 3/Build Methodology.w b/inbuild/inbuild-module/Chapter 3/Build Methodology.w new file mode 100644 index 000000000..323dffe8c --- /dev/null +++ b/inbuild/inbuild-module/Chapter 3/Build Methodology.w @@ -0,0 +1,50 @@ +[BuildMethodology::] Build Methodology. + +Whether to run tasks internally in some merged tool, or run via the shell, or +simply trace to the standard output what we think ought to be done. + +@ + +@e DRY_RUN_METHODOLOGY from 1 +@e SHELL_METHODOLOGY +@e INTERNAL_METHODOLOGY + += +typedef struct build_methodology { + filename *to_inter; + filename *to_inform6; + filename *to_inform7; + filename *to_inblorb; + int methodology; + MEMORY_MANAGEMENT +} build_methodology; + +build_methodology *BuildMethodology::new(pathname *tools_path, int dev) { + build_methodology *meth = CREATE(build_methodology); + meth->methodology = DRY_RUN_METHODOLOGY; + pathname *inter_path = tools_path; + if (dev) { + inter_path = Pathnames::subfolder(inter_path, I"inter"); + inter_path = Pathnames::subfolder(inter_path, I"Tangled"); + } + meth->to_inter = Filenames::in_folder(inter_path, I"inter"); + pathname *inform6_path = tools_path; + if (dev) { + inform6_path = Pathnames::subfolder(inform6_path, I"inform6"); + inform6_path = Pathnames::subfolder(inform6_path, I"Tangled"); + } + meth->to_inform6 = Filenames::in_folder(inform6_path, I"inform6"); + pathname *inform7_path = tools_path; + if (dev) { + inform7_path = Pathnames::subfolder(inform7_path, I"inform7"); + inform7_path = Pathnames::subfolder(inform7_path, I"Tangled"); + } + meth->to_inform7 = Filenames::in_folder(inform7_path, I"inform7"); + pathname *inblorb_path = tools_path; + if (dev) { + inblorb_path = Pathnames::subfolder(inblorb_path, I"inblorb"); + inblorb_path = Pathnames::subfolder(inblorb_path, I"Tangled"); + } + meth->to_inblorb = Filenames::in_folder(inblorb_path, I"inblorb"); + return meth; +} diff --git a/inbuild/inbuild-module/Chapter 3/Build Scripts.w b/inbuild/inbuild-module/Chapter 3/Build Scripts.w new file mode 100644 index 000000000..a87fa3a96 --- /dev/null +++ b/inbuild/inbuild-module/Chapter 3/Build Scripts.w @@ -0,0 +1,37 @@ +[BuildScripts::] Build Scripts. + +Scripts are nothing more than list of build steps. + +@h Build scripts. +Simple lists of steps: nothing to see here... + += +typedef struct build_script { + struct linked_list *steps; /* of |build_step| */ + MEMORY_MANAGEMENT +} build_script; + +build_script *BuildScripts::new(void) { + build_script *BS = CREATE(build_script); + BS->steps = NEW_LINKED_LIST(build_step); + return BS; +} + +void BuildScripts::add_step(build_script *BS, build_step *S) { + ADD_TO_LINKED_LIST(S, build_step, BS->steps); +} + +void BuildScripts::concatenate(build_script *BT, build_script *BF) { + build_step *S; + LOOP_OVER_LINKED_LIST(S, build_step, BF->steps) + BuildScripts::add_step(BT, S); +} + +int BuildScripts::execute(build_vertex *V, build_script *BS, build_methodology *meth) { + int rv = TRUE; + build_step *S; + LOOP_OVER_LINKED_LIST(S, build_step, BS->steps) + if (rv) + rv = BuildSteps::execute(V, S, meth); + return rv; +} diff --git a/inbuild/inbuild-module/Chapter 3/Build Steps.w b/inbuild/inbuild-module/Chapter 3/Build Steps.w index 6c51c7d7e..3511792c5 100644 --- a/inbuild/inbuild-module/Chapter 3/Build Steps.w +++ b/inbuild/inbuild-module/Chapter 3/Build Steps.w @@ -1,32 +1,8 @@ [BuildSteps::] Build Steps. -Graphs in which vertices correspond to files or copies, and arrows to -dependencies between them. +A build step is a task such as running inform7 or inblorb on some file. -@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_script { - struct linked_list *steps; /* of |build_step| */ - MEMORY_MANAGEMENT -} build_script; - -typedef struct build_step { - int what_to_do; - struct pathname *arg_p1; - struct text_stream *arg_t1; - struct target_vm *arg_vm; - MEMORY_MANAGEMENT -} build_step; - -@ +@h Build steps. @e ASSIMILATE_BSTEP from 1 @e COMPILE_I7_TO_GEN_BSTEP @@ -34,104 +10,130 @@ typedef struct build_step { @e BLORB_STORY_FILE_BSTEP = -build_script *BuildSteps::new_script(void) { - build_script *BS = CREATE(build_script); - BS->steps = NEW_LINKED_LIST(build_step); - return BS; -} - -build_step *BuildSteps::new_step(int to_do, pathname *P, text_stream *T) { - build_step *S = CREATE(build_step); - S->what_to_do = to_do; - S->arg_p1 = P; - S->arg_t1 = T; - S->arg_vm = NULL; - return S; -} - -void BuildSteps::add_step(build_script *BS, build_step *S) { - ADD_TO_LINKED_LIST(S, build_step, BS->steps); -} - -void BuildSteps::concatenate(build_script *BT, build_script *BF) { - build_step *S; - LOOP_OVER_LINKED_LIST(S, build_step, BF->steps) - BuildSteps::add_step(BT, S); -} +typedef struct build_step { + int what_to_do; + struct build_vertex *vertex; + struct linked_list *search_path; /* of |inbuild_nest| */ + struct target_vm *for_vm; + struct inter_architecture *for_arch; + int for_release; + struct inbuild_copy *associated_copy; + MEMORY_MANAGEMENT +} build_step; @ -@e DRY_RUN_METHODOLOGY from 1 -@e SHELL_METHODOLOGY -@e INTERNAL_METHODOLOGY - = -typedef struct build_methodology { - filename *to_inter; - filename *to_inform6; - filename *to_inform7; - filename *to_inblorb; - int methodology; - MEMORY_MANAGEMENT -} build_methodology; - -build_methodology *BuildSteps::methodology(pathname *tools_path, int dev) { - build_methodology *meth = CREATE(build_methodology); - meth->methodology = DRY_RUN_METHODOLOGY; - pathname *inter_path = tools_path; - if (dev) { - inter_path = Pathnames::subfolder(inter_path, I"inter"); - inter_path = Pathnames::subfolder(inter_path, I"Tangled"); - } - meth->to_inter = Filenames::in_folder(inter_path, I"inter"); - pathname *inform6_path = tools_path; - if (dev) { - inform6_path = Pathnames::subfolder(inform6_path, I"inform6"); - inform6_path = Pathnames::subfolder(inform6_path, I"Tangled"); - } - meth->to_inform6 = Filenames::in_folder(inform6_path, I"inform6"); - pathname *inform7_path = tools_path; - if (dev) { - inform7_path = Pathnames::subfolder(inform7_path, I"inform7"); - inform7_path = Pathnames::subfolder(inform7_path, I"Tangled"); - } - meth->to_inform7 = Filenames::in_folder(inform7_path, I"inform7"); - pathname *inblorb_path = tools_path; - if (dev) { - inblorb_path = Pathnames::subfolder(inblorb_path, I"inblorb"); - inblorb_path = Pathnames::subfolder(inblorb_path, I"Tangled"); - } - meth->to_inblorb = Filenames::in_folder(inblorb_path, I"inblorb"); - return meth; +build_step *BuildSteps::attach(build_vertex *vertex, int to_do, linked_list *search, + int rel, target_vm *VM, inter_architecture *arch, inbuild_copy *assoc) { + build_step *S = CREATE(build_step); + S->vertex = vertex; + S->what_to_do = to_do; + S->search_path = search; + S->for_vm = VM; + S->for_arch = arch; + if ((VM) && (arch == NULL)) S->for_arch = TargetVMs::get_architecture(VM); + S->for_release = rel; + S->associated_copy = assoc; + BuildScripts::add_step(vertex->script, S); + return S; } -void BuildSteps::execute(build_vertex *V, build_script *BS, build_methodology *meth) { - build_step *S; - LOOP_OVER_LINKED_LIST(S, build_step, BS->steps) { - TEMPORARY_TEXT(command); - @; - BuildSteps::shell(command, meth); - DISCARD_TEXT(command); - } +int BuildSteps::execute(build_vertex *V, build_step *S, build_methodology *meth) { + int rv = TRUE; + TEMPORARY_TEXT(command); + @; + if (rv) rv = BuildSteps::shell(command, meth); + if (rv == FALSE) WRITE_TO(STDERR, "Build failed at '%S'\n", command); + DISCARD_TEXT(command); + return rv; } @ = switch (S->what_to_do) { - case ASSIMILATE_BSTEP: - Shell::quote_file(command, meth->to_inter); - WRITE_TO(command, " -architecture %S -assimilate ", S->arg_t1); - Shell::quote_path(command, S->arg_p1); - break; - default: internal_error("unimplemented step"); + case ASSIMILATE_BSTEP: rv = BuildSteps::use_inter(S, command, meth); break; + case COMPILE_I7_TO_GEN_BSTEP: rv = BuildSteps::use_inform7(S, command, meth); break; + case COMPILE_GEN_TO_STORY_FILE_BSTEP: rv = BuildSteps::use_inform6(S, command, meth); break; + case BLORB_STORY_FILE_BSTEP: rv = BuildSteps::use_inblorb(S, command, meth); break; + default: rv = FALSE; Errors::nowhere("unimplemented build step"); break; } @ = -void BuildSteps::shell(text_stream *command, build_methodology *meth) { - switch (meth->methodology) { - case DRY_RUN_METHODOLOGY: - case SHELL_METHODOLOGY: { - WRITE_TO(STDOUT, "%S\n", command); - if (meth->methodology == SHELL_METHODOLOGY) Shell::run(command); - } - } +int BuildSteps::shell(text_stream *command, build_methodology *meth) { + int rv = TRUE; + WRITE_TO(STDOUT, "%S\n", command); + if (meth->methodology == SHELL_METHODOLOGY) rv = (Shell::run(command) == 0)?TRUE:FALSE; + return rv; +} + +@ = +int BuildSteps::use_inter(build_step *S, text_stream *command, build_methodology *meth) { + if (command == NULL) internal_error("not available in-app"); + Shell::quote_file(command, meth->to_inter); + WRITE_TO(command, "-architecture %S ", Architectures::to_codename(S->for_arch)); + WRITE_TO(command, "-assimilate "); + Shell::quote_path(command, S->associated_copy->location_if_path); + return TRUE; +} + +@ = +int BuildSteps::use_inform7(build_step *S, text_stream *command, build_methodology *meth) { + if (command == NULL) internal_error("not available in-app"); + Shell::quote_file(command, meth->to_inform7); + + inform_project *project = ProjectBundleManager::from_copy(S->associated_copy); + if (project == NULL) project = ProjectFileManager::from_copy(S->associated_copy); + if (project == NULL) internal_error("no project"); + + inform_kit *K; + LOOP_OVER_LINKED_LIST(K, inform_kit, project->kits_to_include) { + WRITE_TO(command, "-kit %S ", K->as_copy->edition->work->title); + } + WRITE_TO(command, "-format=%S ", TargetVMs::get_unblorbed_extension(S->for_vm)); + + inbuild_nest *N; + LOOP_OVER_LINKED_LIST(N, inbuild_nest, S->search_path) { + switch (Nests::get_tag(N)) { + case MATERIALS_NEST_TAG: continue; + case EXTERNAL_NEST_TAG: WRITE_TO(command, "-external "); break; + case GENERIC_NEST_TAG: WRITE_TO(command, "-nest "); break; + case INTERNAL_NEST_TAG: WRITE_TO(command, "-internal "); break; + default: internal_error("mystery nest"); + } + Shell::quote_path(command, N->location); + } + + WRITE_TO(command, "-project "); + Shell::quote_path(command, S->associated_copy->location_if_path); + return TRUE; +} + +@ = +int BuildSteps::use_inform6(build_step *S, text_stream *command, build_methodology *meth) { + if (command == NULL) internal_error("not available in-app"); + Shell::quote_file(command, meth->to_inform6); + + inform_project *project = ProjectBundleManager::from_copy(S->associated_copy); + if (project == NULL) project = ProjectFileManager::from_copy(S->associated_copy); + if (project == NULL) internal_error("no project"); + + pathname *build_folder = Pathnames::subfolder(project->as_copy->location_if_path, I"Build"); + filename *inf_F = Filenames::in_folder(build_folder, I"auto.inf"); + + WRITE_TO(command, "-kE2S"); + if (TargetVMs::debug_enabled((S->for_vm))) WRITE_TO(command, "D"); + text_stream *ext = TargetVMs::get_unblorbed_extension(S->for_vm); + if (Str::eq(ext, I"ulx")) ext = I"G"; + WRITE_TO(command, "w%S ", ext); + + Shell::quote_file(command, inf_F); + Shell::quote_file(command, S->vertex->buildable_if_internal_file); + return TRUE; +} + +@ = +int BuildSteps::use_inblorb(build_step *S, text_stream *command, build_methodology *meth) { + if (command == NULL) internal_error("not available in-app"); + WRITE_TO(command, "echo 'Not done yet'"); + return TRUE; } diff --git a/inbuild/inbuild-module/Chapter 4/Kit Manager.w b/inbuild/inbuild-module/Chapter 4/Kit Manager.w index 8571d3534..8d44e0a3b 100644 --- a/inbuild/inbuild-module/Chapter 4/Kit Manager.w +++ b/inbuild/inbuild-module/Chapter 4/Kit Manager.w @@ -14,6 +14,7 @@ void KitManager::start(void) { METHOD_ADD(kit_genre, GENRE_SEARCH_NEST_FOR_MTID, KitManager::search_nest_for); METHOD_ADD(kit_genre, GENRE_COPY_TO_NEST_MTID, KitManager::copy_to_nest); METHOD_ADD(kit_genre, GENRE_GO_OPERATIONAL_MTID, KitManager::go_operational); + METHOD_ADD(kit_genre, GENRE_BUILD_COPY_MTID, KitManager::build); } void KitManager::write_work(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) { @@ -161,12 +162,15 @@ void KitManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbuild_nest } @h Build graph. -The build graph for a kit is quite extensive, since a kit contains Inter -binaries for four different architectures; and each of those has a -dependency on every section file of the web of Inform 6 source for the kit. -If there are $S$ sections then the graph has $S+5$ vertices and $4(S+1)$ edges. = +void KitManager::build(inbuild_genre *gen, text_stream *OUT, inbuild_copy *C, + build_methodology *BM, int rebuild, int describe_only) { + if (describe_only) Graphs::describe(OUT, C->vertex, TRUE); + else if (rebuild) Graphs::rebuild(OUT, C->vertex, BM); + else Graphs::build(OUT, C->vertex, BM); +} + void KitManager::build_vertex(inbuild_copy *C) { Graphs::copy_vertex(C); } diff --git a/inbuild/inbuild-module/Chapter 4/Project Bundle Manager.w b/inbuild/inbuild-module/Chapter 4/Project Bundle Manager.w index e8572269b..cee3389b8 100644 --- a/inbuild/inbuild-module/Chapter 4/Project Bundle Manager.w +++ b/inbuild/inbuild-module/Chapter 4/Project Bundle Manager.w @@ -14,6 +14,7 @@ void ProjectBundleManager::start(void) { METHOD_ADD(project_bundle_genre, GENRE_COPY_TO_NEST_MTID, ProjectBundleManager::copy_to_nest); METHOD_ADD(project_bundle_genre, GENRE_GO_OPERATIONAL_MTID, ProjectBundleManager::go_operational); METHOD_ADD(project_bundle_genre, GENRE_READ_SOURCE_TEXT_FOR_MTID, ProjectBundleManager::read_source_text_for); + METHOD_ADD(project_bundle_genre, GENRE_BUILD_COPY_MTID, ProjectBundleManager::build); } void ProjectBundleManager::write_work(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) { @@ -86,7 +87,18 @@ void ProjectBundleManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inb } @h Build graph. -The build graph for a project will need further thought... + += +void ProjectBundleManager::build(inbuild_genre *gen, text_stream *OUT, inbuild_copy *C, + build_methodology *BM, int rebuild, int describe_only) { + inform_project *project = ProjectBundleManager::from_copy(C); + build_vertex *V = project->chosen_build_target; + if (describe_only) Graphs::describe(OUT, V, TRUE); + else if (rebuild) Graphs::rebuild(OUT, V, BM); + else Graphs::build(OUT, V, BM); +} + +@ The build graph for a project will need further thought... = void ProjectBundleManager::build_vertex(inbuild_copy *C) { diff --git a/inbuild/inbuild-module/Chapter 4/Project File Manager.w b/inbuild/inbuild-module/Chapter 4/Project File Manager.w index e37a29d1b..d303ff7cd 100644 --- a/inbuild/inbuild-module/Chapter 4/Project File Manager.w +++ b/inbuild/inbuild-module/Chapter 4/Project File Manager.w @@ -14,6 +14,7 @@ void ProjectFileManager::start(void) { METHOD_ADD(project_file_genre, GENRE_COPY_TO_NEST_MTID, ProjectFileManager::copy_to_nest); METHOD_ADD(project_file_genre, GENRE_GO_OPERATIONAL_MTID, ProjectFileManager::go_operational); METHOD_ADD(project_file_genre, GENRE_READ_SOURCE_TEXT_FOR_MTID, ProjectFileManager::read_source_text_for); + METHOD_ADD(project_file_genre, GENRE_BUILD_COPY_MTID, ProjectFileManager::build); } void ProjectFileManager::write_work(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) { @@ -89,7 +90,18 @@ void ProjectFileManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbui } @h Build graph. -The build graph for a project will need further thought. + += +void ProjectFileManager::build(inbuild_genre *gen, text_stream *OUT, inbuild_copy *C, + build_methodology *BM, int rebuild, int describe_only) { + inform_project *project = ProjectBundleManager::from_copy(C); + build_vertex *V = project->chosen_build_target; + if (describe_only) Graphs::describe(OUT, V, TRUE); + else if (rebuild) Graphs::rebuild(OUT, V, BM); + else Graphs::build(OUT, V, BM); +} + +@ The build graph for a project will need further thought... = void ProjectFileManager::build_vertex(inbuild_copy *C) { diff --git a/inbuild/inbuild-module/Chapter 5/Kit Services.w b/inbuild/inbuild-module/Chapter 5/Kit Services.w index c9ddba58c..392b9c38e 100644 --- a/inbuild/inbuild-module/Chapter 5/Kit Services.w +++ b/inbuild/inbuild-module/Chapter 5/Kit Services.w @@ -210,6 +210,12 @@ linked_list *Kits::inter_paths(void) { return inter_paths; } +@ The build graph for a kit is quite extensive, since a kit contains Inter +binaries for four different architectures; and each of those has a +dependency on every section file of the web of Inform 6 source for the kit. +If there are $S$ sections then the graph has $S+5$ vertices and $4(S+1)$ edges. + += void Kits::construct_graph(inform_kit *K) { RUN_ONLY_IN_PHASE(GOING_OPERATIONAL_INBUILD_PHASE) if (K == NULL) return; @@ -221,9 +227,8 @@ void Kits::construct_graph(inform_kit *K) { LOOP_OVER(A, inter_architecture) { build_vertex *BV = Graphs::file_vertex(Architectures::canonical_binary(P, A)); Graphs::need_this_to_build(KV, BV); - build_step *BS = BuildSteps::new_step( - ASSIMILATE_BSTEP, P, Architectures::to_codename(A)); - BuildSteps::add_step(BV->script, BS); + BuildSteps::attach(BV, ASSIMILATE_BSTEP, + Inbuild::nest_list(), FALSE, NULL, A, K->as_copy); ADD_TO_LINKED_LIST(BV, build_vertex, BVL); } diff --git a/inbuild/inbuild-module/Chapter 5/Project Services.w b/inbuild/inbuild-module/Chapter 5/Project Services.w index 1888a4c5b..17e34b2f1 100644 --- a/inbuild/inbuild-module/Chapter 5/Project Services.w +++ b/inbuild/inbuild-module/Chapter 5/Project Services.w @@ -256,9 +256,8 @@ void Projects::construct_build_target(inform_project *project, target_vm *VM, in filename *inf_F = Filenames::in_folder(build_folder, I"auto.inf"); build_vertex *inf_V = Graphs::file_vertex(inf_F); Graphs::need_this_to_build(inf_V, project->as_copy->vertex); - build_step *BS = BuildSteps::new_step(COMPILE_I7_TO_GEN_BSTEP, NULL, NULL); - BS->arg_vm = VM; - BuildSteps::add_step(inf_V->script, BS); + BuildSteps::attach(inf_V, COMPILE_I7_TO_GEN_BSTEP, + Inbuild::nest_list(), releasing, VM, NULL, project->as_copy); TEMPORARY_TEXT(story_file_leafname); WRITE_TO(story_file_leafname, "output.%S", TargetVMs::get_unblorbed_extension(VM)); @@ -266,9 +265,8 @@ void Projects::construct_build_target(inform_project *project, target_vm *VM, in DISCARD_TEXT(story_file_leafname); build_vertex *unblorbed_V = Graphs::file_vertex(unblorbed_F); Graphs::need_this_to_build(unblorbed_V, inf_V); - build_step *BS2 = BuildSteps::new_step(COMPILE_GEN_TO_STORY_FILE_BSTEP, NULL, NULL); - BS2->arg_vm = VM; - BuildSteps::add_step(unblorbed_V->script, BS2); + BuildSteps::attach(unblorbed_V, COMPILE_GEN_TO_STORY_FILE_BSTEP, + Inbuild::nest_list(), releasing, VM, NULL, project->as_copy); if (releasing) { TEMPORARY_TEXT(story_file_leafname); @@ -277,9 +275,8 @@ void Projects::construct_build_target(inform_project *project, target_vm *VM, in DISCARD_TEXT(story_file_leafname); build_vertex *blorbed_V = Graphs::file_vertex(blorbed_F); Graphs::need_this_to_build(unblorbed_V, inf_V); - build_step *BS3 = BuildSteps::new_step(BLORB_STORY_FILE_BSTEP, NULL, NULL); - BS3->arg_vm = VM; - BuildSteps::add_step(blorbed_V->script, BS3); + BuildSteps::attach(blorbed_V, BLORB_STORY_FILE_BSTEP, + Inbuild::nest_list(), releasing, VM, NULL, project->as_copy); project->chosen_build_target = blorbed_V; } else { diff --git a/inbuild/inbuild-module/Contents.w b/inbuild/inbuild-module/Contents.w index 9f852e1bc..bc4e8ab1f 100644 --- a/inbuild/inbuild-module/Contents.w +++ b/inbuild/inbuild-module/Contents.w @@ -18,6 +18,8 @@ Chapter 2: Conceptual Framework Chapter 3: Incremental Builds Build Graphs + Build Methodology + Build Scripts Build Steps Chapter 4: Managing Genres of Work diff --git a/inform7/Internal/HTML/xrefs.txt b/inform7/Internal/HTML/xrefs.txt index 824f1f596..f8b46e6c8 100644 --- a/inform7/Internal/HTML/xrefs.txt +++ b/inform7/Internal/HTML/xrefs.txt @@ -4,7 +4,7 @@ PM_EnigmaticThey PM_EnigmaticPronoun PM_WordTooLong PM_TooMuchQuotedText PM_Unen PM_BadTitleSentence PM_HeadingStopsBeforeEndOfLine PM_HeadingOverLine HEADINGS _ doc14 "2.5" "2.5. Headings" PM_UnknownInternalTest PM_TestDoubleWith PM_TestCommandTooLong PM_TestContainsUndo PM_TestBadRequirements PM_TestDuplicate PM_TestMultiWord _ doc17 "2.8" "2.8. The TEST command" PM_BogusExtension _ doc19 "2.10" "2.10. Installing extensions" -PM_ExtMisidentifiedEnds PM_ExtInadequateVM PM_ExtMalformedVM PM_ExtMiswordedBeginsHere PM_ExtVersionMalformed PM_IncludeExtQuoted _ doc20 "2.11" "2.11. Including extensions" +PM_ExtMisidentifiedEnds PM_ExtInadequateVM PM_ExtMiswordedBeginsHere PM_ExtVersionMalformed PM_IncludeExtQuoted _ doc20 "2.11" "2.11. Including extensions" OPTIONS PM_UnknownUseOption PM_UONotNumerical _ doc21 "2.12" "2.12. Use options" OPTIONSFILE _ doc22 "2.13" "2.13. Administering classroom use" STORYFILES PM_BadICLIdentifier _ doc23 "2.14" "2.14. Limits and the Settings panel" diff --git a/inform7/core-module/Chapter 1/Where Everything Lives.w b/inform7/core-module/Chapter 1/Where Everything Lives.w index b803128cc..5a80a7848 100644 --- a/inform7/core-module/Chapter 1/Where Everything Lives.w +++ b/inform7/core-module/Chapter 1/Where Everything Lives.w @@ -146,42 +146,12 @@ not distinguish between permanent and transient external resources. @ = inbuild_nest *E = Inbuild::external(); - if (E == NULL) { - pathname *P = home_path; - char *subfolder_within = INFORM_FOLDER_RELATIVE_TO_HOME; - if (subfolder_within[0]) { - TEMPORARY_TEXT(SF); - WRITE_TO(SF, "%s", subfolder_within); - P = Pathnames::subfolder(home_path, SF); - DISCARD_TEXT(SF); - } - P = Pathnames::subfolder(P, I"Inform"); - E = Inbuild::add_nest(P, EXTERNAL_NEST_TAG); - } pathname *pathname_of_external_folder = E->location; - - if (Pathnames::create_in_file_system(pathname_of_external_folder) == 0) return FALSE; - @; - - pathname *pathname_of_transient_external_resources = Inbuild::transient(); - if (Pathnames::create_in_file_system(pathname_of_transient_external_resources) == 0) return FALSE; - @; - -@ The permanent resources are read-only as far as we are concerned. (The -user interface application, and the user directly, write to this area when -they (say) install new extensions. But the compiler only reads.) - -Once again we have a set of EILT resources, but we also have a curiosity: -a useful little file to add source text to everything Inform compiles, -generally to set use options. - -@ = filename_of_options = Filenames::in_folder(pathname_of_external_folder, I"Options.txt"); -@ The transient resources are all written by us. - -@ = + pathname *pathname_of_transient_external_resources = Inbuild::transient(); + if (Pathnames::create_in_file_system(pathname_of_transient_external_resources) == 0) return FALSE; @; @; diff --git a/scripts/gitignorescript.txt b/scripts/gitignorescript.txt index c424b6771..990e349b3 100644 --- a/scripts/gitignorescript.txt +++ b/scripts/gitignorescript.txt @@ -3,6 +3,7 @@ .DS_Store gameinfo.dbg +gametext.txt makefile