#include "BackendUtils.hpp" #include "../include/FileUtil.hpp" #include "../include/Exec.hpp" #include "ninja/Ninja.hpp" using namespace std; using namespace sibs; static const char *cCompilerPath = nullptr; static const char *cppCompilerPath = nullptr; static const char *linkerPath = nullptr; namespace backend { static bool isPathSubPathOf(const FileString &path, const FileString &subPathOf) { return _tinydir_strncmp(path.c_str(), subPathOf.c_str(), subPathOf.size()) == 0; } const _tinydir_char_t *cFileExtensions[] = { TINYDIR_STRING("c"), TINYDIR_STRING("C"), TINYDIR_STRING("cc") }; const _tinydir_char_t *cppFileExtensions[] = { TINYDIR_STRING("cp"), TINYDIR_STRING("cpp"), TINYDIR_STRING("cxx"), TINYDIR_STRING("c++") }; sibs::FileString BackendUtils::getFileExtension(const sibs::FileString &filepath) { size_t indexOfDot = filepath.find_last_of('.'); if(indexOfDot == sibs::FileString::npos) return TINYDIR_STRING(""); indexOfDot += 1; return filepath.substr(indexOfDot); } sibs::Language BackendUtils::getFileLanguage(const _tinydir_char_t *extension) { for(const _tinydir_char_t *sourceFileExtension : cFileExtensions) { if(_tinydir_strcmp(sourceFileExtension, extension) == 0) return sibs::Language::C; } for(const _tinydir_char_t *sourceFileExtension : cppFileExtensions) { if(_tinydir_strcmp(sourceFileExtension, extension) == 0) return sibs::Language::CPP; } if(_tinydir_strcmp(TINYDIR_STRING("zig"), extension) == 0) return sibs::Language::ZIG; return sibs::Language::NONE; } sibs::Language BackendUtils::getFileLanguage(tinydir_file *file) { if(!file->is_reg) return sibs::Language::NONE; return getFileLanguage(file->extension); } void BackendUtils::collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const SibsConfig &sibsConfig, bool recursive) { walkDir(projectPath, [ninjaProject, &sibsConfig, recursive](tinydir_file *file) { FileString pathNative = file->path; #if OS_FAMILY == OS_FAMILY_WINDOWS replaceChar(pathNative, L'/', L'\\'); #endif if(file->is_reg) { sibs::Language fileLanguage = getFileLanguage(file); if (fileLanguage != sibs::Language::NONE) { string filePathUtf8 = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size()); ninjaProject->addSourceFile(fileLanguage, filePathUtf8.c_str()); } else { //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); } } else { if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) { string filePathUtf8 = toUtf8(pathNative.c_str()); ninjaProject->setTestSourceDir(filePathUtf8.c_str()); } else if(recursive && !directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs()) && _tinydir_strcmp(file->name, TINYDIR_STRING("sibs-build")) != 0) { FileString projectConfPath = file->path; #if OS_FAMILY == OS_FAMILY_WINDOWS projectConfPath += L'\\'; #else projectConfPath += '/'; #endif projectConfPath += TINYDIR_STRING("project.conf"); auto projectConfFileType = getFileType(projectConfPath.c_str()); if(!sibsConfig.isTest() && getFileType(projectConfPath.c_str()) == FileType::REGULAR) { backend::Ninja *subProject = new backend::Ninja(); SibsConfig *subProjectConfig = new SibsConfig(sibsConfig.getCompiler(), file->path, sibsConfig.getOptimizationLevel(), false); subProjectConfig->packaging = sibsConfig.packaging; subProjectConfig->platform = sibsConfig.platform; subProjectConfig->bundling = sibsConfig.bundling; FileString subProjectBuildPath; readSibsConfig(file->path, projectConfPath, *subProjectConfig, subProjectBuildPath); collectSourceFiles(file->path, subProject, *subProjectConfig, true); ninjaProject->addSubProject(subProject, subProjectConfig, move(subProjectBuildPath)); } else collectSourceFiles(file->path, ninjaProject, sibsConfig, true); } } return true; }); } string BackendUtils::getCompilerCExecutable(Compiler compiler) { if(cCompilerPath) return cCompilerPath; char *cc = std::getenv("CC"); if(cc) { cCompilerPath = cc; return cCompilerPath; } switch(compiler) { case Compiler::GCC: cCompilerPath = "ccache cc"; break; case Compiler::MINGW_W64: cCompilerPath = "x86_64-w64-mingw32-cc"; break; case Compiler::MSVC: cCompilerPath = "cl.exe"; break; } return cCompilerPath; } string BackendUtils::getCompilerCppExecutable(Compiler compiler) { if(cppCompilerPath) return cppCompilerPath; char *cxx = std::getenv("CXX"); if(cxx) { cppCompilerPath = cxx; return cppCompilerPath; } switch(compiler) { case Compiler::GCC: cppCompilerPath = "ccache c++"; break; case Compiler::MINGW_W64: cppCompilerPath = "x86_64-w64-mingw32-c++"; break; case Compiler::MSVC: cppCompilerPath = "cl.exe"; break; } return cppCompilerPath; } string BackendUtils::getCompilerLinker(Compiler compiler) { if(linkerPath) return linkerPath; char *ar = std::getenv("AR"); if(ar) { linkerPath = ar; return linkerPath; } switch(compiler) { case Compiler::GCC: linkerPath = "ar"; break; case Compiler::MINGW_W64: linkerPath = "x86_64-w64-mingw32-ar"; break; case Compiler::MSVC: linkerPath = "lib.exe"; break; } return linkerPath; } RuntimeCompilerType BackendUtils::getCCompilerType(Compiler compiler) { RuntimeCompilerType cCompilerType = RuntimeCompilerType::NONE; Result cCompilerVersion = exec(toFileString(getCompilerCExecutable(compiler)) + TINYDIR_STRING(" --version")); if(cCompilerVersion && cCompilerVersion.unwrap().exitCode == 0) { if(cCompilerVersion.unwrap().execStdout.find("Emscripten") != string::npos) cCompilerType = RuntimeCompilerType::EMSCRIPTEN; else if(cCompilerVersion.unwrap().execStdout.find("clang") != string::npos) cCompilerType = RuntimeCompilerType::CLANG; else cCompilerType = RuntimeCompilerType::OTHER; } return cCompilerType; } RuntimeCompilerType BackendUtils::getCppCompilerType(Compiler compiler) { RuntimeCompilerType cppCompilerType = RuntimeCompilerType::NONE; Result cppCompilerVersion = exec(toFileString(getCompilerCppExecutable(compiler)) + TINYDIR_STRING(" --version")); if(cppCompilerVersion && cppCompilerVersion.unwrap().exitCode == 0) { if(cppCompilerVersion.unwrap().execStdout.find("Emscripten") != string::npos) cppCompilerType = RuntimeCompilerType::EMSCRIPTEN; else if(cppCompilerVersion.unwrap().execStdout.find("clang") != string::npos) cppCompilerType = RuntimeCompilerType::CLANG; else cppCompilerType = RuntimeCompilerType::OTHER; } return cppCompilerType; } }