1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-26 04:00:43 +03:00

Rudimentary inbuild now incrementally builds kits

This commit is contained in:
Graham Nelson 2020-01-29 19:58:43 +00:00
parent c6e8fcd813
commit 3a9365b2ce
10 changed files with 710 additions and 96 deletions

View file

@ -7,26 +7,130 @@ this plan out.
@d INTOOL_NAME "inbuild"
@e INSPECT_TTASK from 1
@e GRAPH_TTASK
@e BUILD_TTASK
@e REBUILD_TTASK
=
pathname *path_to_inbuild = NULL;
pathname *path_to_tools = NULL;
int inbuild_task = INSPECT_TTASK;
int dry_run_mode = FALSE;
linked_list *targets = NULL; /* of |inbuild_copy| */
int main(int argc, char **argv) {
Foundation::start();
InbuildModule::start();
targets = NEW_LINKED_LIST(inbuild_copy);
@<Read the command line@>;
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 (dry_run_mode == FALSE) BM->methodology = SHELL_METHODOLOGY;
inbuild_copy *C;
LOOP_OVER_LINKED_LIST(C, inbuild_copy, targets) {
switch (inbuild_task) {
case INSPECT_TTASK: Graphs::describe(STDOUT, C->graph, FALSE); break;
case GRAPH_TTASK: Graphs::describe(STDOUT, C->graph, TRUE); break;
case BUILD_TTASK: Graphs::build(C->graph, BM); break;
case REBUILD_TTASK: Graphs::rebuild(C->graph, BM); break;
}
}
InbuildModule::end();
Foundation::end();
return 0;
}
@ We use Foundation to read the command line:
@e BUILD_CLSW
@e REBUILD_CLSW
@e GRAPH_CLSW
@e INSPECT_CLSW
@e DRY_CLSW
@e TOOLS_CLSW
@e CONTENTS_OF_CLSW
@<Read the command line@> =
CommandLine::declare_heading(
L"[[Purpose]]\n\n"
L"usage: inbuild\n");
L"usage: inbuild [-TASK] TARGET1 TARGET2 ...\n");
CommandLine::declare_switch(BUILD_CLSW, L"build", 1,
L"incrementally build target(s)");
CommandLine::declare_switch(REBUILD_CLSW, L"rebuild", 1,
L"completely rebuild target(s)");
CommandLine::declare_switch(INSPECT_CLSW, L"inspect", 1,
L"show target(s) but take no action");
CommandLine::declare_switch(GRAPH_CLSW, L"graph", 1,
L"show dependency graph of target(s) but take no action");
CommandLine::declare_switch(TOOLS_CLSW, L"tools", 2,
L"make X the directory of intools executables, and exit developer mode");
CommandLine::declare_boolean_switch(DRY_CLSW, L"dry", 1,
L"make this a dry run (print but do not execute shell commands)");
CommandLine::declare_boolean_switch(CONTENTS_OF_CLSW, L"contents-of", 2,
L"apply to all targets in the directory X");
CommandLine::read(argc, argv, NULL, &Main::option, &Main::bareword);
@ =
void Main::option(int id, int val, text_stream *arg, void *state) {
switch (id) {
case BUILD_CLSW: inbuild_task = BUILD_TTASK; break;
case REBUILD_CLSW: inbuild_task = REBUILD_TTASK; break;
case INSPECT_CLSW: inbuild_task = INSPECT_TTASK; break;
case GRAPH_CLSW: inbuild_task = GRAPH_TTASK; break;
case TOOLS_CLSW: path_to_tools = Pathnames::from_text(arg); break;
case CONTENTS_OF_CLSW: Main::load_many(Pathnames::from_text(arg)); break;
case DRY_CLSW: dry_run_mode = val; break;
default: internal_error("unimplemented switch");
}
}
void Main::bareword(int id, text_stream *arg, void *state) {
Main::load_one(arg);
}
void Main::load_many(pathname *P) {
scan_directory *D = Directories::open(P);
TEMPORARY_TEXT(LEAFNAME);
while (Directories::next(D, LEAFNAME)) {
TEMPORARY_TEXT(FILENAME);
WRITE_TO(FILENAME, "%p%c%S", P, FOLDER_SEPARATOR, LEAFNAME);
Main::load_one(FILENAME);
DISCARD_TEXT(FILENAME);
}
DISCARD_TEXT(LEAFNAME);
Directories::close(D);
}
void Main::load_one(text_stream *arg) {
int pos = Str::len(arg) - 1, dotpos = -1;
while (pos >= 0) {
wchar_t c = Str::get_at(arg, pos);
if (c == FOLDER_SEPARATOR) break;
if (c == '.') dotpos = pos;
pos--;
}
if (dotpos >= 0) {
TEMPORARY_TEXT(extension);
Str::substr(extension, Str::at(arg, dotpos+1), Str::end(arg));
if (Str::eq(extension, I"i7x")) {
;
}
DISCARD_TEXT(extension);
return;
}
if (Str::get_last_char(arg) == FOLDER_SEPARATOR)
Str::delete_last_character(arg);
int kitpos = Str::len(arg) - 3;
if ((kitpos >= 0) && (Str::get_at(arg, kitpos) == 'K') &&
(Str::get_at(arg, kitpos+1) == 'i') &&
(Str::get_at(arg, kitpos+2) == 't')) {
pathname *P = Pathnames::from_text(arg);
inform_kit *K = Kits::load_at(Pathnames::directory_name(P), P);
ADD_TO_LINKED_LIST(K->as_copy, inbuild_copy, targets);
}
}

