From 2d489e3c1bb20ccb38aca07f02e3c3fd4fb7ed6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gheorghi=C8=9B=C4=83=20Mutu?= Date: Sun, 12 Jan 2025 00:50:55 +0300 Subject: [PATCH 1/6] ^ better error message for module (plugin/DLL) loading failure on Windows #460 --- AppCUI/include/AppCUI.hpp | 5 ++--- AppCUI/src/OS/Windows/Library.cpp | 30 ++++++++++++++++++------------ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/AppCUI/include/AppCUI.hpp b/AppCUI/include/AppCUI.hpp index f8afe381..8c198c1a 100644 --- a/AppCUI/include/AppCUI.hpp +++ b/AppCUI/include/AppCUI.hpp @@ -2351,11 +2351,10 @@ namespace OS class EXPORT Library { - void* libraryHandle; + void* libraryHandle{ nullptr }; public: - Library(); - bool Load(const std::filesystem::path& path); + bool Load(const std::filesystem::path& path, std::string& errorMessage); void* GetFunction(const char* functionName) const; template inline T GetFunction(const char* functionName) const diff --git a/AppCUI/src/OS/Windows/Library.cpp b/AppCUI/src/OS/Windows/Library.cpp index aeef3da6..9b7d9de1 100644 --- a/AppCUI/src/OS/Windows/Library.cpp +++ b/AppCUI/src/OS/Windows/Library.cpp @@ -1,27 +1,33 @@ #include "Internal.hpp" +#include namespace AppCUI::OS { -Library::Library() +bool Library::Load(const std::filesystem::path& path, std::string& errorMessage) { - this->libraryHandle = nullptr; -} -bool Library::Load(const std::filesystem::path& path) -{ - CHECK(this->libraryHandle == nullptr, false, "Library already opened !"); - this->libraryHandle = LoadLibraryW(path.native().c_str()); - CHECK(this->libraryHandle, - false, - "Error: %u! Fail to load library: %s", - GetLastError(), - path.generic_string().c_str()); + if (libraryHandle) + { + errorMessage = "Library already opened!"; + RETURNERROR(false, errorMessage.c_str()); + } + libraryHandle = LoadLibraryW(path.native().c_str()); + if (!libraryHandle) + { + const auto code = GetLastError(); + std::string sCode = std::to_string(code); + errorMessage = "(" + sCode + ") " + std::system_category().message(code); + RETURNERROR(false, errorMessage.c_str()); + } + return true; } + void* Library::GetFunction(const char* functionName) const { CHECK(this->libraryHandle, nullptr, "Library was not loaded --> have you call Load(...) first ?"); CHECK(functionName, nullptr, "Expecting a valid (non-null) function name !"); CHECK(*functionName, nullptr, "Expecting a valid (non-empty) function name !"); + // all good void* fnPtr = GetProcAddress((HMODULE) this->libraryHandle, functionName); CHECK(fnPtr, nullptr, "Unable to find address of function: %s", functionName); From 99aae17312d0243e3969b15629dfbd8cf8a7cb58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gheorghi=C8=9B=C4=83=20Mutu?= Date: Sun, 12 Jan 2025 01:06:12 +0300 Subject: [PATCH 2/6] ^ better error message for module (plugin/DLL) loading failure on Linux #460 --- AppCUI/src/OS/Unix/Library.cpp | 48 +++++++++++++++---------------- AppCUI/src/OS/Windows/Library.cpp | 14 ++++----- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/AppCUI/src/OS/Unix/Library.cpp b/AppCUI/src/OS/Unix/Library.cpp index 3c26eb5f..de25a2c0 100644 --- a/AppCUI/src/OS/Unix/Library.cpp +++ b/AppCUI/src/OS/Unix/Library.cpp @@ -1,38 +1,36 @@ -#include #include "Internal.hpp" +#include namespace AppCUI::OS { -Library::Library() +bool Library::Load(const std::filesystem::path& path, std::string& errorMessage) { - this->libraryHandle = nullptr; -} + if (libraryHandle) + { + errorMessage = "Library already opened!"; + RETURNERROR(false, errorMessage.c_str()); + } + libraryHandle = dlopen(path.native().c_str(), RTLD_LAZY); + if (!libraryHandle) + { + const auto error = dlerror(); + errorMessage = "Fail to load library: " + path.generic_string() + " " + "[dlerror=" + error + "]!"; + RETURNERROR(false, errorMessage.c_str()); + } -bool Library::Load(const std::filesystem::path& path) -{ - CHECK(this->libraryHandle == nullptr, false, "Library already opened !"); - this->libraryHandle = dlopen(path.native().c_str(), RTLD_LAZY); - CHECK(this->libraryHandle, - false, - "Fail to load library: %s [dlerror=%s]", - path.generic_string().c_str(), - dlerror()); return true; } -void* Library::GetFunction(const char* functionName) const +void* Library::GetFunction(const char* name) const { - CHECK(this->libraryHandle, nullptr, "Library was not loaded --> have you call Load(...) first ?"); - CHECK(functionName, nullptr, "Expecting a valid (non-null) function name !"); - CHECK(*functionName, nullptr, "Expecting a valid (non-empty) function name !"); + CHECK(libraryHandle, nullptr, "Library was not loaded --> have you call Load(...) first ?"); + CHECK(name, nullptr, "Expecting a valid (non-null) function name !"); + CHECK(*name, nullptr, "Expecting a valid (non-empty) function name !"); + // all good - void* fnPtr = dlsym(libraryHandle, functionName); - const char* dlsym_error = dlerror(); - CHECK((dlsym_error == nullptr) && (fnPtr), - nullptr, - "Unable to find address of function: %s [dlerror=%s]", - functionName, - dlsym_error); + void* fnPtr = dlsym(libraryHandle, name); + const char* error = dlerror(); + CHECK(!error && fnPtr, nullptr, "Unable to find address of function: %s [dlerror=%s]", name, error); return fnPtr; } -} +} // namespace AppCUI::OS diff --git a/AppCUI/src/OS/Windows/Library.cpp b/AppCUI/src/OS/Windows/Library.cpp index 9b7d9de1..36a491a7 100644 --- a/AppCUI/src/OS/Windows/Library.cpp +++ b/AppCUI/src/OS/Windows/Library.cpp @@ -22,15 +22,15 @@ bool Library::Load(const std::filesystem::path& path, std::string& errorMessage) return true; } -void* Library::GetFunction(const char* functionName) const +void* Library::GetFunction(const char* name) const { - CHECK(this->libraryHandle, nullptr, "Library was not loaded --> have you call Load(...) first ?"); - CHECK(functionName, nullptr, "Expecting a valid (non-null) function name !"); - CHECK(*functionName, nullptr, "Expecting a valid (non-empty) function name !"); + CHECK(libraryHandle, nullptr, "Library was not loaded --> have you call Load(...) first ?"); + CHECK(name, nullptr, "Expecting a valid (non-null) function name !"); + CHECK(*name, nullptr, "Expecting a valid (non-empty) function name !"); // all good - void* fnPtr = GetProcAddress((HMODULE) this->libraryHandle, functionName); - CHECK(fnPtr, nullptr, "Unable to find address of function: %s", functionName); + void* fnPtr = GetProcAddress((HMODULE) libraryHandle, name); + CHECK(fnPtr, nullptr, "Unable to find address of function: %s", name); return fnPtr; } -} // namespace AppCUI::OS \ No newline at end of file +} // namespace AppCUI::OS From 020fc4d8f1bc0f38afd0ffe6ebb7140d17504e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gheorghi=C8=9B=C4=83=20Mutu?= Date: Wed, 15 Jan 2025 01:11:24 +0300 Subject: [PATCH 3/6] ^ replace cmakerc hardcoded with a vcpkg managed version #460 --- AppCUI/CMakeLists.txt | 4 +- cmake/CMakeRC.cmake | 645 ------------------------------------------ vcpkg | 2 +- vcpkg.json | 4 + 4 files changed, 7 insertions(+), 648 deletions(-) delete mode 100644 cmake/CMakeRC.cmake diff --git a/AppCUI/CMakeLists.txt b/AppCUI/CMakeLists.txt index 8d35aec8..545e8253 100644 --- a/AppCUI/CMakeLists.txt +++ b/AppCUI/CMakeLists.txt @@ -113,8 +113,8 @@ target_link_libraries(${PROJECT_NAME} PRIVATE $ ${FREETYPE_LIBRARIES}") target_link_libraries(${PROJECT_NAME} PRIVATE ${FREETYPE_LIBRARIES}) -# Add font used by SDL -include(CMakeRC) +# Add font used by SDL +find_package(CMakeRC CONFIG REQUIRED) set(FONT_NAME JuliaMono-Regular.ttf) set(FONT_PATH resources/${FONT_NAME}) diff --git a/cmake/CMakeRC.cmake b/cmake/CMakeRC.cmake deleted file mode 100644 index 6349b0df..00000000 --- a/cmake/CMakeRC.cmake +++ /dev/null @@ -1,645 +0,0 @@ -# This block is executed when generating an intermediate resource file, not when -# running in CMake configure mode -if(_CMRC_GENERATE_MODE) - # Read in the digits - file(READ "${INPUT_FILE}" bytes HEX) - # Format each pair into a character literal. Heuristics seem to favor doing - # the conversion in groups of five for fastest conversion - string(REGEX REPLACE "(..)(..)(..)(..)(..)" "'\\\\x\\1','\\\\x\\2','\\\\x\\3','\\\\x\\4','\\\\x\\5'," chars "${bytes}") - # Since we did this in groups, we have some leftovers to clean up - string(LENGTH "${bytes}" n_bytes2) - math(EXPR n_bytes "${n_bytes2} / 2") - math(EXPR remainder "${n_bytes} % 5") # <-- '5' is the grouping count from above - set(cleanup_re "$") - set(cleanup_sub ) - while(remainder) - set(cleanup_re "(..)${cleanup_re}") - set(cleanup_sub "'\\\\x\\${remainder}',${cleanup_sub}") - math(EXPR remainder "${remainder} - 1") - endwhile() - if(NOT cleanup_re STREQUAL "$") - string(REGEX REPLACE "${cleanup_re}" "${cleanup_sub}" chars "${chars}") - endif() - string(CONFIGURE [[ - namespace { const char file_array[] = { @chars@ 0 }; } - namespace cmrc { namespace @NAMESPACE@ { namespace res_chars { - extern const char* const @SYMBOL@_begin = file_array; - extern const char* const @SYMBOL@_end = file_array + @n_bytes@; - }}} - ]] code) - file(WRITE "${OUTPUT_FILE}" "${code}") - # Exit from the script. Nothing else needs to be processed - return() -endif() - -set(_version 2.0.0) - -cmake_minimum_required(VERSION 3.3) -include(CMakeParseArguments) - -if(COMMAND cmrc_add_resource_library) - if(NOT DEFINED _CMRC_VERSION OR NOT (_version STREQUAL _CMRC_VERSION)) - message(WARNING "More than one CMakeRC version has been included in this project.") - endif() - # CMakeRC has already been included! Don't do anything - return() -endif() - -set(_CMRC_VERSION "${_version}" CACHE INTERNAL "CMakeRC version. Used for checking for conflicts") - -set(_CMRC_SCRIPT "${CMAKE_CURRENT_LIST_FILE}" CACHE INTERNAL "Path to CMakeRC script") - -function(_cmrc_normalize_path var) - set(path "${${var}}") - file(TO_CMAKE_PATH "${path}" path) - while(path MATCHES "//") - string(REPLACE "//" "/" path "${path}") - endwhile() - string(REGEX REPLACE "/+$" "" path "${path}") - set("${var}" "${path}" PARENT_SCOPE) -endfunction() - -get_filename_component(_inc_dir "${CMAKE_BINARY_DIR}/_cmrc/include" ABSOLUTE) -set(CMRC_INCLUDE_DIR "${_inc_dir}" CACHE INTERNAL "Directory for CMakeRC include files") -# Let's generate the primary include file -file(MAKE_DIRECTORY "${CMRC_INCLUDE_DIR}/cmrc") -set(hpp_content [==[ -#ifndef CMRC_CMRC_HPP_INCLUDED -#define CMRC_CMRC_HPP_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !(defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) || defined(CMRC_NO_EXCEPTIONS)) -#define CMRC_NO_EXCEPTIONS 1 -#endif - -namespace cmrc { namespace detail { struct dummy; } } - -#define CMRC_DECLARE(libid) \ - namespace cmrc { namespace detail { \ - struct dummy; \ - static_assert(std::is_same::value, "CMRC_DECLARE() must only appear at the global namespace"); \ - } } \ - namespace cmrc { namespace libid { \ - cmrc::embedded_filesystem get_filesystem(); \ - } } static_assert(true, "") - -namespace cmrc { - -class file { - const char* _begin = nullptr; - const char* _end = nullptr; - -public: - using iterator = const char*; - using const_iterator = iterator; - iterator begin() const noexcept { return _begin; } - iterator cbegin() const noexcept { return _begin; } - iterator end() const noexcept { return _end; } - iterator cend() const noexcept { return _end; } - std::size_t size() const { return static_cast(std::distance(begin(), end())); } - - file() = default; - file(iterator beg, iterator end) noexcept : _begin(beg), _end(end) {} -}; - -class directory_entry; - -namespace detail { - -class directory; -class file_data; - -class file_or_directory { - union _data_t { - class file_data* file_data; - class directory* directory; - } _data; - bool _is_file = true; - -public: - explicit file_or_directory(file_data& f) { - _data.file_data = &f; - } - explicit file_or_directory(directory& d) { - _data.directory = &d; - _is_file = false; - } - bool is_file() const noexcept { - return _is_file; - } - bool is_directory() const noexcept { - return !is_file(); - } - const directory& as_directory() const noexcept { - assert(!is_file()); - return *_data.directory; - } - const file_data& as_file() const noexcept { - assert(is_file()); - return *_data.file_data; - } -}; - -class file_data { -public: - const char* begin_ptr; - const char* end_ptr; - file_data(const file_data&) = delete; - file_data(const char* b, const char* e) : begin_ptr(b), end_ptr(e) {} -}; - -inline std::pair split_path(const std::string& path) { - auto first_sep = path.find("/"); - if (first_sep == path.npos) { - return std::make_pair(path, ""); - } else { - return std::make_pair(path.substr(0, first_sep), path.substr(first_sep + 1)); - } -} - -struct created_subdirectory { - class directory& directory; - class file_or_directory& index_entry; -}; - -class directory { - std::list _files; - std::list _dirs; - std::map _index; - - using base_iterator = std::map::const_iterator; - -public: - - directory() = default; - directory(const directory&) = delete; - - created_subdirectory add_subdir(std::string name) & { - _dirs.emplace_back(); - auto& back = _dirs.back(); - auto& fod = _index.emplace(name, file_or_directory{back}).first->second; - return created_subdirectory{back, fod}; - } - - file_or_directory* add_file(std::string name, const char* begin, const char* end) & { - assert(_index.find(name) == _index.end()); - _files.emplace_back(begin, end); - return &_index.emplace(name, file_or_directory{_files.back()}).first->second; - } - - const file_or_directory* get(const std::string& path) const { - auto pair = split_path(path); - auto child = _index.find(pair.first); - if (child == _index.end()) { - return nullptr; - } - auto& entry = child->second; - if (pair.second.empty()) { - // We're at the end of the path - return &entry; - } - - if (entry.is_file()) { - // We can't traverse into a file. Stop. - return nullptr; - } - // Keep going down - return entry.as_directory().get(pair.second); - } - - class iterator { - base_iterator _base_iter; - base_iterator _end_iter; - public: - using value_type = directory_entry; - using difference_type = std::ptrdiff_t; - using pointer = const value_type*; - using reference = const value_type&; - using iterator_category = std::input_iterator_tag; - - iterator() = default; - explicit iterator(base_iterator iter, base_iterator end) : _base_iter(iter), _end_iter(end) {} - - iterator begin() const noexcept { - return *this; - } - - iterator end() const noexcept { - return iterator(_end_iter, _end_iter); - } - - inline value_type operator*() const noexcept; - - bool operator==(const iterator& rhs) const noexcept { - return _base_iter == rhs._base_iter; - } - - bool operator!=(const iterator& rhs) const noexcept { - return !(*this == rhs); - } - - iterator operator++() noexcept { - auto cp = *this; - ++_base_iter; - return cp; - } - - iterator& operator++(int) noexcept { - ++_base_iter; - return *this; - } - }; - - using const_iterator = iterator; - - iterator begin() const noexcept { - return iterator(_index.begin(), _index.end()); - } - - iterator end() const noexcept { - return iterator(); - } -}; - -inline std::string normalize_path(std::string path) { - while (path.find("/") == 0) { - path.erase(path.begin()); - } - while (!path.empty() && (path.rfind("/") == path.size() - 1)) { - path.pop_back(); - } - auto off = path.npos; - while ((off = path.find("//")) != path.npos) { - path.erase(path.begin() + static_cast(off)); - } - return path; -} - -using index_type = std::map; - -} // detail - -class directory_entry { - std::string _fname; - const detail::file_or_directory* _item; - -public: - directory_entry() = delete; - explicit directory_entry(std::string filename, const detail::file_or_directory& item) - : _fname(filename) - , _item(&item) - {} - - const std::string& filename() const & { - return _fname; - } - std::string filename() const && { - return std::move(_fname); - } - - bool is_file() const { - return _item->is_file(); - } - - bool is_directory() const { - return _item->is_directory(); - } -}; - -directory_entry detail::directory::iterator::operator*() const noexcept { - assert(begin() != end()); - return directory_entry(_base_iter->first, _base_iter->second); -} - -using directory_iterator = detail::directory::iterator; - -class embedded_filesystem { - // Never-null: - const cmrc::detail::index_type* _index; - const detail::file_or_directory* _get(std::string path) const { - path = detail::normalize_path(path); - auto found = _index->find(path); - if (found == _index->end()) { - return nullptr; - } else { - return found->second; - } - } - -public: - explicit embedded_filesystem(const detail::index_type& index) - : _index(&index) - {} - - file open(const std::string& path) const { - auto entry_ptr = _get(path); - if (!entry_ptr || !entry_ptr->is_file()) { -#ifdef CMRC_NO_EXCEPTIONS - fprintf(stderr, "Error no such file or directory: %s\n", path.c_str()); - abort(); -#else - throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path); -#endif - } - auto& dat = entry_ptr->as_file(); - return file{dat.begin_ptr, dat.end_ptr}; - } - - bool is_file(const std::string& path) const noexcept { - auto entry_ptr = _get(path); - return entry_ptr && entry_ptr->is_file(); - } - - bool is_directory(const std::string& path) const noexcept { - auto entry_ptr = _get(path); - return entry_ptr && entry_ptr->is_directory(); - } - - bool exists(const std::string& path) const noexcept { - return !!_get(path); - } - - directory_iterator iterate_directory(const std::string& path) const { - auto entry_ptr = _get(path); - if (!entry_ptr) { -#ifdef CMRC_NO_EXCEPTIONS - fprintf(stderr, "Error no such file or directory: %s\n", path.c_str()); - abort(); -#else - throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path); -#endif - } - if (!entry_ptr->is_directory()) { -#ifdef CMRC_NO_EXCEPTIONS - fprintf(stderr, "Error not a directory: %s\n", path.c_str()); - abort(); -#else - throw std::system_error(make_error_code(std::errc::not_a_directory), path); -#endif - } - return entry_ptr->as_directory().begin(); - } -}; - -} - -#endif // CMRC_CMRC_HPP_INCLUDED -]==]) - -set(cmrc_hpp "${CMRC_INCLUDE_DIR}/cmrc/cmrc.hpp" CACHE INTERNAL "") -set(_generate 1) -if(EXISTS "${cmrc_hpp}") - file(READ "${cmrc_hpp}" _current) - if(_current STREQUAL hpp_content) - set(_generate 0) - endif() -endif() -file(GENERATE OUTPUT "${cmrc_hpp}" CONTENT "${hpp_content}" CONDITION ${_generate}) - -add_library(cmrc-base INTERFACE) -target_include_directories(cmrc-base INTERFACE "${CMRC_INCLUDE_DIR}") -# Signal a basic C++11 feature to require C++11. -target_compile_features(cmrc-base INTERFACE cxx_nullptr) -set_property(TARGET cmrc-base PROPERTY INTERFACE_CXX_EXTENSIONS OFF) -add_library(cmrc::base ALIAS cmrc-base) - -function(cmrc_add_resource_library name) - set(args ALIAS NAMESPACE TYPE) - cmake_parse_arguments(ARG "" "${args}" "" "${ARGN}") - # Generate the identifier for the resource library's namespace - set(ns_re "[a-zA-Z_][a-zA-Z0-9_]*") - if(NOT DEFINED ARG_NAMESPACE) - # Check that the library name is also a valid namespace - if(NOT name MATCHES "${ns_re}") - message(SEND_ERROR "Library name is not a valid namespace. Specify the NAMESPACE argument") - endif() - set(ARG_NAMESPACE "${name}") - else() - if(NOT ARG_NAMESPACE MATCHES "${ns_re}") - message(SEND_ERROR "NAMESPACE for ${name} is not a valid C++ namespace identifier (${ARG_NAMESPACE})") - endif() - endif() - set(libname "${name}") - # Check that type is either "STATIC" or "OBJECT", or default to "STATIC" if - # not set - if(NOT DEFINED ARG_TYPE) - set(ARG_TYPE STATIC) - elseif(NOT "${ARG_TYPE}" MATCHES "^(STATIC|OBJECT)$") - message(SEND_ERROR "${ARG_TYPE} is not a valid TYPE (STATIC and OBJECT are acceptable)") - set(ARG_TYPE STATIC) - endif() - # Generate a library with the compiled in character arrays. - string(CONFIGURE [=[ - #include - #include - #include - - namespace cmrc { - namespace @ARG_NAMESPACE@ { - - namespace res_chars { - // These are the files which are available in this resource library - $, - > - } - - namespace { - - const cmrc::detail::index_type& - get_root_index() { - static cmrc::detail::directory root_directory_; - static cmrc::detail::file_or_directory root_directory_fod{root_directory_}; - static cmrc::detail::index_type root_index; - root_index.emplace("", &root_directory_fod); - struct dir_inl { - class cmrc::detail::directory& directory; - }; - dir_inl root_directory_dir{root_directory_}; - (void)root_directory_dir; - $, - > - $, - > - return root_index; - } - - } - - cmrc::embedded_filesystem get_filesystem() { - static auto& index = get_root_index(); - return cmrc::embedded_filesystem{index}; - } - - } // @ARG_NAMESPACE@ - } // cmrc - ]=] cpp_content @ONLY) - get_filename_component(libdir "${CMAKE_CURRENT_BINARY_DIR}/__cmrc_${name}" ABSOLUTE) - get_filename_component(lib_tmp_cpp "${libdir}/lib_.cpp" ABSOLUTE) - string(REPLACE "\n " "\n" cpp_content "${cpp_content}") - file(GENERATE OUTPUT "${lib_tmp_cpp}" CONTENT "${cpp_content}") - get_filename_component(libcpp "${libdir}/lib.cpp" ABSOLUTE) - add_custom_command(OUTPUT "${libcpp}" - DEPENDS "${lib_tmp_cpp}" "${cmrc_hpp}" - COMMAND ${CMAKE_COMMAND} -E copy_if_different "${lib_tmp_cpp}" "${libcpp}" - COMMENT "Generating ${name} resource loader" - ) - # Generate the actual static library. Each source file is just a single file - # with a character array compiled in containing the contents of the - # corresponding resource file. - add_library(${name} ${ARG_TYPE} ${libcpp}) - set_property(TARGET ${name} PROPERTY CMRC_LIBDIR "${libdir}") - set_property(TARGET ${name} PROPERTY CMRC_NAMESPACE "${ARG_NAMESPACE}") - target_compile_options(${name} PRIVATE -fPIC) - target_link_libraries(${name} PUBLIC cmrc::base) - set_property(TARGET ${name} PROPERTY CMRC_IS_RESOURCE_LIBRARY TRUE) - if(ARG_ALIAS) - add_library("${ARG_ALIAS}" ALIAS ${name}) - endif() - cmrc_add_resources(${name} ${ARG_UNPARSED_ARGUMENTS}) -endfunction() - -function(_cmrc_register_dirs name dirpath) - if(dirpath STREQUAL "") - return() - endif() - # Skip this dir if we have already registered it - get_target_property(registered "${name}" _CMRC_REGISTERED_DIRS) - if(dirpath IN_LIST registered) - return() - endif() - # Register the parent directory first - get_filename_component(parent "${dirpath}" DIRECTORY) - if(NOT parent STREQUAL "") - _cmrc_register_dirs("${name}" "${parent}") - endif() - # Now generate the registration - set_property(TARGET "${name}" APPEND PROPERTY _CMRC_REGISTERED_DIRS "${dirpath}") - _cm_encode_fpath(sym "${dirpath}") - if(parent STREQUAL "") - set(parent_sym root_directory) - else() - _cm_encode_fpath(parent_sym "${parent}") - endif() - get_filename_component(leaf "${dirpath}" NAME) - set_property( - TARGET "${name}" - APPEND PROPERTY CMRC_MAKE_DIRS - "static auto ${sym}_dir = ${parent_sym}_dir.directory.add_subdir(\"${leaf}\")\;" - "root_index.emplace(\"${dirpath}\", &${sym}_dir.index_entry)\;" - ) -endfunction() - -function(cmrc_add_resources name) - get_target_property(is_reslib ${name} CMRC_IS_RESOURCE_LIBRARY) - if(NOT TARGET ${name} OR NOT is_reslib) - message(SEND_ERROR "cmrc_add_resources called on target '${name}' which is not an existing resource library") - return() - endif() - - set(options) - set(args WHENCE PREFIX) - set(list_args) - cmake_parse_arguments(ARG "${options}" "${args}" "${list_args}" "${ARGN}") - - if(NOT ARG_WHENCE) - set(ARG_WHENCE ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - _cmrc_normalize_path(ARG_WHENCE) - get_filename_component(ARG_WHENCE "${ARG_WHENCE}" ABSOLUTE) - - # Generate the identifier for the resource library's namespace - get_target_property(lib_ns "${name}" CMRC_NAMESPACE) - - get_target_property(libdir ${name} CMRC_LIBDIR) - get_target_property(target_dir ${name} SOURCE_DIR) - file(RELATIVE_PATH reldir "${target_dir}" "${CMAKE_CURRENT_SOURCE_DIR}") - if(reldir MATCHES "^\\.\\.") - message(SEND_ERROR "Cannot call cmrc_add_resources in a parent directory from the resource library target") - return() - endif() - - foreach(input IN LISTS ARG_UNPARSED_ARGUMENTS) - _cmrc_normalize_path(input) - get_filename_component(abs_in "${input}" ABSOLUTE) - # Generate a filename based on the input filename that we can put in - # the intermediate directory. - file(RELATIVE_PATH relpath "${ARG_WHENCE}" "${abs_in}") - if(relpath MATCHES "^\\.\\.") - # For now we just error on files that exist outside of the soure dir. - message(SEND_ERROR "Cannot add file '${input}': File must be in a subdirectory of ${ARG_WHENCE}") - continue() - endif() - if(DEFINED ARG_PREFIX) - _cmrc_normalize_path(ARG_PREFIX) - endif() - if(ARG_PREFIX AND NOT ARG_PREFIX MATCHES "/$") - set(ARG_PREFIX "${ARG_PREFIX}/") - endif() - get_filename_component(dirpath "${ARG_PREFIX}${relpath}" DIRECTORY) - _cmrc_register_dirs("${name}" "${dirpath}") - get_filename_component(abs_out "${libdir}/intermediate/${relpath}.cpp" ABSOLUTE) - # Generate a symbol name relpath the file's character array - _cm_encode_fpath(sym "${relpath}") - # Get the symbol name for the parent directory - if(dirpath STREQUAL "") - set(parent_sym root_directory) - else() - _cm_encode_fpath(parent_sym "${dirpath}") - endif() - # Generate the rule for the intermediate source file - _cmrc_generate_intermediate_cpp(${lib_ns} ${sym} "${abs_out}" "${abs_in}") - target_sources(${name} PRIVATE "${abs_out}") - set_property(TARGET ${name} APPEND PROPERTY CMRC_EXTERN_DECLS - "// Pointers to ${input}" - "extern const char* const ${sym}_begin\;" - "extern const char* const ${sym}_end\;" - ) - get_filename_component(leaf "${relpath}" NAME) - set_property( - TARGET ${name} - APPEND PROPERTY CMRC_MAKE_FILES - "root_index.emplace(" - " \"${ARG_PREFIX}${relpath}\"," - " ${parent_sym}_dir.directory.add_file(" - " \"${leaf}\"," - " res_chars::${sym}_begin," - " res_chars::${sym}_end" - " )" - ")\;" - ) - endforeach() -endfunction() - -function(_cmrc_generate_intermediate_cpp lib_ns symbol outfile infile) - add_custom_command( - # This is the file we will generate - OUTPUT "${outfile}" - # These are the primary files that affect the output - DEPENDS "${infile}" "${_CMRC_SCRIPT}" - COMMAND - "${CMAKE_COMMAND}" - -D_CMRC_GENERATE_MODE=TRUE - -DNAMESPACE=${lib_ns} - -DSYMBOL=${symbol} - "-DINPUT_FILE=${infile}" - "-DOUTPUT_FILE=${outfile}" - -P "${_CMRC_SCRIPT}" - COMMENT "Generating intermediate file for ${infile}" - ) -endfunction() - -function(_cm_encode_fpath var fpath) - string(MAKE_C_IDENTIFIER "${fpath}" ident) - string(MD5 hash "${fpath}") - string(SUBSTRING "${hash}" 0 4 hash) - set(${var} f_${hash}_${ident} PARENT_SCOPE) -endfunction() \ No newline at end of file diff --git a/vcpkg b/vcpkg index 136a0d8b..d4f3e122 160000 --- a/vcpkg +++ b/vcpkg @@ -1 +1 @@ -Subproject commit 136a0d8b8c4584e07e5b394d69e492f679d81737 +Subproject commit d4f3e122069912636c123b7ece673f6e01513cea diff --git a/vcpkg.json b/vcpkg.json index d753bf14..387f914c 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -37,6 +37,10 @@ { "name": "libjpeg-turbo", "platform": "windows | linux | osx" + }, + { + "name": "cmakerc", + "platform": "windows | linux | osx" } ], "vcpkg-configuration": { From 5a043a8b198e8338fd2b3f8821a2fffdbe4c2b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gheorghi=C8=9B=C4=83=20Mutu?= Date: Wed, 15 Jan 2025 01:12:09 +0300 Subject: [PATCH 4/6] # fix missing Windows SDL binaries (main & ttf) in build folder #460 --- AppCUI/CMakeLists.txt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/AppCUI/CMakeLists.txt b/AppCUI/CMakeLists.txt index 545e8253..2425aa0f 100644 --- a/AppCUI/CMakeLists.txt +++ b/AppCUI/CMakeLists.txt @@ -56,7 +56,7 @@ find_package(libjpeg-turbo CONFIG REQUIRED) find_package(PNG REQUIRED) find_package(Freetype REQUIRED) find_package(SDL2 CONFIG REQUIRED) -find_package(SDL2TTF REQUIRED) +find_package(SDL2_ttf CONFIG REQUIRED) if (UNIX) if (APPLE) @@ -125,8 +125,18 @@ message("FONT_NAME => ${FONT_NAME}") message("FONT_PATH => ${FONT_PATH}") message("FONT_LIB_NAME => ${FONT_LIB_NAME}") -target_include_directories(${PROJECT_NAME} PRIVATE ${SDL2_INCLUDE_DIR} ${SDL2TTF_INCLUDE_DIR}) -target_link_libraries(${PROJECT_NAME} PRIVATE ${SDL2_LIBRARIES} ${SDL2TTF_LIBRARY}) +target_include_directories(${PROJECT_NAME} PRIVATE ${SDL2_INCLUDE_DIR}) +target_link_libraries(${PROJECT_NAME} + PRIVATE + $ + $,SDL2::SDL2,SDL2::SDL2-static> +) + +target_include_directories(${PROJECT_NAME} PRIVATE ${SDL2TTF_INCLUDE_DIR}) +target_link_libraries(${PROJECT_NAME} + PRIVATE + $,SDL2_ttf::SDL2_ttf,SDL2_ttf::SDL2_ttf-static> +) target_link_libraries(${PROJECT_NAME} PRIVATE ${FONT_LIB_NAME}) if (APPLE AND NOT APPCUI_ENABLE_OUTPUT_LOCATION) From ee89cbf95fd4d28748ddef70c847ddc28cfa4282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gheorghi=C8=9B=C4=83=20Mutu?= Date: Wed, 15 Jan 2025 01:33:51 +0300 Subject: [PATCH 5/6] # bump codeql version #460 --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 09bf7556..8c40ea4b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -53,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. From e72c408cf04868dc0676dd50011c2f89e5fdc8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gheorghi=C8=9B=C4=83=20Mutu?= Date: Wed, 15 Jan 2025 01:37:01 +0300 Subject: [PATCH 6/6] # bump codeql version (2) #460 --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8c40ea4b..238b1710 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -86,4 +86,4 @@ jobs: run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3