diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1a139ac --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# cmkr +/**/CMakeLists.txt linguist-generated +/**/cmkr.cmake linguist-vendored diff --git a/.gitignore b/.gitignore index dfd8bfa..bfe6c1f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,9 @@ expected.out cmake-build*/ build*/ .idea/ +.cache/ +*.pp.h + +# cmkr +CMakerLists.txt +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..115b610 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,80 @@ +# This file is automatically generated from cmake.toml - DO NOT EDIT +# See https://github.com/build-cpp/cmkr for more information + +cmake_minimum_required(VERSION 3.15) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build") +endif() + +set(CMKR_ROOT_PROJECT OFF) +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(CMKR_ROOT_PROJECT ON) + + # Bootstrap cmkr and automatically regenerate CMakeLists.txt + include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT) + if(CMKR_INCLUDE_RESULT) + cmkr() + endif() + + # Enable folder support + set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + # Create a configure-time dependency on cmake.toml to improve IDE support + configure_file(cmake.toml cmake.toml COPYONLY) +endif() + +project(btparser) + +# Target: btparser +set(btparser_SOURCES + "btparser/lexer.cpp" + "btparser/preprocessor.cpp" + "btparser/types.cpp" + "btparser/typesparser.cpp" + "btparser/ast.h" + "btparser/helpers.h" + "btparser/keywords.h" + "btparser/lexer.h" + "btparser/operators.h" + "btparser/preprocessor.h" + "btparser/testfiles.h" + "btparser/types.h" + cmake.toml +) + +add_library(btparser STATIC) + +target_sources(btparser PRIVATE ${btparser_SOURCES}) +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${btparser_SOURCES}) + +target_compile_features(btparser PUBLIC + cxx_std_14 +) + +target_include_directories(btparser PUBLIC + btparser +) + +# Target: test +if(CMKR_ROOT_PROJECT) # root + set(test_SOURCES + "btparser/main.cpp" + cmake.toml + ) + + add_executable(test) + + target_sources(test PRIVATE ${test_SOURCES}) + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${test_SOURCES}) + + target_link_libraries(test PRIVATE + btparser + ) + + get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT) + if(NOT CMKR_VS_STARTUP_PROJECT) + set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT test) + endif() + +endif() diff --git a/btparser/helpers.h b/btparser/helpers.h index 593006f..725491f 100644 --- a/btparser/helpers.h +++ b/btparser/helpers.h @@ -2,9 +2,33 @@ #include #include -#include #include +#ifdef _WIN32 +#include +#else +#endif // _WIN32 + +#if defined(_MSC_VER) +#include +#elif defined(__clang__) +#define __debugbreak() __builtin_debugtrap() +#elif defined(__GNUC__) +#define __debugbreak() __builtin_trap() +#else +#warning Unsupported platform/compiler +#include +#define __debugbreak() raise(SIGTRAP) +#endif // _MSC_VER + +#ifndef _MSC_VER +template +static int sprintf_s(char (&dst)[Count], const char* fmt, Args&&... args) +{ + return snprintf(dst, Count, fmt, std::forward(args)...); +} +#endif // _MSC_VER + namespace StringUtils { inline std::string sprintf(const char* format, ...) @@ -14,7 +38,11 @@ namespace StringUtils std::vector buffer(256, '\0'); while(true) { +#ifdef _WIN32 int res = _vsnprintf_s(buffer.data(), buffer.size(), _TRUNCATE, format, args); +#else + int res = vsnprintf(buffer.data(), buffer.size(), format, args); +#endif // _WIN32 if(res == -1) { buffer.resize(buffer.size() * 2); @@ -52,7 +80,9 @@ namespace StringUtils return "\\\""; default: if(!isprint(ch)) //unknown unprintable character + { sprintf_s(buf, "\\x%02X", ch); + } else *buf = ch; return buf; @@ -65,19 +95,7 @@ namespace StringUtils return escaped; } - inline std::string Utf16ToUtf8(const std::wstring & wstr) - { - std::string convertedString; - auto requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); - if(requiredSize > 0) - { - std::vector buffer(requiredSize); - WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &buffer[0], requiredSize, nullptr, nullptr); - convertedString.assign(buffer.begin(), buffer.end() - 1); - } - return convertedString; - } - +#ifdef _WIN32 inline std::wstring Utf8ToUtf16(const std::string & str) { std::wstring convertedString; @@ -90,6 +108,7 @@ namespace StringUtils } return convertedString; } +#endif // _WIN32 inline void Split(const std::string& s, char delim, std::vector& elems) { @@ -119,42 +138,44 @@ namespace StringUtils } }; +#include + namespace FileHelper { inline bool ReadAllData(const std::string & fileName, std::vector & content) { - auto hFile = CreateFileW(StringUtils::Utf8ToUtf16(fileName).c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); - auto result = false; - if(hFile != INVALID_HANDLE_VALUE) + std::ifstream file(fileName, std::ios::binary); + + if (!file.is_open()) { - unsigned int filesize = GetFileSize(hFile, nullptr); - if(!filesize) - { - content.clear(); - result = true; - } - else - { - content.resize(filesize); - DWORD read = 0; - result = !!ReadFile(hFile, content.data(), filesize, &read, nullptr); - } - CloseHandle(hFile); + return false; } - return result; + + // Get the size of the file + file.seekg(0, std::ios::end); + std::streampos fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + + // Resize the vector to fit the entire file + content.resize(static_cast(fileSize)); + + // Read the file into the vector + file.read(reinterpret_cast(&content[0]), fileSize); + return !file.bad(); } inline bool WriteAllData(const std::string & fileName, const void* data, size_t size) { - auto hFile = CreateFileW(StringUtils::Utf8ToUtf16(fileName).c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr); - auto result = false; - if(hFile != INVALID_HANDLE_VALUE) + std::ofstream file(fileName, std::ios::binary); + + if (!file.is_open()) { - DWORD written = 0; - result = !!WriteFile(hFile, data, DWORD(size), &written, nullptr); - CloseHandle(hFile); + return false; } - return result; + + // Write the data to the file + file.write(static_cast(data), size); + return !file.bad(); } inline bool ReadAllText(const std::string & fileName, std::string & content) diff --git a/btparser/lexer.cpp b/btparser/lexer.cpp index 263a459..71514ec 100644 --- a/btparser/lexer.cpp +++ b/btparser/lexer.cpp @@ -1,8 +1,8 @@ #include "lexer.h" -#include -#include #include "helpers.h" +#include + #define MAKE_OP_TRIPLE(ch1, ch2, ch3) (ch3 << 16 | ch2 << 8 | ch1) #define MAKE_OP_DOUBLE(ch1, ch2) (ch2 << 8 | ch1) #define MAKE_OP_SINGLE(ch1) (ch1) diff --git a/btparser/main.cpp b/btparser/main.cpp index ff8e53f..214e45b 100644 --- a/btparser/main.cpp +++ b/btparser/main.cpp @@ -1,11 +1,10 @@ -#include -#include #include "testfiles.h" #include "lexer.h" -#include "parser.h" #include "helpers.h" #include "preprocessor.h" #include "types.h" + +#include #include bool TestLexer(Lexer& lexer, const std::string& filename) @@ -156,7 +155,7 @@ static void HandleVTable(Types::Model& model) bool DebugParser(const std::string& filename) { std::string data; - if (!FileHelper::ReadAllText("tests\\" + filename, data)) + if (!FileHelper::ReadAllText(filename, data)) { printf("Failed to read: %s\n", filename.c_str()); return false; @@ -173,7 +172,14 @@ bool DebugParser(const std::string& filename) return false; } - FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData); + auto basename = filename; + auto lastSlashIdx = basename.find_last_of("\\/"); + if(lastSlashIdx != std::string::npos) + { + basename = basename.substr(lastSlashIdx + 1); + } + + FileHelper::WriteAllText(basename + ".pp.h", ppData); std::vector errors; Types::Model model; @@ -191,15 +197,13 @@ bool DebugParser(const std::string& filename) return true; } -int main() +int main(int argc, char** argv) { - //GenerateExpectedTests(); - auto ticks = GetTickCount(); - DebugParser("cursor.hpp"); - //Lexer lexer; - //DebugLexer(lexer, "AndroidManifestTemplate.bt", false); - //RunLexerTests(); - printf("finished in %ums\n", (unsigned int)(GetTickCount() - ticks)); - system("pause"); - return 0; + if(argc < 2) + { + printf("Usage: test my.h\n"); + return EXIT_FAILURE; + } + DebugParser(argv[1]); + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/btparser/types.cpp b/btparser/types.cpp index 9b3a9b3..6a2c933 100644 --- a/btparser/types.cpp +++ b/btparser/types.cpp @@ -1,9 +1,11 @@ #include "types.h" #include "helpers.h" + #include #include #include + using namespace Types; #define EXCLUSIVE_ACQUIRE(x) diff --git a/cmake.toml b/cmake.toml new file mode 100644 index 0000000..babdd80 --- /dev/null +++ b/cmake.toml @@ -0,0 +1,21 @@ +# Reference: https://build-cpp.github.io/cmkr/cmake-toml +[project] +name = "btparser" + +[target.btparser] +type = "static" +sources = [ + "btparser/lexer.cpp", + "btparser/preprocessor.cpp", + "btparser/types.cpp", + "btparser/typesparser.cpp", +] +headers = ["btparser/*.h"] +include-directories = ["btparser"] +compile-features = ["cxx_std_14"] + +[target.test] +condition = "root" +type = "executable" +sources = ["btparser/main.cpp"] +link-libraries = ["btparser"] diff --git a/cmkr.cmake b/cmkr.cmake new file mode 100644 index 0000000..cdeea6e --- /dev/null +++ b/cmkr.cmake @@ -0,0 +1,253 @@ +include_guard() + +# Change these defaults to point to your infrastructure if desired +set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE) +set(CMKR_TAG "v0.2.26" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE) +set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE) + +# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake +if(CMAKE_SCRIPT_MODE_FILE) + set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/build") + set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}") + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}") +endif() + +# Set these from the command line to customize for development/debugging purposes +set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable") +set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation") +set(CMKR_BUILD_TYPE "Debug" CACHE STRING "cmkr build configuration") +mark_as_advanced(CMKR_REPO CMKR_TAG CMKR_COMMIT_HASH CMKR_EXECUTABLE CMKR_SKIP_GENERATION CMKR_BUILD_TYPE) + +# Disable cmkr if generation is disabled +if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION OR CMKR_BUILD_SKIP_GENERATION) + message(STATUS "[cmkr] Skipping automatic cmkr generation") + unset(CMKR_BUILD_SKIP_GENERATION CACHE) + macro(cmkr) + endmacro() + return() +endif() + +# Disable cmkr if no cmake.toml file is found +if(NOT CMAKE_SCRIPT_MODE_FILE AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml") + message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml") + macro(cmkr) + endmacro() + return() +endif() + +# Convert a Windows native path to CMake path +if(CMKR_EXECUTABLE MATCHES "\\\\") + string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}") + set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE) + unset(CMKR_EXECUTABLE_CMAKE) +endif() + +# Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher) +function(cmkr_exec) + execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT) + if(NOT CMKR_EXEC_RESULT EQUAL 0) + message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})") + endif() +endfunction() + +# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment) +if(WIN32) + set(CMKR_EXECUTABLE_NAME "cmkr.exe") +else() + set(CMKR_EXECUTABLE_NAME "cmkr") +endif() + +# Use cached cmkr if found +if(DEFINED ENV{CMKR_CACHE}) + set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}") + string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}") + if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$") + set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/") + endif() + # Build in release mode for the cache + set(CMKR_BUILD_TYPE "Release") +else() + set(CMKR_DIRECTORY_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_") +endif() +set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}") +set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}") + +# Helper function to check if a string starts with a prefix +# Cannot use MATCHES, see: https://github.com/build-cpp/cmkr/issues/61 +function(cmkr_startswith str prefix result) + string(LENGTH "${prefix}" prefix_length) + string(LENGTH "${str}" str_length) + if(prefix_length LESS_EQUAL str_length) + string(SUBSTRING "${str}" 0 ${prefix_length} str_prefix) + if(prefix STREQUAL str_prefix) + set("${result}" ON PARENT_SCOPE) + return() + endif() + endif() + set("${result}" OFF PARENT_SCOPE) +endfunction() + +# Handle upgrading logic +if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE) + cmkr_startswith("${CMKR_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/_cmkr" CMKR_STARTSWITH_BUILD) + cmkr_startswith("${CMKR_EXECUTABLE}" "${CMKR_DIRECTORY_PREFIX}" CMKR_STARTSWITH_CACHE) + if(CMKR_STARTSWITH_BUILD) + if(DEFINED ENV{CMKR_CACHE}) + message(AUTHOR_WARNING "[cmkr] Switching to cached cmkr: '${CMKR_CACHED_EXECUTABLE}'") + if(EXISTS "${CMKR_CACHED_EXECUTABLE}") + set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE) + else() + unset(CMKR_EXECUTABLE CACHE) + endif() + else() + message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'") + unset(CMKR_EXECUTABLE CACHE) + endif() + elseif(DEFINED ENV{CMKR_CACHE} AND CMKR_STARTSWITH_CACHE) + message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'") + unset(CMKR_EXECUTABLE CACHE) + endif() +endif() + +if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}") + message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'") +elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE) + message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found") +elseif(NOT CMKR_EXECUTABLE AND EXISTS "${CMKR_CACHED_EXECUTABLE}") + set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE) + message(STATUS "[cmkr] Found cached cmkr: '${CMKR_EXECUTABLE}'") +else() + set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE) + message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'") + + message(STATUS "[cmkr] Fetching cmkr...") + if(EXISTS "${CMKR_DIRECTORY}") + cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}") + endif() + find_package(Git QUIET REQUIRED) + cmkr_exec("${GIT_EXECUTABLE}" + clone + --config advice.detachedHead=false + --branch ${CMKR_TAG} + --depth 1 + ${CMKR_REPO} + "${CMKR_DIRECTORY}" + ) + if(CMKR_COMMIT_HASH) + execute_process( + COMMAND "${GIT_EXECUTABLE}" checkout -q "${CMKR_COMMIT_HASH}" + RESULT_VARIABLE CMKR_EXEC_RESULT + WORKING_DIRECTORY "${CMKR_DIRECTORY}" + ) + if(NOT CMKR_EXEC_RESULT EQUAL 0) + message(FATAL_ERROR "Tag '${CMKR_TAG}' hash is not '${CMKR_COMMIT_HASH}'") + endif() + endif() + message(STATUS "[cmkr] Building cmkr (using system compiler)...") + cmkr_exec("${CMAKE_COMMAND}" + --no-warn-unused-cli + "${CMKR_DIRECTORY}" + "-B${CMKR_DIRECTORY}/build" + "-DCMAKE_BUILD_TYPE=${CMKR_BUILD_TYPE}" + "-DCMAKE_UNITY_BUILD=ON" + "-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}" + "-DCMKR_GENERATE_DOCUMENTATION=OFF" + ) + cmkr_exec("${CMAKE_COMMAND}" + --build "${CMKR_DIRECTORY}/build" + --config "${CMKR_BUILD_TYPE}" + --parallel + ) + cmkr_exec("${CMAKE_COMMAND}" + --install "${CMKR_DIRECTORY}/build" + --config "${CMKR_BUILD_TYPE}" + --prefix "${CMKR_DIRECTORY}" + --component cmkr + ) + if(NOT EXISTS ${CMKR_EXECUTABLE}) + message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'") + endif() + cmkr_exec("${CMKR_EXECUTABLE}" version) + message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}") +endif() +execute_process(COMMAND "${CMKR_EXECUTABLE}" version + RESULT_VARIABLE CMKR_EXEC_RESULT +) +if(NOT CMKR_EXEC_RESULT EQUAL 0) + message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding") +endif() + +# Use cmkr.cmake as a script +if(CMAKE_SCRIPT_MODE_FILE) + if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml") + execute_process(COMMAND "${CMKR_EXECUTABLE}" init + RESULT_VARIABLE CMKR_EXEC_RESULT + ) + if(NOT CMKR_EXEC_RESULT EQUAL 0) + message(FATAL_ERROR "[cmkr] Failed to bootstrap cmkr project. Please report an issue: https://github.com/build-cpp/cmkr/issues/new") + else() + message(STATUS "[cmkr] Modify cmake.toml and then configure using: cmake -B build") + endif() + else() + execute_process(COMMAND "${CMKR_EXECUTABLE}" gen + RESULT_VARIABLE CMKR_EXEC_RESULT + ) + if(NOT CMKR_EXEC_RESULT EQUAL 0) + message(FATAL_ERROR "[cmkr] Failed to generate project.") + else() + message(STATUS "[cmkr] Configure using: cmake -B build") + endif() + endif() +endif() + +# This is the macro that contains black magic +macro(cmkr) + # When this macro is called from the generated file, fake some internal CMake variables + get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE) + if(CMKR_CURRENT_LIST_FILE) + set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}") + get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) + endif() + + # File-based include guard (include_guard is not documented to work) + get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD) + if(NOT CMKR_INCLUDE_GUARD) + set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE) + + file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE) + + # Generate CMakeLists.txt + cmkr_exec("${CMKR_EXECUTABLE}" gen + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + + file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST) + + # Delete the temporary file if it was left for some reason + set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt") + if(EXISTS "${CMKR_TEMP_FILE}") + file(REMOVE "${CMKR_TEMP_FILE}") + endif() + + if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST) + # Copy the now-generated CMakeLists.txt to CMakerLists.txt + # This is done because you cannot include() a file you are currently in + configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY) + + # Add the macro required for the hack at the start of the cmkr macro + set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES + CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" + ) + + # 'Execute' the newly-generated CMakeLists.txt + include("${CMKR_TEMP_FILE}") + + # Delete the generated file + file(REMOVE "${CMKR_TEMP_FILE}") + + # Do not execute the rest of the original CMakeLists.txt + return() + endif() + # Resume executing the unmodified CMakeLists.txt + endif() +endmacro()