aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CmakeModule.cpp206
-rw-r--r--src/FileUtil.cpp26
-rw-r--r--src/GlobalLib.cpp159
-rw-r--r--src/main.cpp95
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());