Overhaul scaninc to work recursively

This also fixes the bug where scaninc would ignore #include lines
in assembly files.
This commit is contained in:
Phlosioneer 2019-03-03 21:59:57 -05:00 committed by huderlem
parent 0081474018
commit 105e1721d6
10 changed files with 238 additions and 71 deletions

View File

@ -168,7 +168,7 @@ $(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s $$(asm_dep)
ifeq ($(NODEP),1) ifeq ($(NODEP),1)
$(DATA_ASM_BUILDDIR)/%.o: data_dep := $(DATA_ASM_BUILDDIR)/%.o: data_dep :=
else else
$(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) $(DATA_ASM_SUBDIR)/$*.s) $(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) -I include $(DATA_ASM_SUBDIR)/$*.s)
endif endif
$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep) $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep)

View File

@ -1,6 +1,6 @@
#include <string.h>
#include "global.h" #include "global.h"
#include "menu.h" #include "menu.h"
#include "string.h"
#include "string_util.h" #include "string_util.h"
#include "task.h" #include "task.h"
#include "text.h" #include "text.h"

View File

@ -1,3 +1,4 @@
#include <string.h>
#include "global.h" #include "global.h"
#include "item_menu.h" #include "item_menu.h"
#include "battle.h" #include "battle.h"
@ -40,7 +41,6 @@
#include "shop.h" #include "shop.h"
#include "sound.h" #include "sound.h"
#include "sprite.h" #include "sprite.h"
#include "string.h"
#include "strings.h" #include "strings.h"
#include "string_util.h" #include "string_util.h"
#include "task.h" #include "task.h"

View File

@ -1,3 +1,4 @@
#include <string.h>
#include "global.h" #include "global.h"
#include "trainer_pokemon_sprites.h" #include "trainer_pokemon_sprites.h"
#include "bg.h" #include "bg.h"
@ -30,7 +31,6 @@
#include "scanline_effect.h" #include "scanline_effect.h"
#include "sound.h" #include "sound.h"
#include "sprite.h" #include "sprite.h"
#include "string.h"
#include "strings.h" #include "strings.h"
#include "string_util.h" #include "string_util.h"
#include "task.h" #include "task.h"

View File

@ -2,9 +2,9 @@ CXX = g++
CXXFLAGS = -Wall -Werror -std=c++11 -O2 CXXFLAGS = -Wall -Werror -std=c++11 -O2
SRCS = scaninc.cpp c_file.cpp asm_file.cpp SRCS = scaninc.cpp c_file.cpp asm_file.cpp source_file.cpp
HEADERS := scaninc.h asm_file.h c_file.h HEADERS := scaninc.h asm_file.h c_file.h source_file.h
.PHONY: clean .PHONY: clean

View File