View file

@ -11,15 +11,31 @@ Setting up the use of this module.
@e inform_kit_MT
@e inform_kit_ittt_MT
@e element_activation_MT
@e inbuild_genre_MT
@e inbuild_work_MT
@e inbuild_edition_MT
@e inbuild_requirement_MT
@e inbuild_copy_MT
@e build_graph_MT
@e build_methodology_MT
@e build_script_MT
@e build_step_MT
=
ALLOCATE_INDIVIDUALLY(inform_kit)
ALLOCATE_INDIVIDUALLY(inform_kit_ittt)
ALLOCATE_INDIVIDUALLY(element_activation)
ALLOCATE_INDIVIDUALLY(inbuild_genre)
ALLOCATE_INDIVIDUALLY(inbuild_work)
ALLOCATE_INDIVIDUALLY(inbuild_edition)
ALLOCATE_INDIVIDUALLY(inbuild_requirement)
ALLOCATE_INDIVIDUALLY(inbuild_copy)
ALLOCATE_INDIVIDUALLY(build_graph)
ALLOCATE_INDIVIDUALLY(build_methodology)
ALLOCATE_INDIVIDUALLY(build_script)
ALLOCATE_INDIVIDUALLY(build_step)
@h The beginning.
(The client doesn't need to call the start and end routines, because the
foundation module does that automatically.)
=
void InbuildModule::start(void) {
@ -28,6 +44,7 @@ void InbuildModule::start(void) {
@<Register this module's debugging log aspects@>;
@<Register this module's debugging log writers@>;
@<Register this module's command line switches@>;
Kits::start();
}
@

View file

@ -0,0 +1,116 @@
[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);
Model::write_work(OUT, V->buildable_if_copy->edition->work);
inbuild_version_number N = V->buildable_if_copy->edition->version;
if (VersionNumbers::is_null(N) == FALSE) {
WRITE(" v"); VersionNumbers::to_text(OUT, N);
}
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);
}

View file

@ -0,0 +1,127 @@
[BuildSteps::] Build Steps.
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_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;
MEMORY_MANAGEMENT
} build_step;
@
@e ASSIMILATE_BSTEP from 1
=
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;
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);
}
@
@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;
}
void BuildSteps::execute(build_script *BS, build_methodology *meth) {
build_step *S;
LOOP_OVER_LINKED_LIST(S, build_step, BS->steps) {
switch (meth->methodology) {
case DRY_RUN_METHODOLOGY:
case SHELL_METHODOLOGY: {
TEMPORARY_TEXT(command);
@<Write a shell command for the step@>;
WRITE_TO(STDOUT, "%S\n", command);
if (meth->methodology == SHELL_METHODOLOGY) Shell::run(command);
DISCARD_TEXT(command);
}
}
}
}
@<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");
}

