Add possibility to build different targets in the same project for e.g. IPaks

This commit is contained in:
Jan 2023-10-21 14:11:20 +02:00
parent 2c09cc11e9
commit 0b4a0ac070
3 changed files with 76 additions and 33 deletions

View File

@ -168,7 +168,7 @@ class LinkerImpl final : public Linker
return true;
}
static bool GetNameFromZoneDefinition(std::string& name, const std::string& projectName, const ZoneDefinition& zoneDefinition)
static bool GetNameFromZoneDefinition(std::string& name, const std::string& targetName, const ZoneDefinition& zoneDefinition)
{
auto firstNameEntry = true;
const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata_lookup.equal_range(METADATA_NAME);
@ -183,27 +183,27 @@ class LinkerImpl final : public Linker
{
if (name != i->second->m_value)
{
std::cout << "Conflicting names in project \"" << projectName << "\": " << name << " != " << i->second << std::endl;
std::cout << "Conflicting names in target \"" << targetName << "\": " << name << " != " << i->second << std::endl;
return false;
}
}
}
if (firstNameEntry)
name = projectName;
name = targetName;
return true;
}
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(const std::string& projectName, ISearchPath* sourceSearchPath) const
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(const std::string& targetName, ISearchPath* sourceSearchPath) const
{
std::unique_ptr<ZoneDefinition> zoneDefinition;
{
const auto definitionFileName = projectName + ".zone";
const auto definitionFileName = targetName + ".zone";
const auto definitionStream = sourceSearchPath->Open(definitionFileName);
if (!definitionStream.IsOpen())
{
std::cout << "Could not find zone definition file for project \"" << projectName << "\"." << std::endl;
std::cout << "Could not find zone definition file for target \"" << targetName << "\"." << std::endl;
return nullptr;
}
@ -213,14 +213,14 @@ class LinkerImpl final : public Linker
if (!zoneDefinition)
{
std::cout << "Failed to read zone definition file for project \"" << projectName << "\"." << std::endl;
std::cout << "Failed to read zone definition file for target \"" << targetName << "\"." << std::endl;
return nullptr;
}
if (!GetNameFromZoneDefinition(zoneDefinition->m_name, projectName, *zoneDefinition))
if (!GetNameFromZoneDefinition(zoneDefinition->m_name, targetName, *zoneDefinition))
return nullptr;
if (!IncludeAdditionalZoneDefinitions(projectName, *zoneDefinition, sourceSearchPath))
if (!IncludeAdditionalZoneDefinitions(targetName, *zoneDefinition, sourceSearchPath))
return nullptr;
if (!IncludeAssetLists(*zoneDefinition, sourceSearchPath))
@ -229,7 +229,7 @@ class LinkerImpl final : public Linker
return zoneDefinition;
}
bool ProcessZoneDefinitionIgnores(const std::string& projectName, ZoneCreationContext& context, ISearchPath* sourceSearchPath) const
bool ProcessZoneDefinitionIgnores(const std::string& targetName, ZoneCreationContext& context, ISearchPath* sourceSearchPath) const
{
if (context.m_definition->m_ignores.empty())
return true;
@ -242,7 +242,7 @@ class LinkerImpl final : public Linker
for (const auto& ignore : context.m_definition->m_ignores)
{
if (ignore == projectName)
if (ignore == targetName)
continue;
std::vector<AssetListEntry> assetList;
@ -269,7 +269,7 @@ class LinkerImpl final : public Linker
return false;
}
static bool GetProjectTypeFromZoneDefinition(ProjectType& projectType, const std::string& projectName, const ZoneDefinition& zoneDefinition)
static bool GetProjectTypeFromZoneDefinition(ProjectType& projectType, const std::string& targetName, const ZoneDefinition& zoneDefinition)
{
auto firstGameEntry = true;
const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata_lookup.equal_range(METADATA_TYPE);
@ -291,7 +291,7 @@ class LinkerImpl final : public Linker
{
if (projectType != parsedProjectType)
{
std::cerr << "Conflicting types in project \"" << projectName << "\": " << PROJECT_TYPE_NAMES[static_cast<unsigned>(projectType)]
std::cerr << "Conflicting types in target \"" << targetName << "\": " << PROJECT_TYPE_NAMES[static_cast<unsigned>(projectType)]
<< " != " << PROJECT_TYPE_NAMES[static_cast<unsigned>(parsedProjectType)] << std::endl;
return false;
}
@ -304,7 +304,7 @@ class LinkerImpl final : public Linker
return true;
}
static bool GetGameNameFromZoneDefinition(std::string& gameName, const std::string& projectName, const ZoneDefinition& zoneDefinition)
static bool GetGameNameFromZoneDefinition(std::string& gameName, const std::string& targetName, const ZoneDefinition& zoneDefinition)
{
auto firstGameEntry = true;
const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata_lookup.equal_range(METADATA_GAME);
@ -319,7 +319,7 @@ class LinkerImpl final : public Linker
{
if (gameName != i->second->m_value)
{
std::cout << "Conflicting game names in project \"" << projectName << "\": " << gameName << " != " << i->second << std::endl;
std::cout << "Conflicting game names in target \"" << targetName << "\": " << gameName << " != " << i->second << std::endl;
return false;
}
}
@ -327,7 +327,7 @@ class LinkerImpl final : public Linker
if (firstGameEntry)
{
std::cout << "No game name was specified for project \"" << projectName << "\"" << std::endl;
std::cout << "No game name was specified for target \"" << targetName << "\"" << std::endl;
return false;
}
@ -360,13 +360,13 @@ class LinkerImpl final : public Linker
return true;
}
std::unique_ptr<Zone> CreateZoneForDefinition(const std::string& projectName, ZoneDefinition& zoneDefinition, ISearchPath* assetSearchPath, ISearchPath* gdtSearchPath,
std::unique_ptr<Zone> CreateZoneForDefinition(const std::string& targetName, ZoneDefinition& zoneDefinition, ISearchPath* assetSearchPath, ISearchPath* gdtSearchPath,
ISearchPath* sourceSearchPath) const
{
const auto context = std::make_unique<ZoneCreationContext>(assetSearchPath, &zoneDefinition);
if (!ProcessZoneDefinitionIgnores(projectName, *context, sourceSearchPath))
if (!ProcessZoneDefinitionIgnores(targetName, *context, sourceSearchPath))
return nullptr;
if (!GetGameNameFromZoneDefinition(context->m_game_name, projectName, zoneDefinition))
if (!GetGameNameFromZoneDefinition(context->m_game_name, targetName, zoneDefinition))
return nullptr;
if (!LoadGdtFilesFromZoneDefinition(context->m_gdt_files, zoneDefinition, gdtSearchPath))
return nullptr;
@ -405,9 +405,10 @@ class LinkerImpl final : public Linker
return true;
}
bool BuildFastFile(const std::string& projectName, ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths, SearchPaths& gdtSearchPaths, SearchPaths& sourceSearchPaths) const
bool BuildFastFile(const std::string& projectName, const std::string& targetName, ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths, SearchPaths& gdtSearchPaths,
SearchPaths& sourceSearchPaths) const
{
const auto zone = CreateZoneForDefinition(projectName, zoneDefinition, &assetSearchPaths, &gdtSearchPaths, &sourceSearchPaths);
const auto zone = CreateZoneForDefinition(targetName, zoneDefinition, &assetSearchPaths, &gdtSearchPaths, &sourceSearchPaths);
auto result = zone != nullptr;
if (zone)
result = WriteZoneToFile(projectName, zone.get());
@ -415,7 +416,7 @@ class LinkerImpl final : public Linker
return result;
}
bool BuildIPak(const std::string& projectName, const ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths, SearchPaths& sourceSearchPaths) const
bool BuildIPak(const std::string& projectName, const ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths) const
{
const fs::path ipakFolderPath(m_args.GetOutputFolderPathForProject(projectName));
auto ipakFilePath(ipakFolderPath);
@ -450,20 +451,20 @@ class LinkerImpl final : public Linker
return true;
}
bool BuildProject(const std::string& projectName)
bool BuildProject(const std::string& projectName, const std::string& targetName)
{
auto sourceSearchPaths = m_search_paths.GetSourceSearchPathsForProject(projectName);
const auto zoneDefinition = ReadZoneDefinition(projectName, &sourceSearchPaths);
const auto zoneDefinition = ReadZoneDefinition(targetName, &sourceSearchPaths);
if (!zoneDefinition)
return false;
ProjectType projectType;
if (!GetProjectTypeFromZoneDefinition(projectType, projectName, *zoneDefinition))
if (!GetProjectTypeFromZoneDefinition(projectType, targetName, *zoneDefinition))
return false;
std::string gameName;
if (!GetGameNameFromZoneDefinition(gameName, projectName, *zoneDefinition))
if (!GetGameNameFromZoneDefinition(gameName, targetName, *zoneDefinition))
return false;
utils::MakeStringLowerCase(gameName);
@ -474,11 +475,11 @@ class LinkerImpl final : public Linker
switch (projectType)
{
case ProjectType::FASTFILE:
result = BuildFastFile(projectName, *zoneDefinition, assetSearchPaths, gdtSearchPaths, sourceSearchPaths);
result = BuildFastFile(projectName, targetName, *zoneDefinition, assetSearchPaths, gdtSearchPaths, sourceSearchPaths);
break;
case ProjectType::IPAK:
result = BuildIPak(projectName, *zoneDefinition, assetSearchPaths, sourceSearchPaths);
result = BuildIPak(projectName, *zoneDefinition, assetSearchPaths);
break;
default:
@ -536,6 +537,40 @@ class LinkerImpl final : public Linker
m_loaded_zones.clear();
}
static bool GetProjectAndTargetFromProjectSpecifier(const std::string& projectSpecifier, std::string& projectName, std::string& targetName)
{
const auto targetNameSeparatorIndex = projectSpecifier.find_first_of('/');
if (targetNameSeparatorIndex == std::string::npos)
{
projectName = projectSpecifier;
targetName = projectSpecifier;
}
else if (projectSpecifier.find_first_of('/', targetNameSeparatorIndex + 1) != std::string::npos)
{
std::cerr << "Project specifier cannot have more than one target name: \"" << projectSpecifier << "\"\n";
return false;
}
else
{
projectName = projectSpecifier.substr(0, targetNameSeparatorIndex);
targetName = projectSpecifier.substr(targetNameSeparatorIndex + 1);
}
if (projectName.empty())
{
std::cerr << "Project name cannot be empty: \"" << projectSpecifier << "\"\n";
return false;
}
if (targetName.empty())
{
std::cerr << "Target name cannot be empty: \"" << projectSpecifier << "\"\n";
return false;
}
return true;
}
public:
LinkerImpl()
: m_search_paths(m_args)
@ -554,9 +589,17 @@ public:
return false;
auto result = true;
for (const auto& projectName : m_args.m_projects_to_build)
for (const auto& projectSpecifier : m_args.m_project_specifiers_to_build)
{
if (!BuildProject(projectName))
std::string projectName;
std::string targetName;
if (!GetProjectAndTargetFromProjectSpecifier(projectSpecifier, projectName, targetName))
{
result = false;
break;
}
if (!BuildProject(projectName, targetName))
{
result = false;
break;

View File

@ -210,8 +210,8 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv)
return false;
}
m_projects_to_build = m_argument_parser.GetArguments();
if (m_projects_to_build.empty())
m_project_specifiers_to_build = m_argument_parser.GetArguments();
if (m_project_specifiers_to_build.empty())
{
// No projects to build specified...
PrintUsage();

View File

@ -41,7 +41,7 @@ private:
public:
std::vector<std::string> m_zones_to_load;
std::vector<std::string> m_projects_to_build;
std::vector<std::string> m_project_specifiers_to_build;
std::string m_base_folder;
std::string m_out_folder;