diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68ad731e0..0286dc332 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ env: jobs: - lin: + linux: runs-on: ubuntu-20.04 name: 🐧 Ubuntu 20.04 steps: @@ -138,6 +138,26 @@ jobs: with: path: msys2/*.zst + macos-build: + runs-on: macos-11.0 + name: 🍎 macOS 11.0 + steps: + + - name: 🧰 Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: ⬇️ Install dependencies + run: | + brew bundle --no-lock --file dist/Brewfile + + - name: ✋ Build + run: | + mkdir build + cd build + CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" cmake .. + make -j 4 win-test: needs: win-makepkg diff --git a/CMakeLists.txt b/CMakeLists.txt index 073cb2d4c..fb32de728 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,14 @@ cmake_minimum_required(VERSION 3.16) + project(HexEditor) SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL) SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) - set(CMAKE_CXX_STANDARD 20) +# Enforce that we use non system Python 3 on macOS. +set(Python_FIND_FRAMEWORK NEVER) + find_package(PkgConfig REQUIRED) pkg_search_module(GLFW REQUIRED glfw3) @@ -24,6 +27,11 @@ if(Python_VERSION LESS 3) message(FATAL_ERROR "No valid version of Python 3 was found.") endif() +pkg_search_module(MAGIC libmagic) +if(NOT MAGIC_FOUND) + find_library(MAGIC magic REQUIRED) +endif() + include_directories(include ${GLFW_INCLUDE_DIRS} ${GLM_INCLUDE_DIRS} ${CRYPTO_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} libs/ImGui/include libs/glad/include ${Python_INCLUDE_DIRS}) # Get Python major and minor @@ -89,6 +97,8 @@ add_executable(ImHex resource.rc ) +set_target_properties(ImHex PROPERTIES CXX_VISIBILITY_PRESET hidden) + target_link_directories(ImHex PRIVATE ${GLFW_LIBRARY_DIRS} ${CRYPTO_LIBRARY_DIRS} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS}) if (WIN32) diff --git a/README.md b/README.md index 9b17bdb67..837daba6e 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,9 @@ You need a C++20 compatible compiler such as GCC 10.2.0 to compile ImHex. Moreov - nlohmann json - Python3 - freetype2 +- Brew (macOS only) + +### Windows and Linux Find all-in-one dependency installation scripts for Arch Linux, Fedora, Debian/Ubuntu and/or MSYS2 in [dist](dist). @@ -123,6 +126,18 @@ On both Windows and Linux: - Place your patterns in the `pattern` folder next to your built executable - Place your include pattern files in the `include` folder next to your built executable +### macOS + +To build ImHex on macOS, run the following commands: + +```sh +brew bundle --no-lock --file dist/Brewfile +mkdir build +cd build +CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" cmake .. +make -j +``` + ## Credits - Thanks a lot to ocornut for their amazing [Dear ImGui](https://github.com/ocornut/imgui) which is used for building the entire interface diff --git a/dist/Brewfile b/dist/Brewfile new file mode 100644 index 000000000..8fde92a01 --- /dev/null +++ b/dist/Brewfile @@ -0,0 +1,12 @@ +brew "glfw3" +brew "openssl@1.1" +brew "capstone" +brew "nlohmann-json" +brew "glm" +brew "cmake" +brew "python3" +brew "freetype2" +brew "libmagic" + +# TODO: Remove this when XCode version of clang will support the same level as LLVM 10 +brew "llvm" \ No newline at end of file diff --git a/include/helpers/utils.hpp b/include/helpers/utils.hpp index 5df2cc35f..38bfd4270 100644 --- a/include/helpers/utils.hpp +++ b/include/helpers/utils.hpp @@ -18,6 +18,33 @@ #include "lang/token.hpp" +#ifdef __APPLE__ + #define off64_t off_t + #define fopen64 fopen + #define fseeko64 fseek + #define ftello64 ftell +#endif + +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 12000 +#if __has_include() +// Make sure we break when derived_from is implemented in libc++. Then we can fix a compatibility version above +#include +#endif +// libcxx 12 still doesn't have derived_from implemented, as a result we need to define it ourself using clang built-ins. +// [concept.derived] (patch from https://reviews.llvm.org/D74292) +namespace hex { +template + concept derived_from = + __is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*); +} +#else +// Assume supported +#include +namespace hex { + using std::derived_from; +} +#endif + namespace hex { template @@ -99,6 +126,19 @@ namespace hex { throw std::invalid_argument("Invalid value size!"); } + template< class T > + constexpr T bit_width(T x) noexcept { + return std::numeric_limits::digits - std::countl_zero(x); + } + + template + constexpr T bit_ceil(T x) noexcept { + if (x <= 1u) + return T(1); + + return T(1) << bit_width(T(x - 1)); + } + std::vector readFile(std::string_view path); class ScopeExit { diff --git a/include/providers/provider.hpp b/include/providers/provider.hpp index 594c9a977..6e146ff89 100644 --- a/include/providers/provider.hpp +++ b/include/providers/provider.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/include/views/view_pattern.hpp b/include/views/view_pattern.hpp index 1429f6877..564a26b6c 100644 --- a/include/views/view_pattern.hpp +++ b/include/views/view_pattern.hpp @@ -7,7 +7,6 @@ #include "providers/provider.hpp" -#include #include #include diff --git a/include/window.hpp b/include/window.hpp index 549cbe935..e23c55b82 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -1,10 +1,10 @@ #pragma once -#include #include #include #include +#include "helpers/utils.hpp" #include "views/view.hpp" struct GLFWwindow; @@ -19,7 +19,7 @@ namespace hex { void loop(); - template T, typename ... Args> + template T, typename ... Args> T* addView(Args&& ... args) { this->m_views.emplace_back(new T(std::forward(args)...)); diff --git a/source/helpers/patches.cpp b/source/helpers/patches.cpp index 5b0277185..4fcd31e73 100644 --- a/source/helpers/patches.cpp +++ b/source/helpers/patches.cpp @@ -1,6 +1,5 @@ #include "helpers/patches.hpp" -#include #include #include #include diff --git a/source/lang/evaluator.cpp b/source/lang/evaluator.cpp index 8a1f25c02..9b2f5d3d0 100644 --- a/source/lang/evaluator.cpp +++ b/source/lang/evaluator.cpp @@ -36,7 +36,7 @@ namespace hex::lang { const auto typeDeclNode = static_cast(this->m_types[member->getCustomVariableTypeName()]); PatternData *pattern = nullptr; - u64 memberSize = 0; + size_t memberSize = 0; if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) { std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset); @@ -128,7 +128,7 @@ namespace hex::lang { const auto typeDeclNode = static_cast(this->m_types[member->getCustomVariableTypeName()]); PatternData *pattern = nullptr; - u64 memberSize = 0; + size_t memberSize = 0; if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) { std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset); @@ -222,7 +222,7 @@ namespace hex::lang { for (auto &[fieldName, fieldSize] : bitfieldType->getFields()) size += fieldSize; - size = std::bit_ceil(size) / 8; + size = bit_ceil(size) / 8; return { new PatternDataBitfield(offset, size, varDeclNode->getVariableName(), bitfieldType->getName(), bitfieldType->getFields(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), size }; } diff --git a/source/lang/lexer.cpp b/source/lang/lexer.cpp index 8099d830f..f0aed7cc5 100644 --- a/source/lang/lexer.cpp +++ b/source/lang/lexer.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace hex::lang { diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 87e1db6fe..80587e665 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -245,7 +245,7 @@ namespace hex { lang::PatternData::resetPalette(); } - template T> + template T> static std::vector findNodes(const lang::ASTNode::Type type, const std::vector &nodes) { std::vector result; @@ -300,7 +300,7 @@ namespace hex { return; } - hex::ScopeExit deleteAst([&ast]{ for(auto &node : ast) delete node; }); + hex::ScopeExit deleteAst([&ast=ast]{ for(auto &node : ast) delete node; }); hex::lang::Validator validator; auto validatorResult = validator.validate(ast);