diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CmakeModule.cpp | 206 | ||||
-rw-r--r-- | src/FileUtil.cpp | 26 | ||||
-rw-r--r-- | src/GlobalLib.cpp | 159 | ||||
-rw-r--r-- | src/main.cpp | 95 |
4 files changed, 371 insertions, 115 deletions
diff --git a/src/CmakeModule.cpp b/src/CmakeModule.cpp new file mode 100644 index 0000000..1995023 --- /dev/null +++ b/src/CmakeModule.cpp @@ -0,0 +1,206 @@ +#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<bool> CmakeModule::compile(const SibsConfig &config, const FileString &buildPath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) + { + Result<FileString> globalLibDirResult = getHomeDir(); + if (!globalLibDirResult) + return Result<bool>::Err(globalLibDirResult); + FileString globalLibDir = globalLibDirResult.unwrap(); + globalLibDir += TINYDIR_STRING("/.sibs/lib"); + Result<bool> 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<bool> 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<bool> 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<bool>::Err(globalLibLinkerFlagsResult); + } + else + { + return Result<bool>::Err(globalLibLinkerFlagsResult); + } + } + } + + Result<bool> 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> execResult = exec(cmd.c_str(), true); + if(execResult.isOk()) + { + if(execResult.unwrap().exitCode != 0) + return Result<bool>::Err(execResult.unwrap().execStdout); + } + else + return Result<bool>::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<bool>::Err(execResult.unwrap().execStdout); + } + else + return Result<bool>::Err(execResult); + + if(config.getPackageType() != PackageType::EXECUTABLE) + { + #if OS_TYPE == OS_TYPE_WINDOWS + const _tinydir_char_t *libFileExtension = TINYDIR_STRING("lib"); + #elif OS_TYPE == OS_TYPE_LINUX + const _tinydir_char_t *libFileExtension = TINYDIR_STRING("so"); + #endif + + FileString libFile; + u64 libFileLastModified = 0; + + string buildPathUtf8 = toUtf8(buildPath); + nprintf("Searching for library generate by cmake in build path: %s\n", buildPathUtf8.c_str()); + walkDirFiles(buildPath.c_str(), [&libFileExtension, &libFile, &libFileLastModified](tinydir_file *file) + { + if(_tinydir_strcmp(file->extension, libFileExtension) == 0) + { + u32 fileLastModified = getFileLastModifiedTime(file->path); + if(fileLastModified > libFileLastModified) + { + libFileLastModified = fileLastModified; + libFile = file->path; + } + } + }); + + if(libFileLastModified == 0) + { + string errMsg = "Package "; + errMsg += config.getPackageName(); + errMsg += " was built using cmake but no generated library was found"; + return Result<bool>::Err(errMsg); + } + string libFileUtf8 = toUtf8(libFile); + 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()); + printf("BUILD CMAKE MODULE!, num global include dirs: %d\n", config.getGlobalIncludeDirs().size()); + for (const string &globalIncludeDir : config.getGlobalIncludeDirs()) + { + string globalIncludeDirFull = projectPathUtf8; + globalIncludeDirFull += "/"; + globalIncludeDirFull += globalIncludeDir; + if(globalIncludeDirCallback) + globalIncludeDirCallback(globalIncludeDirFull); + } + } + + return Result<bool>::Ok(true); + } +} diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp index 2626ee3..7541a61 100644 --- a/src/FileUtil.cpp +++ b/src/FileUtil.cpp @@ -101,6 +101,19 @@ namespace sibs else return FileType::FILE_NOT_FOUND; } + + Result<u64> getFileLastModifiedTime(const _tinydir_char_t *path) + { + struct stat64 fileStat; + if (stat64(path, &fileStat) == 0) + return Result<u64>::Ok(fileStat.st_mtim.tv_sec); + else + { + string errMsg = "File not found: "; + errMsg += toUtf8(path); + return Result<u64>::Err(errMsg); + } + } #else FileType getFileType(const _tinydir_char_t *path) { @@ -110,6 +123,19 @@ namespace sibs else return FileType::FILE_NOT_FOUND; } + + Result<u64> getFileLastModifiedTime(const _tinydir_char_t *path) + { + struct _stat64i32 fileStat; + if (_wstat(path, &fileStat) == 0) + rreturn Result<u64>::Ok(fileStat.st_mtim.tv_sec); + else + { + string errMsg = "File not found: "; + errMsg += toUtf8(path); + return Result<u64>::Err(errMsg); + } + } #endif // TODO: Handle failure (directory doesn't exist, no permission etc) diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp index 69c4ebb..3334655 100644 --- a/src/GlobalLib.cpp +++ b/src/GlobalLib.cpp @@ -4,6 +4,7 @@ #include "../include/Conf.hpp" #include "../include/curl.hpp" #include "../include/Archive.hpp" +#include "../include/CmakeModule.hpp" using namespace std; @@ -147,43 +148,7 @@ namespace sibs errMsg += ")"; return Result<bool>::Err(errMsg); } - - backend::Ninja ninja; - // TODO: Use same source file finder as in main.cpp - FileWalkCallbackFunc collectSourceFiles = [&ninja, &sibsConfig, &collectSourceFiles](tinydir_file *file) - { - FileString pathNative = file->path; -#if OS_FAMILY == OS_FAMILY_WINDOWS - replaceChar(pathNative, L'/', L'\\'); -#endif - if(file->is_reg) - { - if (isSourceFile(file)) - { - string fileNameNative = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size() + 1); - ninja.addSourceFile(fileNameNative.c_str()); - } - else - { - //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); - } - } - else - { - // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests... - // OR I believe there is no reason to run tests in dependencies. The main projects tests should cover that? - // But you might want to know exactly which dependency is causing issue and which part of it... - if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) - { - string filePathUtf8 = toUtf8(pathNative.c_str()); - ninja.addTestSourceDir(filePathUtf8.c_str()); - } - else if(!directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs())) - walkDir(file->path, collectSourceFiles); - } - }; - walkDir(packageDir.c_str(), collectSourceFiles); - + FileString buildPath = packageDir + TINYDIR_STRING("/sibs-build/"); switch (sibsConfig.getOptimizationLevel()) { @@ -214,60 +179,106 @@ namespace sibs break; } } - - if (!ninja.getSourceFiles().empty()) + + if(sibsConfig.shouldUseCmake()) + { + CmakeModule cmakeModule; + Result<bool> cmakeCompileResult = cmakeModule.compile(sibsConfig, buildPath, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback); + if(!cmakeCompileResult) + return cmakeCompileResult; + } + else { - string libPath = toUtf8(buildPath); - switch (sibsConfig.getCompiler()) + backend::Ninja ninja; + // TODO: Use same source file finder as in main.cpp + FileWalkCallbackFunc collectSourceFiles = [&ninja, &sibsConfig, &collectSourceFiles](tinydir_file *file) { - case Compiler::GCC: + FileString pathNative = file->path; + #if OS_FAMILY == OS_FAMILY_WINDOWS + replaceChar(pathNative, L'/', L'\\'); + #endif + if(file->is_reg) { - libPath += "/lib"; - libPath += name; - if (sibsConfig.getPackageType() == PackageType::STATIC) + if (isSourceFile(file)) { - libPath += ".a"; - string libPathCmd = "'"; - libPathCmd += libPath; - libPathCmd += "'"; - staticLinkerFlagCallbackFunc(libPathCmd); + string fileNameNative = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size() + 1); + ninja.addSourceFile(fileNameNative.c_str()); } else { - libPath += ".so"; - string libPathCmd = "'"; - libPathCmd += libPath; - libPathCmd += "'"; - dynamicLinkerFlagCallbackFunc(libPathCmd); + //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); } - break; } - case Compiler::MSVC: + else { - libPath += "/"; - libPath += name; - if (sibsConfig.getPackageType() == PackageType::STATIC) + // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests... + // OR I believe there is no reason to run tests in dependencies. The main projects tests should cover that? + // But you might want to know exactly which dependency is causing issue and which part of it... + if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) { - libPath += ".lib"; - string libPathCmd = "\""; - libPathCmd += libPath; - libPathCmd += "\""; - staticLinkerFlagCallbackFunc(libPathCmd); + string filePathUtf8 = toUtf8(pathNative.c_str()); + ninja.addTestSourceDir(filePathUtf8.c_str()); } - else + else if(!directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs())) + walkDir(file->path, collectSourceFiles); + } + }; + walkDir(packageDir.c_str(), collectSourceFiles); + + if (!ninja.getSourceFiles().empty()) + { + string libPath = toUtf8(buildPath); + switch (sibsConfig.getCompiler()) + { + case Compiler::GCC: { - libPath += ".lib"; - string libPathCmd = "\""; - libPathCmd += libPath; - libPathCmd += "\""; - dynamicLinkerFlagCallbackFunc(libPathCmd); + libPath += "/lib"; + libPath += name; + if (sibsConfig.getPackageType() == PackageType::STATIC) + { + libPath += ".a"; + string libPathCmd = "'"; + libPathCmd += libPath; + libPathCmd += "'"; + staticLinkerFlagCallbackFunc(libPathCmd); + } + else + { + libPath += ".so"; + string libPathCmd = "'"; + libPathCmd += libPath; + libPathCmd += "'"; + dynamicLinkerFlagCallbackFunc(libPathCmd); + } + break; + } + case Compiler::MSVC: + { + libPath += "/"; + libPath += name; + if (sibsConfig.getPackageType() == PackageType::STATIC) + { + libPath += ".lib"; + string libPathCmd = "\""; + libPathCmd += libPath; + libPathCmd += "\""; + staticLinkerFlagCallbackFunc(libPathCmd); + } + else + { + libPath += ".lib"; + string libPathCmd = "\""; + libPathCmd += libPath; + libPathCmd += "\""; + dynamicLinkerFlagCallbackFunc(libPathCmd); + } + break; } - break; } } - } - return ninja.build(sibsConfig, buildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback); + return ninja.build(sibsConfig, buildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback); + } } Result<bool> GlobalLib::downloadDependency(const Dependency &dependency) diff --git a/src/main.cpp b/src/main.cpp index a4e493e..b3b6d63 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "../include/FileUtil.hpp" #include "../include/Conf.hpp" #include "../include/Exec.hpp" +#include "../include/CmakeModule.hpp" #include "../backend/ninja/Ninja.hpp" using namespace std; @@ -226,43 +227,7 @@ int buildProject(int argc, const _tinydir_char_t **argv) cerr << errMsg << endl; exit(11); } - - //string projectSrcPath = projectPath + "/src"; - //validateDirectoryPath(projectSrcPath.c_str()); - - backend::Ninja ninja; - FileWalkCallbackFunc collectSourceFiles = [&ninja, &sibsConfig, &collectSourceFiles](tinydir_file *file) - { - FileString pathNative = file->path; -#if OS_FAMILY == OS_FAMILY_WINDOWS - replaceChar(pathNative, L'/', L'\\'); -#endif - if(file->is_reg) - { - if (isSourceFile(file)) - { - string filePathUtf8 = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size()); - ninja.addSourceFile(filePathUtf8.c_str()); - } - else - { - //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); - } - } - else - { - // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests - if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) - { - string filePathUtf8 = toUtf8(pathNative.c_str()); - ninja.addTestSourceDir(filePathUtf8.c_str()); - } - else if(!directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs())) - walkDir(file->path, collectSourceFiles); - } - }; - walkDir(projectPath.c_str(), collectSourceFiles); - + FileString buildPath = projectPath + TINYDIR_STRING("/sibs-build/"); switch(sibsConfig.getOptimizationLevel()) { @@ -275,11 +240,59 @@ int buildProject(int argc, const _tinydir_char_t **argv) } auto startTime = high_resolution_clock::now(); - Result<bool> buildFileResult = ninja.build(sibsConfig, buildPath.c_str()); - if(buildFileResult.isErr()) + if(sibsConfig.shouldUseCmake()) + { + auto dummyCallback = [](const string&){}; + + CmakeModule cmakeModule; + Result<bool> cmakeCompileResult = cmakeModule.compile(sibsConfig, buildPath, dummyCallback, dummyCallback, dummyCallback); + if(!cmakeCompileResult) + { + ferr << "Failed to compile using cmake: " << toFileString(cmakeCompileResult.getErrMsg()) << endl; + exit(7); + } + } + else { - ferr << "Failed to build ninja file: " << toFileString(buildFileResult.getErrMsg()) << endl; - exit(7); + backend::Ninja ninja; + FileWalkCallbackFunc collectSourceFiles = [&ninja, &sibsConfig, &collectSourceFiles](tinydir_file *file) + { + FileString pathNative = file->path; + #if OS_FAMILY == OS_FAMILY_WINDOWS + replaceChar(pathNative, L'/', L'\\'); + #endif + if(file->is_reg) + { + if (isSourceFile(file)) + { + string filePathUtf8 = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size()); + ninja.addSourceFile(filePathUtf8.c_str()); + } + else + { + //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); + } + } + else + { + // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests + if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) + { + string filePathUtf8 = toUtf8(pathNative.c_str()); + ninja.addTestSourceDir(filePathUtf8.c_str()); + } + else if(!directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs())) + walkDir(file->path, collectSourceFiles); + } + }; + walkDir(projectPath.c_str(), collectSourceFiles); + + Result<bool> buildFileResult = ninja.build(sibsConfig, buildPath.c_str()); + if(buildFileResult.isErr()) + { + ferr << "Failed to build ninja file: " << toFileString(buildFileResult.getErrMsg()) << endl; + exit(7); + } } auto elapsedTime = duration_cast<duration<double>>(high_resolution_clock::now() - startTime); printf("Build finished in %fs\n", elapsedTime.count()); |