mirror of
https://github.com/ganelson/inform.git
synced 2024-05-19 09:28:51 +03:00
Finally able to incrementally build Inform projects
This commit is contained in:
parent
828619fd96
commit
7cc9c598f3
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,6 +3,7 @@
|
|||
|
||||
.DS_Store
|
||||
gameinfo.dbg
|
||||
gametext.txt
|
||||
|
||||
makefile
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
@<Create the default externals nest@>;
|
||||
@<Create the materials nest@>;
|
||||
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;
|
||||
}
|
||||
|
||||
@<Create the default externals nest@> =
|
||||
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);
|
||||
}
|
||||
|
||||
@<Create the materials nest@> =
|
||||
pathname *materials = NULL;
|
||||
if (pathname_of_bundle) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 @<Decide based on timestamps@>;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@<Decide based on timestamps@> =
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
50
inbuild/inbuild-module/Chapter 3/Build Methodology.w
Normal file
50
inbuild/inbuild-module/Chapter 3/Build Methodology.w
Normal file
|
@ -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;
|
||||
}
|
37
inbuild/inbuild-module/Chapter 3/Build Scripts.w
Normal file
37
inbuild/inbuild-module/Chapter 3/Build Scripts.w
Normal file
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
@<Write a shell command for the step@>;
|
||||
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);
|
||||
@<Write a shell command for the step@>;
|
||||
if (rv) rv = BuildSteps::shell(command, meth);
|
||||
if (rv == FALSE) WRITE_TO(STDERR, "Build failed at '%S'\n", command);
|
||||
DISCARD_TEXT(command);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@<Write a shell command for the step@> =
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -146,42 +146,12 @@ not distinguish between permanent and transient external resources.
|
|||
|
||||
@<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;
|
||||
@<Permanent external resources@>;
|
||||
|
||||
pathname *pathname_of_transient_external_resources = Inbuild::transient();
|
||||
if (Pathnames::create_in_file_system(pathname_of_transient_external_resources) == 0) return FALSE;
|
||||
@<Transient external resources@>;
|
||||
|
||||
@ 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.
|
||||
|
||||
@<Permanent external resources@> =
|
||||
filename_of_options =
|
||||
Filenames::in_folder(pathname_of_external_folder, I"Options.txt");
|
||||
|
||||
@ The transient resources are all written by us.
|
||||
|
||||
@<Transient external resources@> =
|
||||
pathname *pathname_of_transient_external_resources = Inbuild::transient();
|
||||
if (Pathnames::create_in_file_system(pathname_of_transient_external_resources) == 0) return FALSE;
|
||||
@<Transient documentation@>;
|
||||
@<Transient telemetry@>;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
.DS_Store
|
||||
gameinfo.dbg
|
||||
gametext.txt
|
||||
|
||||
makefile
|
||||
|
||||
|
|
Loading…
Reference in a new issue