#include "../include/GlobalLib.hpp" #include "../include/FileUtil.hpp" #include "../backend/ninja/Ninja.hpp" #include "../include/Conf.hpp" #include "../include/curl.hpp" #include "../include/Archive.hpp" using namespace std; namespace sibs { Result GlobalLib::validatePackageExists(const string &globalLibRootDir, const string &name) { string packageDir = globalLibRootDir + "/"; packageDir += name; FileType packageDirFileType = getFileType(packageDir.c_str()); switch(packageDirFileType) { case FileType::FILE_NOT_FOUND: { string errMsg = "Global lib dependency not found: "; errMsg += name; return Result::Err(errMsg, DependencyError::DEPENDENCY_NOT_FOUND); } case FileType::REGULAR: { string errMsg = "Corrupt library directory. "; errMsg += packageDir; errMsg += " is a file, expected it to be a directory"; return Result::Err(errMsg); } case FileType::DIRECTORY: { return Result::Ok(true); } default: { return Result::Err("Unexpected error!"); } } } const char *sourceFileExtensions[] = { "c", "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; } Result GlobalLib::getStaticLibsLinkerFlags(const string &globalLibRootDir, const string &name, const string &version, LinkerFlagCallbackFunc linkerFlagCallbackFunc) { Result packageExistsResult = validatePackageExists(globalLibRootDir, name); if(packageExistsResult.isErr()) return Result::Err(packageExistsResult); string packageDir = globalLibRootDir + "/"; packageDir += name; // TODO: Instead of checking if version is exact match, check if package has same major version // and same or newer minor version string foundVersion; walkDir(packageDir.c_str(), [&foundVersion, &version](tinydir_file *file) { if(file->is_dir) { //printf("version: %s\n", file->name); if(_tinydir_strcmp(version.c_str(), file->name) == 0) foundVersion = file->name; } }); if(foundVersion.empty()) return Result::Err("Global lib dependency found, but version doesn't match dependency version", DependencyError::DEPENDENCY_VERSION_NO_MATCH); packageDir += "/"; packageDir += version; string projectConfFilePath = packageDir; projectConfFilePath += "/project.conf"; FileType projectConfFileType = getFileType(projectConfFilePath.c_str()); switch(projectConfFileType) { case FileType::FILE_NOT_FOUND: { string errMsg = "Global lib dependency found: "; errMsg += packageDir; errMsg += ", but it's missing a project.conf file"; return Result::Err(errMsg); } case FileType::DIRECTORY: { string errMsg = "Global lib dependency found: "; errMsg += packageDir; errMsg += ", but it's corrupt (Found directory instead of file)"; return Result::Err(errMsg); } } SibsConfig sibsConfig; Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if(result.isErr()) return Result::Err(result.getErrMsg()); if(sibsConfig.getPackageName().empty()) return Result::Err("project.conf is missing required field package.name"); if(sibsConfig.getPackageType() == PackageType::EXECUTABLE) { string errMsg = "The dependency "; errMsg += name; errMsg += " is an executable. Only libraries can be dependencies"; return Result::Err(errMsg); } backend::Ninja ninja(backend::Ninja::LibraryType::STATIC); walkDirFilesRecursive(packageDir.c_str(), [&ninja, &packageDir](tinydir_file *file) { if (isSourceFile(file)) { printf("Adding source file: %s\n", file->path + packageDir.size() + 1); ninja.addSourceFile(file->path + packageDir.size() + 1); } else { //printf("Ignoring non-source file: %s\n", file->path + packageDir.size() + 1); } }); if(ninja.getSourceFiles().empty()) { return Result::Ok("No source files in dependency (header only library?)"); } else { string debugBuildPath = packageDir + "/sibs-build/debug"; string staticLibPath = debugBuildPath; staticLibPath += "/lib"; staticLibPath += name; staticLibPath += ".a"; linkerFlagCallbackFunc(staticLibPath); // TODO: Use different directories depending on the project type, but .o build files should be in the same directory // no matter what project type, since they are used for executables, static/dynamic libraries Result createBuildDirResult = createDirectoryRecursive(debugBuildPath.c_str()); if(createBuildDirResult.isErr()) return Result::Err(createBuildDirResult); Result buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), debugBuildPath.c_str(), linkerFlagCallbackFunc); if (buildFileResult.isErr()) return Result::Err(buildFileResult.getErrMsg()); Result buildResult = ninja.build(debugBuildPath.c_str()); if (buildResult.isErr()) return Result::Err(buildResult.getErrMsg()); return Result::Ok(staticLibPath); } } Result GlobalLib::downloadDependency(const Dependency &dependency) { string url = "https://github.com/DEC05EBA/"; url += dependency.name; url += "/archive/"; url += dependency.version; url += ".tar.gz"; string libPath = getHomeDir(); libPath += "/.sibs/lib/"; libPath += dependency.name; libPath += "/"; libPath += dependency.version; string libArchivedFilePath = getHomeDir(); libArchivedFilePath += "/.sibs/archive/"; libArchivedFilePath += dependency.name; Result createArchiveDirResult = createDirectoryRecursive(libArchivedFilePath.c_str()); if(createArchiveDirResult.isErr()) return createArchiveDirResult; libArchivedFilePath += "/"; libArchivedFilePath += dependency.version; Result downloadResult = curl::downloadFile(url.c_str(), libArchivedFilePath.c_str()); if(downloadResult.isErr()) return downloadResult; // Create build path. This is done here because we dont want to create it if download fails Result createLibDirResult = createDirectoryRecursive(libPath.c_str()); if(createLibDirResult.isErr()) return createLibDirResult; return Archive::extract(libArchivedFilePath.c_str(), libPath.c_str()); } }