mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Support -P/--preinclude to pre-INCLUDE a file (#1043)
Fixes #1041 Co-authored-by: ISSOtm <eldredhabert0@gmail.com>
This commit is contained in:
@@ -38,6 +38,7 @@ _rgbasm_completions() {
|
|||||||
[i]="include:dir"
|
[i]="include:dir"
|
||||||
[M]="dependfile:glob-*.mk *.d"
|
[M]="dependfile:glob-*.mk *.d"
|
||||||
[o]="output:glob-*.o"
|
[o]="output:glob-*.o"
|
||||||
|
[P]="preinclude:glob-*.asm *.inc"
|
||||||
[p]="pad-value:unk"
|
[p]="pad-value:unk"
|
||||||
[Q]="q-precision:unk"
|
[Q]="q-precision:unk"
|
||||||
[r]="recursion-depth:unk"
|
[r]="recursion-depth:unk"
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ local args=(
|
|||||||
'*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
'*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
||||||
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
||||||
'(-o --output)'{-o,--output}'+[Output file]:output file:_files'
|
'(-o --output)'{-o,--output}'+[Output file]:output file:_files'
|
||||||
|
'(-P --preinclude)'{-P,--preinclude}"+[Pre-include a file]:include file:_files -g '*.{asm,inc}'"
|
||||||
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
||||||
'(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:'
|
'(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:'
|
||||||
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
|
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ struct FileStackNode *fstk_GetFileStack(void);
|
|||||||
char const *fstk_GetFileName(void);
|
char const *fstk_GetFileName(void);
|
||||||
|
|
||||||
void fstk_AddIncludePath(char const *s);
|
void fstk_AddIncludePath(char const *s);
|
||||||
|
void fstk_SetPreIncludeFile(char const *s);
|
||||||
/*
|
/*
|
||||||
* @param path The user-provided file name
|
* @param path The user-provided file name
|
||||||
* @param fullPath The address of a pointer, which will be made to point at the full path
|
* @param fullPath The address of a pointer, which will be made to point at the full path
|
||||||
|
|||||||
31
man/rgbasm.1
31
man/rgbasm.1
@@ -24,21 +24,21 @@
|
|||||||
.Op Fl MT Ar target_file
|
.Op Fl MT Ar target_file
|
||||||
.Op Fl MQ Ar target_file
|
.Op Fl MQ Ar target_file
|
||||||
.Op Fl o Ar out_file
|
.Op Fl o Ar out_file
|
||||||
|
.Op Fl P Ar include_file
|
||||||
.Op Fl p Ar pad_value
|
.Op Fl p Ar pad_value
|
||||||
.Op Fl Q Ar fix_precision
|
.Op Fl Q Ar fix_precision
|
||||||
.Op Fl r Ar recursion_depth
|
.Op Fl r Ar recursion_depth
|
||||||
.Op Fl W Ar warning
|
.Op Fl W Ar warning
|
||||||
.Ar
|
.Ar asmfile
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
program creates an RGB object file from an assembly source file.
|
program creates an RGB object file from an assembly source file.
|
||||||
The input
|
The input
|
||||||
.Ar file
|
.Ar asmfile
|
||||||
can be a file path, or
|
can be a path to a file, or
|
||||||
.Cm \-
|
.Cm \-
|
||||||
denoting
|
to read from standard input.
|
||||||
.Cm stdin .
|
|
||||||
.Pp
|
.Pp
|
||||||
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||||
.Fl Fl verb
|
.Fl Fl verb
|
||||||
@@ -87,7 +87,19 @@ instruction immediately after any
|
|||||||
.Ic halt
|
.Ic halt
|
||||||
instruction.
|
instruction.
|
||||||
.It Fl i Ar path , Fl Fl include Ar path
|
.It Fl i Ar path , Fl Fl include Ar path
|
||||||
Add an include path.
|
Add a new
|
||||||
|
.Dq include path ; Ar path
|
||||||
|
must point to a directory.
|
||||||
|
When a
|
||||||
|
.Ic INCLUDE
|
||||||
|
.Pq including the implicit one from Fl P
|
||||||
|
or
|
||||||
|
.Ic INCBIN
|
||||||
|
is attempted,
|
||||||
|
.Nm
|
||||||
|
first looks up the provided path from its working directory; if this fails, it tries again from each of the
|
||||||
|
.Dq include path
|
||||||
|
directories, in the order they were provided.
|
||||||
.It Fl L , Fl Fl preserve-ld
|
.It Fl L , Fl Fl preserve-ld
|
||||||
By default,
|
By default,
|
||||||
.Nm
|
.Nm
|
||||||
@@ -116,6 +128,7 @@ This makes
|
|||||||
.Nm
|
.Nm
|
||||||
assume that missing files are auto-generated: when
|
assume that missing files are auto-generated: when
|
||||||
.Ic INCLUDE
|
.Ic INCLUDE
|
||||||
|
.Pq including the implicit one from Fl P
|
||||||
or
|
or
|
||||||
.Ic INCBIN
|
.Ic INCBIN
|
||||||
is attempted on a non-existent file, it is added as a dependency, then
|
is attempted on a non-existent file, it is added as a dependency, then
|
||||||
@@ -146,6 +159,12 @@ characters, essentially
|
|||||||
.Sq $ .
|
.Sq $ .
|
||||||
.It Fl o Ar out_file , Fl Fl output Ar out_file
|
.It Fl o Ar out_file , Fl Fl output Ar out_file
|
||||||
Write an object file to the given filename.
|
Write an object file to the given filename.
|
||||||
|
.It Fl P Ar include_file , Fl Fl preinclude Ar include_file
|
||||||
|
Pre-include a file.
|
||||||
|
This acts as if a
|
||||||
|
.Ql Ic INCLUDE Qq Ar include_file
|
||||||
|
was read before the input
|
||||||
|
.Ar asmfile .
|
||||||
.It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value
|
.It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value
|
||||||
When padding an image, pad with this value.
|
When padding an image, pad with this value.
|
||||||
The default is 0x00.
|
The default is 0x00.
|
||||||
|
|||||||
@@ -1972,6 +1972,13 @@ calls infinitely (or until you run out of memory, whichever comes first).
|
|||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
INCLUDE "irq.inc"
|
INCLUDE "irq.inc"
|
||||||
.Ed
|
.Ed
|
||||||
|
.Pp
|
||||||
|
You may also implicitly
|
||||||
|
.Ic INCLUDE
|
||||||
|
a file before the source file with the
|
||||||
|
.Fl P
|
||||||
|
option of
|
||||||
|
.Xr rgbasm 1 .
|
||||||
.Ss Conditional assembling
|
.Ss Conditional assembling
|
||||||
The four commands
|
The four commands
|
||||||
.Ic IF , ELIF , ELSE ,
|
.Ic IF , ELIF , ELSE ,
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ size_t maxRecursionDepth;
|
|||||||
static unsigned int nbIncPaths = 0;
|
static unsigned int nbIncPaths = 0;
|
||||||
static char const *includePaths[MAXINCPATHS];
|
static char const *includePaths[MAXINCPATHS];
|
||||||
|
|
||||||
|
static const char *preIncludeName;
|
||||||
|
|
||||||
static const char *dumpNodeAndParents(struct FileStackNode const *node)
|
static const char *dumpNodeAndParents(struct FileStackNode const *node)
|
||||||
{
|
{
|
||||||
char const *name;
|
char const *name;
|
||||||
@@ -133,6 +135,11 @@ void fstk_AddIncludePath(char const *path)
|
|||||||
includePaths[nbIncPaths++] = str;
|
includePaths[nbIncPaths++] = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fstk_SetPreIncludeFile(char const *path)
|
||||||
|
{
|
||||||
|
preIncludeName = path;
|
||||||
|
}
|
||||||
|
|
||||||
static void printDep(char const *path)
|
static void printDep(char const *path)
|
||||||
{
|
{
|
||||||
if (dependfile) {
|
if (dependfile) {
|
||||||
@@ -274,6 +281,7 @@ bool yywrap(void)
|
|||||||
|
|
||||||
lexer_SetState(contextStack->lexerState);
|
lexer_SetState(contextStack->lexerState);
|
||||||
macro_SetUniqueID(contextStack->uniqueID);
|
macro_SetUniqueID(contextStack->uniqueID);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +350,41 @@ void fstk_RunInclude(char const *path)
|
|||||||
contextStack->uniqueID = macro_UndefUniqueID();
|
contextStack->uniqueID = macro_UndefUniqueID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Similar to `fstk_RunInclude`, but not subject to `-MG`, and
|
||||||
|
// calling `lexer_SetState` instead of `lexer_SetStateAtEOL`.
|
||||||
|
static void runPreIncludeFile(void)
|
||||||
|
{
|
||||||
|
if (!preIncludeName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char *fullPath = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
if (!fstk_FindFile(preIncludeName, &fullPath, &size)) {
|
||||||
|
free(fullPath);
|
||||||
|
error("Unable to open included file '%s': %s\n", preIncludeName, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + size);
|
||||||
|
|
||||||
|
if (!fileInfo) {
|
||||||
|
error("Failed to alloc file info for pre-include: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fileInfo->node.type = NODE_FILE;
|
||||||
|
strcpy(fileInfo->name, fullPath);
|
||||||
|
free(fullPath);
|
||||||
|
|
||||||
|
newContext((struct FileStackNode *)fileInfo);
|
||||||
|
contextStack->lexerState = lexer_OpenFile(fileInfo->name);
|
||||||
|
if (!contextStack->lexerState)
|
||||||
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
|
lexer_SetState(contextStack->lexerState);
|
||||||
|
// We're back at top-level, so most things are reset
|
||||||
|
contextStack->uniqueID = macro_UndefUniqueID();
|
||||||
|
}
|
||||||
|
|
||||||
void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
||||||
{
|
{
|
||||||
struct Symbol *macro = sym_FindExactSymbol(macroName);
|
struct Symbol *macro = sym_FindExactSymbol(macroName);
|
||||||
@@ -563,4 +606,6 @@ void fstk_Init(char const *mainPath, size_t maxDepth)
|
|||||||
// Make sure that the default of 64 is OK, though
|
// Make sure that the default of 64 is OK, though
|
||||||
assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
|
assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
|
||||||
#undef DEPTH_LIMIT
|
#undef DEPTH_LIMIT
|
||||||
|
|
||||||
|
runPreIncludeFile();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ static char *make_escape(char const *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Short options
|
// Short options
|
||||||
static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:Q:r:VvW:w";
|
static const char *optstring = "b:D:Eg:Hhi:LlM:o:P:p:Q:r:VvW:w";
|
||||||
|
|
||||||
// Variables for the long-only options
|
// Variables for the long-only options
|
||||||
static int depType; // Variants of `-M`
|
static int depType; // Variants of `-M`
|
||||||
@@ -116,6 +116,7 @@ static struct option const longopts[] = {
|
|||||||
{ "MT", required_argument, &depType, 'T' },
|
{ "MT", required_argument, &depType, 'T' },
|
||||||
{ "MQ", required_argument, &depType, 'Q' },
|
{ "MQ", required_argument, &depType, 'Q' },
|
||||||
{ "output", required_argument, NULL, 'o' },
|
{ "output", required_argument, NULL, 'o' },
|
||||||
|
{ "preinclude", required_argument, NULL, 'P' },
|
||||||
{ "pad-value", required_argument, NULL, 'p' },
|
{ "pad-value", required_argument, NULL, 'p' },
|
||||||
{ "q-precision", required_argument, NULL, 'Q' },
|
{ "q-precision", required_argument, NULL, 'Q' },
|
||||||
{ "recursion-depth", required_argument, NULL, 'r' },
|
{ "recursion-depth", required_argument, NULL, 'r' },
|
||||||
@@ -130,8 +131,8 @@ static void print_usage(void)
|
|||||||
fputs(
|
fputs(
|
||||||
"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-i path]\n"
|
"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-i path]\n"
|
||||||
" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
|
" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
|
||||||
" [-o out_file] [-p pad_value] [-Q precision] [-r depth]\n"
|
" [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n"
|
||||||
" [-W warning] <file>\n"
|
" [-r depth] [-W warning] <file>\n"
|
||||||
"Useful options:\n"
|
"Useful options:\n"
|
||||||
" -E, --export-all export all labels\n"
|
" -E, --export-all export all labels\n"
|
||||||
" -M, --dependfile <path> set the output dependency file\n"
|
" -M, --dependfile <path> set the output dependency file\n"
|
||||||
@@ -254,6 +255,10 @@ int main(int argc, char *argv[])
|
|||||||
out_SetFileName(musl_optarg);
|
out_SetFileName(musl_optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
fstk_SetPreIncludeFile(musl_optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
unsigned long padByte;
|
unsigned long padByte;
|
||||||
case 'p':
|
case 'p':
|
||||||
padByte = strtoul(musl_optarg, &ep, 0);
|
padByte = strtoul(musl_optarg, &ep, 0);
|
||||||
|
|||||||
3
test/asm/preinclude.asm
Normal file
3
test/asm/preinclude.asm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
warn "main {__FILE__}"
|
||||||
|
def v3 = v1 + v2
|
||||||
|
println "{d:v1} + {d:v2} = {d:v3}"
|
||||||
4
test/asm/preinclude.err
Normal file
4
test/asm/preinclude.err
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
warning: preinclude.asm(0) -> preinclude.inc(1): [-Wuser]
|
||||||
|
pre-include "preinclude.inc"
|
||||||
|
warning: preinclude.asm(1): [-Wuser]
|
||||||
|
main "preinclude.asm"
|
||||||
1
test/asm/preinclude.flags
Normal file
1
test/asm/preinclude.flags
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-Weverything -P preinclude.inc
|
||||||
11
test/asm/preinclude.inc
Normal file
11
test/asm/preinclude.inc
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
warn "pre-include {__FILE__}"
|
||||||
|
|
||||||
|
def v1 = 12
|
||||||
|
rept 3
|
||||||
|
println "rept 3"
|
||||||
|
endr
|
||||||
|
|
||||||
|
def v2 = 34
|
||||||
|
for i, 3
|
||||||
|
println "for {d:i}/3"
|
||||||
|
endr
|
||||||
7
test/asm/preinclude.out
Normal file
7
test/asm/preinclude.out
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
rept 3
|
||||||
|
rept 3
|
||||||
|
rept 3
|
||||||
|
for 0/3
|
||||||
|
for 1/3
|
||||||
|
for 2/3
|
||||||
|
12 + 34 = 46
|
||||||
@@ -76,6 +76,11 @@ if ! diff --strip-trailing-cr syntax-error.err $errput; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
for i in *.asm; do
|
for i in *.asm; do
|
||||||
|
flags=${i%.asm}.flags
|
||||||
|
RGBASMFLAGS=-Weverything
|
||||||
|
if [ -f $flags ]; then
|
||||||
|
RGBASMFLAGS="$(head -n 1 "$flags")" # Allow other lines to serve as comments
|
||||||
|
fi
|
||||||
for variant in '' '.pipe'; do
|
for variant in '' '.pipe'; do
|
||||||
echo "${bold}${green}${i%.asm}${variant}...${rescolors}${resbold}"
|
echo "${bold}${green}${i%.asm}${variant}...${rescolors}${resbold}"
|
||||||
desired_errname=${i%.asm}.err
|
desired_errname=${i%.asm}.err
|
||||||
@@ -83,7 +88,7 @@ for i in *.asm; do
|
|||||||
desired_errname=${i%.asm}.simple.err
|
desired_errname=${i%.asm}.simple.err
|
||||||
fi
|
fi
|
||||||
if [ -z "$variant" ]; then
|
if [ -z "$variant" ]; then
|
||||||
$RGBASM -Weverything -o $o $i > $output 2> $errput
|
$RGBASM $RGBASMFLAGS -o $o $i > $output 2> $errput
|
||||||
desired_output=${i%.asm}.out
|
desired_output=${i%.asm}.out
|
||||||
desired_errput=$desired_errname
|
desired_errput=$desired_errname
|
||||||
else
|
else
|
||||||
@@ -97,7 +102,7 @@ for i in *.asm; do
|
|||||||
# stdin redirection makes the input an unseekable pipe - a scenario
|
# stdin redirection makes the input an unseekable pipe - a scenario
|
||||||
# that's harder to deal with and was broken when the feature was
|
# that's harder to deal with and was broken when the feature was
|
||||||
# first implemented.
|
# first implemented.
|
||||||
cat $i | $RGBASM -Weverything -o $o - > $output 2> $errput
|
cat $i | $RGBASM $RGBASMFLAGS -o $o - > $output 2> $errput
|
||||||
|
|
||||||
# Use two otherwise unused files for temp storage
|
# Use two otherwise unused files for temp storage
|
||||||
desired_output=$input
|
desired_output=$input
|
||||||
|
|||||||
Reference in New Issue
Block a user