View file

@ -0,0 +1,130 @@
[Model::] Conceptual Model.
The main concepts of inbuild.
@h Genres.
For example, "kit" and "extension" will both be both genres. There will be
few of these.
@e GENRE_WRITE_WORK_MTID
=
typedef struct inbuild_genre {
text_stream *genre_name;
METHOD_CALLS
MEMORY_MANAGEMENT
} inbuild_genre;
VMETHOD_TYPE(GENRE_WRITE_WORK_MTID, inbuild_genre *gen, text_stream *OUT, inbuild_work *work)
@ =
inbuild_genre *Model::genre(text_stream *name) {
inbuild_genre *gen;
LOOP_OVER(gen, inbuild_genre)
if (Str::eq(gen->genre_name, name))
return gen;
gen = CREATE(inbuild_genre);
gen->genre_name = Str::duplicate(name);
ENABLE_METHOD_CALLS(gen);
return gen;
}
@h Works.
A "work" is a single creative work; for example, Bronze by Emily Short might
be a work. Mamy versions of this IF story may exist over time, but they will
all be versions of the same "work".
=
typedef struct inbuild_work {
struct inbuild_genre *genre;
struct text_stream *name;
struct text_stream *author;
MEMORY_MANAGEMENT
} inbuild_work;
inbuild_work *Model::work(inbuild_genre *genre, text_stream *name, text_stream *author) {
inbuild_work *work = CREATE(inbuild_work);
work->genre = genre;
work->name = Str::duplicate(name);
work->author = Str::duplicate(author);
return work;
}
void Model::write_work(OUTPUT_STREAM, inbuild_work *work) {
VMETHOD_CALL(work->genre, GENRE_WRITE_WORK_MTID, OUT, work);
}
@h Editions.
An "edition" of a work is a particular version numbered form of it. For
example, release 7 of Bronze by Emily Short would be an edition of Bronze.
=
typedef struct inbuild_edition {
struct inbuild_work *work;
struct inbuild_version_number version;
MEMORY_MANAGEMENT
} inbuild_edition;
inbuild_edition *Model::edition(inbuild_work *work, inbuild_version_number version) {
inbuild_edition *edition = CREATE(inbuild_edition);
edition->work = work;
edition->version = version;
return edition;
}
@h Requirements.
A "requirement" is when we want to get hold of a work in some edition which
meets a range of possible versions. A null minimum version means "no minimum",
a null maximum means "no maximum".
=
typedef struct inbuild_requirement {
struct inbuild_work *work;
struct inbuild_version_number min_version;
struct inbuild_version_number max_version;
MEMORY_MANAGEMENT
} inbuild_requirement;
inbuild_requirement *Model::requirement(inbuild_work *work,
inbuild_version_number min, inbuild_version_number max) {
inbuild_requirement *req = CREATE(inbuild_requirement);
req->work = work;
req->min_version = min;
req->max_version = max;
return req;
}
@h Copies.
A "copy" of a work exists in the file system when we've actually got hold of
some edition of it. For some genres, copies will be files; for others,
directories holding a set of files.
=
typedef struct inbuild_copy {
struct inbuild_edition *edition;
struct pathname *location_if_path;
struct filename *location_if_file;
general_pointer content; /* the type of which depends on the work's genre */
struct build_graph *graph;
MEMORY_MANAGEMENT
} inbuild_copy;
inbuild_copy *Model::copy_in_file(inbuild_edition *edition, filename *F, general_pointer C) {
inbuild_copy *copy = CREATE(inbuild_copy);
copy->edition = edition;
copy->location_if_path = NULL;
copy->location_if_file = F;
copy->content = C;
copy->graph = NULL;
return copy;
}
inbuild_copy *Model::copy_in_directory(inbuild_edition *edition, pathname *P, general_pointer C) {
inbuild_copy *copy = CREATE(inbuild_copy);
copy->edition = edition;
copy->location_if_path = P;
copy->location_if_file = NULL;
copy->content = C;
copy->graph = NULL;
return copy;
}

View file