@ -64,7 +64,8 @@ IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
IncDirectiveType incDirectiveType = IncDirectiveType::None; IncDirectiveType incDirectiveType = IncDirectiveType::None;
if (PeekChar() == '.') char c = PeekChar();
if (c == '.' || c == '#')
{ {
m_pos++; m_pos++;

View File

@ -25,8 +25,7 @@
#include <set> #include <set>
#include <string> #include <string>
#include "scaninc.h" #include "scaninc.h"
#include "asm_file.h" #include "source_file.h"
#include "c_file.h"
bool CanOpenFile(std::string path) bool CanOpenFile(std::string path)
{ {
@ -46,7 +45,7 @@ int main(int argc, char **argv)
std::queue<std::string> filesToProcess; std::queue<std::string> filesToProcess;
std::set<std::string> dependencies; std::set<std::string> dependencies;
std::list<std::string> includeDirs; std::vector<std::string> includeDirs;
argc--; argc--;
argv++; argv++;
@ -83,79 +82,50 @@ int main(int argc, char **argv)
std::string initialPath(argv[0]); std::string initialPath(argv[0]);
std::size_t pos = initialPath.find_last_of('.'); filesToProcess.push(initialPath);
if (pos == std::string::npos) while (!filesToProcess.empty())
FATAL_ERROR("no file extension in path \"%s\"\n", initialPath.c_str());
std::string extension = initialPath.substr(pos + 1);
std::string srcDir("");
std::size_t slash = initialPath.rfind('/');
if (slash != std::string::npos)
{ {
srcDir = initialPath.substr(0, slash + 1); std::string filePath = filesToProcess.front();
} SourceFile file(filePath);
includeDirs.push_back(srcDir); filesToProcess.pop();
if (extension == "c" || extension == "h") includeDirs.push_back(file.GetSrcDir());
{ for (auto incbin : file.GetIncbins())
filesToProcess.push(initialPath);
while (!filesToProcess.empty())
{ {
CFile file(filesToProcess.front()); dependencies.insert(incbin);
filesToProcess.pop(); }
for (auto include : file.GetIncludes())
file.FindIncbins(); {
for (auto incbin : file.GetIncbins()) bool found = false;
for (auto includeDir : includeDirs)
{ {
dependencies.insert(incbin); std::string path(includeDir + include);
} if (CanOpenFile(path))
for (auto include : file.GetIncludes())
{
for (auto includeDir : includeDirs)
{ {
std::string path(includeDir + include); bool inserted = dependencies.insert(path).second;
if (CanOpenFile(path)) if (inserted)
{ {
bool inserted = dependencies.insert(path).second; filesToProcess.push(path);
if (inserted)
{
filesToProcess.push(path);
}
break;
} }
found = true;
break;
} }
} }
} if (!found)
}
else if (extension == "s" || extension == "inc")
{
filesToProcess.push(initialPath);
while (!filesToProcess.empty())
{
AsmFile file(filesToProcess.front());
filesToProcess.pop();
IncDirectiveType incDirectiveType;
std::string path;
while ((incDirectiveType = file.ReadUntilIncDirective(path)) != IncDirectiveType::None)
{ {
bool inserted = dependencies.insert(path).second; if (GetFileType(include) == SourceFileType::Header)
if (inserted // We don't have any generated .h files... yet.
&& incDirectiveType == IncDirectiveType::Include // Better to give a warning; debugging the makefile when a
&& CanOpenFile(path)) // header is missing is very difficult.
filesToProcess.push(path); fprintf(stderr, "scaninc: warning: C header file \"%s\" not found. (included from \"%s\")\n",
include.c_str(), filePath.c_str());
// It's probably a generated file.
dependencies.insert(include);
} }
} }
} includeDirs.pop_back();
else
{
FATAL_ERROR("unknown extension \"%s\"\n", extension.c_str());
} }
for (const std::string &path : dependencies) for (const std::string &path : dependencies)

View File

@ -1,4 +1,4 @@
// Copyright(c) 2015-2017 YamaArashi // Copyright(c) 2019 Phlosioneer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal

View File

@ -0,0 +1,125 @@
// Copyright(c) 2019 Phlosioneer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <new>
#include "source_file.h"
SourceFileType GetFileType(std::string& path)
{
std::size_t pos = path.find_last_of('.');
if (pos == std::string::npos)
FATAL_ERROR("no file extension in path \"%s\"\n", path.c_str());
std::string extension = path.substr(pos + 1);
if (extension == "c")
return SourceFileType::Cpp;
else if (extension == "s")
return SourceFileType::Asm;
else if (extension == "h")
return SourceFileType::Header;
else if (extension == "inc")
return SourceFileType::Inc;
else
FATAL_ERROR("Unrecognized extension \"%s\"\n", extension.c_str());
// Unreachable
return SourceFileType::Cpp;
}
std::string GetDir(std::string& path)
{
std::size_t slash = path.rfind('/');
if (slash != std::string::npos)
return path.substr(0, slash + 1);
else
return std::string("");
}
SourceFile::SourceFile(std::string path)
{
m_file_type = GetFileType(path);
m_src_dir = GetDir(path);
if (m_file_type == SourceFileType::Cpp
|| m_file_type == SourceFileType::Header)
{
new (&m_source_file.c_file) CFile(path);
m_source_file.c_file.FindIncbins();
}
else
{
AsmFile file(path);
std::set<std::string> incbins;
std::set<std::string> includes;
IncDirectiveType incDirectiveType;
std::string outputPath;
while ((incDirectiveType = file.ReadUntilIncDirective(outputPath)) != IncDirectiveType::None)
{
if (incDirectiveType == IncDirectiveType::Include)
includes.insert(outputPath);
else
incbins.insert(outputPath);
}
new (&m_source_file.asm_wrapper) SourceFile::InnerUnion::AsmWrapper{incbins, includes};
}
}
SourceFile::~SourceFile()
{
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
{
m_source_file.c_file.~CFile();
}
else
{
m_source_file.asm_wrapper.asm_incbins.~set();
m_source_file.asm_wrapper.asm_includes.~set();
}
}
const std::set<std::string>& SourceFile::GetIncbins()
{
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
return m_source_file.c_file.GetIncbins();
else
return m_source_file.asm_wrapper.asm_incbins;
}
const std::set<std::string>& SourceFile::GetIncludes()
{
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
return m_source_file.c_file.GetIncludes();
else
return m_source_file.asm_wrapper.asm_includes;
}
std::string& SourceFile::GetSrcDir()
{
return m_src_dir;
}

View File

@ -0,0 +1,71 @@
// Copyright(c) 2015-2017 YamaArashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef SOURCE_FILE_H
#define SOURCE_FILE_H
#include <string>
#include "scaninc.h"
#include "asm_file.h"
#include "c_file.h"
enum class SourceFileType
{
Cpp,
Header,
Asm,
Inc
};
SourceFileType GetFileType(std::string& path);
class SourceFile
{
public:
SourceFile(std::string path);
~SourceFile();
SourceFile(SourceFile const&) = delete;
SourceFile(SourceFile&&) = delete;
SourceFile& operator =(SourceFile const&) = delete;
SourceFile& operator =(SourceFile&&) = delete;
bool HasIncbins();
const std::set<std::string>& GetIncbins();
const std::set<std::string>& GetIncludes();
std::string& GetSrcDir();
private:
union InnerUnion {
CFile c_file;
struct AsmWrapper {
std::set<std::string> asm_incbins;
std::set<std::string> asm_includes;
} asm_wrapper;
// Construction and destruction handled by SourceFile.
InnerUnion() {};
~InnerUnion() {};
} m_source_file;
SourceFileType m_file_type;
std::string m_src_dir;
};
#endif // SOURCE_FILE_H