A build step is a task which exercises one of the build skills.
§1. Build skills. A "skill" is a single atomic task which we know how to perform. For example, assimilating a binary for a kit is a skill.
Each different skill is an instance of:
typedef struct build_skill { struct text_stream *name; struct method_set *methods; CLASS_DEFINITION } build_skill; build_skill *BuildSteps::new_skill(text_stream *name) { build_skill *S = CREATE(build_skill); S->name = Str::duplicate(name); S->methods = Methods::new_set(); return S; }
- The structure build_skill is accessed in 2/gnr, 7/tm, 7/dc, 7/dr, 7/il, 7/ei and here.
§2. Skills provide two method functions: one constructs a shell command to perform the skill, and the other performs the skill directly by calling some function within the current executable. These methods are optional, and if one is absent then the skill can't be performed that way.
enum BUILD_SKILL_COMMAND_MTID enum BUILD_SKILL_INTERNAL_MTID
VOID_METHOD_TYPE(BUILD_SKILL_COMMAND_MTID, build_skill *S, build_step *BS, text_stream *command, build_methodology *meth, linked_list *search) INT_METHOD_TYPE(BUILD_SKILL_INTERNAL_MTID, build_skill *S, build_step *BS, build_methodology *meth, linked_list *search)
§3. Build steps. These are essentially just skills, but with a docket of contextual data. The idea is that a function outside the supervisor module can carry out a skill for us using only the contextual information in this structure, without having to access any of inbuild's variables directly.
typedef struct build_step { struct build_skill *what_to_do; struct build_vertex *vertex; what to do it to struct target_vm *for_vm; struct inter_architecture *for_arch; int for_release; struct inbuild_copy *associated_copy; e.g., the Inform project causing this work CLASS_DEFINITION } build_step;
- The structure build_step is accessed in 2/cps, 3/bg, 3/is, 3/is2, 3/is3, 3/is4, 4/em, 4/ebm, 4/km, 5/es, 5/ks, 5/ps2, 6/hdn, 6/inc and here.
§4. We build scripts for a vertex by attaching one step at a time to it:
build_step *BuildSteps::attach(build_vertex *vertex, build_skill *to_do, int rel, target_vm *VM, inter_architecture *arch, inbuild_copy *assoc) { build_step *S = CREATE(build_step); S->what_to_do = to_do; S->vertex = vertex; 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; }
§5. Execution. Note that this prints a log of shell commands generated to stdout when we are running inside Inbuild at the command line, but not when we are running inside the inform7 executable, where we are silent throughout.
int BuildSteps::execute(build_vertex *V, build_step *S, build_methodology *BM, linked_list *search_list) { int rv = TRUE; TEMPORARY_TEXT(command) Work out a shell command, and perhaps print or call it5.1; Perform the skill internally if that's called for5.2; #ifndef CORE_MODULE if (rv == FALSE) WRITE_TO(STDERR, "Build failed at '%S'\n", command); #endif DISCARD_TEXT(command) return rv; }
§5.1. Work out a shell command, and perhaps print or call it5.1 =
VOID_METHOD_CALL(S->what_to_do, BUILD_SKILL_COMMAND_MTID, S, command, BM, search_list); if (Str::len(command) > 0) rv = BuildSteps::shell(command, BM);
- This code is used in §5.
§5.2. Perform the skill internally if that's called for5.2 =
if (BM->methodology == INTERNAL_METHODOLOGY) { int returned = 0; INT_METHOD_CALL(returned, S->what_to_do, BUILD_SKILL_INTERNAL_MTID, S, BM, search_list); if (returned != TRUE) rv = FALSE; }
- This code is used in §5.
§6. This prints a shell command to stdout (except when inside inform7) and also executes it if the methodology allows, returning the result. Note that shell commands return 0 to indicate happiness.
int BuildSteps::shell(text_stream *command, build_methodology *BM) { int rv = TRUE; #ifndef CORE_MODULE WRITE_TO(STDOUT, "%S\n", command); #endif if (BM->methodology == SHELL_METHODOLOGY) rv = (Shell::run(command) == 0)?TRUE:FALSE; return rv; }