diff options
author | dec05eba <dec05eba@protonmail.com> | 2018-10-30 13:35:36 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-07-06 07:39:33 +0200 |
commit | 31899d0a48108515d13508b660fb3bb82b869430 (patch) | |
tree | 38bae83a3d5dc919e89906ce43571eaf2a210d5f | |
parent | fa358bcce18c4c6b343eb2a82475d76a6638096a (diff) |
Add support for emscripten, fix compdb for tests
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | backend/ninja/Ninja.cpp | 125 | ||||
-rw-r--r-- | include/Exec.hpp | 1 | ||||
-rw-r--r-- | include/env.hpp | 5 | ||||
-rw-r--r-- | src/Exec.cpp | 4 |
5 files changed, 103 insertions, 37 deletions
@@ -51,13 +51,16 @@ Users are required to manually install some libraries as they can't be included 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. +Automatic cross compilation (`sibs build --platform <platform>`)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. To run `scripts/mingw_package.py` you need to install pefile python library `sudo pip install pefile`. + +Manual cross compilation can be done by replacing c, c++ compilers and linker (ar) using the environment variable CC, CXX and AR. # 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 or cquery. To generate compile_commands.json that also finds header files (non-relative) you need to have compdb installed and available in your PATH environment variable: https://github.com/Sarcasm/compdb 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. I recommend using Visual Studio Code along with cquery (https://github.com/cquery-project/cquery/wiki), which gives you very good IDE support for your C/C++ projects: ![Image of cquery extension in Visual Studio Code](preview.png) +If you are using Visual Studio Code then you should add .vscode/ to .gitignore or Visual Studio Code will lag a lot (because cquery adds a lot of files in .vscode directory). # Tests If your project contains a sub directory called "tests" then that directory will be used a test project. The test directory may contain a project.conf file which can contain \[dependencies] block for specifying test only dependencies. The test automatically includes the parent project as a dependency. # Project configuration template diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 6aad314..71e9c08 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -390,10 +390,9 @@ namespace backend static vector<ninja::NinjaArg> getCompilerSanitizerFlags(const SibsConfig &config) { - if(config.getCompiler() == Compiler::GCC && config.getSanitize()) + if(config.getCompiler() == Compiler::GCC || config.getCompiler() == Compiler::MINGW_W64) { return { - ninja::NinjaArg::createRaw("-fno-omit-frame-pointer"), ninja::NinjaArg::createRaw("-fsanitize=address"), ninja::NinjaArg::createRaw("-fsanitize=undefined") }; @@ -417,7 +416,8 @@ namespace backend ninja::NinjaArg::createRaw("-D_FORTIFY_SOURCE=2"), ninja::NinjaArg::createRaw("-D_GLIBCXX_ASSERTIONS"), ninja::NinjaArg::createRaw("-fasynchronous-unwind-tables"), - ninja::NinjaArg::createRaw("-D_DEBUG") + ninja::NinjaArg::createRaw("-D_DEBUG"), + ninja::NinjaArg::createRaw("-fno-omit-frame-pointer"), }; } case OPT_LEV_RELEASE: @@ -767,6 +767,10 @@ namespace backend static string getCompilerLinker(Compiler compiler) { + char *ar = std::getenv("AR"); + if(ar) + return ar; + string result; switch(compiler) { @@ -783,17 +787,54 @@ namespace backend return result; } + enum class RuntimeCompilerType + { + NONE, + OTHER, + CLANG, + EMSCRIPTEN + }; + Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) { - bool isCCompilerClang = false; - Result<ExecResult> cCompilerVersion = exec(TINYDIR_STRING("cc --version")); - if(cCompilerVersion && cCompilerVersion.unwrap().exitCode == 0 && cCompilerVersion.unwrap().execStdout.find("clang") != string::npos) - isCCompilerClang = true; + string cCompilerName = getCompilerCExecutable(config.getCompiler()); + string cppCompilerName = getCompilerCppExecutable(config.getCompiler()); + string compilerLinker = getCompilerLinker(config.getCompiler()); + + RuntimeCompilerType cCompilerType = RuntimeCompilerType::NONE; + Result<ExecResult> cCompilerVersion = exec(toFileString(cCompilerName) + TINYDIR_STRING(" --version")); + if(cCompilerVersion && cCompilerVersion.unwrap().exitCode == 0) + { + if(cCompilerVersion.unwrap().execStdout.find("Emscripten") != string::npos) + cCompilerType = RuntimeCompilerType::EMSCRIPTEN; + else if(cCompilerVersion.unwrap().execStdout.find("clang") != string::npos) + cCompilerType = RuntimeCompilerType::CLANG; + else + cCompilerType = RuntimeCompilerType::OTHER; + } - bool isCppCompilerClang = false; - Result<ExecResult> cppCompilerVersion = exec(TINYDIR_STRING("c++ --version")); - if(cppCompilerVersion && cppCompilerVersion.unwrap().exitCode == 0 && cppCompilerVersion.unwrap().execStdout.find("clang") != string::npos) - isCppCompilerClang = true; + RuntimeCompilerType cppCompilerType = RuntimeCompilerType::NONE; + Result<ExecResult> cppCompilerVersion = exec(toFileString(cppCompilerName) + TINYDIR_STRING(" --version")); + if(cppCompilerVersion && cppCompilerVersion.unwrap().exitCode == 0) + { + if(cppCompilerVersion.unwrap().execStdout.find("Emscripten") != string::npos) + cppCompilerType = RuntimeCompilerType::EMSCRIPTEN; + else if(cppCompilerVersion.unwrap().execStdout.find("clang") != string::npos) + cppCompilerType = RuntimeCompilerType::CLANG; + else + cppCompilerType = RuntimeCompilerType::OTHER; + } + + if(cCompilerType != RuntimeCompilerType::NONE && cppCompilerType != RuntimeCompilerType::NONE && cCompilerType != cppCompilerType) + return Result<bool>::Err("The c and c++ compiler has to be of the same type"); + + RuntimeCompilerType compilerType = cCompilerType; + if(compilerType == RuntimeCompilerType::NONE) + compilerType = cppCompilerType; + + bool sanitize = config.getSanitize(); + if(compilerType == RuntimeCompilerType::EMSCRIPTEN) + sanitize = false; Result<bool> createBuildDirResult = createDirectoryRecursive(savePath); if (!createBuildDirResult) @@ -818,16 +859,16 @@ namespace backend if(config.packaging && !config.isMainProject()) libraryType = LibraryType::STATIC; + // TODO: Emscripten dynamic library support is not good at the moment, remove this once emscripten has been improved + if(libraryType == LibraryType::DYNAMIC && compilerType == RuntimeCompilerType::EMSCRIPTEN) + libraryType = LibraryType::STATIC; + string savePathUtf8 = toUtf8(savePath); string projectPathUtf8 = toUtf8(config.getProjectPath()); 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; @@ -1053,8 +1094,11 @@ namespace backend vector<ninja::NinjaArg> optimizationFlags = getCompilerOptimizationFlags(config); compileCCommand.insert(compileCCommand.end(), optimizationFlags.begin(), optimizationFlags.end()); - vector<ninja::NinjaArg> sanitizerFlags = getCompilerSanitizerFlags(config); - compileCCommand.insert(compileCCommand.end(), sanitizerFlags.begin(), sanitizerFlags.end()); + if(sanitize) + { + vector<ninja::NinjaArg> sanitizerFlags = getCompilerSanitizerFlags(config); + compileCCommand.insert(compileCCommand.end(), sanitizerFlags.begin(), sanitizerFlags.end()); + } compileCppCommand = compileCCommand; compileCppCommand[0] = ninja::NinjaArg::createRaw(cppCompilerName); @@ -1101,8 +1145,11 @@ namespace backend vector<ninja::NinjaArg> optimizationFlags = getCompilerOptimizationFlags(config); compileCCommand.insert(compileCCommand.end(), optimizationFlags.begin(), optimizationFlags.end()); - vector<ninja::NinjaArg> sanitizerFlags = getCompilerSanitizerFlags(config); - compileCCommand.insert(compileCCommand.end(), sanitizerFlags.begin(), sanitizerFlags.end()); + if(sanitize) + { + vector<ninja::NinjaArg> sanitizerFlags = getCompilerSanitizerFlags(config); + compileCCommand.insert(compileCCommand.end(), sanitizerFlags.begin(), sanitizerFlags.end()); + } compileCppCommand = compileCCommand; compileCppCommand.push_back(ninja::NinjaArg("/EHs")); @@ -1288,7 +1335,7 @@ namespace backend case Compiler::MINGW_W64: case Compiler::GCC: { - packagingFlags = "-static -static-libgcc -static-libstdc++"; + packagingFlags = "-static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic"; break; } case Compiler::MSVC: @@ -1319,10 +1366,11 @@ namespace backend string noUndefinedFlag; if(!onlyZigFiles) { + bool isCompilerClangLike = (compilerType == RuntimeCompilerType::CLANG) || (compilerType == RuntimeCompilerType::EMSCRIPTEN); if(usesCppFiles) - noUndefinedFlag = isCppCompilerClang ? "-Wl,-undefined,error" : "-Wl,--no-undefined,--as-needed"; + noUndefinedFlag = isCompilerClangLike ? "-Wl,-undefined,error" : "-Wl,--no-undefined,--as-needed"; else - noUndefinedFlag = isCCompilerClang ? "-Wl,-undefined,error" : "-Wl,--no-undefined,--as-needed"; + noUndefinedFlag = isCompilerClangLike ? "-Wl,-undefined,error" : "-Wl,--no-undefined,--as-needed"; } ninja::NinjaVariable zigObjectArgs("object_args"); @@ -1371,10 +1419,15 @@ namespace backend ninja::NinjaArg::createRaw(noUndefinedFlag) }); + if(compilerType == RuntimeCompilerType::EMSCRIPTEN) + { + buildExeArgs.push_back(ninja::NinjaArg::createRaw("-s MAIN_MODULE=1")); + } + if(!rpath.empty()) buildExeArgs.push_back(ninja::NinjaArg("-Wl,-rpath," + rpath)); - if(config.getSanitize()) + if(sanitize) { buildExeArgs.insert(buildExeArgs.end(), { ninja::NinjaArg::createRaw("-lasan"), @@ -1451,7 +1504,7 @@ namespace backend ninja::NinjaArg::createRaw("-luserenv"), ninja::NinjaArg::createRaw("-lopengl32"), ninja::NinjaArg::createRaw("-lglu32"), - ninja::NinjaArg::createRaw("-Wl,-Bstatic -lwinpthread"), + ninja::NinjaArg::createRaw("-Wl,-Bstatic -lwinpthread -Wl,-Bdynamic"), ninja::NinjaArg::createRaw("-lshell32") }); } @@ -1551,7 +1604,10 @@ namespace backend case Compiler::MINGW_W64: case Compiler::GCC: { - generatedFile = "lib" + config.getPackageName() + "." + CONFIG_DYNAMIC_LIB_FILE_EXTENSION; + const char *fileExtension = CONFIG_DYNAMIC_LIB_FILE_EXTENSION; + if(compilerType == RuntimeCompilerType::EMSCRIPTEN) + fileExtension = "wasm"; + generatedFile = "lib" + config.getPackageName() + "." + fileExtension; break; } case Compiler::MSVC: @@ -1594,7 +1650,12 @@ namespace backend ninja::NinjaArg::createRaw(noUndefinedFlag) }); - if(config.getSanitize()) + if(compilerType == RuntimeCompilerType::EMSCRIPTEN) + { + buildDynamicArgs.push_back(ninja::NinjaArg::createRaw("-s SIDE_MODULE=1")); + } + + if(sanitize) { buildDynamicArgs.insert(buildDynamicArgs.end(), { ninja::NinjaArg::createRaw("-lasan"), @@ -1665,7 +1726,7 @@ namespace backend ninja::NinjaArg::createRaw("-luserenv"), ninja::NinjaArg::createRaw("-lopengl32"), ninja::NinjaArg::createRaw("-lglu32"), - ninja::NinjaArg::createRaw("-Wl,-Bstatic -lwinpthread"), + ninja::NinjaArg::createRaw("-Wl,-Bstatic -lwinpthread -Wl,-Bdynamic"), ninja::NinjaArg::createRaw("-lshell32") }); } @@ -1697,7 +1758,7 @@ namespace backend if (!buildResult) return buildResult; - if(config.isMainProject()) + if((config.isMainProject() && !config.shouldBuildTests()) || config.isTest()) { buildResult = buildCompilationDatabase(savePath, config.getProjectPath()); if(!buildResult) @@ -1820,14 +1881,6 @@ namespace backend Result<bool> buildFileResult = ninja.build(sibsTestConfig, buildPath.c_str()); if (!buildFileResult) return buildFileResult; - - // Main projects test should also have compilation database, so we can use it inside IDE - if(config.isMainProject()) - { - buildFileResult = buildCompilationDatabase(buildPath.c_str(), testSourceDirNative); - if(!buildFileResult) - return buildFileResult; - } if(!zigTest) { diff --git a/include/Exec.hpp b/include/Exec.hpp index 9996073..93ce307 100644 --- a/include/Exec.hpp +++ b/include/Exec.hpp @@ -14,6 +14,7 @@ namespace sibs }; Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print = false); + Result<ExecResult> exec(const FileString &cmd, bool print = false); } #endif //SIBS_EXEC_HPP diff --git a/include/env.hpp b/include/env.hpp index 72b7828..b25cb69 100644 --- a/include/env.hpp +++ b/include/env.hpp @@ -59,6 +59,11 @@ #define OS_TYPE OS_TYPE_LINUX #endif +#ifdef __EMSCRIPTEN__ + #define OS_FAMILY OS_FAMILY_POSIX + #define OS_TYPE OS_TYPE_LINUX +#endif + #if defined(__GNUC__) #if defined(__x86_64__) || defined(__pc64__) #define SIBS_ENV_64BIT diff --git a/src/Exec.cpp b/src/Exec.cpp index cfeb19d..cc82897 100644 --- a/src/Exec.cpp +++ b/src/Exec.cpp @@ -139,4 +139,8 @@ namespace sibs return Result<ExecResult>::Err(errMsg); } #endif + Result<ExecResult> exec(const FileString &cmd, bool print) + { + return exec(cmd.c_str(), print); + } } |