aboutsummaryrefslogtreecommitdiff
path: root/backend/ninja/Ninja.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2017-12-30 04:32:49 +0100
committerdec05eba <dec05eba@protonmail.com>2017-12-30 05:08:10 +0100
commit98ad7dd049a366e21d60a34548736a3c8ef72877 (patch)
tree45e34eb02f6be9f9130a870a19ef1533e24bf343 /backend/ninja/Ninja.cpp
parent1f583ebb6e3973c992d59886659bf53ff87f41de (diff)
Add support for windows (ugly fast solution)
Diffstat (limited to 'backend/ninja/Ninja.cpp')
-rw-r--r--backend/ninja/Ninja.cpp314
1 files changed, 259 insertions, 55 deletions
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp
index ddc20dd..b2a073b 100644
--- a/backend/ninja/Ninja.cpp
+++ b/backend/ninja/Ninja.cpp
@@ -8,6 +8,12 @@
using namespace std;
using namespace sibs;
+#if OS_FAMILY == OS_FAMILY_POSIX
+#define nprintf printf
+#else
+#define nprintf wprintf
+#endif
+
namespace backend
{
string join(const vector<string> &list, const char *joinStr)
@@ -30,7 +36,7 @@ namespace backend
i = 0;
for(const string &str : list)
{
- if(i > 0);
+ if(i > 0)
result += joinStr;
result += str;
++i;
@@ -39,6 +45,78 @@ namespace backend
return move(result);
}
+ string getIncludeOptionFlag(Compiler compiler, const string &filepath)
+ {
+ string result;
+ switch (compiler)
+ {
+ case Compiler::GCC:
+ {
+ result = "'-I";
+ result += filepath;
+ result += "'";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result = "/I \"";
+ result += filepath;
+ result += "\"";
+ break;
+ }
+ }
+ return result;
+ }
+
+ string getCompileWithoutLinkingFlag(Compiler compiler)
+ {
+ string result;
+ switch (compiler)
+ {
+ case Compiler::GCC:
+ {
+ result = "-c";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result = "/c";
+ break;
+ }
+ }
+ return result;
+ }
+
+ string getObjectFileNameFlag(Compiler compiler, const string &objectFileName)
+ {
+ string result;
+ switch (compiler)
+ {
+ case Compiler::GCC:
+ {
+ result = "-o ";
+ result += objectFileName;
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result = "/Fo";
+ result += objectFileName;
+ break;
+ }
+ }
+ return result;
+ }
+
+ const char* getObjectFileExtension(Compiler compiler)
+ {
+ switch (compiler)
+ {
+ case Compiler::GCC: return ".o";
+ case Compiler::MSVC: return ".obj";
+ }
+ }
+
Ninja::Ninja(LibraryType _libraryType) :
libraryType(_libraryType)
{
@@ -105,7 +183,8 @@ namespace backend
}
return false;
}
-
+
+#if OS_FAMILY == OS_FAMILY_POSIX
Result<bool> validatePkgConfigPackageVersionExists(const Dependency &dependency)
{
Result<bool> dependencyValidationResult = PkgConfig::validatePackageExists(dependency.name);
@@ -118,7 +197,7 @@ namespace backend
return Result<bool>::Ok(true);
}
-
+#endif
// TODO: First check if pkg-config is installed. If it's not, only check dependencies that exists in the dependencies sub directory.
// If pkg-config is installed and dependency is not installed, check in dependencies sub directory.
Result<bool> Ninja::getLinkerFlags(const SibsConfig &config, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const
@@ -126,14 +205,18 @@ namespace backend
const vector<Dependency> &dependencies = config.getDependencies();
if(dependencies.empty()) return Result<bool>::Ok(true);
- string globalLibDir = getHomeDir();
- globalLibDir += "/.sibs/lib";
+ 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;
- vector<Dependency> pkgConfigDependencies;
vector<Dependency> globalLibDependencies;
+#if OS_FAMILY == OS_FAMILY_POSIX
+ vector<Dependency> pkgConfigDependencies;
for(const Dependency &dependency : dependencies)
{
Result<bool> pkgConfigDependencyValidation = validatePkgConfigPackageVersionExists(dependency);
@@ -148,11 +231,11 @@ namespace backend
}
Result<string> pkgConfigLinkerFlagsResult = PkgConfig::getDynamicLibsLinkerFlags(pkgConfigDependencies);
- if(pkgConfigLinkerFlagsResult.isErr())
+ if (pkgConfigLinkerFlagsResult.isErr())
{
printf("%s, using global lib...\n", pkgConfigLinkerFlagsResult.getErrMsg().c_str());
globalLibDependencies.reserve(globalLibDependencies.size() + pkgConfigDependencies.size());
- for(const Dependency &pkgConfigDependency : pkgConfigDependencies)
+ for (const Dependency &pkgConfigDependency : pkgConfigDependencies)
{
globalLibDependencies.push_back(pkgConfigDependency);
}
@@ -160,9 +243,15 @@ namespace backend
}
else
{
- if(!pkgConfigLinkerFlagsResult.unwrap().empty())
+ if (!pkgConfigLinkerFlagsResult.unwrap().empty())
dynamicLinkerFlagCallback(pkgConfigLinkerFlagsResult.unwrap());
}
+#else
+ for (const Dependency &dependency : dependencies)
+ {
+ globalLibDependencies.push_back(dependency);
+ }
+#endif
for(const Dependency &globalLibDependency : globalLibDependencies)
{
@@ -200,7 +289,7 @@ namespace backend
return Result<bool>::Ok(true);
}
- Result<bool> Ninja::build(const SibsConfig &config, const char *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback)
+ Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback)
{
// TODO: Do not quit here if no source files are provided. The source-less project could have dependencies
if(sourceFiles.empty())
@@ -210,41 +299,76 @@ namespace backend
if(createBuildDirResult.isErr())
return createBuildDirResult;
- string ninjaBuildFilePath = savePath;
- ninjaBuildFilePath += "/build.ninja";
+ string savePathUtf8 = toUtf8(savePath);
+
+ FileString ninjaBuildFilePath = savePath;
+ ninjaBuildFilePath += TINYDIR_STRING("/build.ninja");
string result;
result.reserve(16384);
- string globalIncDir = getHomeDir();
- globalIncDir += "/.sibs/lib";
+ Result<FileString> globalIncDirResult = getHomeDir();
+ if (!globalIncDirResult)
+ return Result<bool>::Err(globalIncDirResult);
- result += "globalIncDir = '-I";
- result += globalIncDir;
- result += "'";
+ FileString globalIncDir = globalIncDirResult.unwrap();
+ globalIncDir += TINYDIR_STRING("/.sibs/lib");
+
+ result += "globalIncDir = ";
+ result += getIncludeOptionFlag(config.getCompiler(), toUtf8(globalIncDir));
for(const auto &includeDir : config.getIncludeDirs())
{
- result += " '-I../../";
- result += includeDir;
- result += "'";
+ string includeDirRelative = "../../";
+ includeDirRelative += includeDir;
+ result += " ";
+ result += getIncludeOptionFlag(config.getCompiler(), includeDirRelative);
}
result += "\n\n";
+ string compilerName;
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ compilerName = "ccache c++";
+ break;
+ case Compiler::MSVC:
+ compilerName = "cl.exe";
+ break;
+ }
+
string buildJob;
switch(libraryType)
{
case LibraryType::EXECUTABLE:
{
- result += "rule cpp_COMPILER\n";
- result += " command = ccache c++ $ARGS -c $in -o $out\n\n";
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ {
+ result += "rule cpp_COMPILER\n";
+ result += " command = ccache c++ $ARGS -c $in -o $out\n\n";
+
+ result += "rule cpp_BUILD_EXEC\n";
+ result += " command = ccache c++ $ARGS -o $out $in $LINK_ARGS $aliasing\n\n";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result += "rule cpp_COMPILER\n";
+ result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
+
+ result += "rule cpp_BUILD_EXEC\n";
+ result += " command = cl.exe $ARGS $in /Fe$out $LINK_ARGS\n\n";
+ break;
+ }
+ }
- result += "rule cpp_BUILD_EXEC\n";
- result += " command = ccache c++ $ARGS -o $out $in $LINK_ARGS $aliasing\n\n";
buildJob = "cpp_BUILD_EXEC";
break;
}
case LibraryType::STATIC:
{
+ // TODO: Write equivalent code for msvc
result += "rule cpp_COMPILER\n";
result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n";
@@ -258,12 +382,32 @@ namespace backend
}
case LibraryType::DYNAMIC:
{
- result += "rule cpp_COMPILER\n";
- result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n";
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ {
+ result += "rule cpp_COMPILER\n";
+ result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n";
+
+ // --whole-archive
+ result += "rule cpp_BUILD_DYNAMIC\n";
+ result += " command = ccache c++ $in -shared -o $out $LINK_ARGS $aliasing\n\n";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result += "rule cpp_COMPILER\n";
+ result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
+
+ //result += "rule cpp_BUILD_DYNAMIC\n";
+ //result += " command = cl.exe /LD $in /Fe$out $LINK_ARGS\n\n";
+
+ result += "rule cpp_BUILD_DYNAMIC\n";
+ result += " command = lib.exe /OUT:$out $in\n\n";
+ break;
+ }
+ }
- // --whole-archive
- result += "rule cpp_BUILD_DYNAMIC\n";
- result += " command = ccache c++ $in -shared -o $out $LINK_ARGS $aliasing\n\n";
buildJob = "cpp_BUILD_DYNAMIC";
break;
}
@@ -289,18 +433,26 @@ namespace backend
{
//string sourceFileEncoded = sourceFile;
//replace(sourceFileEncoded, '/', '@');
- string objectName = config.getPackageName() + "@exe/" + sourceFile + ".o";
+ string objectName = config.getPackageName() + "@exe/" + sourceFile;
+ objectName += getObjectFileExtension(config.getCompiler());
result += "build ";
result += objectName;
result += ": cpp_COMPILER ../../";
result += sourceFile;
result += "\n";
- result += " ARGS = $globalIncDir '-I" + config.getPackageName() + "@exe' '-I..' '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' " + optimizationFlags + " '-g'\n\n";
+ result += " ARGS = $globalIncDir";
+ if(config.getCompiler() != Compiler::MSVC)
+ result += " '-I" + config.getPackageName() + "@exe' '-I..' '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' " + optimizationFlags + " '-g'";
+ result += "\n\n";
objectNames.emplace_back(objectName);
}
+#if OS_TYPE == OS_TYPE_LINUX
// TODO: Allow configuring default linking flags. Maybe have `package.useThreads = false` to disable this flag
string allLinkerFlags = "-pthread";
+#else
+ string allLinkerFlags = "";
+#endif
// TODO: Somehow check loading order, because it has to be correct to work.. Or does it for dynamic libraries?
// Anyways it's required for static libraries (especially on Windows)
@@ -332,7 +484,7 @@ namespace backend
string projectGeneratedBinary = allLinkerFlags;
projectGeneratedBinary += " '";
- projectGeneratedBinary += savePath;
+ projectGeneratedBinary += savePathUtf8;
projectGeneratedBinary += "/";
switch(libraryType)
{
@@ -343,7 +495,20 @@ namespace backend
result += ": " + buildJob + " ";
result += join(objectNames, " ");
result += "\n";
- result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' ";
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ {
+ result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' ";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result += " LINK_ARGS = ";
+ break;
+ }
+ }
+
if(!allLinkerFlags.empty())
{
result += allLinkerFlags;
@@ -359,24 +524,56 @@ namespace backend
result += ": " + buildJob + " ";
result += join(objectNames, " ");
result += "\n\n";
- projectGeneratedBinary += config.getPackageName() + ".a";
+
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ {
+ projectGeneratedBinary += config.getPackageName() + ".a";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ projectGeneratedBinary += config.getPackageName() + ".lib";
+ break;
+ }
+ }
break;
}
case LibraryType::DYNAMIC:
{
- result += "build lib";
- result += config.getPackageName();
- result += ".so: " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n";
- result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' ";
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ {
+ result += "build lib";
+ result += config.getPackageName();
+ result += ".so: " + buildJob + " ";
+ result += join(objectNames, " ");
+ result += "\n";
+ result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' ";
+ projectGeneratedBinary += "lib" + config.getPackageName() + ".so";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result += "build ";
+ result += config.getPackageName();
+ result += ".lib: " + buildJob + " ";
+ result += join(objectNames, " ");
+ result += "\n";
+ result += " LINK_ARGS = ";
+ projectGeneratedBinary += config.getPackageName() + ".lib";
+ break;
+ }
+ }
+
if(!allLinkerFlags.empty())
{
result += allLinkerFlags;
//result += " '-Wl,--no-whole-archive'";
}
result += "\n\n";
- projectGeneratedBinary += "lib" + config.getPackageName() + ".so";
break;
}
default:
@@ -389,26 +586,26 @@ namespace backend
if(fileOverwriteResult.isErr())
return fileOverwriteResult;
- printf("Created ninja build file: %s\n", ninjaBuildFilePath.c_str());
+ nprintf(TINYDIR_STRING("Created ninja build file: %s\n"), ninjaBuildFilePath.c_str());
Result<bool> buildResult = build(savePath);
if(!buildResult)
return buildResult;
- Result<bool> buildTestResult = buildTests(projectGeneratedBinary);
+ Result<bool> buildTestResult = buildTests(config, projectGeneratedBinary);
if(!buildTestResult)
return buildTestResult;
return Result<bool>::Ok(true);
}
- const char *sourceFileExtensions[] = { "c", "cc", "cpp", "cxx" };
+ const _tinydir_char_t *sourceFileExtensions[] = { TINYDIR_STRING("c"), TINYDIR_STRING("cc"), TINYDIR_STRING("cpp"), TINYDIR_STRING("cxx") };
bool isSourceFile(tinydir_file *file)
{
if(!file->is_reg)
return false;
- for(const char *sourceFileExtension : sourceFileExtensions)
+ for(const _tinydir_char_t *sourceFileExtension : sourceFileExtensions)
{
if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
return true;
@@ -417,7 +614,7 @@ namespace backend
return false;
}
- Result<bool> Ninja::buildTests(const std::string &projectGeneratedBinary)
+ Result<bool> Ninja::buildTests(const SibsConfig &parentConfig, const std::string &projectGeneratedBinary)
{
if(testSourceDirs.empty())
return Result<bool>::Ok(true);
@@ -428,11 +625,17 @@ namespace backend
for(const string &testSourceDir : testSourceDirs)
{
- string projectConfFilePath = testSourceDir;
- projectConfFilePath += "/project.conf";
+#if OS_FAMILY == OS_FAMILY_POSIX
+ FileString testSourceDirNative = testSourceDir;
+ FileString projectConfFilePath = testSourceDir;
+#else
+ FileString testSourceDirNative = utf8To16(testSourceDir);
+ FileString projectConfFilePath = testSourceDirNative;
+#endif
+ projectConfFilePath += TINYDIR_STRING("/project.conf");
FileType projectConfFileType = getFileType(projectConfFilePath.c_str());
- SibsTestConfig sibsTestConfig(testSourceDir);
+ SibsTestConfig sibsTestConfig(parentConfig.getCompiler(), testSourceDirNative);
if(projectConfFileType == FileType::REGULAR)
{
Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig);
@@ -442,11 +645,12 @@ namespace backend
backend::Ninja ninja;
ninja.addDependency(projectGeneratedBinary);
- walkDirFilesRecursive(testSourceDir.c_str(), [&ninja, &sibsTestConfig](tinydir_file *file)
+ walkDirFilesRecursive(testSourceDirNative.c_str(), [&ninja, &sibsTestConfig](tinydir_file *file)
{
if (isSourceFile(file))
{
- ninja.addSourceFile(file->path + sibsTestConfig.getProjectPath().size() + 1);
+ string filePathUtf8 = toUtf8(file->path + sibsTestConfig.getProjectPath().size() + 1);
+ ninja.addSourceFile(filePathUtf8.c_str());
}
else
{
@@ -456,7 +660,7 @@ namespace backend
if(!ninja.getSourceFiles().empty())
{
- string debugBuildPath = testSourceDir + "/sibs-build/debug";
+ FileString debugBuildPath = testSourceDirNative + TINYDIR_STRING("/sibs-build/debug");
Result<bool> buildFileResult = ninja.build(sibsTestConfig, debugBuildPath.c_str());
if (!buildFileResult)
return buildFileResult;
@@ -470,11 +674,11 @@ namespace backend
return Result<bool>::Ok(true);
}
- Result<bool> Ninja::build(const char *buildFilePath)
+ Result<bool> Ninja::build(const _tinydir_char_t *buildFilePath)
{
- string command = "ninja -C '";
+ FileString command = TINYDIR_STRING("ninja -C \"");
command += buildFilePath;
- command += "'";
+ command += TINYDIR_STRING("\"");
Result<ExecResult> execResult = exec(command.c_str(), true);
if(execResult.isOk())
{