mirror of
https://github.com/pret/pokeemerald.git
synced 2026-08-26 04:24:48 -05:00
INCGFX: in-source arguments for gbagfx
'INCGFX' is like 'INCBIN' except that it specifies the arguments to pass to 'gbagfx' which alleviates the user-unfriendliness caused by catch-all rules. Specifically, users frequently forget to add to 'spritesheet_rules.mk' when adding object event graphics, and then the built '.4bpp' file is not invalidated when the add their rule so they have to 'touch' the source file or similar. The built artifacts are placed in 'build/assets'.
This commit is contained in:
14
Makefile
14
Makefile
@@ -71,6 +71,7 @@ ROM_NAME := $(FILE_NAME).gba
|
||||
OBJ_DIR_NAME := $(BUILD_DIR)/emerald
|
||||
MODERN_ROM_NAME := $(FILE_NAME)_modern.gba
|
||||
MODERN_OBJ_DIR_NAME := $(BUILD_DIR)/modern
|
||||
ASSETS_DIR_NAME := $(BUILD_DIR)/assets
|
||||
|
||||
ELF_NAME := $(ROM_NAME:.gba=.elf)
|
||||
MAP_NAME := $(ROM_NAME:.gba=.map)
|
||||
@@ -234,6 +235,7 @@ clean: tidy clean-tools clean-generated clean-assets
|
||||
@$(MAKE) clean -C libagbsyscall
|
||||
|
||||
clean-assets:
|
||||
rm -rf $(ASSETS_DIR_NAME)
|
||||
rm -f $(MID_SUBDIR)/*.s
|
||||
rm -f $(DATA_ASM_SUBDIR)/layouts/layouts.inc $(DATA_ASM_SUBDIR)/layouts/layouts_table.inc
|
||||
rm -f $(DATA_ASM_SUBDIR)/maps/connections.inc $(DATA_ASM_SUBDIR)/maps/events.inc $(DATA_ASM_SUBDIR)/maps/groups.inc $(DATA_ASM_SUBDIR)/maps/headers.inc
|
||||
@@ -306,16 +308,16 @@ endif
|
||||
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c
|
||||
ifneq ($(KEEP_TEMPS),1)
|
||||
@echo "$(CC1) <flags> -o $@ $<"
|
||||
@$(CPP) $(CPPFLAGS) $< | $(PREPROC) -i $< charmap.txt | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ -
|
||||
@$(CPP) $(CPPFLAGS) $< | $(PREPROC) -i -g $(ASSETS_DIR_NAME) $< charmap.txt | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ -
|
||||
else
|
||||
@$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
|
||||
@$(PREPROC) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
|
||||
@$(PREPROC) -g $(ASSETS_DIR_NAME) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
|
||||
@echo -e ".text\n\t.align\t2, 0\n" >> $(C_BUILDDIR)/$*.s
|
||||
$(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/$*.s
|
||||
endif
|
||||
|
||||
$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.c
|
||||
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I tools/agbcc/include $<
|
||||
$(SCANINC) -M $@ -g $(ASSETS_DIR_NAME) $(INCLUDE_SCANINC_ARGS) -I tools/agbcc/include $<
|
||||
|
||||
ifneq ($(NODEP),1)
|
||||
-include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d))
|
||||
@@ -325,7 +327,7 @@ $(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s
|
||||
$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
$(ASM_BUILDDIR)/%.d: $(ASM_SUBDIR)/%.s
|
||||
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $<
|
||||
$(SCANINC) -M $@ -g $(ASSETS_DIR_NAME) $(INCLUDE_SCANINC_ARGS) -I "" $<
|
||||
|
||||
ifneq ($(NODEP),1)
|
||||
-include $(addprefix $(OBJ_DIR)/,$(ASM_SRCS:.s=.d))
|
||||
@@ -335,7 +337,7 @@ $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s
|
||||
$(PREPROC) $< charmap.txt | $(CPP) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@
|
||||
|
||||
$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.s
|
||||
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $<
|
||||
$(SCANINC) -M $@ -g $(ASSETS_DIR_NAME) $(INCLUDE_SCANINC_ARGS) -I "" $<
|
||||
|
||||
ifneq ($(NODEP),1)
|
||||
-include $(addprefix $(OBJ_DIR)/,$(C_ASM_SRCS:.s=.d))
|
||||
@@ -345,7 +347,7 @@ $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s
|
||||
$(PREPROC) $< charmap.txt | $(CPP) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@
|
||||
|
||||
$(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s
|
||||
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $<
|
||||
$(SCANINC) -M $@ -g $(ASSETS_DIR_NAME) $(INCLUDE_SCANINC_ARGS) -I "" $<
|
||||
|
||||
ifneq ($(NODEP),1)
|
||||
-include $(addprefix $(OBJ_DIR)/,$(REGULAR_DATA_ASM_SRCS:.s=.d))
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <stdexcept>
|
||||
@@ -32,7 +33,7 @@
|
||||
#include "string_parser.h"
|
||||
#include "io.h"
|
||||
|
||||
CFile::CFile(const char * filenameCStr, bool isStdin)
|
||||
CFile::CFile(const char * filenameCStr, bool isStdin, const char * graphicsRootCStr)
|
||||
{
|
||||
if (isStdin)
|
||||
m_filename = std::string{"<stdin>/"}.append(filenameCStr);
|
||||
@@ -44,6 +45,9 @@ CFile::CFile(const char * filenameCStr, bool isStdin)
|
||||
m_pos = 0;
|
||||
m_lineNum = 1;
|
||||
m_isStdin = isStdin;
|
||||
m_graphicsRoot = graphicsRootCStr;
|
||||
if (m_graphicsRoot.empty()) m_graphicsRoot = "./";
|
||||
if (m_graphicsRoot[m_graphicsRoot.length() - 1] != '/') m_graphicsRoot.push_back('/');
|
||||
}
|
||||
|
||||
CFile::CFile(CFile&& other) : m_filename(std::move(other.m_filename))
|
||||
@@ -94,6 +98,7 @@ void CFile::Preproc()
|
||||
{
|
||||
TryConvertString();
|
||||
TryConvertIncbin();
|
||||
TryConvertIncgfx();
|
||||
|
||||
if (m_pos >= m_size)
|
||||
break;
|
||||
@@ -237,6 +242,37 @@ bool CFile::CheckIdentifier(const std::string& ident)
|
||||
return (i == ident.length());
|
||||
}
|
||||
|
||||
std::string CFile::ReadString()
|
||||
{
|
||||
if (m_buffer[m_pos] != '"')
|
||||
RaiseError("expected '\"'");
|
||||
m_pos++;
|
||||
|
||||
long startPos = m_pos;
|
||||
|
||||
while (m_buffer[m_pos] != '"')
|
||||
{
|
||||
if (m_buffer[m_pos] == 0)
|
||||
{
|
||||
if (m_pos >= m_size)
|
||||
RaiseError("unexpected EOF in string");
|
||||
else
|
||||
RaiseError("unexpected null character in string");
|
||||
}
|
||||
|
||||
if (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n')
|
||||
RaiseError("unexpected end of line character in string");
|
||||
|
||||
if (m_buffer[m_pos] == '\\')
|
||||
RaiseError("unexpected escape in string");
|
||||
|
||||
m_pos++;
|
||||
}
|
||||
m_pos++;
|
||||
|
||||
return std::string(&m_buffer[startPos], m_pos - 1 - startPos);
|
||||
}
|
||||
|
||||
std::unique_ptr<unsigned char[]> CFile::ReadWholeFile(const std::string& path, int& size)
|
||||
{
|
||||
FILE* fp = std::fopen(path.c_str(), "rb");
|
||||
@@ -319,36 +355,7 @@ void CFile::TryConvertIncbin()
|
||||
while (true)
|
||||
{
|
||||
SkipWhitespace();
|
||||
|
||||
if (m_buffer[m_pos] != '"')
|
||||
RaiseError("expected double quote");
|
||||
|
||||
m_pos++;
|
||||
|
||||
int startPos = m_pos;
|
||||
|
||||
while (m_buffer[m_pos] != '"')
|
||||
{
|
||||
if (m_buffer[m_pos] == 0)
|
||||
{
|
||||
if (m_pos >= m_size)
|
||||
RaiseError("unexpected EOF in path string");
|
||||
else
|
||||
RaiseError("unexpected null character in path string");
|
||||
}
|
||||
|
||||
if (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n')
|
||||
RaiseError("unexpected end of line character in path string");
|
||||
|
||||
if (m_buffer[m_pos] == '\\')
|
||||
RaiseError("unexpected escape in path string");
|
||||
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
std::string path(&m_buffer[startPos], m_pos - startPos);
|
||||
|
||||
m_pos++;
|
||||
auto path = ReadString();
|
||||
|
||||
int fileSize;
|
||||
std::unique_ptr<unsigned char[]> buffer = ReadWholeFile(path, fileSize);
|
||||
@@ -382,6 +389,108 @@ void CFile::TryConvertIncbin()
|
||||
std::printf("}");
|
||||
}
|
||||
|
||||
void CFile::TryConvertIncgfx()
|
||||
{
|
||||
if (!CheckIdentifier("INCGFX_"))
|
||||
return;
|
||||
|
||||
std::string idents[3] = { "INCGFX_U8", "INCGFX_U16", "INCGFX_U32" };
|
||||
int incgfxType = -1;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (CheckIdentifier(idents[i]))
|
||||
{
|
||||
incgfxType = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (incgfxType == -1)
|
||||
return;
|
||||
|
||||
int size = 1 << incgfxType;
|
||||
|
||||
long oldPos = m_pos;
|
||||
long oldLineNum = m_lineNum;
|
||||
|
||||
m_pos += idents[incgfxType].length();
|
||||
|
||||
SkipWhitespace();
|
||||
if (m_buffer[m_pos] != '(')
|
||||
{
|
||||
m_pos = oldPos;
|
||||
m_lineNum = oldLineNum;
|
||||
return;
|
||||
}
|
||||
m_pos++;
|
||||
|
||||
SkipWhitespace();
|
||||
auto source = ReadString();
|
||||
|
||||
SkipWhitespace();
|
||||
if (m_buffer[m_pos] != ',')
|
||||
RaiseError("expected ','");
|
||||
m_pos++;
|
||||
|
||||
SkipWhitespace();
|
||||
auto extensions = ReadString();
|
||||
|
||||
SkipWhitespace();
|
||||
std::string arguments;
|
||||
if (m_buffer[m_pos] == ',')
|
||||
{
|
||||
m_pos++;
|
||||
SkipWhitespace();
|
||||
arguments = ReadString();
|
||||
|
||||
SkipWhitespace();
|
||||
if (m_buffer[m_pos] != ')')
|
||||
RaiseError("expected ')'");
|
||||
m_pos++;
|
||||
}
|
||||
else if (m_buffer[m_pos] == ')')
|
||||
{
|
||||
m_pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseError("exected ')' or ','");
|
||||
}
|
||||
|
||||
// WARNING: This must stay in-sync with 'tools/scaninc/source_file.cpp'.
|
||||
std::string arguments_as_path;
|
||||
for (auto c : arguments)
|
||||
{
|
||||
if (std::isalnum(c))
|
||||
arguments_as_path += c;
|
||||
else
|
||||
arguments_as_path += '_';
|
||||
}
|
||||
|
||||
// WARNING: This must stay in-sync with 'tools/scaninc/scaninc.cpp'.
|
||||
auto converted = m_graphicsRoot + source + arguments_as_path + extensions;
|
||||
|
||||
int fileSize;
|
||||
std::unique_ptr<unsigned char[]> buffer = ReadWholeFile(converted, fileSize);
|
||||
|
||||
if ((fileSize % size) != 0)
|
||||
RaiseError("Size %d doesn't evenly divide file size %d.\n", size, fileSize);
|
||||
|
||||
std::printf("{");
|
||||
|
||||
int count = fileSize / size;
|
||||
int offset = 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int data = ExtractData(buffer, offset, size);
|
||||
offset += size;
|
||||
std::printf("%uu,", data);
|
||||
}
|
||||
|
||||
std::printf("}");
|
||||
}
|
||||
|
||||
// Reports a diagnostic message.
|
||||
void CFile::ReportDiagnostic(const char* type, const char* format, std::va_list args)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
class CFile
|
||||
{
|
||||
public:
|
||||
CFile(const char * filenameCStr, bool isStdin);
|
||||
CFile(const char * filenameCStr, bool isStdin, const char * graphicsRootCStr);
|
||||
CFile(CFile&& other);
|
||||
CFile(const CFile&) = delete;
|
||||
~CFile();
|
||||
@@ -43,6 +43,7 @@ private:
|
||||
long m_lineNum;
|
||||
std::string m_filename;
|
||||
bool m_isStdin;
|
||||
std::string m_graphicsRoot;
|
||||
|
||||
bool ConsumeHorizontalWhitespace();
|
||||
bool ConsumeNewline();
|
||||
@@ -50,7 +51,9 @@ private:
|
||||
void TryConvertString();
|
||||
std::unique_ptr<unsigned char[]> ReadWholeFile(const std::string& path, int& size);
|
||||
bool CheckIdentifier(const std::string& ident);
|
||||
std::string ReadString();
|
||||
void TryConvertIncbin();
|
||||
void TryConvertIncgfx();
|
||||
void ReportDiagnostic(const char* type, const char* format, std::va_list args);
|
||||
void RaiseError(const char* format, ...);
|
||||
void RaiseWarning(const char* format, ...);
|
||||
|
||||
@@ -118,9 +118,9 @@ void PreprocAsmFile(std::string filename, bool isStdin, bool doEnum)
|
||||
}
|
||||
}
|
||||
|
||||
void PreprocCFile(const char * filename, bool isStdin)
|
||||
void PreprocCFile(const char * filename, bool isStdin, const char * graphicsRoot)
|
||||
{
|
||||
CFile cFile(filename, isStdin);
|
||||
CFile cFile(filename, isStdin, graphicsRoot);
|
||||
cFile.Preproc();
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ const char* GetFileExtension(const char* filename)
|
||||
|
||||
static void UsageAndExit(const char *program)
|
||||
{
|
||||
std::fprintf(stderr, "Usage: %s [-i] [-e] SRC_FILE CHARMAP_FILE\nwhere -i denotes if input is from stdin\n -e enables enum handling\n", program);
|
||||
std::fprintf(stderr, "Usage: %s [-i] [-e] [-g PATH] SRC_FILE CHARMAP_FILE\nwhere -i denotes if input is from stdin\n -e enables enum handling\n-g specifies the root for INCGFX\n", program);
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -158,9 +158,10 @@ int main(int argc, char **argv)
|
||||
const char *charmap = NULL;
|
||||
bool isStdin = false;
|
||||
bool doEnum = false;
|
||||
const char *graphicsRoot = "";
|
||||
|
||||
/* preproc [-i] [-e] SRC_FILE CHARMAP_FILE */
|
||||
while ((opt = getopt(argc, argv, "ie")) != -1)
|
||||
/* preproc [-i] [-e] [-g PATH] SRC_FILE CHARMAP_FILE */
|
||||
while ((opt = getopt(argc, argv, "ieg:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
@@ -170,6 +171,9 @@ int main(int argc, char **argv)
|
||||
case 'e':
|
||||
doEnum = true;
|
||||
break;
|
||||
case 'g':
|
||||
graphicsRoot = optarg;
|
||||
break;
|
||||
default:
|
||||
UsageAndExit(argv[0]);
|
||||
break;
|
||||
@@ -202,7 +206,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
if (doEnum)
|
||||
FATAL_ERROR("-e is invalid for C sources\n");
|
||||
PreprocCFile(source, isStdin);
|
||||
PreprocCFile(source, isStdin, graphicsRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <cstring>
|
||||
#include "c_file.h"
|
||||
|
||||
CFile::CFile(std::string path)
|
||||
@@ -86,6 +87,7 @@ void CFile::FindIncbins()
|
||||
SkipWhitespace();
|
||||
CheckInclude();
|
||||
CheckIncbin();
|
||||
CheckIncgfx();
|
||||
|
||||
if (m_pos >= m_size)
|
||||
break;
|
||||
@@ -215,7 +217,7 @@ void CFile::CheckIncbin()
|
||||
&& m_buffer[m_pos+5] == 'N'
|
||||
&& m_buffer[m_pos+6] == '_'))
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string idents[3] = { "INCBIN_U8", "INCBIN_U16", "INCBIN_U32" };
|
||||
@@ -272,6 +274,86 @@ void CFile::CheckIncbin()
|
||||
|
||||
}
|
||||
|
||||
void CFile::CheckIncgfx()
|
||||
{
|
||||
// Optimization: assume most lines are not incgfxs
|
||||
if (!(m_buffer[m_pos+0] == 'I'
|
||||
&& m_buffer[m_pos+1] == 'N'
|
||||
&& m_buffer[m_pos+2] == 'C'
|
||||
&& m_buffer[m_pos+3] == 'G'
|
||||
&& m_buffer[m_pos+4] == 'F'
|
||||
&& m_buffer[m_pos+5] == 'X'
|
||||
&& m_buffer[m_pos+6] == '_'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string idents[3] = { "INCGFX_U8", "INCGFX_U16", "INCGFX_U32" };
|
||||
int incgfxType = -1;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (CheckIdentifier(idents[i]))
|
||||
{
|
||||
incgfxType = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (incgfxType == -1)
|
||||
return;
|
||||
|
||||
long oldPos = m_pos;
|
||||
long oldLineNum = m_lineNum;
|
||||
|
||||
m_pos += idents[incgfxType].length();
|
||||
|
||||
SkipWhitespace();
|
||||
if (m_buffer[m_pos] != '(')
|
||||
{
|
||||
m_pos = oldPos;
|
||||
m_lineNum = oldLineNum;
|
||||
return;
|
||||
}
|
||||
m_pos++;
|
||||
|
||||
SkipWhitespace();
|
||||
std::string path = ReadPath();
|
||||
|
||||
SkipWhitespace();
|
||||
if (m_buffer[m_pos] != ',')
|
||||
FATAL_INPUT_ERROR("expected ','");
|
||||
m_pos++;
|
||||
|
||||
SkipWhitespace();
|
||||
std::string extensions = ReadString();
|
||||
|
||||
SkipWhitespace();
|
||||
std::string arguments;
|
||||
if (m_buffer[m_pos] == ',')
|
||||
{
|
||||
m_pos++;
|
||||
SkipWhitespace();
|
||||
arguments = ReadString();
|
||||
|
||||
SkipWhitespace();
|
||||
if (m_buffer[m_pos] != ')')
|
||||
FATAL_INPUT_ERROR("expected ')'");
|
||||
m_pos++;
|
||||
}
|
||||
else if (m_buffer[m_pos] == ')')
|
||||
{
|
||||
m_pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_INPUT_ERROR("expected ')' or ','");
|
||||
}
|
||||
|
||||
Incgfx incgfx = { path, extensions, arguments };
|
||||
m_incgfxs.emplace(incgfx);
|
||||
}
|
||||
|
||||
std::string CFile::ReadPath()
|
||||
{
|
||||
if (m_buffer[m_pos] != '"')
|
||||
@@ -285,7 +367,7 @@ std::string CFile::ReadPath()
|
||||
|
||||
m_pos++;
|
||||
|
||||
int startPos = m_pos;
|
||||
long startPos = m_pos;
|
||||
|
||||
while (m_buffer[m_pos] != '"')
|
||||
{
|
||||
@@ -310,3 +392,34 @@ std::string CFile::ReadPath()
|
||||
|
||||
return std::string(m_buffer + startPos, m_pos - 1 - startPos);
|
||||
}
|
||||
|
||||
std::string CFile::ReadString()
|
||||
{
|
||||
if (m_buffer[m_pos] != '"')
|
||||
FATAL_INPUT_ERROR("expected '\"', got: '%c'", m_buffer[m_pos]);
|
||||
m_pos++;
|
||||
|
||||
long startPos = m_pos;
|
||||
|
||||
while (m_buffer[m_pos] != '"')
|
||||
{
|
||||
if (m_buffer[m_pos] == 0)
|
||||
{
|
||||
if (m_pos >= m_size)
|
||||
FATAL_INPUT_ERROR("expected EOF in string");
|
||||
else
|
||||
FATAL_INPUT_ERROR("unexpected null character in string");
|
||||
}
|
||||
|
||||
if (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n')
|
||||
FATAL_INPUT_ERROR("unexpected end of line character in string");
|
||||
|
||||
if (m_buffer[m_pos] == '\\')
|
||||
FATAL_INPUT_ERROR("unexpected escape in string");
|
||||
|
||||
m_pos++;
|
||||
}
|
||||
m_pos++;
|
||||
|
||||
return std::string(m_buffer + startPos, m_pos - 1 - startPos);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
#ifndef C_FILE_H
|
||||
#define C_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "scaninc.h"
|
||||
|
||||
class CFile
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
~CFile();
|
||||
void FindIncbins();
|
||||
const std::set<std::string>& GetIncbins() { return m_incbins; }
|
||||
const std::set<Incgfx>& GetIncgfxs() { return m_incgfxs; }
|
||||
const std::set<std::string>& GetIncludes() { return m_includes; }
|
||||
|
||||
private:
|
||||
@@ -42,6 +44,7 @@ private:
|
||||
int m_lineNum;
|
||||
std::string m_path;
|
||||
std::set<std::string> m_incbins;
|
||||
std::set<Incgfx> m_incgfxs;
|
||||
std::set<std::string> m_includes;
|
||||
|
||||
bool ConsumeHorizontalWhitespace();
|
||||
@@ -51,7 +54,9 @@ private:
|
||||
bool CheckIdentifier(const std::string& ident);
|
||||
void CheckInclude();
|
||||
void CheckIncbin();
|
||||
void CheckIncgfx();
|
||||
std::string ReadPath();
|
||||
std::string ReadString();
|
||||
};
|
||||
|
||||
#endif // C_FILE_H
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -41,18 +43,20 @@ bool CanOpenFile(std::string path)
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] [-M DEPENDENCY_OUT_PATH] FILE_PATH\n";
|
||||
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] [-M DEPENDENCY_OUT_PATH] [-g PATH] FILE_PATH\n";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::queue<std::string> filesToProcess;
|
||||
std::set<std::string> dependencies;
|
||||
std::set<std::string> dependencies_includes;
|
||||
std::map<std::string, std::pair<std::string, std::string>> dependencies_gfx_rules;
|
||||
|
||||
std::vector<std::string> includeDirs;
|
||||
|
||||
bool makeformat = false;
|
||||
std::string make_outfile;
|
||||
std::string gfx_root;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
@@ -82,6 +86,12 @@ int main(int argc, char **argv)
|
||||
argv++;
|
||||
make_outfile = std::string(argv[0]);
|
||||
}
|
||||
else if (arg.substr(0, 2) == "-g")
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
gfx_root = std::string(argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_ERROR(USAGE);
|
||||
@@ -94,6 +104,11 @@ int main(int argc, char **argv)
|
||||
FATAL_ERROR(USAGE);
|
||||
}
|
||||
|
||||
size_t ext_pos = make_outfile.find_last_of(".");
|
||||
auto object_file = make_outfile.substr(0, ext_pos + 1) + "o";
|
||||
if (gfx_root.empty()) gfx_root = "./";
|
||||
if (gfx_root[gfx_root.length() - 1] != '/') gfx_root.push_back('/');
|
||||
|
||||
std::string initialPath(argv[0]);
|
||||
|
||||
filesToProcess.push(initialPath);
|
||||
@@ -109,6 +124,34 @@ int main(int argc, char **argv)
|
||||
{
|
||||
dependencies.insert(incbin);
|
||||
}
|
||||
for (auto incgfx : file.GetIncgfxs())
|
||||
{
|
||||
// WARNING: This must stay in-sync with 'tools/preproc/c_file.cpp'.
|
||||
std::string arguments_as_path;
|
||||
for (auto c : incgfx.arguments)
|
||||
{
|
||||
if (std::isalnum(c))
|
||||
arguments_as_path += c;
|
||||
else
|
||||
arguments_as_path += '_';
|
||||
}
|
||||
|
||||
// WARNING: This must stay in-sync with 'tools/preproc/c_file.cpp'.
|
||||
auto target = gfx_root + incgfx.source + arguments_as_path + incgfx.extensions;
|
||||
size_t target_slash_pos = target.find_last_of('/');
|
||||
auto mk_target_basedir = target_slash_pos == std::string::npos
|
||||
? ""
|
||||
: "\t@mkdir -p '" + target.substr(0, target_slash_pos) + "'\n";
|
||||
auto rule = mk_target_basedir + "\t$(GFX) $< $@ " + incgfx.arguments + "\n";
|
||||
|
||||
dependencies.insert(target);
|
||||
|
||||
// If "foo.4bpp.lz" we want a rule for "foo.4bpp", the ".lz"
|
||||
// doesn't require any arguments.
|
||||
size_t dot_pos = incgfx.extensions.find_first_of('.', 1);
|
||||
auto firstTarget = gfx_root + incgfx.source + arguments_as_path + incgfx.extensions.substr(0, dot_pos);
|
||||
dependencies_gfx_rules[firstTarget] = std::make_pair(incgfx.source, rule);
|
||||
}
|
||||
for (auto include : file.GetIncludes())
|
||||
{
|
||||
bool exists = false;
|
||||
@@ -141,7 +184,7 @@ int main(int argc, char **argv)
|
||||
includeDirs.pop_back();
|
||||
}
|
||||
|
||||
if(!makeformat)
|
||||
if (!makeformat)
|
||||
{
|
||||
for (const std::string &path : dependencies)
|
||||
{
|
||||
@@ -155,8 +198,6 @@ int main(int argc, char **argv)
|
||||
std::ofstream output(make_outfile);
|
||||
|
||||
// Print a make rule for the object file
|
||||
size_t ext_pos = make_outfile.find_last_of(".");
|
||||
auto object_file = make_outfile.substr(0, ext_pos + 1) + "o";
|
||||
output << object_file.c_str() << ":";
|
||||
for (const std::string &path : dependencies)
|
||||
{
|
||||
@@ -180,6 +221,27 @@ int main(int argc, char **argv)
|
||||
output << path << ":\n";
|
||||
}
|
||||
|
||||
// Graphics rules
|
||||
// GNU make will issue a warning if there is more than one
|
||||
// recipe for a target. This would occur whenever a target is
|
||||
// 'INCGFX'ed multiple times, which is something that happens a
|
||||
// few times in vanilla. As a workaround, we maintain a variable
|
||||
// with all the 'INCGFX' targets and only emit the recipe if
|
||||
// the target is not in that variable. This is safe, because
|
||||
// targets with the same name necessarily have the same recipe.
|
||||
output
|
||||
<< "ifndef _INCGFX\n"
|
||||
<< "_INCGFX :=\n"
|
||||
<< "endif\n";
|
||||
for (auto gfx_rule : dependencies_gfx_rules)
|
||||
{
|
||||
output
|
||||
<< "ifeq (,$(findstring " << gfx_rule.first << ",$(_INCGFX)))\n"
|
||||
<< "_INCGFX += " << gfx_rule.first << "\n"
|
||||
<< gfx_rule.first << ": " << gfx_rule.second.first << "\n" << gfx_rule.second.second
|
||||
<< "endif\n";
|
||||
}
|
||||
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
|
||||
@@ -56,4 +56,18 @@ do { \
|
||||
|
||||
#define SCANINC_MAX_PATH 255
|
||||
|
||||
struct Incgfx
|
||||
{
|
||||
std::string source;
|
||||
std::string extensions;
|
||||
std::string arguments;
|
||||
|
||||
bool operator<(const struct Incgfx &rhs) const
|
||||
{
|
||||
return source < rhs.source
|
||||
|| extensions < rhs.extensions
|
||||
|| arguments < rhs.arguments;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SCANINC_H
|
||||
|
||||
@@ -72,6 +72,7 @@ SourceFile::SourceFile(std::string path)
|
||||
{
|
||||
AsmFile file(path);
|
||||
std::set<std::string> incbins;
|
||||
std::set<Incgfx> incgfxs;
|
||||
std::set<std::string> includes;
|
||||
|
||||
IncDirectiveType incDirectiveType;
|
||||
@@ -85,7 +86,7 @@ SourceFile::SourceFile(std::string path)
|
||||
incbins.insert(outputPath);
|
||||
}
|
||||
|
||||
new (&m_source_file.asm_wrapper) SourceFile::InnerUnion::AsmWrapper{incbins, includes};
|
||||
new (&m_source_file.asm_wrapper) SourceFile::InnerUnion::AsmWrapper{incbins, incgfxs, includes};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +104,7 @@ SourceFile::~SourceFile()
|
||||
else
|
||||
{
|
||||
m_source_file.asm_wrapper.asm_incbins.~set();
|
||||
m_source_file.asm_wrapper.asm_incgfxs.~set();
|
||||
m_source_file.asm_wrapper.asm_includes.~set();
|
||||
}
|
||||
}
|
||||
@@ -115,6 +117,14 @@ const std::set<std::string>& SourceFile::GetIncbins()
|
||||
return m_source_file.asm_wrapper.asm_incbins;
|
||||
}
|
||||
|
||||
const std::set<Incgfx>& SourceFile::GetIncgfxs()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
return m_source_file.c_file.GetIncgfxs();
|
||||
else
|
||||
return m_source_file.asm_wrapper.asm_incgfxs;
|
||||
}
|
||||
|
||||
const std::set<std::string>& SourceFile::GetIncludes()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
|
||||
@@ -46,8 +46,8 @@ public:
|
||||
SourceFile(SourceFile&&) = delete;
|
||||
SourceFile& operator =(SourceFile const&) = delete;
|
||||
SourceFile& operator =(SourceFile&&) = delete;
|
||||
bool HasIncbins();
|
||||
const std::set<std::string>& GetIncbins();
|
||||
const std::set<Incgfx>& GetIncgfxs();
|
||||
const std::set<std::string>& GetIncludes();
|
||||
std::string& GetSrcDir();
|
||||
SourceFileType FileType();
|
||||
@@ -57,6 +57,7 @@ private:
|
||||
CFile c_file;
|
||||
struct AsmWrapper {
|
||||
std::set<std::string> asm_incbins;
|
||||
std::set<Incgfx> asm_incgfxs;
|
||||
std::set<std::string> asm_includes;
|
||||
} asm_wrapper;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user