From 5250cb90406693163763a214af95f670e0e3a4e0 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 5 Oct 2018 05:02:49 +0200 Subject: Add cross compilation (mingw-w64 x86_64) Currently only cross compiling from linux64 to win64 works. Need to test cross compilation more, currently the cross compilation uses same profile as GCC, is that correct? --- README.md | 3 + backend/BackendUtils.cpp | 3 + backend/ninja/Ninja.cpp | 148 ++++++++++++++++++++++++------ examples/hello_lua/.gitignore | 5 + examples/hello_lua/hello.lua | 1 + examples/hello_lua/project.conf | 8 ++ examples/hello_lua/src/main.cpp | 31 +++++++ examples/hello_lua_mingw_w64/.gitignore | 5 + examples/hello_lua_mingw_w64/README.md | 1 + examples/hello_lua_mingw_w64/hello.lua | 1 + examples/hello_lua_mingw_w64/project.conf | 8 ++ examples/hello_lua_mingw_w64/run.sh | 8 ++ examples/hello_lua_mingw_w64/src/main.cpp | 32 +++++++ include/Conf.hpp | 7 +- include/FileUtil.hpp | 1 + include/PkgConfig.hpp | 2 + include/Platform.hpp | 1 + src/FileUtil.cpp | 27 ++++++ src/GlobalLib.cpp | 2 + src/PkgConfig.cpp | 17 +++- src/Platform.cpp | 5 + src/main.cpp | 53 ++++++++++- 22 files changed, 330 insertions(+), 39 deletions(-) create mode 100644 examples/hello_lua/.gitignore create mode 100644 examples/hello_lua/hello.lua create mode 100644 examples/hello_lua/project.conf create mode 100644 examples/hello_lua/src/main.cpp create mode 100644 examples/hello_lua_mingw_w64/.gitignore create mode 100644 examples/hello_lua_mingw_w64/README.md create mode 100644 examples/hello_lua_mingw_w64/hello.lua create mode 100644 examples/hello_lua_mingw_w64/project.conf create mode 100755 examples/hello_lua_mingw_w64/run.sh create mode 100644 examples/hello_lua_mingw_w64/src/main.cpp diff --git a/README.md b/README.md index 1b24b35..6bee538 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,9 @@ The package command also comes with --bundle-install option which reduces the si Users are required to manually install some libraries as they can't be included in a distributed package (install with their package manager). These libraries are commonly gpu driver libraries, which vary even if you have the same cpu architecture. This requirement might be removed later, if the gpu driver libraries required can somehow be detected and downloaded cross platform. Libraries that are downloaded are available at: https://github.com/DEC05EBA/libraries +# Cross compilation +Cross compilation currently only works from linux64 to win64 by using mingw-w64. You need to install `mingw-w64-gcc` and optionally `mingw-w64-pkg-config` if you want to use mingw-w64 system installed packages. +Cross compilation does currently not work if you have zig files as zig doesn't support libc when cross compiling at the moment. # IDE support Sibs generates a compile_commands.json in the project root directory when executing `sibs build` and tools that support clang completion can be used, such as YouCompleteMe. There are several editors that support YouCompleteMe, including Vim, Emacs and Visual Studio Code. Visual studio code now also supports clang completion with C/C++ extension by Microsoft; the extension will ask you which compile_commands.json file you want to use and you can choose the compile_commands.json in the project root directory. diff --git a/backend/BackendUtils.cpp b/backend/BackendUtils.cpp index 92a73ef..d5fad04 100644 --- a/backend/BackendUtils.cpp +++ b/backend/BackendUtils.cpp @@ -109,6 +109,9 @@ namespace backend 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); diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 4495bd4..27608cc 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -98,6 +98,7 @@ namespace backend string result; switch (compiler) { + case Compiler::MINGW_W64: case Compiler::GCC: { result = "'-I"; @@ -123,6 +124,7 @@ namespace backend { switch (compiler) { + case Compiler::MINGW_W64: case Compiler::GCC: { return "'-D" + name + "=" + value + "'"; @@ -143,6 +145,7 @@ namespace backend string result; switch (compiler) { + case Compiler::MINGW_W64: case Compiler::GCC: { result = "-o "; @@ -166,6 +169,7 @@ namespace backend { switch (compiler) { + case Compiler::MINGW_W64: case Compiler::GCC: { switch(cVersion) @@ -193,6 +197,7 @@ namespace backend { switch (compiler) { + case Compiler::MINGW_W64: case Compiler::GCC: { switch(cppVersion) @@ -223,6 +228,7 @@ namespace backend { switch (compiler) { + case Compiler::MINGW_W64: case Compiler::GCC: return ".o"; case Compiler::MSVC: return ".obj"; default: return nullptr; @@ -387,6 +393,7 @@ namespace backend { switch (config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { switch (config.getOptimizationLevel()) @@ -460,6 +467,7 @@ namespace backend switch (compiler) { + case Compiler::MINGW_W64: case Compiler::GCC: { includeStartStr = "-I"; @@ -693,6 +701,60 @@ namespace backend return result; } + static string getCompilerCExecutable(Compiler compiler) + { + string result; + switch(compiler) + { + case Compiler::GCC: + result = "cc"; + break; + case Compiler::MINGW_W64: + result = "x86_64-w64-mingw32-cc"; + break; + case Compiler::MSVC: + result = "cl.exe"; + break; + } + return result; + } + + static string getCompilerCppExecutable(Compiler compiler) + { + string result; + switch(compiler) + { + case Compiler::GCC: + result = "c++"; + break; + case Compiler::MINGW_W64: + result = "x86_64-w64-mingw32-c++"; + break; + case Compiler::MSVC: + result = "cl.exe"; + break; + } + return result; + } + + static string getCompilerLinker(Compiler compiler) + { + string result; + switch(compiler) + { + case Compiler::GCC: + result = "ar"; + break; + case Compiler::MINGW_W64: + result = "x86_64-w64-mingw32-ar"; + break; + case Compiler::MSVC: + result = "lib.exe"; + break; + } + return result; + } + Result Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) { bool isCCompilerClang = false; @@ -734,6 +796,10 @@ namespace backend FileString ninjaBuildFilePath = savePath; ninjaBuildFilePath += TINYDIR_STRING("/build.ninja"); + string cCompilerName = getCompilerCExecutable(config.getCompiler()); + string cppCompilerName = getCompilerCppExecutable(config.getCompiler()); + string compilerLinker = getCompilerLinker(config.getCompiler()); + ninja::NinjaBuildFile ninjaBuildFile; string globalIncDir; @@ -764,12 +830,10 @@ namespace backend parentGlobalIncludeDirCallback(globalIncludeDir); }; -#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 + string allLinkerFlags; + if(isSamePlatformFamily(config.platform, PLATFORM_LINUX)) + allLinkerFlags = "-pthread"; // 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 @@ -866,6 +930,7 @@ namespace backend switch(config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { vector baseCompileCArgs; @@ -875,7 +940,7 @@ namespace backend { baseCompileCArgs.insert(baseCompileCArgs.end(), { ninja::NinjaArg("ccache"), - ninja::NinjaArg("cc"), + ninja::NinjaArg(cCompilerName), ninja::NinjaArg("-c"), ninja::NinjaArg("-fpie"), ninja::NinjaArg("$in"), @@ -889,7 +954,7 @@ namespace backend { baseCompileCArgs.insert(baseCompileCArgs.end(), { ninja::NinjaArg("ccache"), - ninja::NinjaArg("cc"), + ninja::NinjaArg(cCompilerName), ninja::NinjaArg("-c"), ninja::NinjaArg("-fpic"), ninja::NinjaArg("$in"), @@ -936,7 +1001,7 @@ namespace backend compileCCommand.insert(compileCCommand.end(), sanitizerFlags.begin(), sanitizerFlags.end()); compileCppCommand = compileCCommand; - compileCppCommand[1] = ninja::NinjaArg("c++"); + compileCppCommand[1] = ninja::NinjaArg(cppCompilerName); compileCppCommand.insert(compileCppCommand.end(), { ninja::NinjaArg("-fexceptions"), ninja::NinjaArg("-Wnon-virtual-dtor") @@ -1001,6 +1066,7 @@ namespace backend switch(config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { compileCRule->depFile = "$out.d"; @@ -1015,6 +1081,8 @@ namespace backend } } + bool crossOsCompiling = !isSamePlatformFamily(config.platform, SYSTEM_PLATFORM); + // TODO: Specify -mconsole or -mwindows for windows. // TODO: Convert sibs defines to const variables in a zig file that other zig files can include (like a config file). @@ -1026,6 +1094,9 @@ namespace backend ninja::NinjaArg::createRaw("$globalIncDirZig") }; + if(isSamePlatformFamily(SYSTEM_PLATFORM, PLATFORM_LINUX) && isSamePlatformFamily(config.platform, PLATFORM_WIN)) + commonZigArgs.push_back(ninja::NinjaArg::createRaw("--target-os windows --target-arch x86_64 --target-environ gnu --libc-lib-dir /usr/x86_64-w64-mingw32/lib --libc-static-lib-dir /usr/x86_64-w64-mingw32/lib")); + // TODO: Remove this if project does not depend on c libraries or project only has .zig files if(!config.packaging) commonZigArgs.push_back(ninja::NinjaArg::createRaw("--library c")); @@ -1112,6 +1183,7 @@ namespace backend onlyZigFiles = false; } + bool containsZigFiles = false; for(const sibs::SourceFile &sourceFile : sourceFiles) { string objectName; @@ -1136,6 +1208,7 @@ namespace backend case sibs::Language::ZIG: { // Already built above + containsZigFiles = true; break; } default: @@ -1147,11 +1220,15 @@ namespace backend objectNames.emplace_back(move(objectName)); } + if(containsZigFiles && isSamePlatformFamily(config.platform, PLATFORM_WIN) && !isSamePlatformFamily(SYSTEM_PLATFORM, PLATFORM_WIN)) + return Result::Err("Cross compiling a project with zig files from a non-windows platform to windows is currently not supported because zig doesn't support libc when cross compiling"); + string packagingFlags; if(config.packaging) { switch(config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { packagingFlags = "-static -static-libgcc -static-libstdc++"; @@ -1164,6 +1241,14 @@ namespace backend } } } + else + { + // By statically compiling when using mingw w64, we dont have to bundle our application with several runtime dlls + if(config.getCompiler() == Compiler::MINGW_W64) + { + packagingFlags = "-static -static-libgcc -static-libstdc++"; + } + } // TODO: For now zig projects (zig object files) are built with c/c++ compiler, // they should be built with zig if project only contains zig files. @@ -1196,7 +1281,7 @@ namespace backend { vector buildExeArgs; string executableName = config.getPackageName(); - if(OS_FAMILY == OS_FAMILY_WINDOWS) + if(isSamePlatformFamily(config.platform, PLATFORM_WIN)) executableName += ".exe"; if(onlyZigFiles) { @@ -1218,12 +1303,13 @@ namespace backend { switch (config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { string rpath = extractDynamicLibDirsFromLinkerFlags(dynamicLinkerFlags); buildExeArgs.insert(buildExeArgs.end(), { ninja::NinjaArg::createRaw("ccache"), - ninja::NinjaArg::createRaw(usesCppFiles ? "c++" : "cc"), + ninja::NinjaArg::createRaw(usesCppFiles ? cppCompilerName : cCompilerName), ninja::NinjaArg::createRaw("-o"), ninja::NinjaArg::createRaw("$out"), ninja::NinjaArg::createRaw("$in"), @@ -1252,10 +1338,13 @@ namespace backend ninja::NinjaArg::createRaw("-lm") }); #else - buildExeArgs.insert(buildExeArgs.end(), { - ninja::NinjaArg::createRaw("-ldl"), - ninja::NinjaArg::createRaw("-lm") - }); + if(!isSamePlatformFamily(config.platform, PLATFORM_WIN)) + { + buildExeArgs.insert(buildExeArgs.end(), { + ninja::NinjaArg::createRaw("-ldl"), + ninja::NinjaArg::createRaw("-lm") + }); + } #endif break; } @@ -1263,7 +1352,7 @@ namespace backend { // TODO: Do not link all of these. Find a way to only link the ones that are needed buildExeArgs.insert(buildExeArgs.end(), { - ninja::NinjaArg::createRaw("cl.exe"), + ninja::NinjaArg::createRaw(cppCompilerName), ninja::NinjaArg::createRaw("$in"), ninja::NinjaArg::createRaw("/Fe$out"), ninja::NinjaArg::createRaw("Ws2_32.lib"), @@ -1299,10 +1388,7 @@ namespace backend buildExeRule->build(objectNames, executableName, {}); } - projectGeneratedBinary += config.getPackageName(); - #if OS_FAMILY == OS_FAMILY_WINDOWS - projectGeneratedBinary += ".exe"; - #endif + projectGeneratedBinary += executableName; projectGeneratedBinary += "\""; break; } @@ -1312,6 +1398,7 @@ namespace backend string generatedFile; switch (config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { generatedFile = "lib" + config.getPackageName() + ".a"; @@ -1341,10 +1428,11 @@ namespace backend { switch (config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { buildStaticArgs.insert(buildStaticArgs.end(), { - ninja::NinjaArg::createRaw("ar"), + ninja::NinjaArg::createRaw(compilerLinker), ninja::NinjaArg::createRaw("rcs"), ninja::NinjaArg::createRaw("$out"), ninja::NinjaArg::createRaw("$in") @@ -1354,7 +1442,7 @@ namespace backend case Compiler::MSVC: { buildStaticArgs.insert(buildStaticArgs.end(), { - ninja::NinjaArg::createRaw("lib.exe"), + ninja::NinjaArg::createRaw(compilerLinker), ninja::NinjaArg::createRaw("/OUT:$out"), ninja::NinjaArg::createRaw("$in") }); @@ -1389,6 +1477,7 @@ namespace backend string generatedFile; switch (config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { generatedFile = "lib" + config.getPackageName() + ".so"; @@ -1421,11 +1510,12 @@ namespace backend { switch (config.getCompiler()) { + case Compiler::MINGW_W64: case Compiler::GCC: { buildDynamicArgs.insert(buildDynamicArgs.end(), { ninja::NinjaArg::createRaw("ccache"), - ninja::NinjaArg::createRaw(usesCppFiles ? "c++" : "cc"), + ninja::NinjaArg::createRaw(usesCppFiles ? cppCompilerName : cCompilerName), ninja::NinjaArg::createRaw("$in"), ninja::NinjaArg::createRaw("-shared"), ninja::NinjaArg("-Wl,-soname," + generatedFile), @@ -1448,17 +1538,20 @@ namespace backend ninja::NinjaArg::createRaw("-lm") }); #else - buildDynamicArgs.insert(buildDynamicArgs.end(), { - ninja::NinjaArg::createRaw("-ldl"), - ninja::NinjaArg::createRaw("-lm") - }); + if(!isSamePlatformFamily(config.platform, PLATFORM_WIN)) + { + buildDynamicArgs.insert(buildDynamicArgs.end(), { + ninja::NinjaArg::createRaw("-ldl"), + ninja::NinjaArg::createRaw("-lm") + }); + } #endif break; } case Compiler::MSVC: { buildDynamicArgs.insert(buildDynamicArgs.end(), { - ninja::NinjaArg::createRaw("lib.exe"), + ninja::NinjaArg::createRaw(compilerLinker), ninja::NinjaArg::createRaw("/OUT:$out"), ninja::NinjaArg::createRaw("$in"), ninja::NinjaArg::createRaw("Ws2_32.lib"), @@ -1567,6 +1660,7 @@ namespace backend FileType projectConfFileType = getFileType(projectConfFilePath.c_str()); SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative, config.getOptimizationLevel()); + sibsTestConfig.platform = config.platform; sibsTestConfig.setSanitize(config.getSanitize()); sibsTestConfig.zigTestFiles = move(config.zigTestFiles); sibsTestConfig.zigTestAllFiles = config.zigTestAllFiles; diff --git a/examples/hello_lua/.gitignore b/examples/hello_lua/.gitignore new file mode 100644 index 0000000..636c6b9 --- /dev/null +++ b/examples/hello_lua/.gitignore @@ -0,0 +1,5 @@ +# Compiled sibs files +sibs-build/ +compile_commands.json +tests/sibs-build/ +tests/compile_commands.json diff --git a/examples/hello_lua/hello.lua b/examples/hello_lua/hello.lua new file mode 100644 index 0000000..4601856 --- /dev/null +++ b/examples/hello_lua/hello.lua @@ -0,0 +1 @@ +print("inside lua!") diff --git a/examples/hello_lua/project.conf b/examples/hello_lua/project.conf new file mode 100644 index 0000000..e416497 --- /dev/null +++ b/examples/hello_lua/project.conf @@ -0,0 +1,8 @@ +[package] +name = "hello_lua" +type = "executable" +version = "0.1.0" +platforms = ["any"] + +[dependencies] +lua51 = "5.1.5" diff --git a/examples/hello_lua/src/main.cpp b/examples/hello_lua/src/main.cpp new file mode 100644 index 0000000..57f9194 --- /dev/null +++ b/examples/hello_lua/src/main.cpp @@ -0,0 +1,31 @@ +#include +extern "C" { +#include +#include +#include +} +int main(int argc, char *argv[]) { + // Open lua + lua_State *L = lua_open(); + + // Load the libraries + luaL_openlibs(L); + + // Execution of a lua string + luaL_dostring(L, "print \"Yo dude\""); + + // Load a string and then execute it. + luaL_loadstring(L, "io.write(\"I'm here too\\n\")"); + lua_pcall(L, 0, LUA_MULTRET, 0); + + // Load from a file and then execute + if (luaL_loadfile(L, "hello.lua") == 0) { + // File loaded call it + lua_pcall(L, 0, LUA_MULTRET, 0); + } + + // Close lua + lua_close (L); + + return 0; +} diff --git a/examples/hello_lua_mingw_w64/.gitignore b/examples/hello_lua_mingw_w64/.gitignore new file mode 100644 index 0000000..636c6b9 --- /dev/null +++ b/examples/hello_lua_mingw_w64/.gitignore @@ -0,0 +1,5 @@ +# Compiled sibs files +sibs-build/ +compile_commands.json +tests/sibs-build/ +tests/compile_commands.json diff --git a/examples/hello_lua_mingw_w64/README.md b/examples/hello_lua_mingw_w64/README.md new file mode 100644 index 0000000..524476d --- /dev/null +++ b/examples/hello_lua_mingw_w64/README.md @@ -0,0 +1 @@ +This is an example of using system lua5.1 package (pkg-config). diff --git a/examples/hello_lua_mingw_w64/hello.lua b/examples/hello_lua_mingw_w64/hello.lua new file mode 100644 index 0000000..4601856 --- /dev/null +++ b/examples/hello_lua_mingw_w64/hello.lua @@ -0,0 +1 @@ +print("inside lua!") diff --git a/examples/hello_lua_mingw_w64/project.conf b/examples/hello_lua_mingw_w64/project.conf new file mode 100644 index 0000000..b568575 --- /dev/null +++ b/examples/hello_lua_mingw_w64/project.conf @@ -0,0 +1,8 @@ +[package] +name = "hello_lua" +type = "executable" +version = "0.1.0" +platforms = ["any"] + +[dependencies] +lua5.1 = "5.1.5" diff --git a/examples/hello_lua_mingw_w64/run.sh b/examples/hello_lua_mingw_w64/run.sh new file mode 100755 index 0000000..0f23a37 --- /dev/null +++ b/examples/hello_lua_mingw_w64/run.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e + +script_path=`readlink -f $0` +script_dir=`dirname $script_path` +cd "$script_dir" +sibs build --platform win64 && ./sibs-build/debug/hello_lua.exe diff --git a/examples/hello_lua_mingw_w64/src/main.cpp b/examples/hello_lua_mingw_w64/src/main.cpp new file mode 100644 index 0000000..1486b98 --- /dev/null +++ b/examples/hello_lua_mingw_w64/src/main.cpp @@ -0,0 +1,32 @@ +// Example taken from http://lua-users.org/lists/lua-l/2010-06/msg00153.html +#include +extern "C" { +#include +#include +#include +} +int main(int argc, char *argv[]) { + // Open lua + lua_State *L = lua_open(); + + // Load the libraries + luaL_openlibs(L); + + // Execution of a lua string + luaL_dostring(L, "print \"Yo dude\""); + + // Load a string and then execute it. + luaL_loadstring(L, "io.write(\"I'm here too\\n\")"); + lua_pcall(L, 0, LUA_MULTRET, 0); + + // Load from a file and then execute + if (luaL_loadfile(L, "hello.lua") == 0) { + // File loaded call it + lua_pcall(L, 0, LUA_MULTRET, 0); + } + + // Close lua + lua_close (L); + + return 0; +} diff --git a/include/Conf.hpp b/include/Conf.hpp index 17ecc6b..15c8471 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -107,7 +107,8 @@ namespace sibs enum class Compiler { GCC, - MSVC + MSVC, + MINGW_W64 }; enum class CVersion @@ -303,7 +304,8 @@ namespace sibs showWarnings(false), zigTestAllFiles(false), packaging(false), - bundling(false) + bundling(false), + platform(SYSTEM_PLATFORM) { cmakeDirGlobal = projectPath; cmakeDirStatic = cmakeDirGlobal; @@ -504,6 +506,7 @@ namespace sibs bool packaging; bool bundling; std::string version; + Platform platform; protected: virtual void processObject(StringView name) override; virtual void processField(StringView name, const ConfigValue &value) override; diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp index 3e2e302..0106c19 100644 --- a/include/FileUtil.hpp +++ b/include/FileUtil.hpp @@ -60,6 +60,7 @@ namespace sibs Result getRealPath(const _tinydir_char_t *path); bool pathEquals(const std::string &path, const std::string &otherPath); Result getFileLastModifiedTime(const _tinydir_char_t *path); + Result copyFile(const FileString &src, const FileString &dst); } #endif //SIBS_FILEUTIL_HPP diff --git a/include/PkgConfig.hpp b/include/PkgConfig.hpp index 2a52f2b..9181a2f 100644 --- a/include/PkgConfig.hpp +++ b/include/PkgConfig.hpp @@ -5,6 +5,7 @@ #include "Result.hpp" #include #include +#include "FileUtil.hpp" namespace sibs { @@ -19,6 +20,7 @@ namespace sibs class PkgConfig { public: + static void setPkgConfigPath(const FileString &path); static Result validatePkgConfigPackageVersionExists(PackageListDependency *dependency); static Result validatePackageExists(const std::string &name); static Result validatePackageVersionAtLeast(const std::string &name, const std::string &version); diff --git a/include/Platform.hpp b/include/Platform.hpp index 995d307..74b3a3d 100644 --- a/include/Platform.hpp +++ b/include/Platform.hpp @@ -50,4 +50,5 @@ namespace sibs bool containsPlatform(const std::vector &platforms, Platform platform); const char* asString(Platform platform); Platform getPlatformByName(StringView name); + bool isSamePlatformFamily(Platform a, Platform b); } \ No newline at end of file diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp index 498f638..e317304 100644 --- a/src/FileUtil.cpp +++ b/src/FileUtil.cpp @@ -1,5 +1,6 @@ #include "../include/FileUtil.hpp" #include +#include #if OS_FAMILY == OS_FAMILY_POSIX #include @@ -497,4 +498,30 @@ namespace sibs return pathIndex == path.size() && otherPathIndex == otherPath.size(); } + + Result copyFile(const FileString &src, const FileString &dst) + { + ifstream srcFile(src.c_str(), ios::binary); + if(!srcFile) + { + string errMsg = "Failed to open file "; + errMsg += toUtf8(src); + errMsg += ", reason: "; + errMsg += strerror(errno); + return Result::Err(errMsg); + } + + ofstream dstFile(dst.c_str(), ios::binary); + if(!dstFile) + { + string errMsg = "Failed to create/overwrite file "; + errMsg += toUtf8(dst); + errMsg += ", reason: "; + errMsg += strerror(errno); + return Result::Err(errMsg); + } + + dstFile << srcFile.rdbuf(); + return Result::Ok(true); + } } diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp index a175e02..242e621 100644 --- a/src/GlobalLib.cpp +++ b/src/GlobalLib.cpp @@ -202,7 +202,9 @@ namespace sibs } SibsConfig sibsConfig(parentConfig.getCompiler(), packageDir, parentConfig.getOptimizationLevel(), false); + sibsConfig.platform = parentConfig.platform; sibsConfig.packaging = parentConfig.packaging; + sibsConfig.bundling = parentConfig.bundling; Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if (result.isErr()) return result; diff --git a/src/PkgConfig.cpp b/src/PkgConfig.cpp index faed146..9efc238 100644 --- a/src/PkgConfig.cpp +++ b/src/PkgConfig.cpp @@ -4,12 +4,14 @@ using namespace std; +static sibs::FileString pkgConfigPath = "pkg-config"; + // TODO: Do not use pkg-config program. The same functionality can easily be achieved // by reading files in /usr/share/pkgconfig // Or is there no downside to calling pkg-config program? namespace sibs { - string trimRight(const string &input) + static string trimRight(const string &input) { for(int i = input.size() - 1; i >= 0; --i) { @@ -18,6 +20,11 @@ namespace sibs } return ""; } + + void PkgConfig::setPkgConfigPath(const FileString &path) + { + pkgConfigPath = path; + } Result PkgConfig::validatePkgConfigPackageVersionExists(PackageListDependency *dependency) { @@ -34,7 +41,7 @@ namespace sibs Result PkgConfig::validatePackageExists(const string &name) { - FileString command = TINYDIR_STRING("pkg-config --exists '"); + FileString command = pkgConfigPath + TINYDIR_STRING(" --exists '"); command += toFileString(name); command += TINYDIR_STRING("'"); Result execResult = exec(command.c_str()); @@ -68,7 +75,7 @@ namespace sibs // Use --modversion instead and check if the version returned is newer or equal to dependency version. // This way we can output installed version vs expected dependency version - FileString command = TINYDIR_STRING("pkg-config '--atleast-version="); + FileString command = pkgConfigPath + TINYDIR_STRING(" '--atleast-version="); command += toFileString(version); command += TINYDIR_STRING("' '"); command += toFileString(name); @@ -111,7 +118,7 @@ namespace sibs args += "'"; } - FileString command = TINYDIR_STRING("pkg-config --libs"); + FileString command = pkgConfigPath + TINYDIR_STRING(" --libs"); command += toFileString(args); Result execResult = exec(command.c_str()); if(execResult.isErr()) @@ -154,7 +161,7 @@ namespace sibs args += "'"; } - FileString command = TINYDIR_STRING("pkg-config --cflags"); + FileString command = pkgConfigPath + TINYDIR_STRING(" --cflags"); command += toFileString(args); Result execResult = exec(command.c_str()); if(execResult.isErr()) diff --git a/src/Platform.cpp b/src/Platform.cpp index 44f42db..2df019c 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -41,4 +41,9 @@ namespace sibs return it->second; return PLATFORM_INVALID; } + + bool isSamePlatformFamily(Platform a, Platform b) + { + return a & b; + } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index e55014e..3ffb264 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include "../include/CmakeModule.hpp" #include "../backend/BackendUtils.hpp" #include "../backend/ninja/Ninja.hpp" +#include "../include/PkgConfig.hpp" using namespace std; using namespace sibs; @@ -118,18 +119,20 @@ static void usage() static void usageBuild() { - printf("Usage: sibs build [project_path] [--debug|--release] [--sanitize]\n\n"); + printf("Usage: sibs build [project_path] [--debug|--release] [--sanitize] [--platform ]\n\n"); printf("Build a sibs project\n\n"); printf("Options:\n"); printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current directory)\n"); printf(" --debug|--release\t\tOptimization level to build project and dependencies with (if not a system package) - Optional (default: --debug)\n"); printf(" --sanitize\t\tAdd runtime address/undefined behavior sanitization. Program can be up to 3 times slower and use 10 times as much RAM. Ignored if compiler doesn't support sanitization - Optional (default: disabled)\n"); + printf(" --platform\t\tThe platform to build for - Optional (default: the running platform). Platform can be either linux32, linux64, win32 or win64\n"); printf("Examples:\n"); printf(" sibs build\n"); printf(" sibs build dirA/dirB\n"); printf(" sibs build --release\n"); printf(" sibs build dirA --release\n"); printf(" sibs build --sanitize\n"); + printf(" sibs build --release --platform win64\n"); exit(1); } @@ -150,7 +153,7 @@ static void usageNew() static void usageTest() { - printf("Usage: sibs test [project_path] [--no-sanitize] [--file filepath...|--all-files]\n\n"); + printf("Usage: sibs test [project_path] [--no-sanitize] [--file ...|--all-files]\n\n"); printf("Build and run tests for a sibs project\n\n"); printf("Options:\n"); printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current directory)\n"); @@ -428,12 +431,10 @@ static int buildProject(const FileString &projectPath, const FileString &project static int buildProject(int argc, const _tinydir_char_t **argv) { - if(argc > 3) - usageBuild(); - OptimizationLevel optimizationLevel = OPT_LEV_NONE; FileString projectPath; bool sanitize = false; + const _tinydir_char_t *platformName = nullptr; for(int i = 0; i < argc; ++i) { @@ -460,6 +461,24 @@ static int buildProject(int argc, const _tinydir_char_t **argv) { sanitize = true; } + else if(_tinydir_strcmp(arg, TINYDIR_STRING("--platform")) == 0) + { + if(i == argc - 1) + { + ferr << "Error: Expected platform to target after --platform" << endl; + usageBuild(); + } + + ++i; + arg = argv[i]; + + if(platformName) + { + ferr << "Error: Platform defined twice. First as " << platformName << " then as " << arg << endl; + usageBuild(); + } + platformName = arg; + } else if(_tinydir_strncmp(arg, TINYDIR_STRING("--"), 2) == 0) { ferr << "Error: Invalid argument " << arg << endl; @@ -479,6 +498,24 @@ static int buildProject(int argc, const _tinydir_char_t **argv) if(optimizationLevel == OPT_LEV_NONE) optimizationLevel = OPT_LEV_DEBUG; + if(!platformName) + platformName = SYSTEM_PLATFORM_NAME; + + string platformUtf8 = toUtf8(platformName); + Platform platform = getPlatformByName(StringView(platformUtf8.data(), platformUtf8.size())); + if(platform == PLATFORM_INVALID) + { + ferr << "Invalid platform " << platformName << endl; + usageBuild(); + } + + bool crossCompileLinux64ToWin64 = (SYSTEM_PLATFORM == PLATFORM_LINUX64 && platform == PLATFORM_WIN64); + if(platform != SYSTEM_PLATFORM && !crossCompileLinux64ToWin64) + { + ferr << "Cross compilation is currently only supported from linux64 to win64" << endl; + exit(33); + } + // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found if(projectPath.empty()) projectPath = TINYDIR_STRING("."); @@ -503,12 +540,18 @@ static int buildProject(int argc, const _tinydir_char_t **argv) // by passing argument to `sibs build` #if OS_FAMILY == OS_FAMILY_POSIX Compiler compiler = Compiler::GCC; + if(crossCompileLinux64ToWin64) + { + compiler = Compiler::MINGW_W64; + PkgConfig::setPkgConfigPath(TINYDIR_STRING("x86_64-w64-mingw32-pkg-config")); + } #else Compiler compiler = Compiler::MSVC; #endif SibsConfig sibsConfig(compiler, projectPath, optimizationLevel, false); sibsConfig.showWarnings = true; + sibsConfig.platform = platform; sibsConfig.setSanitize(sanitize); return buildProject(projectPath, projectConfFilePath, sibsConfig); } -- cgit v1.2.3