Warning, /sdk/kshim/cmake/cmakerc/CMakeRC.cmake is written in an unsupported language. File is not indexed.

0001 # This block is executed when generating an intermediate resource file, not when
0002 # running in CMake configure mode
0003 if(_CMRC_GENERATE_MODE)
0004     # Read in the digits
0005     file(READ "${INPUT_FILE}" bytes HEX)
0006     # Format each pair into a character literal. Heuristics seem to favor doing
0007     # the conversion in groups of five for fastest conversion
0008     string(REGEX REPLACE "(..)(..)(..)(..)(..)" "'\\\\x\\1','\\\\x\\2','\\\\x\\3','\\\\x\\4','\\\\x\\5'," chars "${bytes}")
0009     # Since we did this in groups, we have some leftovers to clean up
0010     string(LENGTH "${bytes}" n_bytes2)
0011     math(EXPR n_bytes "${n_bytes2} / 2")
0012     math(EXPR remainder "${n_bytes} % 5") # <-- '5' is the grouping count from above
0013     set(cleanup_re "$")
0014     set(cleanup_sub )
0015     while(remainder)
0016         set(cleanup_re "(..)${cleanup_re}")
0017         set(cleanup_sub "'\\\\x\\${remainder}',${cleanup_sub}")
0018         math(EXPR remainder "${remainder} - 1")
0019     endwhile()
0020     if(NOT cleanup_re STREQUAL "$")
0021         string(REGEX REPLACE "${cleanup_re}" "${cleanup_sub}" chars "${chars}")
0022     endif()
0023     string(CONFIGURE [[
0024         namespace { const char file_array[] = { @chars@ 0 }; }
0025         namespace cmrc { namespace @NAMESPACE@ { namespace res_chars {
0026         extern const char* const @SYMBOL@_begin = file_array;
0027         extern const char* const @SYMBOL@_end = file_array + @n_bytes@;
0028         }}}
0029     ]] code)
0030     file(WRITE "${OUTPUT_FILE}" "${code}")
0031     # Exit from the script. Nothing else needs to be processed
0032     return()
0033 endif()
0034 
0035 set(_version 2.0.0)
0036 
0037 cmake_minimum_required(VERSION 3.12)
0038 include(CMakeParseArguments)
0039 
0040 if(COMMAND cmrc_add_resource_library)
0041     if(NOT DEFINED _CMRC_VERSION OR NOT (_version STREQUAL _CMRC_VERSION))
0042         message(WARNING "More than one CMakeRC version has been included in this project.")
0043     endif()
0044     # CMakeRC has already been included! Don't do anything
0045     return()
0046 endif()
0047 
0048 set(_CMRC_VERSION "${_version}" CACHE INTERNAL "CMakeRC version. Used for checking for conflicts")
0049 
0050 set(_CMRC_SCRIPT "${CMAKE_CURRENT_LIST_FILE}" CACHE INTERNAL "Path to CMakeRC script")
0051 
0052 function(_cmrc_normalize_path var)
0053     set(path "${${var}}")
0054     file(TO_CMAKE_PATH "${path}" path)
0055     while(path MATCHES "//")
0056         string(REPLACE "//" "/" path "${path}")
0057     endwhile()
0058     string(REGEX REPLACE "/+$" "" path "${path}")
0059     set("${var}" "${path}" PARENT_SCOPE)
0060 endfunction()
0061 
0062 get_filename_component(_inc_dir "${CMAKE_BINARY_DIR}/_cmrc/include" ABSOLUTE)
0063 set(CMRC_INCLUDE_DIR "${_inc_dir}" CACHE INTERNAL "Directory for CMakeRC include files")
0064 # Let's generate the primary include file
0065 file(MAKE_DIRECTORY "${CMRC_INCLUDE_DIR}/cmrc")
0066 set(hpp_content [==[
0067 #ifndef CMRC_CMRC_HPP_INCLUDED
0068 #define CMRC_CMRC_HPP_INCLUDED
0069 
0070 #include <cassert>
0071 #include <functional>
0072 #include <iterator>
0073 #include <list>
0074 #include <map>
0075 #include <mutex>
0076 #include <string>
0077 #include <system_error>
0078 #include <type_traits>
0079 
0080 #if !(defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) || defined(CMRC_NO_EXCEPTIONS))
0081 #define CMRC_NO_EXCEPTIONS 1
0082 #endif
0083 
0084 namespace cmrc { namespace detail { struct dummy; } }
0085 
0086 #define CMRC_DECLARE(libid) \
0087     namespace cmrc { namespace detail { \
0088     struct dummy; \
0089     static_assert(std::is_same<dummy, ::cmrc::detail::dummy>::value, "CMRC_DECLARE() must only appear at the global namespace"); \
0090     } } \
0091     namespace cmrc { namespace libid { \
0092     cmrc::embedded_filesystem get_filesystem(); \
0093     } } static_assert(true, "")
0094 
0095 namespace cmrc {
0096 
0097 class file {
0098     const char* _begin = nullptr;
0099     const char* _end = nullptr;
0100 
0101 public:
0102     using iterator = const char*;
0103     using const_iterator = iterator;
0104     iterator begin() const noexcept { return _begin; }
0105     iterator cbegin() const noexcept { return _begin; }
0106     iterator end() const noexcept { return _end; }
0107     iterator cend() const noexcept { return _end; }
0108     std::size_t size() const { return static_cast<std::size_t>(std::distance(begin(), end())); }
0109 
0110     file() = default;
0111     file(iterator beg, iterator end) noexcept : _begin(beg), _end(end) {}
0112 };
0113 
0114 class directory_entry;
0115 
0116 namespace detail {
0117 
0118 class directory;
0119 class file_data;
0120 
0121 class file_or_directory {
0122     union _data_t {
0123         class file_data* file_data;
0124         class directory* directory;
0125     } _data;
0126     bool _is_file = true;
0127 
0128 public:
0129     explicit file_or_directory(file_data& f) {
0130         _data.file_data = &f;
0131     }
0132     explicit file_or_directory(directory& d) {
0133         _data.directory = &d;
0134         _is_file = false;
0135     }
0136     bool is_file() const noexcept {
0137         return _is_file;
0138     }
0139     bool is_directory() const noexcept {
0140         return !is_file();
0141     }
0142     const directory& as_directory() const noexcept {
0143         assert(!is_file());
0144         return *_data.directory;
0145     }
0146     const file_data& as_file() const noexcept {
0147         assert(is_file());
0148         return *_data.file_data;
0149     }
0150 };
0151 
0152 class file_data {
0153 public:
0154     const char* begin_ptr;
0155     const char* end_ptr;
0156     file_data(const file_data&) = delete;
0157     file_data(const char* b, const char* e) : begin_ptr(b), end_ptr(e) {}
0158 };
0159 
0160 inline std::pair<std::string, std::string> split_path(const std::string& path) {
0161     auto first_sep = path.find("/");
0162     if (first_sep == path.npos) {
0163         return std::make_pair(path, "");
0164     } else {
0165         return std::make_pair(path.substr(0, first_sep), path.substr(first_sep + 1));
0166     }
0167 }
0168 
0169 struct created_subdirectory {
0170     class directory& directory;
0171     class file_or_directory& index_entry;
0172 };
0173 
0174 class directory {
0175     std::list<file_data> _files;
0176     std::list<directory> _dirs;
0177     std::map<std::string, file_or_directory> _index;
0178 
0179     using base_iterator = std::map<std::string, file_or_directory>::const_iterator;
0180 
0181 public:
0182 
0183     directory() = default;
0184     directory(const directory&) = delete;
0185 
0186     created_subdirectory add_subdir(std::string name) & {
0187         _dirs.emplace_back();
0188         auto& back = _dirs.back();
0189         auto& fod = _index.emplace(name, file_or_directory{back}).first->second;
0190         return created_subdirectory{back, fod};
0191     }
0192 
0193     file_or_directory* add_file(std::string name, const char* begin, const char* end) & {
0194         assert(_index.find(name) == _index.end());
0195         _files.emplace_back(begin, end);
0196         return &_index.emplace(name, file_or_directory{_files.back()}).first->second;
0197     }
0198 
0199     const file_or_directory* get(const std::string& path) const {
0200         auto pair = split_path(path);
0201         auto child = _index.find(pair.first);
0202         if (child == _index.end()) {
0203             return nullptr;
0204         }
0205         auto& entry  = child->second;
0206         if (pair.second.empty()) {
0207             // We're at the end of the path
0208             return &entry;
0209         }
0210 
0211         if (entry.is_file()) {
0212             // We can't traverse into a file. Stop.
0213             return nullptr;
0214         }
0215         // Keep going down
0216         return entry.as_directory().get(pair.second);
0217     }
0218 
0219     class iterator {
0220         base_iterator _base_iter;
0221         base_iterator _end_iter;
0222     public:
0223         using value_type = directory_entry;
0224         using difference_type = std::ptrdiff_t;
0225         using pointer = const value_type*;
0226         using reference = const value_type&;
0227         using iterator_category = std::input_iterator_tag;
0228 
0229         iterator() = default;
0230         explicit iterator(base_iterator iter, base_iterator end) : _base_iter(iter), _end_iter(end) {}
0231 
0232         iterator begin() const noexcept {
0233             return *this;
0234         }
0235 
0236         iterator end() const noexcept {
0237             return iterator(_end_iter, _end_iter);
0238         }
0239 
0240         inline value_type operator*() const noexcept;
0241 
0242         bool operator==(const iterator& rhs) const noexcept {
0243             return _base_iter == rhs._base_iter;
0244         }
0245 
0246         bool operator!=(const iterator& rhs) const noexcept {
0247             return !(*this == rhs);
0248         }
0249 
0250         iterator& operator++() noexcept {
0251             ++_base_iter;
0252             return *this;
0253         }
0254 
0255         iterator operator++(int) noexcept {
0256             auto cp = *this;
0257             ++_base_iter;
0258             return cp;
0259         }
0260     };
0261 
0262     using const_iterator = iterator;
0263 
0264     iterator begin() const noexcept {
0265         return iterator(_index.begin(), _index.end());
0266     }
0267 
0268     iterator end() const noexcept {
0269         return iterator();
0270     }
0271 };
0272 
0273 inline std::string normalize_path(std::string path) {
0274     while (path.find("/") == 0) {
0275         path.erase(path.begin());
0276     }
0277     while (!path.empty() && (path.rfind("/") == path.size() - 1)) {
0278         path.pop_back();
0279     }
0280     auto off = path.npos;
0281     while ((off = path.find("//")) != path.npos) {
0282         path.erase(path.begin() + static_cast<std::string::difference_type>(off));
0283     }
0284     return path;
0285 }
0286 
0287 using index_type = std::map<std::string, const cmrc::detail::file_or_directory*>;
0288 
0289 } // detail
0290 
0291 class directory_entry {
0292     std::string _fname;
0293     const detail::file_or_directory* _item;
0294 
0295 public:
0296     directory_entry() = delete;
0297     explicit directory_entry(std::string filename, const detail::file_or_directory& item)
0298         : _fname(filename)
0299         , _item(&item)
0300     {}
0301 
0302     const std::string& filename() const & {
0303         return _fname;
0304     }
0305     std::string filename() const && {
0306         return std::move(_fname);
0307     }
0308 
0309     bool is_file() const {
0310         return _item->is_file();
0311     }
0312 
0313     bool is_directory() const {
0314         return _item->is_directory();
0315     }
0316 };
0317 
0318 directory_entry detail::directory::iterator::operator*() const noexcept {
0319     assert(begin() != end());
0320     return directory_entry(_base_iter->first, _base_iter->second);
0321 }
0322 
0323 using directory_iterator = detail::directory::iterator;
0324 
0325 class embedded_filesystem {
0326     // Never-null:
0327     const cmrc::detail::index_type* _index;
0328     const detail::file_or_directory* _get(std::string path) const {
0329         path = detail::normalize_path(path);
0330         auto found = _index->find(path);
0331         if (found == _index->end()) {
0332             return nullptr;
0333         } else {
0334             return found->second;
0335         }
0336     }
0337 
0338 public:
0339     explicit embedded_filesystem(const detail::index_type& index)
0340         : _index(&index)
0341     {}
0342 
0343     file open(const std::string& path) const {
0344         auto entry_ptr = _get(path);
0345         if (!entry_ptr || !entry_ptr->is_file()) {
0346 #ifdef CMRC_NO_EXCEPTIONS
0347             fprintf(stderr, "Error no such file or directory: %s\n", path.c_str());
0348             abort();
0349 #else
0350             throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path);
0351 #endif
0352         }
0353         auto& dat = entry_ptr->as_file();
0354         return file{dat.begin_ptr, dat.end_ptr};
0355     }
0356 
0357     bool is_file(const std::string& path) const noexcept {
0358         auto entry_ptr = _get(path);
0359         return entry_ptr && entry_ptr->is_file();
0360     }
0361 
0362     bool is_directory(const std::string& path) const noexcept {
0363         auto entry_ptr = _get(path);
0364         return entry_ptr && entry_ptr->is_directory();
0365     }
0366 
0367     bool exists(const std::string& path) const noexcept {
0368         return !!_get(path);
0369     }
0370 
0371     directory_iterator iterate_directory(const std::string& path) const {
0372         auto entry_ptr = _get(path);
0373         if (!entry_ptr) {
0374 #ifdef CMRC_NO_EXCEPTIONS
0375             fprintf(stderr, "Error no such file or directory: %s\n", path.c_str());
0376             abort();
0377 #else
0378             throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path);
0379 #endif
0380         }
0381         if (!entry_ptr->is_directory()) {
0382 #ifdef CMRC_NO_EXCEPTIONS
0383             fprintf(stderr, "Error not a directory: %s\n", path.c_str());
0384             abort();
0385 #else
0386             throw std::system_error(make_error_code(std::errc::not_a_directory), path);
0387 #endif
0388         }
0389         return entry_ptr->as_directory().begin();
0390     }
0391 };
0392 
0393 }
0394 
0395 #endif // CMRC_CMRC_HPP_INCLUDED
0396 ]==])
0397 
0398 set(cmrc_hpp "${CMRC_INCLUDE_DIR}/cmrc/cmrc.hpp" CACHE INTERNAL "")
0399 set(_generate 1)
0400 if(EXISTS "${cmrc_hpp}")
0401     file(READ "${cmrc_hpp}" _current)
0402     if(_current STREQUAL hpp_content)
0403         set(_generate 0)
0404     endif()
0405 endif()
0406 file(GENERATE OUTPUT "${cmrc_hpp}" CONTENT "${hpp_content}" CONDITION ${_generate})
0407 
0408 add_library(cmrc-base INTERFACE)
0409 target_include_directories(cmrc-base INTERFACE $<BUILD_INTERFACE:${CMRC_INCLUDE_DIR}>)
0410 # Signal a basic C++11 feature to require C++11.
0411 target_compile_features(cmrc-base INTERFACE cxx_nullptr)
0412 set_property(TARGET cmrc-base PROPERTY INTERFACE_CXX_EXTENSIONS OFF)
0413 add_library(cmrc::base ALIAS cmrc-base)
0414 
0415 function(cmrc_add_resource_library name)
0416     set(args ALIAS NAMESPACE TYPE)
0417     cmake_parse_arguments(ARG "" "${args}" "" "${ARGN}")
0418     # Generate the identifier for the resource library's namespace
0419     set(ns_re "[a-zA-Z_][a-zA-Z0-9_]*")
0420     if(NOT DEFINED ARG_NAMESPACE)
0421         # Check that the library name is also a valid namespace
0422         if(NOT name MATCHES "${ns_re}")
0423             message(SEND_ERROR "Library name is not a valid namespace. Specify the NAMESPACE argument")
0424         endif()
0425         set(ARG_NAMESPACE "${name}")
0426     else()
0427         if(NOT ARG_NAMESPACE MATCHES "${ns_re}")
0428             message(SEND_ERROR "NAMESPACE for ${name} is not a valid C++ namespace identifier (${ARG_NAMESPACE})")
0429         endif()
0430     endif()
0431     set(libname "${name}")
0432     # Check that type is either "STATIC" or "OBJECT", or default to "STATIC" if
0433     # not set
0434     if(NOT DEFINED ARG_TYPE)
0435         set(ARG_TYPE STATIC)
0436     elseif(NOT "${ARG_TYPE}" MATCHES "^(STATIC|OBJECT)$")
0437         message(SEND_ERROR "${ARG_TYPE} is not a valid TYPE (STATIC and OBJECT are acceptable)")
0438         set(ARG_TYPE STATIC)
0439     endif()
0440     # Generate a library with the compiled in character arrays.
0441     string(CONFIGURE [=[
0442         #include <cmrc/cmrc.hpp>
0443         #include <map>
0444         #include <utility>
0445 
0446         namespace cmrc {
0447         namespace @ARG_NAMESPACE@ {
0448 
0449         namespace res_chars {
0450         // These are the files which are available in this resource library
0451         $<JOIN:$<TARGET_PROPERTY:@libname@,CMRC_EXTERN_DECLS>,
0452         >
0453         }
0454 
0455         namespace {
0456 
0457         const cmrc::detail::index_type&
0458         get_root_index() {
0459             static cmrc::detail::directory root_directory_;
0460             static cmrc::detail::file_or_directory root_directory_fod{root_directory_};
0461             static cmrc::detail::index_type root_index;
0462             root_index.emplace("", &root_directory_fod);
0463             struct dir_inl {
0464                 class cmrc::detail::directory& directory;
0465             };
0466             dir_inl root_directory_dir{root_directory_};
0467             (void)root_directory_dir;
0468             $<JOIN:$<TARGET_PROPERTY:@libname@,CMRC_MAKE_DIRS>,
0469             >
0470             $<JOIN:$<TARGET_PROPERTY:@libname@,CMRC_MAKE_FILES>,
0471             >
0472             return root_index;
0473         }
0474 
0475         }
0476 
0477         cmrc::embedded_filesystem get_filesystem() {
0478             static auto& index = get_root_index();
0479             return cmrc::embedded_filesystem{index};
0480         }
0481 
0482         } // @ARG_NAMESPACE@
0483         } // cmrc
0484     ]=] cpp_content @ONLY)
0485     get_filename_component(libdir "${CMAKE_CURRENT_BINARY_DIR}/__cmrc_${name}" ABSOLUTE)
0486     get_filename_component(lib_tmp_cpp "${libdir}/lib_.cpp" ABSOLUTE)
0487     string(REPLACE "\n        " "\n" cpp_content "${cpp_content}")
0488     file(GENERATE OUTPUT "${lib_tmp_cpp}" CONTENT "${cpp_content}")
0489     get_filename_component(libcpp "${libdir}/lib.cpp" ABSOLUTE)
0490     add_custom_command(OUTPUT "${libcpp}"
0491         DEPENDS "${lib_tmp_cpp}" "${cmrc_hpp}"
0492         COMMAND ${CMAKE_COMMAND} -E copy_if_different "${lib_tmp_cpp}" "${libcpp}"
0493         COMMENT "Generating ${name} resource loader"
0494         )
0495     # Generate the actual static library. Each source file is just a single file
0496     # with a character array compiled in containing the contents of the
0497     # corresponding resource file.
0498     add_library(${name} ${ARG_TYPE} ${libcpp})
0499     set_property(TARGET ${name} PROPERTY CMRC_LIBDIR "${libdir}")
0500     set_property(TARGET ${name} PROPERTY CMRC_NAMESPACE "${ARG_NAMESPACE}")
0501     target_link_libraries(${name} PUBLIC cmrc::base)
0502     set_property(TARGET ${name} PROPERTY CMRC_IS_RESOURCE_LIBRARY TRUE)
0503     if(ARG_ALIAS)
0504         add_library("${ARG_ALIAS}" ALIAS ${name})
0505     endif()
0506     cmrc_add_resources(${name} ${ARG_UNPARSED_ARGUMENTS})
0507 endfunction()
0508 
0509 function(_cmrc_register_dirs name dirpath)
0510     if(dirpath STREQUAL "")
0511         return()
0512     endif()
0513     # Skip this dir if we have already registered it
0514     get_target_property(registered "${name}" _CMRC_REGISTERED_DIRS)
0515     if(dirpath IN_LIST registered)
0516         return()
0517     endif()
0518     # Register the parent directory first
0519     get_filename_component(parent "${dirpath}" DIRECTORY)
0520     if(NOT parent STREQUAL "")
0521         _cmrc_register_dirs("${name}" "${parent}")
0522     endif()
0523     # Now generate the registration
0524     set_property(TARGET "${name}" APPEND PROPERTY _CMRC_REGISTERED_DIRS "${dirpath}")
0525     _cm_encode_fpath(sym "${dirpath}")
0526     if(parent STREQUAL "")
0527         set(parent_sym root_directory)
0528     else()
0529         _cm_encode_fpath(parent_sym "${parent}")
0530     endif()
0531     get_filename_component(leaf "${dirpath}" NAME)
0532     set_property(
0533         TARGET "${name}"
0534         APPEND PROPERTY CMRC_MAKE_DIRS
0535         "static auto ${sym}_dir = ${parent_sym}_dir.directory.add_subdir(\"${leaf}\")\;"
0536         "root_index.emplace(\"${dirpath}\", &${sym}_dir.index_entry)\;"
0537         )
0538 endfunction()
0539 
0540 function(cmrc_add_resources name)
0541     get_target_property(is_reslib ${name} CMRC_IS_RESOURCE_LIBRARY)
0542     if(NOT TARGET ${name} OR NOT is_reslib)
0543         message(SEND_ERROR "cmrc_add_resources called on target '${name}' which is not an existing resource library")
0544         return()
0545     endif()
0546 
0547     set(options)
0548     set(args WHENCE PREFIX)
0549     set(list_args)
0550     cmake_parse_arguments(ARG "${options}" "${args}" "${list_args}" "${ARGN}")
0551 
0552     if(NOT ARG_WHENCE)
0553         set(ARG_WHENCE ${CMAKE_CURRENT_SOURCE_DIR})
0554     endif()
0555     _cmrc_normalize_path(ARG_WHENCE)
0556     get_filename_component(ARG_WHENCE "${ARG_WHENCE}" ABSOLUTE)
0557 
0558     # Generate the identifier for the resource library's namespace
0559     get_target_property(lib_ns "${name}" CMRC_NAMESPACE)
0560 
0561     get_target_property(libdir ${name} CMRC_LIBDIR)
0562     get_target_property(target_dir ${name} SOURCE_DIR)
0563     file(RELATIVE_PATH reldir "${target_dir}" "${CMAKE_CURRENT_SOURCE_DIR}")
0564     if(reldir MATCHES "^\\.\\.")
0565         message(SEND_ERROR "Cannot call cmrc_add_resources in a parent directory from the resource library target")
0566         return()
0567     endif()
0568 
0569     foreach(input IN LISTS ARG_UNPARSED_ARGUMENTS)
0570         _cmrc_normalize_path(input)
0571         get_filename_component(abs_in "${input}" ABSOLUTE)
0572         # Generate a filename based on the input filename that we can put in
0573         # the intermediate directory.
0574         file(RELATIVE_PATH relpath "${ARG_WHENCE}" "${abs_in}")
0575         if(relpath MATCHES "^\\.\\.")
0576             # For now we just error on files that exist outside of the soure dir.
0577             message(SEND_ERROR "Cannot add file '${input}': File must be in a subdirectory of ${ARG_WHENCE}")
0578             continue()
0579         endif()
0580         if(DEFINED ARG_PREFIX)
0581             _cmrc_normalize_path(ARG_PREFIX)
0582         endif()
0583         if(ARG_PREFIX AND NOT ARG_PREFIX MATCHES "/$")
0584             set(ARG_PREFIX "${ARG_PREFIX}/")
0585         endif()
0586         get_filename_component(dirpath "${ARG_PREFIX}${relpath}" DIRECTORY)
0587         _cmrc_register_dirs("${name}" "${dirpath}")
0588         get_filename_component(abs_out "${libdir}/intermediate/${ARG_PREFIX}${relpath}.cpp" ABSOLUTE)
0589         # Generate a symbol name relpath the file's character array
0590         _cm_encode_fpath(sym "${relpath}")
0591         # Get the symbol name for the parent directory
0592         if(dirpath STREQUAL "")
0593             set(parent_sym root_directory)
0594         else()
0595             _cm_encode_fpath(parent_sym "${dirpath}")
0596         endif()
0597         # Generate the rule for the intermediate source file
0598         _cmrc_generate_intermediate_cpp(${lib_ns} ${sym} "${abs_out}" "${abs_in}")
0599         target_sources(${name} PRIVATE "${abs_out}")
0600         set_property(TARGET ${name} APPEND PROPERTY CMRC_EXTERN_DECLS
0601             "// Pointers to ${input}"
0602             "extern const char* const ${sym}_begin\;"
0603             "extern const char* const ${sym}_end\;"
0604             )
0605         get_filename_component(leaf "${relpath}" NAME)
0606         set_property(
0607             TARGET ${name}
0608             APPEND PROPERTY CMRC_MAKE_FILES
0609             "root_index.emplace("
0610             "    \"${ARG_PREFIX}${relpath}\","
0611             "    ${parent_sym}_dir.directory.add_file("
0612             "        \"${leaf}\","
0613             "        res_chars::${sym}_begin,"
0614             "        res_chars::${sym}_end"
0615             "    )"
0616             ")\;"
0617             )
0618     endforeach()
0619 endfunction()
0620 
0621 function(_cmrc_generate_intermediate_cpp lib_ns symbol outfile infile)
0622     add_custom_command(
0623         # This is the file we will generate
0624         OUTPUT "${outfile}"
0625         # These are the primary files that affect the output
0626         DEPENDS "${infile}" "${_CMRC_SCRIPT}"
0627         COMMAND
0628             "${CMAKE_COMMAND}"
0629                 -D_CMRC_GENERATE_MODE=TRUE
0630                 -DNAMESPACE=${lib_ns}
0631                 -DSYMBOL=${symbol}
0632                 "-DINPUT_FILE=${infile}"
0633                 "-DOUTPUT_FILE=${outfile}"
0634                 -P "${_CMRC_SCRIPT}"
0635         COMMENT "Generating intermediate file for ${infile}"
0636     )
0637 endfunction()
0638 
0639 function(_cm_encode_fpath var fpath)
0640     string(MAKE_C_IDENTIFIER "${fpath}" ident)
0641     string(MD5 hash "${fpath}")
0642     string(SUBSTRING "${hash}" 0 4 hash)
0643     set(${var} f_${hash}_${ident} PARENT_SCOPE)
0644 endfunction()