inweb-bootstrap/Chapter 6/Makefiles.w

341 lines
12 KiB
OpenEdge ABL
Raw Normal View History

2019-02-04 22:26:45 +00:00
[Makefiles::] Makefiles.
Constructing a suitable makefile for a simple inweb project.
@ This section offers just one function, which constructs a makefile by
following a "prototype".
=
typedef struct makefile_state {
struct web *for_web;
struct text_stream to_makefile;
struct text_stream *repeat_block; /* a "repeatblock" body being scanned */
int inside_block; /* scanning a "repeatblock" into that text? */
int last_line_was_blank; /* used to suppress runs of multiple blank lines */
int allow_commands; /* permit the prototype to use special commands */
2020-04-02 12:30:38 +00:00
int repeat_scope; /* during a repeat, either |MAKEFILE_TOOL_MOM| or |MAKEFILE_MODULE_MOM| */
2020-04-02 17:38:08 +00:00
struct text_stream *repeat_tag;
2020-04-02 12:30:38 +00:00
struct dictionary *tools_dictionary;
2020-04-02 17:38:08 +00:00
struct dictionary *webs_dictionary;
2020-04-02 12:30:38 +00:00
struct dictionary *modules_dictionary;
struct module_search *search_path;
2019-02-04 22:26:45 +00:00
} makefile_state;
2020-04-02 12:30:38 +00:00
void Makefiles::write(web *W, filename *prototype, filename *F, module_search *I) {
2019-02-04 22:26:45 +00:00
makefile_state MS;
MS.for_web = W;
MS.last_line_was_blank = TRUE;
MS.repeat_block = Str::new();
MS.inside_block = FALSE;
MS.allow_commands = TRUE;
2020-04-02 12:30:38 +00:00
MS.tools_dictionary = Dictionaries::new(16, FALSE);
2020-04-02 17:38:08 +00:00
MS.webs_dictionary = Dictionaries::new(16, FALSE);
2020-04-02 12:30:38 +00:00
MS.modules_dictionary = Dictionaries::new(16, FALSE);
MS.search_path = I;
MS.repeat_scope = -1;
2020-04-02 17:38:08 +00:00
MS.repeat_tag = NULL;
2019-02-04 22:26:45 +00:00
text_stream *OUT = &(MS.to_makefile);
if (STREAM_OPEN_TO_FILE(OUT, F, ISO_ENC) == FALSE)
Errors::fatal_with_file("unable to write tangled file", F);
WRITE("# This makefile was automatically written by inweb -makefile\n");
WRITE("# and is not intended for human editing\n\n");
TextFiles::read(prototype, FALSE, "can't open prototype file",
TRUE, Makefiles::scan_makefile_line, NULL, &MS);
STREAM_CLOSE(OUT);
WRITE_TO(STDOUT, "Wrote makefile '%f' from script '%f'\n", F, prototype);
2019-02-04 22:26:45 +00:00
}
@ =
void Makefiles::scan_makefile_line(text_stream *line, text_file_position *tfp, void *X) {
makefile_state *MS = (makefile_state *) X;
text_stream *OUT = &(MS->to_makefile);
match_results mr = Regexp::create_mr();
if (Regexp::match(&mr, line, L" *#%c*")) { Regexp::dispose_of(&mr); return; } // Skip comment lines
if (MS->allow_commands) {
2020-04-02 17:38:08 +00:00
if (Regexp::match(&mr, line, L" *{repeat-tools-block:(%C*)} *"))
@<Begin a repeat tool block@>;
if (Regexp::match(&mr, line, L" *{repeat-webs-block:(%C*)} *"))
@<Begin a repeat web block@>;
if (Regexp::match(&mr, line, L" *{repeat-modules-block:(%C*)} *"))
@<Begin a repeat module block@>;
if (Regexp::match(&mr, line, L" *{end-block} *")) @<End a repeat block@>;
2019-02-04 22:26:45 +00:00
if (MS->inside_block) @<Deal with a line in a repeat block@>;
2020-04-02 12:30:38 +00:00
if (Regexp::match(&mr, line, L"(%c*){repeat-tools-span}(%c*?){end-span}(%c*)"))
@<Deal with a repeat span@>;
2020-04-02 17:38:08 +00:00
if (Regexp::match(&mr, line, L"(%c*){repeat-webs-span}(%c*?){end-span}(%c*)"))
@<Deal with a repeat web span@>;
2020-04-02 12:30:38 +00:00
if (Regexp::match(&mr, line, L"(%c*){repeat-modules-span}(%c*?){end-span}(%c*)"))
@<Deal with a repeat module span@>;
2019-02-04 22:26:45 +00:00
if (Regexp::match(&mr, line, L" *{identity-settings} *")) @<Expand identity-settings@>;
if (Regexp::match(&mr, line, L" *{platform-settings} *")) @<Expand platform-settings@>;
2020-04-02 17:38:08 +00:00
if (Regexp::match(&mr, line, L" *{tool} *(%C+) (%C+) (%c+) (%C+) *")) @<Declare a tool@>;
if (Regexp::match(&mr, line, L" *{web} *(%C+) (%C+) (%c+) (%C+) *")) @<Declare a web@>;
if (Regexp::match(&mr, line, L" *{module} *(%C+) (%C+) (%c+) (%C+) *")) @<Declare a module@>;
2019-02-04 22:26:45 +00:00
if (Regexp::match(&mr, line, L"(%c*?) *{dependent-files} *")) @<Expand dependent-files@>;
2020-04-02 17:38:08 +00:00
if (Regexp::match(&mr, line, L"(%c*?) *{dependent-files-for-tool-alone} *(%C+)"))
@<Expand dependent-files-for-tool-alone@>;
if (Regexp::match(&mr, line, L"(%c*?) *{dependent-files-for-tool-and-modules} *(%C+)"))
2020-04-02 12:30:38 +00:00
@<Expand dependent-files-for-tool@>;
if (Regexp::match(&mr, line, L"(%c*?) *{dependent-files-for-module} *(%C+)"))
@<Expand dependent-files-for-module@>;
2019-02-04 22:26:45 +00:00
}
Regexp::dispose_of(&mr);
@<And otherwise copy the line straight through@>;
}
2020-04-02 12:30:38 +00:00
@<Begin a repeat tool block@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_TOOL_MOM;
@<Begin a repeat block@>;
2020-04-02 17:38:08 +00:00
@<Begin a repeat web block@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_WEB_MOM;
@<Begin a repeat block@>;
2020-04-02 12:30:38 +00:00
@<Begin a repeat module block@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_MODULE_MOM;
@<Begin a repeat block@>;
@<Begin a repeat block@> =
2020-04-02 12:30:38 +00:00
if (MS->inside_block) Errors::in_text_file("nested repeat blocks are not allowed", tfp);
MS->inside_block = TRUE;
2020-04-03 15:29:03 +00:00
MS->repeat_scope = marker;
2020-04-02 17:38:08 +00:00
MS->repeat_tag = Str::duplicate(mr.exp[0]);
2019-02-04 22:26:45 +00:00
Str::clear(MS->repeat_block);
Regexp::dispose_of(&mr);
return;
@<Deal with a line in a repeat block@> =
WRITE_TO(MS->repeat_block, "%S\n", line);
return;
@<End a repeat block@> =
if (MS->inside_block == FALSE)
Errors::in_text_file("{endblock} without {repeatblock}", tfp);
MS->inside_block = FALSE;
2020-04-02 17:38:08 +00:00
Makefiles::repeat(OUT, NULL, TRUE, MS->repeat_block, TRUE, NULL, tfp, MS, MS->repeat_scope, MS->repeat_tag);
2019-02-04 22:26:45 +00:00
Str::clear(MS->repeat_block);
Regexp::dispose_of(&mr);
return;
@<Deal with a repeat span@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_TOOL_MOM;
@<Begin a repeat span@>;
2020-04-02 17:38:08 +00:00
@<Deal with a repeat web span@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_WEB_MOM;
@<Begin a repeat span@>;
2020-04-02 12:30:38 +00:00
@<Deal with a repeat module span@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_MODULE_MOM;
@<Begin a repeat span@>;
@<Begin a repeat span@> =
2020-04-02 12:30:38 +00:00
WRITE("%S", mr.exp[0]);
2020-04-03 15:29:03 +00:00
Makefiles::repeat(OUT, I" ", FALSE, mr.exp[1], FALSE, NULL, tfp, MS, marker, I"all");
2019-02-04 22:26:45 +00:00
WRITE("%S\n", mr.exp[2]);
MS->last_line_was_blank = FALSE;
Regexp::dispose_of(&mr);
return;
@<Expand platform-settings@> =
filename *prototype = Filenames::in_folder(path_to_inweb, I"platform-settings.mk");
MS->allow_commands = FALSE;
TextFiles::read(prototype, FALSE, "can't open make settings file",
TRUE, Makefiles::scan_makefile_line, NULL, MS);
Regexp::dispose_of(&mr);
MS->allow_commands = TRUE;
return;
@<Expand identity-settings@> =
2019-03-10 23:46:11 +00:00
WRITE("INWEB = "); Makefiles::pathname_slashed(OUT, path_to_inweb); WRITE("/Tangled/inweb\n");
pathname *path_to_intest = Pathnames::subfolder(Pathnames::up(path_to_inweb), I"intest");
WRITE("INTEST = "); Makefiles::pathname_slashed(OUT, path_to_intest); WRITE("/Tangled/intest\n");
2019-03-12 23:32:12 +00:00
if (MS->for_web) {
WRITE("MYNAME = %S\n", Pathnames::directory_name(MS->for_web->md->path_to_web));
WRITE("ME = "); Makefiles::pathname_slashed(OUT, MS->for_web->md->path_to_web);
2019-03-12 23:32:12 +00:00
WRITE("\n");
MS->last_line_was_blank = FALSE;
2019-02-04 22:26:45 +00:00
}
Regexp::dispose_of(&mr);
return;
@<Declare a tool@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_TOOL_MOM;
@<Declare something@>;
2019-02-04 22:26:45 +00:00
2020-04-02 17:38:08 +00:00
@<Declare a web@> =
2020-04-03 15:29:03 +00:00
int marker = MAKEFILE_WEB_MOM;
@<Declare something@>;
@<Declare a module@> =
int marker = MAKEFILE_MODULE_MOM;
@<Declare something@>;
@<Declare something@> =
2020-04-02 17:38:08 +00:00
WRITE("%SLEAF = %S\n", mr.exp[0], mr.exp[1]);
WRITE("%SWEB = %S\n", mr.exp[0], mr.exp[2]);
WRITE("%SMAKER = $(%SWEB)/%S.mk\n", mr.exp[0], mr.exp[0], mr.exp[1]);
WRITE("%SX = $(%SWEB)/Tangled/%S\n", mr.exp[0], mr.exp[0], mr.exp[1]);
MS->last_line_was_blank = FALSE;
web_md *Wm = Reader::load_web_md(Pathnames::from_text(mr.exp[2]), NULL, MS->search_path, FALSE, TRUE);
Wm->as_module->module_name = Str::duplicate(mr.exp[0]);
Wm->as_module->module_tag = Str::duplicate(mr.exp[3]);
2020-04-03 15:29:03 +00:00
Wm->as_module->origin_marker = marker;
Dictionaries::create(MS->tools_dictionary, mr.exp[0]);
Dictionaries::write_value(MS->tools_dictionary, mr.exp[0], Wm);
2019-02-04 22:26:45 +00:00
Regexp::dispose_of(&mr);
return;
2020-04-02 12:30:38 +00:00
@<Expand dependent-files@> =
WRITE("%S", mr.exp[0]);
Makefiles::pattern(OUT, MS->for_web->md->sections_md, MS->for_web->md->contents_filename);
WRITE("\n");
MS->last_line_was_blank = FALSE;
2019-02-04 22:26:45 +00:00
Regexp::dispose_of(&mr);
return;
2020-04-02 12:30:38 +00:00
@<Expand dependent-files-for-tool@> =
2019-02-04 22:26:45 +00:00
WRITE("%S", mr.exp[0]);
2020-04-02 12:30:38 +00:00
if (Dictionaries::find(MS->tools_dictionary, mr.exp[1])) {
web_md *Wm = Dictionaries::read_value(MS->tools_dictionary, mr.exp[1]);
Makefiles::pattern(OUT, Wm->sections_md, Wm->contents_filename);
2020-04-02 17:38:08 +00:00
} else if (Dictionaries::find(MS->webs_dictionary, mr.exp[1])) {
web_md *Wm = Dictionaries::read_value(MS->webs_dictionary, mr.exp[1]);
Makefiles::pattern(OUT, Wm->sections_md, Wm->contents_filename);
} else {
PRINT("Tool %S\n", mr.exp[0]);
Errors::in_text_file("unknown tool to find dependencies for", tfp);
}
WRITE("\n");
MS->last_line_was_blank = FALSE;
Regexp::dispose_of(&mr);
return;
@<Expand dependent-files-for-tool-alone@> =
WRITE("%S", mr.exp[0]);
if (Dictionaries::find(MS->tools_dictionary, mr.exp[1])) {
web_md *Wm = Dictionaries::read_value(MS->tools_dictionary, mr.exp[1]);
Makefiles::pattern(OUT, Wm->as_module->sections_md, Wm->contents_filename);
} else if (Dictionaries::find(MS->webs_dictionary, mr.exp[1])) {
web_md *Wm = Dictionaries::read_value(MS->webs_dictionary, mr.exp[1]);
Makefiles::pattern(OUT, Wm->as_module->sections_md, Wm->contents_filename);
2020-04-02 12:30:38 +00:00
} else {
PRINT("Tool %S\n", mr.exp[0]);
Errors::in_text_file("unknown tool to find dependencies for", tfp);
2019-02-04 22:26:45 +00:00
}
WRITE("\n");
MS->last_line_was_blank = FALSE;
Regexp::dispose_of(&mr);
return;
2020-04-02 12:30:38 +00:00
@<Expand dependent-files-for-module@> =
2019-02-04 22:26:45 +00:00
WRITE("%S", mr.exp[0]);
2020-04-02 12:30:38 +00:00
if (Dictionaries::find(MS->modules_dictionary, mr.exp[1])) {
web_md *Wm = Dictionaries::read_value(MS->modules_dictionary, mr.exp[1]);
Makefiles::pattern(OUT, Wm->sections_md, Wm->contents_filename);
} else {
Errors::in_text_file("unknown module to find dependencies for", tfp);
2019-02-04 22:26:45 +00:00
}
2020-04-02 12:30:38 +00:00
WRITE("\n");
2019-02-04 22:26:45 +00:00
MS->last_line_was_blank = FALSE;
Regexp::dispose_of(&mr);
return;
@<And otherwise copy the line straight through@> =
if (Str::len(line) == 0) {
if (MS->last_line_was_blank == FALSE) WRITE("\n");
MS->last_line_was_blank = TRUE;
} else {
MS->last_line_was_blank = FALSE;
WRITE("%S\n", line);
}
2019-03-10 23:46:11 +00:00
@ =
void Makefiles::pathname_slashed(OUTPUT_STREAM, pathname *P) {
TEMPORARY_TEXT(PT)
WRITE_TO(PT, "%p", P);
LOOP_THROUGH_TEXT(pos, PT) {
wchar_t c = Str::get(pos);
if (c == ' ') WRITE("\\ ");
else PUT(c);
}
DISCARD_TEXT(PT)
}
2020-04-02 12:30:38 +00:00
void Makefiles::pattern(OUTPUT_STREAM, linked_list *L, filename *F) {
dictionary *patterns_done = Dictionaries::new(16, TRUE);
if (F) @<Add pattern for file F, if not already given@>;
section_md *Sm;
LOOP_OVER_LINKED_LIST(Sm, section_md, L) {
filename *F = Sm->source_file_for_section;
@<Add pattern for file F, if not already given@>;
}
}
@<Add pattern for file F, if not already given@> =
pathname *P = Filenames::get_path_to(F);
TEMPORARY_TEXT(leaf_pattern);
WRITE_TO(leaf_pattern, "%S", Pathnames::directory_name(P));
match_results mr = Regexp::create_mr();
if (Regexp::match(&mr, leaf_pattern, L"Chapter %d*")) {
Str::clear(leaf_pattern); WRITE_TO(leaf_pattern, "Chapter*");
} else if (Regexp::match(&mr, leaf_pattern, L"Appendix %C")) {
Str::clear(leaf_pattern); WRITE_TO(leaf_pattern, "Appendix*");
}
Regexp::dispose_of(&mr);
TEMPORARY_TEXT(tester);
WRITE_TO(tester, "%p/%S/*", Pathnames::up(P), leaf_pattern);
DISCARD_TEXT(leaf_pattern);
Filenames::write_extension(tester, F);
if (Dictionaries::find(patterns_done, tester) == NULL) {
WRITE_TO(Dictionaries::create_text(patterns_done, tester), "got this");
WRITE(" ");
LOOP_THROUGH_TEXT(pos, tester) {
wchar_t c = Str::get(pos);
if (c == ' ') PUT('\\');
PUT(c);
}
}
DISCARD_TEXT(tester);
2019-02-04 22:26:45 +00:00
@ And finally, the following handles repetitions both of blocks and of spans:
=
void Makefiles::repeat(OUTPUT_STREAM, text_stream *prefix, int every_time, text_stream *matter,
2020-04-02 17:38:08 +00:00
int as_lines, text_stream *suffix, text_file_position *tfp, makefile_state *MS, int over, text_stream *tag) {
2019-02-04 22:26:45 +00:00
module *M;
int c = 0;
LOOP_OVER(M, module) {
2020-04-02 17:38:08 +00:00
if ((M->origin_marker == over) &&
((Str::eq(tag, I"all")) || (Str::eq(tag, M->module_tag)))) {
2019-02-04 22:26:45 +00:00
if ((prefix) && ((c++ > 0) || (every_time))) WRITE("%S", prefix);
if (matter) {
TEMPORARY_TEXT(line);
LOOP_THROUGH_TEXT(pos, matter) {
if (Str::get(pos) == '\n') {
if (as_lines) {
Makefiles::scan_makefile_line(line, tfp, (void *) MS);
Str::clear(line);
}
} else {
2020-04-02 17:38:08 +00:00
if (Str::get(pos) == '@') {
2019-02-04 22:26:45 +00:00
WRITE_TO(line, "%S", M->module_name);
} else {
PUT_TO(line, Str::get(pos));
}
}
}
if (!as_lines) WRITE("%S", line);
DISCARD_TEXT(line);
}
if (suffix) WRITE("%S", suffix);
}
}
}