diff --git a/.github/workflows/macos_13.yml b/.github/workflows/macos_13.yml index c5666bc4..8a876e72 100644 --- a/.github/workflows/macos_13.yml +++ b/.github/workflows/macos_13.yml @@ -29,6 +29,13 @@ jobs: - name: Install Brew Dependencies run: brew install cmake llvm@16 boost git openssl@3 cryptopp curl ninja make + - name: Tool Version Dump + run: | + clang++ --version + cmake --version + ninja --version + brew list --versions boost + - name: Configure CMake run: cmake -B ${{github.workspace}}/build/clang_${{env.BUILD_TYPE}} -G"Ninja" -DNUI_ENABLE_TESTS=on -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DNUI_BUILD_EXAMPLES=on -DCMAKE_CXX_EXTENSIONS=on -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@16/bin/clang++ -DCMAKE_C_COMPILER=/usr/local/opt/llvm@16/bin/clang -DNUI_NPM=npm -DNUI_NODE=node -DCMAKE_CXX_STANDARD=20 env: diff --git a/.github/workflows/ubuntu_20.yml b/.github/workflows/ubuntu_20.yml index 9350a4c8..20404849 100644 --- a/.github/workflows/ubuntu_20.yml +++ b/.github/workflows/ubuntu_20.yml @@ -31,6 +31,12 @@ jobs: # OPTIONAL: Specify a platform version platform_version: 20.04 + - name: Tool Version Dump + run: | + clang++ --version + cmake --version + ninja --version + - name: Setup clang uses: egor-tensin/setup-clang@v1 with: @@ -40,7 +46,7 @@ jobs: - name: Configure CMake run: cmake -B ${{github.workspace}}/build/clang_${{env.BUILD_TYPE}} -G"Ninja" -DNUI_ENABLE_TESTS=on -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DNUI_BUILD_EXAMPLES=on -DCMAKE_CXX_EXTENSIONS=on -DCMAKE_CXX_COMPILER=c++ -DCMAKE_C_COMPILER=cc -DCMAKE_CXX_STANDARD=20 env: - BOOST_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }} + Boost_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }} - name: Build run: cmake --build ${{github.workspace}}/build/clang_${{env.BUILD_TYPE}} --config ${{env.BUILD_TYPE}} diff --git a/.github/workflows/ubuntu_22.yml b/.github/workflows/ubuntu_22.yml index 10934109..7c7077d9 100644 --- a/.github/workflows/ubuntu_22.yml +++ b/.github/workflows/ubuntu_22.yml @@ -34,13 +34,19 @@ jobs: # OPTIONAL: Specify a platform version platform_version: 22.04 + - name: Tool Version Dump + run: | + clang++ --version + cmake --version + ninja --version + - name: Symlink xlocale run: sudo ln -s /usr/include/locale.h /usr/include/xlocale.h - name: Configure CMake run: cmake -B ${{github.workspace}}/build/clang_${{env.BUILD_TYPE}} -G"Ninja" -DNUI_ENABLE_TESTS=on -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DNUI_BUILD_EXAMPLES=on -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_CXX_EXTENSIONS=on -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_LINKER=lld -DCMAKE_CXX_STANDARD=20 env: - BOOST_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }} + Boost_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }} - name: Build run: cmake --build ${{github.workspace}}/build/clang_${{env.BUILD_TYPE}} --config ${{env.BUILD_TYPE}} diff --git a/cmake/backend/emscripten.cmake b/cmake/backend/emscripten.cmake index 8057ab8a..cf6986bb 100644 --- a/cmake/backend/emscripten.cmake +++ b/cmake/backend/emscripten.cmake @@ -40,7 +40,7 @@ function(nui_add_emscripten_target) cmake_parse_arguments( NUI_ADD_EMSCRIPTEN_TARGET_ARGS "DISABLE_BIN2HPP;DISABLE_PARCEL_ADAPTER;ENABLE_TAILWIND;ENABLE_DOTENV" - "TARGET;PREJS;SOURCE_DIR" + "TARGET;PREJS;SOURCE_DIR;BIN2HPP_ENCODING" "CMAKE_OPTIONS" ${ARGN} ) @@ -99,8 +99,14 @@ function(nui_add_emscripten_target) set(BUILD_COMMAND BUILD_COMMAND cmake -E copy "${SOURCE_DIR}/package.json" "${CMAKE_BINARY_DIR}/module_${NUI_ADD_EMSCRIPTEN_TARGET_ARGS_TARGET}/package.json") endif() + if (NUI_ADD_EMSCRIPTEN_TARGET_ARGS_BIN2HPP_ENCODING) + set(BIN2HPP_ENCODING ${NUI_ADD_EMSCRIPTEN_TARGET_ARGS_BIN2HPP_ENCODING}) + else() + set(BIN2HPP_ENCODING "raw") + endif() + if (ENABLE_BIN2HPP AND ${ENABLE_BIN2HPP}) - set(BIN2HPP_COMMAND COMMAND $ "on" "${CMAKE_BINARY_DIR}/module_${NUI_ADD_EMSCRIPTEN_TARGET_ARGS_TARGET}/bin/index.html" "${CMAKE_BINARY_DIR}/module_${NUI_ADD_EMSCRIPTEN_TARGET_ARGS_TARGET}/include/index.hpp" index) + set(BIN2HPP_COMMAND COMMAND $ "on" "${CMAKE_BINARY_DIR}/module_${NUI_ADD_EMSCRIPTEN_TARGET_ARGS_TARGET}/bin/index.html" "${CMAKE_BINARY_DIR}/module_${NUI_ADD_EMSCRIPTEN_TARGET_ARGS_TARGET}/include/index.hpp" index ${BIN2HPP_ENCODING}) else() set(BIN2HPP_COMMAND COMMAND cmake -E true) endif() diff --git a/cmake/dependencies/boost.cmake b/cmake/dependencies/boost.cmake index 5aa1b22a..931e1663 100644 --- a/cmake/dependencies/boost.cmake +++ b/cmake/dependencies/boost.cmake @@ -1,5 +1,5 @@ if (CMAKE_VERSION VERSION_LESS "3.30") - find_package(Boost 1.81.0 REQUIRED COMPONENTS system) + find_package(Boost 1.81.0 REQUIRED COMPONENTS system iostreams) else() - find_package(Boost CONFIG 1.81.0 REQUIRED COMPONENTS system) + find_package(Boost CONFIG 1.81.0 REQUIRED COMPONENTS system iostreams) endif() \ No newline at end of file diff --git a/cmake/dependencies/roar.cmake b/cmake/dependencies/roar.cmake index 5611c5ad..94f326f7 100644 --- a/cmake/dependencies/roar.cmake +++ b/cmake/dependencies/roar.cmake @@ -1,6 +1,6 @@ option(NUI_FETCH_ROAR "Fetch roar" ON) set(NUI_ROAR_REPOSITORY "https://github.com/5cript/roar.git" CACHE STRING "roar repository") -set(NUI_ROAR_TAG "4ac9a877b70fbb821de2edbb7dd3fcad1b0a7f08" CACHE STRING "roar tag") +set(NUI_ROAR_TAG "2781a88fcd1fce9af1a697673e26fd3ad55817e9" CACHE STRING "roar tag") if(NUI_FETCH_ROAR) include(FetchContent) diff --git a/tools/bin2hpp/CMakeLists.txt b/tools/bin2hpp/CMakeLists.txt index 7ac51554..3b6a0507 100644 --- a/tools/bin2hpp/CMakeLists.txt +++ b/tools/bin2hpp/CMakeLists.txt @@ -2,10 +2,14 @@ cmake_minimum_required(VERSION 3.16) project(bin2hpp VERSION 0.1.0) -add_executable(bin2hpp main.cpp) +add_executable(bin2hpp main.cpp raw_encoder.cpp base64_encoder.cpp compressed_encoder.cpp) target_compile_features(bin2hpp PRIVATE cxx_std_20) +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/dependencies/boost.cmake") + set_target_properties(bin2hpp PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tools_bin" -) \ No newline at end of file +) + +target_link_libraries(bin2hpp PRIVATE roar Boost::iostreams) \ No newline at end of file diff --git a/tools/bin2hpp/base64_encoder.cpp b/tools/bin2hpp/base64_encoder.cpp new file mode 100644 index 00000000..b2d6888d --- /dev/null +++ b/tools/bin2hpp/base64_encoder.cpp @@ -0,0 +1,58 @@ +#include "base64_encoder.hpp" +#include "raw_encoder.hpp" +#include "constants.hpp" + +#include + +#include +#include + +std::ostream& Base64Encoder::header(std::ostream& output) const +{ + output << + R"(#pragma once + +#include + +#include +#include + +static const std::string_view )" + << name_ << R"(_data[] = {)"; + + return output; +} + +std::ostream& Base64Encoder::content(std::ostream& output, std::istream& input) const +{ + std::stringstream readStream; + readStream << input.rdbuf(); + + auto encoded = Roar::base64Encode(std::move(readStream).str()); + + std::cout << "Encoded size: " << encoded.size() << "\n"; + + std::stringstream ss(std::move(encoded)); + + RawEncoder rawEncoder(name_); + return rawEncoder.content(output, ss); +} + +std::ostream& Base64Encoder::index(std::ostream& output) const +{ + output << "};\n\n"; + output << "static std::string " << name_ << "()\n"; + output << "{\n"; + output << "\tstatic std::string memo;\n"; + output << "\tif(!memo.empty())\n"; + output << "\t\treturn memo;\n"; + output << "\tfor (std::size_t i = 0; i != sizeof(" << name_ << "_data) / sizeof(std::string_view)" + << "; ++i) {\n"; + output << "\t\tmemo += " << name_ << "_data[i];\n"; + output << "\t}\n\n"; + output << "\tmemo = Roar::base64Decode(memo);\n"; + output << "\treturn memo;\n"; + output << "}\n"; + + return output; +} \ No newline at end of file diff --git a/tools/bin2hpp/base64_encoder.hpp b/tools/bin2hpp/base64_encoder.hpp new file mode 100644 index 00000000..ad207863 --- /dev/null +++ b/tools/bin2hpp/base64_encoder.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "encoder.hpp" + +class Base64Encoder : public Encoder +{ + public: + using Encoder::Encoder; + + std::ostream& header(std::ostream& output) const override; + std::ostream& content(std::ostream& output, std::istream& input) const override; + std::ostream& index(std::ostream& output) const override; +}; \ No newline at end of file diff --git a/tools/bin2hpp/compressed_encoder.cpp b/tools/bin2hpp/compressed_encoder.cpp new file mode 100644 index 00000000..ee8f8764 --- /dev/null +++ b/tools/bin2hpp/compressed_encoder.cpp @@ -0,0 +1,74 @@ +#include "compressed_encoder.hpp" +#include "raw_encoder.hpp" +#include "constants.hpp" + +#include +#include +#include +#include + +#include +#include + +std::ostream& CompressedEncoder::header(std::ostream& output) const +{ + output << + R"(#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +static const std::string_view )" + << name_ << R"(_data[] = {)"; + + return output; +} + +std::ostream& CompressedEncoder::content(std::ostream& output, std::istream& input) const +{ + boost::iostreams::filtering_streambuf in; + in.push(boost::iostreams::gzip_compressor()); + in.push(input); + + std::stringstream compressedRaw; + boost::iostreams::copy(in, compressedRaw); + + auto encoded = Roar::base64Encode(std::move(compressedRaw).str()); + std::stringstream ss{std::move(encoded)}; + + RawEncoder rawEncoder(name_); + return rawEncoder.content(output, ss); +} + +std::ostream& CompressedEncoder::index(std::ostream& output) const +{ + output << "};\n\n"; + output << "static std::string " << name_ << "()\n"; + output << "{\n"; + output << "\tstatic std::string memo;\n"; + output << "\tif(!memo.empty())\n"; + output << "\t\treturn memo;\n\n"; + output << "\tstd::string compressed;\n"; + output << "\tfor (std::size_t i = 0; i != sizeof(" << name_ << "_data) / sizeof(std::string_view)" + << "; ++i) {\n"; + output << "\t\tcompressed += " << name_ << "_data[i];\n"; + output << "\t}\n\n"; + output << "\tcompressed = Roar::base64Decode(compressed);\n"; + output << "\tstd::stringstream compressedStream{compressed};\n"; + output << "\tboost::iostreams::filtering_streambuf in;\n"; + output << "\tin.push(boost::iostreams::gzip_decompressor());\n"; + output << "\tin.push(compressedStream);\n"; + output << "\tstd::stringstream decompressed;\n"; + output << "\tboost::iostreams::copy(in, decompressed);\n"; + output << "\tmemo = std::move(decompressed).str();\n"; + output << "\treturn memo;\n"; + output << "}\n"; + + return output; +} \ No newline at end of file diff --git a/tools/bin2hpp/compressed_encoder.hpp b/tools/bin2hpp/compressed_encoder.hpp new file mode 100644 index 00000000..6e0cdf06 --- /dev/null +++ b/tools/bin2hpp/compressed_encoder.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "encoder.hpp" + +class CompressedEncoder : public Encoder +{ + public: + using Encoder::Encoder; + + std::ostream& header(std::ostream& output) const override; + std::ostream& content(std::ostream& output, std::istream& input) const override; + std::ostream& index(std::ostream& output) const override; +}; \ No newline at end of file diff --git a/tools/bin2hpp/constants.hpp b/tools/bin2hpp/constants.hpp new file mode 100644 index 00000000..d99f835a --- /dev/null +++ b/tools/bin2hpp/constants.hpp @@ -0,0 +1,3 @@ +#pragma once + +constexpr std::size_t lineWidth = 120; \ No newline at end of file diff --git a/tools/bin2hpp/encoder.hpp b/tools/bin2hpp/encoder.hpp new file mode 100644 index 00000000..b9b8fa3c --- /dev/null +++ b/tools/bin2hpp/encoder.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +class Encoder +{ + public: + Encoder(std::string name) + : name_(std::move(name)) + {} + + virtual std::ostream& header(std::ostream& output) const = 0; + virtual std::ostream& content(std::ostream& output, std::istream& input) const = 0; + virtual std::ostream& index(std::ostream& output) const = 0; + + virtual ~Encoder() = default; + Encoder(Encoder const&) = default; + Encoder(Encoder&&) = default; + Encoder& operator=(Encoder const&) = default; + Encoder& operator=(Encoder&&) = default; + + protected: + std::string name_; +}; \ No newline at end of file diff --git a/tools/bin2hpp/main.cpp b/tools/bin2hpp/main.cpp index db0de0cd..191c9deb 100644 --- a/tools/bin2hpp/main.cpp +++ b/tools/bin2hpp/main.cpp @@ -1,3 +1,7 @@ +#include "raw_encoder.hpp" +#include "base64_encoder.hpp" +#include "compressed_encoder.hpp" + #include #include #include @@ -6,14 +10,13 @@ #include #include -constexpr std::size_t lineWidth = 120; - int main(int argc, char** argv) { - if (argc != 5) + if (argc != 6) { - std::cout << "Expected 4 arguments: , but got " << argc - 1 << "\n"; - std::cout << "Usage: " << argv[0] << " " + std::cout << "Expected 5 arguments: , but got " << argc - 1 + << "\n"; + std::cout << "Usage: " << argv[0] << " " << "\n"; return 1; } @@ -22,12 +25,26 @@ int main(int argc, char** argv) std::string inputFile = argv[2]; std::string outputFile = argv[3]; std::string name = argv[4]; + std::string encoding = argv[5]; if (enable == "no") { return 0; } + std::unique_ptr encoder; + if (encoding == "raw") + encoder = std::make_unique(name); + else if (encoding == "base64") + encoder = std::make_unique(name); + else if (encoding == "gz_base64") + encoder = std::make_unique(name); + else + { + std::cout << "Unknown encoding: " << encoding << "\n"; + return 1; + } + auto outputPath = std::filesystem::path(outputFile).parent_path(); if (!std::filesystem::exists(outputPath)) std::filesystem::create_directories(outputPath); @@ -45,54 +62,7 @@ int main(int argc, char** argv) return 1; } - output << "#pragma once\n"; - output << "\n"; - output << "#include \n"; - output << "#include \n"; - output << "\n"; - output << "static const std::string_view " << name << "_data[] = {\n"; - - do - { - char buffer[1024]; - input.read(buffer, sizeof(buffer)); - if (input.gcount() == 0) - break; - for (std::streamsize i = 0; i != input.gcount();) - { - std::streamsize j = 0; - output << "\t\""; - std::size_t widthUsed = 0; - for (; (widthUsed < (lineWidth - 9)) && (j + i != input.gcount()); ++j) - { - char c = buffer[i + j]; - if (c < 32 || c == '"' || c == '\\') - { - output << '\\' << std::oct << std::setw(3) << std::setfill('0') << static_cast(c); - widthUsed += 4; - } - else - { - output << c; - ++widthUsed; - } - } - output << "\"\n"; - i += j; - } - output << "\t,\n"; - } while (input.gcount() > 0); - - output << "};\n\n"; - output << "static std::string " << name << "()\n"; - output << "{\n"; - output << "\tstatic std::string memo;\n"; - output << "\tif(!memo.empty())\n"; - output << "\t\treturn memo;\n"; - output << "\tfor (std::size_t i = 0; i != sizeof(" << name << "_data) / sizeof(std::string_view)" - << "; ++i) {\n"; - output << "\t\tmemo += " << name << "_data[i];\n"; - output << "\t}\n"; - output << "\treturn memo;\n"; - output << "}\n"; + encoder->header(output); + encoder->content(output, input); + encoder->index(output); } \ No newline at end of file diff --git a/tools/bin2hpp/raw_encoder.cpp b/tools/bin2hpp/raw_encoder.cpp new file mode 100644 index 00000000..8e8cc83a --- /dev/null +++ b/tools/bin2hpp/raw_encoder.cpp @@ -0,0 +1,61 @@ +#include "raw_encoder.hpp" +#include "constants.hpp" + +#include + +std::ostream& RawEncoder::header(std::ostream& output) const +{ + output << "#pragma once\n"; + output << "\n"; + output << "#include \n"; + output << "#include \n"; + output << "\n"; + output << "static const std::string_view " << name_ << "_data[] = {\n"; + + return output; +} + +std::ostream& RawEncoder::content(std::ostream& output, std::istream& input) const +{ + do + { + char buffer[1024]; + input.read(buffer, sizeof(buffer)); + if (input.gcount() == 0) + break; + for (std::streamsize i = 0; i != input.gcount();) + { + std::streamsize j = 0; + output << "\tR\"NUI("; + std::size_t widthUsed = 0; + for (; (widthUsed < (lineWidth - 14)) && (j + i != input.gcount()); ++j) + { + char c = buffer[i + j]; + output.put(c); + ++widthUsed; + } + output << ")NUI\"\n"; + i += j; + } + output << "\t,\n"; + } while (input.gcount() > 0); + return output; +} + +std::ostream& RawEncoder::index(std::ostream& output) const +{ + output << "};\n\n"; + output << "static std::string " << name_ << "()\n"; + output << "{\n"; + output << "\tstatic std::string memo;\n"; + output << "\tif(!memo.empty())\n"; + output << "\t\treturn memo;\n"; + output << "\tfor (std::size_t i = 0; i != sizeof(" << name_ << "_data) / sizeof(std::string_view)" + << "; ++i) {\n"; + output << "\t\tmemo += " << name_ << "_data[i];\n"; + output << "\t}\n"; + output << "\treturn memo;\n"; + output << "}\n"; + + return output; +} \ No newline at end of file diff --git a/tools/bin2hpp/raw_encoder.hpp b/tools/bin2hpp/raw_encoder.hpp new file mode 100644 index 00000000..12451b06 --- /dev/null +++ b/tools/bin2hpp/raw_encoder.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "encoder.hpp" + +class RawEncoder : public Encoder +{ + public: + using Encoder::Encoder; + + std::ostream& header(std::ostream& output) const override; + std::ostream& content(std::ostream& output, std::istream& input) const override; + std::ostream& index(std::ostream& output) const override; +}; \ No newline at end of file