#include "../include/PkgConfig.hpp" #if OS_FAMILY == OS_FAMILY_POSIX #include "../include/Exec.hpp" using namespace std; // TODO: Do not use pkg-config program. The same functionality can easily be achieved // by reading files in /usr/bin/pkgconfig // Or is there no downside to calling pkg-config program? namespace sibs { string trimRight(const string &input) { for(int i = input.size() - 1; i >= 0; --i) { if(!isspace(input[i])) return input.substr(0, i + 1); } return ""; } #if OS_FAMILY == OS_FAMILY_POSIX Result PkgConfig::validatePkgConfigPackageVersionExists(const Dependency &dependency) { Result dependencyValidationResult = PkgConfig::validatePackageExists(dependency.name); if(dependencyValidationResult.isErr()) return Result::Err(dependencyValidationResult.getErrMsg()); Result dependencyVersionValidationResult = PkgConfig::validatePackageVersionAtLeast(dependency.name, dependency.version); if(dependencyVersionValidationResult.isErr()) return Result::Err(dependencyVersionValidationResult.getErrMsg()); return Result::Ok(true); } #endif Result PkgConfig::validatePackageExists(const string &name) { string command = "pkg-config --exists '"; command += name; command += "'"; Result execResult = exec(command.c_str()); if(execResult.isErr()) return Result::Err(execResult.getErrMsg()); if(execResult.unwrap().exitCode == 1) { string errMsg = "pkg-config dependency not found: "; errMsg += name; return Result::Err(errMsg); } else if(execResult.unwrap().exitCode == 127) { return Result::Err("pkg-config is not installed"); } else if(execResult.unwrap().exitCode != 0) { string errMsg = "Failed to check if dependency exists, Unknown error, exit code: "; errMsg += to_string(execResult.unwrap().exitCode); return Result::Err(errMsg); } return Result::Ok(true); } Result PkgConfig::validatePackageVersionAtLeast(const string &name, const string &version) { // TODO: Instead of checking if package version is same or newer, check if package is same major version // and same or newer minor version // Use --modversion instead and check if the version returned is newer or equal to dependency version. // This way we can output installed version vs expected dependency version string command = "pkg-config '--atleast-version="; command += version; command += "' '"; command += name; command += "'"; Result execResult = exec(command.c_str()); if(execResult.isErr()) return Result::Err(execResult.getErrMsg()); if(execResult.unwrap().exitCode == 1) { string errMsg = "Dependency "; errMsg += name; errMsg += " is installed but the version older than "; errMsg += version; return Result::Err(errMsg); } else if(execResult.unwrap().exitCode == 127) { return Result::Err("pkg-config is not installed"); } else if(execResult.unwrap().exitCode != 0) { string errMsg = "Failed to check dependency version, Unknown error, exit code: "; errMsg += to_string(execResult.unwrap().exitCode); return Result::Err(errMsg); } return Result::Ok(true); } Result PkgConfig::getDynamicLibsLinkerFlags(const vector &libs) { if(libs.empty()) return Result::Ok(""); string args; for(const Dependency &lib : libs) { args += " '"; args += lib.name; args += "'"; } string command = "pkg-config --libs"; command += args; Result execResult = exec(command.c_str()); if(execResult.isErr()) return Result::Err(execResult.getErrMsg()); if(execResult.unwrap().exitCode == 0) { execResult.unwrap().execStdout = trimRight(execResult.unwrap().execStdout); return Result::Ok(execResult.unwrap().execStdout); } else if(execResult.unwrap().exitCode == 1) { // TODO: This shouldn't happen because we check if each dependency is installed before this, // but maybe the package is uninstalled somewhere between here... // Would be better to recheck if each package is installed here again // to know which package was uninstalled return Result::Err("Packages not found"); } else if(execResult.unwrap().exitCode == 127) { return Result::Err("pkg-config is not installed"); } else { string errMsg = "Failed to get package dynamic lib linking flags, Unknown error, exit code: "; errMsg += to_string(execResult.unwrap().exitCode); return Result::Err(errMsg); } } Result PkgConfig::getDynamicLibsCflags(const vector &libs) { if(libs.empty()) return Result::Ok(""); string args; for(const Dependency &lib : libs) { args += " '"; args += lib.name; args += "'"; } string command = "pkg-config --cflags"; command += args; Result execResult = exec(command.c_str()); if(execResult.isErr()) return Result::Err(execResult.getErrMsg()); if(execResult.unwrap().exitCode == 0) { execResult.unwrap().execStdout = trimRight(execResult.unwrap().execStdout); return Result::Ok(execResult.unwrap().execStdout); } else if(execResult.unwrap().exitCode == 1) { // TODO: This shouldn't happen because we check if each dependency is installed before this, // but maybe the package is uninstalled somewhere between here... // Would be better to recheck if each package is installed here again // to know which package was uninstalled return Result::Err("Packages not found"); } else if(execResult.unwrap().exitCode == 127) { return Result::Err("pkg-config is not installed"); } else { string errMsg = "Failed to get package dynamic lib cflags, Unknown error, exit code: "; errMsg += to_string(execResult.unwrap().exitCode); return Result::Err(errMsg); } } Result PkgConfig::getDynamicLibsFlags(const vector &libs) { PkgConfigFlags flags; Result linkerFlagsResult = getDynamicLibsLinkerFlags(libs); if(!linkerFlagsResult) return Result::Err(linkerFlagsResult); Result cflagsResult = getDynamicLibsCflags(libs); if(!cflagsResult) return Result::Err(cflagsResult); flags.linkerFlags = move(linkerFlagsResult.unwrap()); flags.cflags = move(cflagsResult.unwrap()); return Result::Ok(flags); } } #endif // OS_FAMILY_POSIX