aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-10-30 13:35:36 +0100
committerdec05eba <dec05eba@protonmail.com>2020-07-06 07:39:33 +0200
commit31899d0a48108515d13508b660fb3bb82b869430 (patch)
tree38bae83a3d5dc919e89906ce43571eaf2a210d5f
parentfa358bcce18c4c6b343eb2a82475d76a6638096a (diff)
Add support for emscripten, fix compdb for tests
-rw-r--r--README.md5
-rw-r--r--backend/ninja/Ninja.cpp125
-rw-r--r--include/Exec.hpp1
-rw-r--r--include/env.hpp5
-rw-r--r--src/Exec.cpp4
5 files changed, 103 insertions, 37 deletions
diff --git a/README.md b/README.md
index 111d2dd..b80260b 100644
--- a/README.md
+++ b/README.md
@@ -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);
+ }
}