#include #include "../include/FileUtil.hpp" #include "../include/Conf.hpp" #include "../include/Dependency.hpp" #include "../backend/ninja/Ninja.hpp" #include #include using namespace std; using namespace sibs; // TODO: Fail if multiple versions of the same dependency is used // as linking will fail because of multiple definitions of the same thing // TODO: Detect recursive dependencies and give error. void usage() { printf("usage: sibs COMMAND\n\n"); printf("Simple Build System for Native Languages\n\n"); printf("Options:\n"); printf(" -p\t\tPath to project (directory that contains main project.conf file)\n"); printf(" -h\t\tPrint this help menu\n\n"); printf("Commands:\n"); printf(" build\t\tBuild a project that contains a project.conf file\n"); exit(1); } void validateDirectoryPath(const char *projectPath) { FileType projectPathFileType = getFileType(projectPath); if(projectPathFileType == FileType::FILE_NOT_FOUND) { perror(projectPath); exit(2); } else if(projectPathFileType == FileType::REGULAR) { printf("Expected project path (%s) to be a directory, was a file", projectPath); exit(3); } } void validateFilePath(const char *projectConfPath) { FileType projectConfFileType = getFileType(projectConfPath); if(projectConfFileType == FileType::FILE_NOT_FOUND) { perror(projectConfPath); exit(4); } else if(projectConfFileType == FileType::DIRECTORY) { printf("Expected project path (%s) to be a file, was a directory", projectConfPath); exit(5); } } const char *sourceFileExtensions[] = { "cc", "cpp", "cxx" }; bool isSourceFile(tinydir_file *file) { if(!file->is_reg) return false; for(const char *sourceFileExtension : sourceFileExtensions) { if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0) return true; } return false; } void build(string projectPath) { validateDirectoryPath(projectPath.c_str()); if(projectPath.back() != '/') projectPath += "/"; string projectConfFilePath = projectPath; projectConfFilePath += "/project.conf"; validateFilePath(projectConfFilePath.c_str()); SibsConfig sibsConfig; Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if(result.isErr()) { printf("Failed to read config: %s\n", result.getErrMsg().c_str()); exit(6); } if(sibsConfig.getPackageName().empty()) { printf("project.conf is missing required field package.name\n"); exit(10); } //string projectSrcPath = projectPath + "/src"; //validateDirectoryPath(projectSrcPath.c_str()); backend::Ninja ninja; walkDirFilesRecursive(projectPath.c_str(), [&ninja, &projectPath](tinydir_file *file) { if (isSourceFile(file)) { printf("Adding source file: %s\n", file->path + projectPath.size()); ninja.addSourceFile(file->path + projectPath.size()); } else { //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); } }); // TODO: Create build path if it doesn't exist string debugBuildPath = projectPath + "/build/debug"; Result buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), debugBuildPath.c_str()); if(buildFileResult.isErr()) { printf("Failed to build ninja file: %s\n", buildFileResult.getErrMsg().c_str()); exit(7); } Result buildResult = ninja.build(debugBuildPath.c_str()); if(buildResult.isErr()) { exit(8); } } int main(int argc, const char **argv) { string projectPath; string command; for(int i = 1; i < argc; ++i) { const char *arg = argv[i]; if(arg[0] == '-') { // Option if(strcmp(arg, "-p") == 0) { if(!projectPath.empty()) { printf("-p option defined twice, should only be defined once\n"); exit(1); } if(i < argc - 1) { projectPath = argv[i + 1]; ++i; } else { printf("Expected project path after option -p\n"); exit(1); } } else if(strcmp(arg, "-h") == 0) { usage(); } else { printf("Invalid option %s, type sibs -h to see valid options\n", arg); exit(1); } } else { if(!command.empty()) { printf("Found command twice. First as %s, then as %s\n", command.c_str(), arg); exit(1); } command = arg; } } if(projectPath.empty()) { Result projectPathResult = getCwd(); if(projectPathResult.isErr()) { printf("%s\n", projectPathResult.getErrMsg().c_str()); exit(11); } projectPath = projectPathResult.unwrap(); } if(command == "build") build(projectPath); else if(command.empty()) { printf("No command provided, type sibs -h to see valid commands\n"); exit(1); } else { printf("Invalid command %s, expected: build\n", command.c_str()); exit(1); } return 0; }