@ -0,0 +1,118 @@
[VersionNumbers::] Version Numbers.
Semantic version numbers such as 3.7.1.
@ For example, 4, 7.1, and 0.2.3 are all version numbers. Up to |VERSION_NUMBER_DEPTH|
components can be given. The tail of the array should be padded with |-1| values;
otherwise, components should all be non-negative integers.
@d VERSION_NUMBER_DEPTH 4
=
typedef struct inbuild_version_number {
int version_numbers[VERSION_NUMBER_DEPTH];
} inbuild_version_number;
@ All invalid strings of numbers -- i.e., breaking the above rules -- are
called "null" versions, and can never be valid as the version of anything.
Instead they are used to represent the absence of a version number.
(In particular, a string of |-1|s is null.)
=
inbuild_version_number VersionNumbers::null(void) {
inbuild_version_number V;
for (int i=0; i<VERSION_NUMBER_DEPTH; i++) V.version_numbers[i] = -1;
return V;
}
int VersionNumbers::is_null(inbuild_version_number V) {
for (int i=0, allow=TRUE; i<VERSION_NUMBER_DEPTH; i++) {
if (V.version_numbers[i] < -1)
return TRUE;
if (V.version_numbers[i] == -1)
allow = FALSE;
else if (allow == FALSE) return TRUE;
}
if (V.version_numbers[0] < 0) return TRUE;
return FALSE;
}
@ Here we print and parse:
=
void VersionNumbers::to_text(OUTPUT_STREAM, inbuild_version_number V) {
if (VersionNumbers::is_null(V)) WRITE("null");
else
for (int i=0; (i<VERSION_NUMBER_DEPTH) && (V.version_numbers[i] >= 0); i++) {
if (i>0) WRITE(".");
WRITE("%d", V.version_numbers[i]);
}
}
inbuild_version_number VersionNumbers::from_text(text_stream *T) {
inbuild_version_number V;
int component = 0, val = -1;
LOOP_THROUGH_TEXT(pos, T) {
wchar_t c = Str::get(pos);
if (c == '.') {
if (val == -1) return VersionNumbers::null();
if (component >= VERSION_NUMBER_DEPTH) return VersionNumbers::null();
V.version_numbers[component] = val;
component++; val = -1;
} else if (Characters::isdigit(c)) {
int digit = c - '0';
if (val < 0) val = digit; else val = 10*val + digit;
} else return VersionNumbers::null();
}
if (val == -1) return VersionNumbers::null();
if (component >= VERSION_NUMBER_DEPTH) return VersionNumbers::null();
V.version_numbers[component] = val;
for (int i=component+1; i<VERSION_NUMBER_DEPTH; i++) V.version_numbers[i] = -1;
return V;
}
@ And now comparison operators. Note that all null versions are equal, and
are always both |<=| and |>=| all versions. This means our ordering is not
trichotomous (though it is on the set of non-null versions), but this
ensures that null versions can be used to mean "unlimited" in either direction.
=
int VersionNumbers::eq(inbuild_version_number V1, inbuild_version_number V2) {
if (VersionNumbers::is_null(V1)) return VersionNumbers::is_null(V2);
if (VersionNumbers::is_null(V2)) return FALSE;
for (int i=0; i<VERSION_NUMBER_DEPTH; i++)
if (V1.version_numbers[i] != V2.version_numbers[i])
return FALSE;
return TRUE;
}
int VersionNumbers::ne(inbuild_version_number V1, inbuild_version_number V2) {
return (VersionNumbers::eq(V1, V2))?FALSE:TRUE;
}
int VersionNumbers::le(inbuild_version_number V1, inbuild_version_number V2) {
if (VersionNumbers::is_null(V1)) return TRUE;
if (VersionNumbers::is_null(V2)) return TRUE;
for (int i=0; i<VERSION_NUMBER_DEPTH; i++)
if (V1.version_numbers[i] > V2.version_numbers[i])
return FALSE;
return TRUE;
}
int VersionNumbers::gt(inbuild_version_number V1, inbuild_version_number V2) {
return (VersionNumbers::le(V1, V2))?FALSE:TRUE;
}
int VersionNumbers::ge(inbuild_version_number V1, inbuild_version_number V2) {
if (VersionNumbers::is_null(V1)) return TRUE;
if (VersionNumbers::is_null(V2)) return TRUE;
for (int i=0; i<VERSION_NUMBER_DEPTH; i++)
if (V1.version_numbers[i] < V2.version_numbers[i])
return FALSE;
return TRUE;
}
int VersionNumbers::lt(inbuild_version_number V1, inbuild_version_number V2) {
return (VersionNumbers::ge(V1, V2))?FALSE:TRUE;
}

