224 lines
7.1 KiB
C++
Executable File
224 lines
7.1 KiB
C++
Executable File
#include "Makefile.h"
|
|
|
|
#include <fstream>
|
|
#include <map>
|
|
|
|
#include "Common.h"
|
|
#include "IncludeDeps.h"
|
|
#include "Utils.h"
|
|
|
|
void Makefile::Save(ConfigFile& conf, unsigned int flags)
|
|
{
|
|
std::set<HFile> hFiles; // hFile, directory
|
|
std::set<std::string> cppFiles;
|
|
if (flags & FLAG_SIMPLE)
|
|
Utils::GetCppFiles(conf, cppFiles);
|
|
else
|
|
Utils::GetCppAndHFiles(conf, hFiles, cppFiles);
|
|
|
|
std::ofstream outputFile(conf.GetConfigPath() / "Makefile");
|
|
outputFile << "# This Makefile was generated using MakeGen " << MAKEGEN_VERSION << " made by Tim Håkansson"
|
|
<< std::endl;
|
|
outputFile << "# and is licensed under MIT. Full source of the project can be found at" << std::endl;
|
|
outputFile << "# https://gitea.timha.se/Thraix/MakeGen" << std::endl;
|
|
outputFile << "CC=@g++" << std::endl;
|
|
std::string outputtype = conf.GetOutputType();
|
|
if (outputtype != "executable")
|
|
{
|
|
if (outputtype == "sharedlibrary")
|
|
outputFile << "CO=@g++ -shared -o" << std::endl;
|
|
else
|
|
outputFile << "CO=@g++ -o" << std::endl;
|
|
}
|
|
else
|
|
outputFile << "CO=@g++ -o" << std::endl;
|
|
|
|
outputFile << "MKDIR_P=mkdir -p" << std::endl;
|
|
outputFile << "BIN=" << conf.GetOutputDir() << std::endl;
|
|
outputFile << "OBJPATH=$(BIN)intermediates" << std::endl;
|
|
outputFile << "INCLUDES=";
|
|
const std::vector<std::string>& includeDirs = conf.GetIncludeDirs();
|
|
for (const auto& includeDir : includeDirs)
|
|
{
|
|
outputFile << "-I " << includeDir << " ";
|
|
}
|
|
|
|
const std::vector<std::string>& includeDirExclDeps = conf.GetIncludeDirExclDeps();
|
|
for (const auto& includeDirExclDep : includeDirExclDeps)
|
|
{
|
|
outputFile << "-I " << includeDirExclDeps << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
outputFile << "OBJECTS=";
|
|
for (auto it = cppFiles.begin(); it != cppFiles.end(); ++it)
|
|
{
|
|
std::filesystem::path cppFile(*it);
|
|
std::filesystem::path oFile = cppFile.replace_extension("o");
|
|
std::string oFileStr = oFile.string();
|
|
Utils::Replace(oFileStr, "..", "dotdot");
|
|
outputFile << "$(OBJPATH)/" << oFileStr << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
if (outputtype == "executable" || outputtype != "sharedlibrary")
|
|
{
|
|
outputFile << "CFLAGS=$(INCLUDES) -std=c++17 -c ";
|
|
}
|
|
else
|
|
{
|
|
outputFile << "CFLAGS=$(INCLUDES) -fPIC -std=c++17 -c ";
|
|
}
|
|
const std::vector<std::string>& defines = conf.GetDefines();
|
|
for (const auto& define : defines)
|
|
{
|
|
outputFile << "-D" << define << " ";
|
|
}
|
|
const std::vector<std::string>& cFlags = conf.GetCFlags();
|
|
for (const auto& cFlag : cFlags)
|
|
{
|
|
outputFile << cFlag << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
if (outputtype == "executable")
|
|
{
|
|
const std::vector<std::string>& libraryDirs = conf.GetLibraryDirs();
|
|
outputFile << "LIBDIR=";
|
|
for (const auto& libraryDir : libraryDirs)
|
|
{
|
|
outputFile << "-L " << libraryDir << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
const std::vector<std::string>& lFlags = conf.GetLFlags();
|
|
outputFile << "LDFLAGS=";
|
|
for (const auto& lFlag : lFlags)
|
|
{
|
|
outputFile << lFlag << " ";
|
|
}
|
|
for (const auto& libraryDir : libraryDirs)
|
|
{
|
|
outputFile << "-Wl,-rpath=" << libraryDir << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
const std::vector<std::string>& libraries = conf.GetLibraries();
|
|
outputFile << "LIBS=$(LIBDIR) ";
|
|
for (const auto& library : libraries)
|
|
{
|
|
outputFile << "-l" << library << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
const std::vector<Dependency>& dependencies = conf.GetDependencies();
|
|
if (!dependencies.empty())
|
|
{
|
|
outputFile << "DEPENDENCIES=";
|
|
for (const auto& [path, target] : dependencies)
|
|
{
|
|
outputFile << path << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
}
|
|
}
|
|
outputFile << "OUTPUT=$(BIN)" << conf.GetOutputName() << std::endl;
|
|
outputFile << ".PHONY: all directories rebuild clean run" << std::endl;
|
|
|
|
// All
|
|
outputFile << "all: directories $(OUTPUT)" << std::endl;
|
|
|
|
// Directories
|
|
std::set<std::string> intermediateDirectories = GetIntermediateDirectories(cppFiles);
|
|
outputFile << "directories: ";
|
|
for (const auto& intermediateDirectory : intermediateDirectories)
|
|
{
|
|
outputFile << intermediateDirectory << " ";
|
|
}
|
|
outputFile << std::endl;
|
|
|
|
// Intermediate directories
|
|
for (const auto& intermediateDirectory : intermediateDirectories)
|
|
{
|
|
outputFile << intermediateDirectory << ":" << std::endl;
|
|
outputFile << "\t@$(MKDIR_P) $@" << std::endl;
|
|
}
|
|
|
|
// Run
|
|
outputFile << "run: all" << std::endl;
|
|
if (outputtype == "executable")
|
|
{
|
|
const std::vector<std::string>& prearguments = conf.GetPreArguments();
|
|
const std::vector<std::string>& arguments = conf.GetArguments();
|
|
|
|
outputFile << "\t@";
|
|
for (const auto& preargument : prearguments)
|
|
{
|
|
outputFile << preargument << " ";
|
|
}
|
|
outputFile << "./$(OUTPUT)";
|
|
for (const auto& argument : arguments)
|
|
{
|
|
outputFile << " " << argument;
|
|
}
|
|
outputFile << std::endl;
|
|
}
|
|
|
|
// Rebuild
|
|
outputFile << "rebuild: clean all" << std::endl;
|
|
|
|
// Clean
|
|
outputFile << "clean:" << std::endl;
|
|
outputFile << "\t$(info Removing $(OBJPATH) and $(OUTPUT))" << std::endl;
|
|
outputFile << "\t@rm -rf $(OBJPATH)/ $(OUTPUT)" << std::endl;
|
|
|
|
// Output file
|
|
outputFile << "$(OUTPUT): $(OBJECTS)" << std::endl;
|
|
outputFile << "\t$(info Generating output file $(OUTPUT))" << std::endl;
|
|
if (outputtype == "executable")
|
|
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS)" << std::endl;
|
|
else
|
|
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS)" << std::endl;
|
|
|
|
// Install
|
|
outputFile << "install: all" << std::endl;
|
|
outputFile << "\t$(info Installing " << conf.GetProjectName() << " to /usr/bin/)" << std::endl;
|
|
outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.GetOutputName() << std::endl;
|
|
|
|
std::map<std::string, IncludeDeps*> dependencies;
|
|
size_t i = 0;
|
|
for (auto it = cppFiles.begin(); it != cppFiles.end(); ++it)
|
|
{
|
|
i++;
|
|
auto itD = dependencies.find(*it);
|
|
if (itD == dependencies.end())
|
|
{
|
|
std::filesystem::path cppFile(*it);
|
|
std::filesystem::path oFile = cppFile.replace_extension("o");
|
|
std::string oFileStr = oFile.string();
|
|
Utils::Replace(oFileStr, "..", "dotdot");
|
|
outputFile << "$(OBJPATH)/" << oFileStr << ":";
|
|
if (flags & FLAG_SIMPLE)
|
|
{
|
|
outputFile << " " << *it;
|
|
}
|
|
else
|
|
{
|
|
IncludeDeps* deps = new IncludeDeps(*it, hFiles, dependencies);
|
|
deps->Output(outputFile, conf);
|
|
}
|
|
outputFile << std::endl;
|
|
outputFile << "\t$(info -[" << (int)(i / (float)cppFiles.size() * 100) << "%]- $<)" << std::endl;
|
|
outputFile << "\t$(CC) $(CFLAGS) -o $@ $<" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::set<std::string> Makefile::GetIntermediateDirectories(const std::set<std::string>& cppFiles)
|
|
{
|
|
std::set<std::string> intermediateDirectories;
|
|
for (const auto& cppFile : cppFiles)
|
|
{
|
|
std::filesystem::path cppPath{cppFile};
|
|
std::filesystem::path oFile = cppPath.replace_extension("o");
|
|
std::string parentPathStr = oFile.parent_path().string();
|
|
Utils::Replace(parentPathStr, "..", "dotdot");
|
|
intermediateDirectories.emplace("$(OBJPATH)/" + parentPathStr);
|
|
}
|
|
return intermediateDirectories;
|
|
}
|