diff --git a/.gitignore b/.gitignore index 3e93eb9..e8bfdaa 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,8 @@ bindings/java/crnd/messages/ bindings/go/crnd.go bindings/rust/src/protos/*.rs bindings/rust/src/bindings.rs +*.js +*.wasm +*.html +conaninfo.txt +conanmanifest.txt diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index bbd6311..52f87e5 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -1,6 +1,17 @@ cmake_minimum_required(VERSION 3.8.0) -add_subdirectory(cpp) -add_subdirectory(java) -add_subdirectory(go) -add_subdirectory(rust) +if(${BINDINGS_CPP}) + add_subdirectory(cpp) +endif() + +if(${BINDINGS_JAVA}) + add_subdirectory(java) +endif() + +if (${BINDINGS_GO}) + add_subdirectory(go) +endif() + +if (${BINDINGS_RUST}) + add_subdirectory(rust) +endif() diff --git a/conanfile.py b/conanfile.py index 9de4188..3957783 100644 --- a/conanfile.py +++ b/conanfile.py @@ -9,7 +9,7 @@ class CppInside(ConanFile): settings = "os", "arch", "compiler", "build_type" generators = "cmake" - options = {#"cpp": [True, False], # It is always generated + options = {"cpp": [True, False], # It is always generated "csharp": [True, False], "java": [True, False], "js": [True, False], @@ -19,7 +19,7 @@ class CppInside(ConanFile): "ruby": [True, False], "go": [True, False], } - default_options = {#"cpp": True, + default_options = {"cpp": True, "csharp": True, "java": True, "js": True, @@ -37,7 +37,7 @@ def build_requirements(self): def requirements(self): self.requires("protobuf/3.6.1@bincrafters/stable") - self.requires("boost/1.70.0@conan/stable") + #self.requires("boost/1.70.0@conan/stable") self.requires("spdlog/1.3.1@bincrafters/stable") def source(self): @@ -61,13 +61,22 @@ def source(self): else: binding_folder = os.path.join(self.source_folder, "bindings", it, "messages") os.makedirs(binding_folder, exist_ok=True) - command += " --{}_out={}".format(it, binding_folder) + + if it == 'js': + command += " --js_out=import_style=commonjs,binary:{}".format(binding_folder) + else: + command += " --{}_out={}".format(it, binding_folder) command += " {}".format(" ".join(messages)) with tools.environment_append(env): self.run(command) def _cmake(self): cmake = CMake(self) + for it in ["cpp", "csharp", "java", "js", "objc", "php", "python", "ruby", "go"]: + cmake.definitions["bindings_{}".format(it).upper()] = bool(getattr(self.options, it)) + cmake.definitions["example_{}".format(it).upper()] = bool(getattr(self.options, it)) + + cmake.definitions["EMSCRIPTEN"] = bool(self.settings.os == "Emscripten") cmake.configure() return cmake diff --git a/emscripten/bin/index.html b/emscripten/bin/index.html new file mode 100644 index 0000000..3412a8c --- /dev/null +++ b/emscripten/bin/index.html @@ -0,0 +1,104 @@ + + + + + + + + + + +
+ +
+ + + diff --git a/emscripten/build.sh b/emscripten/build.sh new file mode 100755 index 0000000..11a5ad7 --- /dev/null +++ b/emscripten/build.sh @@ -0,0 +1,11 @@ +rm -fr _build +mkdir _build + +pushd _build +conan install ../../conanfile.py -g virtualenv --profile ../profile --build=missing -o csharp=False -o java=False -o objc=False -o php=False -o python=False -o ruby=False -o go=False -o cpp=False +conan source ../../conanfile.py --install-folder=. --source-folder=../../ +conan build ../../conanfile.py +conan package ../../conanfile.py --package-folder=../ +popd + +browserify main.js --standalone crnd -o bin/bundle.js diff --git a/emscripten/main.js b/emscripten/main.js new file mode 100644 index 0000000..b1f2d7e --- /dev/null +++ b/emscripten/main.js @@ -0,0 +1,49 @@ + +var help_pb = require('/Users/jgsogo/dev/projects/cpp-inside/bindings/js/messages/help_pb.js'); +var sample_pb = require('/Users/jgsogo/dev/projects/cpp-inside/bindings/js/messages/sample_pb.js'); +var model_pb = require('/Users/jgsogo/dev/projects/cpp-inside/bindings/js/messages/model_pb.js'); +var sample_request_pb = require('/Users/jgsogo/dev/projects/cpp-inside/bindings/js/messages/sample_request_pb.js'); + +parse_help = function (data) { + json = JSON.parse(UTF8ToString(data)); + var message = new help_pb.Help(); + message.setName(json["name"]); + message.setDescription(json["description"]); + message.setVersion(json["version"]); + return message; +} + +parse_sample = function (data) { + json = JSON.parse(UTF8ToString(data)); + + var model = new model_pb.Model(); + model.setId(json["model"]["id"]); + model.getParamsMap()["mean"] = json["model"]["mean"]; + model.getParamsMap()["stddev"] = json["model"]["stddev"]; + + var message = new sample_pb.Sample(); + message.setModel(model); + message.setSeed(json["seed"]); + message.setSamplesList(json["samples"]); + + return message; +} + +serialize_sample_request = function(sample_request) { + var model = sample_request.getModel(); + var params = model.getParamsMap(); + return JSON.stringify({ + "model": { + "id": "LOGNORMAL", + "params": { + "mean": params["mean"], + "stddev": params["stddev"] + } + }, + "seed": sample_request.getSeed(), + "nSamples": sample_request.getNSamples() + }); +} + + +module.exports = {parse_help: parse_help, parse_sample: parse_sample, serialize_sample_request: serialize_sample_request, sample_request_pb: sample_request_pb, model_pb: model_pb}; diff --git a/emscripten/profile b/emscripten/profile new file mode 100644 index 0000000..6f9e60e --- /dev/null +++ b/emscripten/profile @@ -0,0 +1,12 @@ +include(default) +[settings] +os=Emscripten +arch=wasm +compiler=clang +compiler.version=6.0 +compiler.libcxx=libc++ +[options] +[build_requires] +emsdk_installer/1.38.29@bincrafters/stable +[env] + diff --git a/emscripten/run.sh b/emscripten/run.sh new file mode 100755 index 0000000..bc4170d --- /dev/null +++ b/emscripten/run.sh @@ -0,0 +1,3 @@ + +source _build/activate.sh +emrun ./bin/index.html diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a68811a..0c37d63 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,20 @@ -add_subdirectory(cpp) -add_subdirectory(python) -add_subdirectory(java) -add_subdirectory(go) -add_subdirectory(rust) +if (${EXAMPLE_CPP}) + add_subdirectory(cpp) +endif() + +if (${EXAMPLE_PYTHON}) + add_subdirectory(python) +endif() + +if (${EXAMPLE_JAVA}) + add_subdirectory(java) +endif() + +if (${EXAMPLE_GO}) + add_subdirectory(go) +endif() + +if (${EXAMPLE_RUST}) + add_subdirectory(rust) +endif() diff --git a/library/crnd/CMakeLists.txt b/library/crnd/CMakeLists.txt index efb5a12..93c8192 100644 --- a/library/crnd/CMakeLists.txt +++ b/library/crnd/CMakeLists.txt @@ -23,4 +23,30 @@ target_compile_definitions(crnd PRIVATE SPDLOG_ACTIVE_LEVEL=0) #define SPDLOG_LEVEL_WARN 3 #define SPDLOG_LEVEL_ERROR 4 #define SPDLOG_LEVEL_CRITICAL 5 -#define SPDLOG_LEVEL_OFF 6 \ No newline at end of file +#define SPDLOG_LEVEL_OFF 6 + +if (${EMSCRIPTEN}) + message("CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") + message("CMAKE_CPP_COMPILER: ${CMAKE_CPP_COMPILER}") + + set(EXPORTED_FUNCTIONS + _help + _sample + ) + + # process exported functions + set(EXPORTED_FUNCTIONS_STR "") + list(JOIN EXPORTED_FUNCTIONS "," EXPORTED_FUNCTIONS_STR) + + set(CMAKE_CXX_FLAGS "-s EXPORTED_FUNCTIONS=\"[${EXPORTED_FUNCTIONS_STR}]\" -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\", \"addFunction\", \"removeFunction\", \"UTF8ToString\", \"stringToUTF8\"]' -s RESERVED_FUNCTION_POINTERS=10") + + set_target_properties(crnd PROPERTIES + SUFFIX ".js" + LINK_FLAGS "--emrun") + + install(FILES + ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcrnd.js + ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcrnd.wasm + DESTINATION bin) +endif() + diff --git a/library/crnd/include/api_c.h b/library/crnd/include/api_c.h index 78b92c6..495cb6b 100644 --- a/library/crnd/include/api_c.h +++ b/library/crnd/include/api_c.h @@ -8,7 +8,7 @@ extern "C" { typedef void (*callback_t)(void* state, const void* data, const void* status); CRND_EXPORT void help(void* state, callback_t help_callback); - CRND_EXPORT void sample(void* state, const void* sample_request_in, callback_t sample_callback); + CRND_EXPORT void sample(void* state, char* sample_request_in, callback_t sample_callback); #ifdef __cplusplus } #endif diff --git a/library/crnd/src/api_c.cpp b/library/crnd/src/api_c.cpp index f64ac03..9090c85 100644 --- a/library/crnd/src/api_c.cpp +++ b/library/crnd/src/api_c.cpp @@ -4,6 +4,7 @@ #include "../include/api_cpp.h" #include "serialization.h" +#include extern "C" { @@ -15,20 +16,36 @@ extern "C" { auto status = help(help_message); SPDLOG_TRACE("C::help::before callback"); - help_callback(state, Serialized(help_message), Serialized(*status)); + //help_callback(state, Serialized(help_message), Serialized(*status)); + std::string data; + google::protobuf::util::MessageToJsonString(help_message, &data); + + std::string status_str; + google::protobuf::util::MessageToJsonString(*status, &status_str); + + help_callback(state, (void*)data.c_str(), (void*)status_str.c_str()); SPDLOG_TRACE("C::help::after callback"); SPDLOG_DEBUG("< C::help"); } - void sample(void* state, const void* sample_request_in, callback_t sample_callback) { + void sample(void* state, char* sample_request_in, callback_t sample_callback) { SPDLOG_DEBUG("> C::sample"); - crnd::SampleRequest request_message = Serialized::parse(sample_request_in); + std::string sp(sample_request_in); + crnd::SampleRequest request_message; + google::protobuf::util::JsonStringToMessage(sp, &request_message); + crnd::Sample sample_message; auto status = sample(request_message, sample_message); SPDLOG_TRACE("C::sample::before callback"); - sample_callback(state, Serialized(sample_message), Serialized(*status)); + std::string data; + google::protobuf::util::MessageToJsonString(sample_message, &data); + + std::string status_str; + google::protobuf::util::MessageToJsonString(*status, &status_str); + + sample_callback(state, (void*)data.c_str(), (void*)status_str.c_str()); SPDLOG_TRACE("C::sample::after callback"); SPDLOG_DEBUG("< C::sample");