#include "../include/CmakeModule.hpp" #include "../include/Exec.hpp" #include "../include/GlobalLib.hpp" #if OS_FAMILY == OS_FAMILY_POSIX #define nprintf printf #else #define nprintf wprintf #endif using namespace std; namespace sibs { Result CmakeModule::compile(const SibsConfig &config, const FileString &buildPath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) { Result globalLibDirResult = getHomeDir(); if (!globalLibDirResult) return Result::Err(globalLibDirResult); FileString globalLibDir = globalLibDirResult.unwrap(); globalLibDir += TINYDIR_STRING("/.sibs/lib"); Result createGlobalLibDirResult = createDirectoryRecursive(globalLibDir.c_str()); if(createGlobalLibDirResult.isErr()) return createGlobalLibDirResult; // TODO: Create a cmake module that contains library/include path for the dependencies (https://cmake.org/Wiki/CMake:How_To_Find_Libraries). // Modify the project CMakeLists.txt and add: list(APPEND CMAKE_MODULE_PATH "PathToDependenciesCmakeModulesGoesHere"). // CMakeLists.txt may contain: set(CMAKE_MODULE_PATH "PathToModules"). This needs to be replaced with list append, // otherwise our added module path is replaced. // It may work to do like vcpkg instead - to use -DCMAKE_TOOLCHAIN_FILE program argument to specify path to script (https://github.com/Microsoft/vcpkg/blob/master/docs/examples/using-sqlite.md) for(const Dependency &globalLibDependency : config.getDependencies()) { Result globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback); if(globalLibLinkerFlagsResult.isErr()) { if(globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_NOT_FOUND || globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_VERSION_NO_MATCH) { printf("Dependency not found in global lib, trying to download from github\n"); // TODO: Download several dependencies at the same time by adding them to a list // and then iterate them and download them all using several threads. // All dependecies should be downloaded at the same time, this includes dependencies of dependencies. // If a dependency is missing, fail build BEFORE downloading dependencies and before compiling anything. // You do not want to possibly wait several minutes only for build to fail when there is no compilation error. // TODO: If return error is invalid url, then the message should be converted to // invalid package name/version. A check should be done if it is the name or version // that is invalid. Result downloadDependencyResult = GlobalLib::downloadDependency(globalLibDependency); if(downloadDependencyResult.isErr()) return downloadDependencyResult; globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback); if(globalLibLinkerFlagsResult.isErr()) return Result::Err(globalLibLinkerFlagsResult); } else { return Result::Err(globalLibLinkerFlagsResult); } } } Result createBuildDirResult = createDirectoryRecursive(buildPath.c_str()); if (createBuildDirResult.isErr()) return createBuildDirResult; FileString cmd = TINYDIR_STRING("cmake "); switch(config.getPackageType()) { case PackageType::EXECUTABLE: { cmd += config.getCmakeArgs(); break; } case PackageType::STATIC: { cmd += config.getCmakeArgsStatic(); break; } case PackageType::DYNAMIC: case PackageType::LIBRARY: { cmd += config.getCmakeArgsDynamic(); break; } } cmd += TINYDIR_STRING(" \"-B"); cmd += buildPath; cmd += TINYDIR_STRING("\" \"-H"); switch(config.getPackageType()) { case PackageType::EXECUTABLE: { cmd += config.getCmakeDir(); break; } case PackageType::STATIC: { cmd += config.getCmakeDirStatic(); break; } case PackageType::DYNAMIC: case PackageType::LIBRARY: { cmd += config.getCmakeDirDynamic(); break; } } cmd += TINYDIR_STRING("\""); nprintf("Compiling with cmake with arguments: %s\n", cmd.c_str()); Result execResult = exec(cmd.c_str(), true); if(execResult.isOk()) { if(execResult.unwrap().exitCode != 0) return Result::Err(execResult.unwrap().execStdout); } else return Result::Err(execResult); FileString ninjaCommand = TINYDIR_STRING("ninja -C \""); ninjaCommand += buildPath; ninjaCommand += TINYDIR_STRING("\""); nprintf("Compiling cmake generated ninja file: %s\n", ninjaCommand.c_str()); execResult = exec(ninjaCommand.c_str(), true); if(execResult.isOk()) { if(execResult.unwrap().exitCode != 0) return Result::Err(execResult.unwrap().execStdout); } else return Result::Err(execResult); if(config.getPackageType() != PackageType::EXECUTABLE) { string buildPathUtf8 = toUtf8(buildPath); nprintf("Searching for libraries generate by cmake in build path: %s\n", buildPathUtf8.c_str()); walkDirFiles(buildPath.c_str(), [&config, &staticLinkerFlagCallbackFunc, &dynamicLinkerFlagCallbackFunc](tinydir_file *file) { if(_tinydir_strcmp(file->extension, CONFIG_DYNAMIC_LIB_FILE_EXTENSION) == 0) { string libFileUtf8 = toUtf8(file->path); nprintf("Library generated by cmake: %s\n", libFileUtf8.c_str()); switch(config.getPackageType()) { case PackageType::STATIC: { string libFileCmd = "\""; libFileCmd += libFileUtf8; libFileCmd += "\""; staticLinkerFlagCallbackFunc(libFileCmd); break; } case PackageType::DYNAMIC: case PackageType::LIBRARY: { string libFileCmd = "\""; libFileCmd += libFileUtf8; libFileCmd += "\""; dynamicLinkerFlagCallbackFunc(libFileCmd); break; } } } }); // TODO: Clean this up. The below code is indentical to code in Ninja.cpp....... string projectPathUtf8 = toUtf8(config.getProjectPath()); for (const string &globalIncludeDir : config.getGlobalIncludeDirs()) { string globalIncludeDirFull = projectPathUtf8; globalIncludeDirFull += "/"; globalIncludeDirFull += globalIncludeDir; if(globalIncludeDirCallback) globalIncludeDirCallback(globalIncludeDirFull); } } return Result::Ok(true); } }