View file

@ -5,9 +5,19 @@ A kit is a combination of Inter code with an Inform 7 extension.
@h Kits.
=
inbuild_genre *kit_genre = NULL;
void Kits::start(void) {
kit_genre = Model::genre(I"kit");
METHOD_ADD(kit_genre, GENRE_WRITE_WORK_MTID, Kits::write_copy);
}
void Kits::write_copy(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) {
WRITE("Kit %S", work->name);
}
typedef struct inform_kit {
struct inbuild_copy *as_copy;
struct text_stream *name;
struct pathname *location;
struct text_stream *attachment_point;
struct text_stream *early_source;
struct linked_list *ittt; /* of |inform_kit_ittt| */
@ -15,6 +25,7 @@ typedef struct inform_kit {
struct linked_list *extensions; /* of |text_stream| */
struct linked_list *activations; /* of |element_activation| */
struct text_stream *index_template;
struct inbuild_version_number version;
int defines_Main;
int supports_natural_language;
int priority;
@ -48,7 +59,6 @@ inform_kit *Kits::load_at(text_stream *name, pathname *P) {
K->name = Str::duplicate(name);
K->attachment_point = Str::new();
WRITE_TO(K->attachment_point, "/main/%S", name);
K->location = P;
K->early_source = NULL;
K->priority = 10;
K->ittt = NEW_LINKED_LIST(inform_kit_ittt);
@ -58,14 +68,63 @@ inform_kit *Kits::load_at(text_stream *name, pathname *P) {
K->defines_Main = FALSE;
K->supports_natural_language = FALSE;
K->index_template = NULL;
K->version = VersionNumbers::null();
filename *F = Filenames::in_folder(K->location, I"kit_metadata.txt");
filename *F = Filenames::in_folder(P, I"kit_metadata.txt");
TextFiles::read(F, FALSE,
NULL, FALSE, Kits::read_metadata, NULL, (void *) K);
inbuild_work *work = Model::work(kit_genre, name, NULL);
inbuild_edition *edition = Model::edition(work, K->version);
K->as_copy = Model::copy_in_directory(edition, P, STORE_POINTER_inform_kit(K));
build_graph *KV = Graphs::copy_vertex(K->as_copy);
text_stream *archs[4] = { I"16", I"32", I"16d", I"32d" };
text_stream *binaries[4] = { I"arch-16.interb", I"arch-32.interb", I"arch-16d.interb", I"arch-32d.interb" };
build_graph *BV[4];
for (int i=0; i<4; i++) {
filename *FV = Filenames::in_folder(P, binaries[i]);
BV[i] = Graphs::internal_vertex(FV);
Graphs::arrow(KV, BV[i]);
build_step *BS = BuildSteps::new_step(ASSIMILATE_BSTEP, P, archs[i]);
BuildSteps::add_step(BV[i]->script, BS);
}
filename *contents_page = Filenames::in_folder(K->as_copy->location_if_path, I"Contents.w");
build_graph *CV = Graphs::internal_vertex(contents_page);
for (int i=0; i<4; i++) Graphs::arrow(BV[i], CV);
kit_contents_section_state CSS;
CSS.active = FALSE;
CSS.sects = NEW_LINKED_LIST(text_stream);
TextFiles::read(contents_page, FALSE, NULL, FALSE, Kits::read_contents, NULL, (void *) &CSS);
text_stream *segment;
LOOP_OVER_LINKED_LIST(segment, text_stream, CSS.sects) {
filename *SF = Filenames::in_folder(
Pathnames::subfolder(K->as_copy->location_if_path, I"Sections"), segment);
build_graph *SV = Graphs::internal_vertex(SF);
for (int i=0; i<4; i++) Graphs::arrow(BV[i], SV);
}
return K;
}
typedef struct kit_contents_section_state {
struct linked_list *sects; /* of |text_stream| */
int active;
} kit_contents_section_state;
void Kits::read_contents(text_stream *text, text_file_position *tfp, void *state) {
kit_contents_section_state *CSS = (kit_contents_section_state *) state;
match_results mr = Regexp::create_mr();
if (Regexp::match(&mr, text, L"Sections"))
CSS->active = TRUE;
if ((Regexp::match(&mr, text, L" (%c+)")) && (CSS->active)) {
WRITE_TO(mr.exp[0], ".i6t");
ADD_TO_LINKED_LIST(Str::duplicate(mr.exp[0]), text_stream, CSS->sects);
}
Regexp::dispose_of(&mr);
}
inform_kit *Kits::load(text_stream *name, int N, pathname **PP) {
pathname *P = Kits::find(name, N, PP);
if (P == NULL) Errors::fatal_with_text("cannot find kit", name);
@ -92,6 +151,8 @@ void Kits::read_metadata(text_stream *text, text_file_position *tfp, void *state
match_results mr = Regexp::create_mr();
if ((Str::is_whitespace(text)) || (Regexp::match(&mr, text, L" *#%c*"))) {
;
} else if (Regexp::match(&mr, text, L"version: (%C+)")) {
K->version = VersionNumbers::from_text(mr.exp[0]);
} else if (Regexp::match(&mr, text, L"defines Main: yes")) {
K->defines_Main = TRUE;
} else if (Regexp::match(&mr, text, L"defines Main: no")) {
@ -192,7 +253,7 @@ void Kits::load_types(void) {
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include) {
text_stream *segment;
LOOP_OVER_LINKED_LIST(segment, text_stream, K->kind_definitions) {
pathname *P = Pathnames::subfolder(K->location, I"kinds");
pathname *P = Pathnames::subfolder(K->as_copy->location_if_path, I"kinds");
filename *F = Filenames::in_folder(P, segment);
LOG("Loading kinds definitions from %f\n", F);
I6T::interpret_kindt(F);
@ -282,7 +343,7 @@ linked_list *Kits::list_of_inter_libraries(void) {
requirements_list = NEW_LINKED_LIST(link_instruction);
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include) {
link_instruction *link = CodeGen::LinkInstructions::new(K->location, K->attachment_point);
link_instruction *link = CodeGen::LinkInstructions::new(K->as_copy->location_if_path, K->attachment_point);
ADD_TO_LINKED_LIST(link, link_instruction, requirements_list);
}
return requirements_list;

View file

@ -7,5 +7,11 @@ Licence: Artistic License 2.0
Chapter 1: Setting Up
Inbuild Module
Chapter 2: Everything Else
Chapter 2: Conceptual Framework
Version Numbers
Conceptual Model
Build Graphs
Build Steps
Chapter 3: The Genres
Kits

View file

@ -1,3 +1,4 @@
version: 1.0.2
priority: 0
extension: Basic Inform by Graham Nelson
dependency: if not WorldModelKit then BasicInformExtrasKit

View file

@ -22,6 +22,7 @@ INTESTWEB = ../intest
INWEB = ../inweb/Tangled/inweb
INWEBX = ../inweb/Tangled/inweb
INTERX = inter/Tangled/inter
INBUILDX = inbuild/Tangled/inbuild
# The "-" at the front here tells make to load this file if it exists, and
# continue otherwise. If it does exist, it will define the symbol INTEGRATION.
@ -60,6 +61,7 @@ INTERX = inter/Tangled/inter
{module} INTER inter inter/inter-module
{module} BUILDING building inter/building-module
{module} CODEGEN codegen inter/codegen-module
{module} INBUILD inbuild inbuild/inbuild-module
# First, the tools we need to make, using the same declaration notation.
# In the eventual makefile, the symbol NAMEWEB is the location of NAME;
@ -95,8 +97,9 @@ INTERX = inter/Tangled/inter
{tool} INRTPS inrtps inrtps
{dep} INRTPS on FOUNDATION
{tool} INBUILD inbuild inbuild
{dep} INBUILD on FOUNDATION
{tool} INBUILDTOOL inbuild inbuild
{dep} INBUILDTOOL on FOUNDATION
{dep} INBUILDTOOL on INBUILD
{tool} INTERTOOL inter inter
{dep} INTERTOOL on FOUNDATION
@ -153,11 +156,11 @@ INFORM6X = inform6/Tangled/inform6
.PHONY: all
all: tools srules intertemplate localintegration
all: tools kits srules localintegration
.PHONY: force
force: forcetools forcesrules localintegration
force: forcetools forcekits forcesrules localintegration
.PHONY: localintegration
localintegration: inform7/Internal/Languages/English/Syntax.preform
@ -167,89 +170,6 @@ inform7/Internal/Languages/English/Syntax.preform: inform7/Tangled/Syntax.prefor
# (Of course those other four phony targets are yet to be defined.)
.PHONY: intertemplate
intertemplate: \
inform7/Internal/Inter/BasicInformKit/arch-16d.interb \
inform7/Internal/Inter/BasicInformKit/arch-16.interb \
inform7/Internal/Inter/BasicInformKit/arch-32d.interb \
inform7/Internal/Inter/BasicInformKit/arch-32.interb \
inform7/Internal/Inter/BasicInformExtrasKit/arch-16d.interb \
inform7/Internal/Inter/BasicInformExtrasKit/arch-16.interb \
inform7/Internal/Inter/BasicInformExtrasKit/arch-32d.interb \
inform7/Internal/Inter/BasicInformExtrasKit/arch-32.interb \
inform7/Internal/Inter/EnglishLanguageKit/arch-16d.interb \
inform7/Internal/Inter/EnglishLanguageKit/arch-16.interb \
inform7/Internal/Inter/EnglishLanguageKit/arch-32d.interb \
inform7/Internal/Inter/EnglishLanguageKit/arch-32.interb \
inform7/Internal/Inter/WorldModelKit/arch-16d.interb \
inform7/Internal/Inter/WorldModelKit/arch-16.interb \
inform7/Internal/Inter/WorldModelKit/arch-32d.interb \
inform7/Internal/Inter/WorldModelKit/arch-32.interb \
inform7/Internal/Inter/CommandParserKit/arch-16d.interb \
inform7/Internal/Inter/CommandParserKit/arch-16.interb \
inform7/Internal/Inter/CommandParserKit/arch-32d.interb \
inform7/Internal/Inter/CommandParserKit/arch-32.interb
inform7/Internal/Inter/BasicInformKit/arch-16d.interb: inform7/Internal/Inter/BasicInformKit/Sections/*.i6t
$(INTERX) -architecture 16d -assimilate inform7/Internal/Inter/BasicInformKit
inform7/Internal/Inter/BasicInformKit/arch-16.interb: inform7/Internal/Inter/BasicInformKit/Sections/*.i6t
$(INTERX) -architecture 16 -assimilate inform7/Internal/Inter/BasicInformKit
inform7/Internal/Inter/BasicInformKit/arch-32d.interb: inform7/Internal/Inter/BasicInformKit/Sections/*.i6t
$(INTERX) -architecture 32d -assimilate inform7/Internal/Inter/BasicInformKit
inform7/Internal/Inter/BasicInformKit/arch-32.interb: inform7/Internal/Inter/BasicInformKit/Sections/*.i6t
$(INTERX) -architecture 32 -assimilate inform7/Internal/Inter/BasicInformKit
inform7/Internal/Inter/BasicInformExtrasKit/arch-16d.interb: inform7/Internal/Inter/BasicInformExtrasKit/Sections/*.i6t
$(INTERX) -architecture 16d -assimilate inform7/Internal/Inter/BasicInformExtrasKit
inform7/Internal/Inter/BasicInformExtrasKit/arch-16.interb: inform7/Internal/Inter/BasicInformExtrasKit/Sections/*.i6t
$(INTERX) -architecture 16 -assimilate inform7/Internal/Inter/BasicInformExtrasKit
inform7/Internal/Inter/BasicInformExtrasKit/arch-32d.interb: inform7/Internal/Inter/BasicInformExtrasKit/Sections/*.i6t
$(INTERX) -architecture 32d -assimilate inform7/Internal/Inter/BasicInformExtrasKit
inform7/Internal/Inter/BasicInformExtrasKit/arch-32.interb: inform7/Internal/Inter/BasicInformExtrasKit/Sections/*.i6t
$(INTERX) -architecture 32 -assimilate inform7/Internal/Inter/BasicInformExtrasKit
inform7/Internal/Inter/EnglishLanguageKit/arch-16d.interb: inform7/Internal/Inter/EnglishLanguageKit/Sections/*.i6t
$(INTERX) -architecture 16d -assimilate inform7/Internal/Inter/EnglishLanguageKit
inform7/Internal/Inter/EnglishLanguageKit/arch-16.interb: inform7/Internal/Inter/EnglishLanguageKit/Sections/*.i6t
$(INTERX) -architecture 16 -assimilate inform7/Internal/Inter/EnglishLanguageKit
inform7/Internal/Inter/EnglishLanguageKit/arch-32d.interb: inform7/Internal/Inter/EnglishLanguageKit/Sections/*.i6t
$(INTERX) -architecture 32d -assimilate inform7/Internal/Inter/EnglishLanguageKit
inform7/Internal/Inter/EnglishLanguageKit/arch-32.interb: inform7/Internal/Inter/EnglishLanguageKit/Sections/*.i6t
$(INTERX) -architecture 32 -assimilate inform7/Internal/Inter/EnglishLanguageKit
inform7/Internal/Inter/WorldModelKit/arch-16d.interb: inform7/Internal/Inter/WorldModelKit/Sections/*.i6t
$(INTERX) -architecture 16d -assimilate inform7/Internal/Inter/WorldModelKit
inform7/Internal/Inter/WorldModelKit/arch-16.interb: inform7/Internal/Inter/WorldModelKit/Sections/*.i6t
$(INTERX) -architecture 16 -assimilate inform7/Internal/Inter/WorldModelKit
inform7/Internal/Inter/WorldModelKit/arch-32d.interb: inform7/Internal/Inter/WorldModelKit/Sections/*.i6t
$(INTERX) -architecture 32d -assimilate inform7/Internal/Inter/WorldModelKit
inform7/Internal/Inter/WorldModelKit/arch-32.interb: inform7/Internal/Inter/WorldModelKit/Sections/*.i6t
$(INTERX) -architecture 32 -assimilate inform7/Internal/Inter/WorldModelKit
inform7/Internal/Inter/CommandParserKit/arch-16d.interb: inform7/Internal/Inter/CommandParserKit/Sections/*.i6t
$(INTERX) -architecture 16d -assimilate inform7/Internal/Inter/CommandParserKit
inform7/Internal/Inter/CommandParserKit/arch-16.interb: inform7/Internal/Inter/CommandParserKit/Sections/*.i6t
$(INTERX) -architecture 16 -assimilate inform7/Internal/Inter/CommandParserKit
inform7/Internal/Inter/CommandParserKit/arch-32d.interb: inform7/Internal/Inter/CommandParserKit/Sections/*.i6t
$(INTERX) -architecture 32d -assimilate inform7/Internal/Inter/CommandParserKit
inform7/Internal/Inter/CommandParserKit/arch-32.interb: inform7/Internal/Inter/CommandParserKit/Sections/*.i6t
$(INTERX) -architecture 32 -assimilate inform7/Internal/Inter/CommandParserKit
# -----------------------------------------------------------------------------
# Target "makers"
# -----------------------------------------------------------------------------
@ -314,6 +234,20 @@ forcesrules:
$(INWEBX) inform7/extensions/standard_rules -tangle-to $(SRULES)
$(INWEBX) inform7/extensions/basic_inform -tangle-to $(BINFORM)
# -----------------------------------------------------------------------------
# Targets "kits" and "forcekits"
# -----------------------------------------------------------------------------
# These are easy because Inbuild performs a make-like service on them; that
# saves a great deal of messy make code here.
.PHONY: kits
kits:
$(INBUILDX) -build -contents-of inform7/Internal/Inter
.PHONY: forcekits
forcekits:
$(INBUILDX) -rebuild -contents-of inform7/Internal/Inter
# -----------------------------------------------------------------------------
# Target "tools"
# -----------------------------------------------------------------------------