From 45e00fd7c7695adb9d69e8621ab76fdfa085900b Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 5 Oct 2018 07:15:55 +0200 Subject: Fix for windows & mingw --- .gitignore | 1 + README.md | 1 + backend/ninja/Ninja.cpp | 42 ++++++++++++++++++++++++++++++++++--- include/Conf.hpp | 4 ++-- include/FileUtil.hpp | 1 - include/env.hpp | 2 +- scripts/mingw_ldd.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ scripts/mingw_package.py | 31 +++++++++++++++++++++++++++ scripts/package.py | 2 +- src/Conf.cpp | 6 +++--- src/FileUtil.cpp | 29 +------------------------- src/PkgConfig.cpp | 2 +- src/main.cpp | 29 ++++++++++++++++++++------ 13 files changed, 158 insertions(+), 46 deletions(-) create mode 100755 scripts/mingw_ldd.py create mode 100755 scripts/mingw_package.py diff --git a/.gitignore b/.gitignore index 3a593c3..a0c1f8d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ compile_commands.json tests/sibs-build/ tests/compile_commands.json cmake_msvc/ +scripts/__pycache__ \ No newline at end of file diff --git a/README.md b/README.md index 6bee538..d9f2d4c 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Libraries that are downloaded are available at: https://github.com/DEC05EBA/libr # 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. +You can run `scripts/mingw_package.py` to automatically copy dynamic library dependencies of your executable to the same directory as the executable, so the library can be found when running the executable on windows; this also allows you to bundle your application and distribute it without external dependencies. # 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/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 27608cc..bad224a 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -972,7 +972,12 @@ namespace backend ninja::NinjaArg::createRaw("-pipe"), ninja::NinjaArg::createRaw("-D_FILE_OFFSET_BITS=64"), ninja::NinjaArg::createRaw("-Winvalid-pch"), - ninja::NinjaArg::createRaw("-fstack-protector"), + }); + + if(config.getCompiler() != Compiler::MINGW_W64) + compileCCommand.push_back(ninja::NinjaArg::createRaw("-fstack-protector")); + + compileCCommand.insert(compileCCommand.end(), { ninja::NinjaArg::createRaw("-MMD"), ninja::NinjaArg("-I" + config.getPackageName() + "@exe"), ninja::NinjaArg::createRaw("$globalIncDir") @@ -1243,10 +1248,9 @@ 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++"; + packagingFlags = "-static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic"; } } @@ -1346,6 +1350,22 @@ namespace backend }); } #endif + if(config.getCompiler() == Compiler::MINGW_W64) + { + buildExeArgs.insert(buildExeArgs.end(), { + ninja::NinjaArg::createRaw("-lws2_32"), + ninja::NinjaArg::createRaw("-lwldap32"), + ninja::NinjaArg::createRaw("-lcrypt32"), + ninja::NinjaArg::createRaw("-ladvapi32"), + ninja::NinjaArg::createRaw("-lgdi32"), + ninja::NinjaArg::createRaw("-luser32"), + ninja::NinjaArg::createRaw("-luserenv"), + ninja::NinjaArg::createRaw("-lopengl32"), + ninja::NinjaArg::createRaw("-lglu32"), + ninja::NinjaArg::createRaw("-lwinpthread"), + ninja::NinjaArg::createRaw("-lshell32") + }); + } break; } case Compiler::MSVC: @@ -1546,6 +1566,22 @@ namespace backend }); } #endif + if(config.getCompiler() == Compiler::MINGW_W64) + { + buildDynamicArgs.insert(buildDynamicArgs.end(), { + ninja::NinjaArg::createRaw("-lws2_32"), + ninja::NinjaArg::createRaw("-lwldap32"), + ninja::NinjaArg::createRaw("-lcrypt32"), + ninja::NinjaArg::createRaw("-ladvapi32"), + ninja::NinjaArg::createRaw("-lgdi32"), + ninja::NinjaArg::createRaw("-luser32"), + ninja::NinjaArg::createRaw("-luserenv"), + ninja::NinjaArg::createRaw("-lopengl32"), + ninja::NinjaArg::createRaw("-lglu32"), + ninja::NinjaArg::createRaw("-lwinpthread"), + ninja::NinjaArg::createRaw("-lshell32") + }); + } break; } case Compiler::MSVC: diff --git a/include/Conf.hpp b/include/Conf.hpp index 15c8471..3cd8cd5 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -198,13 +198,13 @@ namespace sibs #if OS_TYPE == OS_TYPE_WINDOWS #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_WIN32; - #define SYSTEM_PLATFORM_NAME "win32" + #define SYSTEM_PLATFORM_NAME L"win32" #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 0 #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 1 #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 2 #else const Platform SYSTEM_PLATFORM = PLATFORM_WIN64; - #define SYSTEM_PLATFORM_NAME "win64" + #define SYSTEM_PLATFORM_NAME L"win64" #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 3 #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 4 #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 5 diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp index 0106c19..3e2e302 100644 --- a/include/FileUtil.hpp +++ b/include/FileUtil.hpp @@ -60,7 +60,6 @@ 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/env.hpp b/include/env.hpp index 33e8068..d8b444b 100644 --- a/include/env.hpp +++ b/include/env.hpp @@ -30,7 +30,7 @@ #define WIN32_LEAN_AND_MEAN #endif - #include + #include #endif #ifdef __linux__ diff --git a/scripts/mingw_ldd.py b/scripts/mingw_ldd.py new file mode 100755 index 0000000..f678176 --- /dev/null +++ b/scripts/mingw_ldd.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# WTFPL - Do What the Fuck You Want to Public License +from __future__ import print_function +import pefile +import os +import sys + + +def get_dependency(filename): + deps = [] + pe = pefile.PE(filename) + for imp in pe.DIRECTORY_ENTRY_IMPORT: + deps.append(imp.dll.decode()) + return deps + + +def dep_tree(root, prefix=None): + if not prefix: + arch = get_arch(root) + #print('Arch =', arch) + prefix = '/usr/'+arch+'-w64-mingw32/bin' + #print('Using default prefix', prefix) + dep_dlls = dict() + + def dep_tree_impl(root, prefix): + for dll in get_dependency(root): + if dll in dep_dlls: + continue + full_path = os.path.join(prefix, dll) + if os.path.exists(full_path): + dep_dlls[dll] = full_path + dep_tree_impl(full_path, prefix=prefix) + else: + dep_dlls[dll] = 'not found' + + dep_tree_impl(root, prefix) + return (dep_dlls) + + +def get_arch(filename): + type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686', + pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'} + pe = pefile.PE(filename) + try: + return type2arch[pe.PE_TYPE] + except KeyError: + sys.stderr.write('Error: unknown architecture') + sys.exit(1) + +if __name__ == '__main__': + filename = sys.argv[1] + for dll, full_path in dep_tree(filename).items(): + print(' ' * 7, dll, '=>', full_path) + diff --git a/scripts/mingw_package.py b/scripts/mingw_package.py new file mode 100755 index 0000000..b304128 --- /dev/null +++ b/scripts/mingw_package.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +import sys +import os +import mingw_ldd +import shutil + +def usage(): + print("usage: mingw-package.py ") + exit(1) + +def main(): + if len(sys.argv) != 2: + usage() + + executable_path = sys.argv[1] + if not os.path.isfile(executable_path): + print("arg executable_path is not a file or it's a directory") + exit(2) + executable_path = os.path.realpath(executable_path) + executable_dir = os.path.dirname(executable_path) + + print("Checking dynamic library dependencies of %s..." % executable_path) + deps = mingw_ldd.dep_tree(executable_path) + for dll, full_path in deps.items(): + if full_path != "not found": + print("Copying %s to %s" % (dll, executable_dir)) + shutil.copyfile(full_path, os.path.join(executable_dir, dll)) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/package.py b/scripts/package.py index e3a6c52..6e861d9 100755 --- a/scripts/package.py +++ b/scripts/package.py @@ -95,7 +95,7 @@ def remove_blacklisted_libs(libs): return new_libs def main(): - if len(sys.argv) <= 4: + if len(sys.argv) != 5: usage() script_dir = os.path.dirname(os.path.realpath(sys.argv[0])) diff --git a/src/Conf.cpp b/src/Conf.cpp index aabb957..38774e0 100644 --- a/src/Conf.cpp +++ b/src/Conf.cpp @@ -486,12 +486,12 @@ namespace sibs return Result::Err(errMsg); } - if (!containsPlatform(config.getPlatforms(), SYSTEM_PLATFORM)) + if (!containsPlatform(config.getPlatforms(), config.platform)) { string errMsg = "The project "; errMsg += config.getPackageName(); - errMsg += " does not support your platform ("; - errMsg += asString(SYSTEM_PLATFORM); + errMsg += " does not support your target platform ("; + errMsg += asString(config.platform); errMsg += ")"; return Result::Err(errMsg); } diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp index e317304..ae24996 100644 --- a/src/FileUtil.cpp +++ b/src/FileUtil.cpp @@ -1,6 +1,5 @@ #include "../include/FileUtil.hpp" #include -#include #if OS_FAMILY == OS_FAMILY_POSIX #include @@ -8,7 +7,7 @@ #include #include #else -#include +#include // Copied from linux libc sys/stat.h: #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) @@ -498,30 +497,4 @@ 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/PkgConfig.cpp b/src/PkgConfig.cpp index 9efc238..e8f742c 100644 --- a/src/PkgConfig.cpp +++ b/src/PkgConfig.cpp @@ -4,7 +4,7 @@ using namespace std; -static sibs::FileString pkgConfigPath = "pkg-config"; +static sibs::FileString pkgConfigPath = TINYDIR_STRING("pkg-config"); // TODO: Do not use pkg-config program. The same functionality can easily be achieved // by reading files in /usr/share/pkgconfig diff --git a/src/main.cpp b/src/main.cpp index 3ffb264..29f6ba3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1144,22 +1144,31 @@ static int packageProject(int argc, const _tinydir_char_t **argv) case PackagingType::BUNDLE: case PackagingType::BUNDLE_INSTALL: { - const char *bundleType = nullptr; + const _tinydir_char_t *bundleType = nullptr; switch(packagingType) { case PackagingType::BUNDLE: - bundleType = "--bundle"; + bundleType = TINYDIR_STRING("--bundle"); break; case PackagingType::BUNDLE_INSTALL: - bundleType = "--bundle-install"; + bundleType = TINYDIR_STRING("--bundle-install"); break; } - string packagePath = toUtf8(projectPath + TINYDIR_STRING("/sibs-build/package")); - string executablePath = toUtf8(projectPath + TINYDIR_STRING("/sibs-build/release/") + sibsConfig.getPackageName()); + FileString packagePath = projectPath + TINYDIR_STRING("/sibs-build/package"); + FileString executablePath = projectPath + TINYDIR_STRING("/sibs-build/release/") + toFileString(sibsConfig.getPackageName()); printf("Creating a package from project and dependencies...\n"); // args: executable_path program_version destination_path <--bundle|--bundle-install> - FileString cmd = "python3 \"" + packageScriptPath + "\" \"" + executablePath + "\" \"" + sibsConfig.version + "\" \"" + packagePath + "\" " + bundleType; + FileString cmd = TINYDIR_STRING("python3 \"") + + packageScriptPath + + TINYDIR_STRING("\" \"") + + executablePath + + TINYDIR_STRING("\" \"") + + toFileString(sibsConfig.version) + + TINYDIR_STRING("\" \"") + + packagePath + + TINYDIR_STRING("\" ") + + bundleType; Result bundleResult = exec(cmd.c_str(), true); if(!bundleResult) { @@ -1413,3 +1422,11 @@ int wmain(int argc, const _tinydir_char_t **argv) usage(); return 0; } + +// Mingw needs this +#if OS_FAMILY == OS_FAMILY_WINDOWS +int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + return wmain(__argc, (const _tinydir_char_t**)__wargv); +} +#endif \ No newline at end of file -- cgit v1.2.3