diff --git a/CMakeLists.txt b/CMakeLists.txt index b34c1f2..3878a57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,3 +29,69 @@ endif() project(Theodosius) +# dependencies +set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) +if(CMAKE_FOLDER) + set(CMAKE_FOLDER "${CMAKE_FOLDER}/dependencies") +else() + set(CMAKE_FOLDER dependencies) +endif() +add_subdirectory(dependencies) +set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) + +# src +set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) +if(CMAKE_FOLDER) + set(CMAKE_FOLDER "${CMAKE_FOLDER}/src") +else() + set(CMAKE_FOLDER src) +endif() +add_subdirectory(src) +set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) + +# Target Theodosius +set(CMKR_TARGET Theodosius) +set(Theodosius_SOURCES "") + +list(APPEND Theodosius_SOURCES + "include/comp/comp.hpp" + "include/comp/symbol_table.hpp" + "include/decomp/decomp.hpp" + "include/decomp/routine.hpp" + "include/decomp/symbol.hpp" + "include/theo.hpp" + "src/theo/theo.cpp" +) + +list(APPEND Theodosius_SOURCES + cmake.toml +) + +set(CMKR_SOURCES ${Theodosius_SOURCES}) +add_library(Theodosius STATIC) + +if(Theodosius_SOURCES) + target_sources(Theodosius PRIVATE ${Theodosius_SOURCES}) +endif() + +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${Theodosius_SOURCES}) + +target_compile_definitions(Theodosius PUBLIC + NOMINMAX +) + +target_compile_features(Theodosius PUBLIC + cxx_std_20 +) + +target_include_directories(Theodosius PUBLIC + include +) + +target_link_libraries(Theodosius PUBLIC + linux-pe +) + +unset(CMKR_TARGET) +unset(CMKR_SOURCES) + diff --git a/cmake.toml b/cmake.toml index e47bbdb..1c9f097 100644 --- a/cmake.toml +++ b/cmake.toml @@ -1,5 +1,14 @@ [project] name = "Theodosius" +[subdir.dependencies] +[subdir.src] + [target.Theodosius] type = "static" +sources = ["include/**.hpp", "src/theo/**.cpp"] + +include-directories = ["include"] +compile-features = ["cxx_std_20"] +compile-definitions = ["NOMINMAX"] +link-libraries = ["linux-pe"] \ No newline at end of file diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt new file mode 100644 index 0000000..ba1e60d --- /dev/null +++ b/dependencies/CMakeLists.txt @@ -0,0 +1,26 @@ +# This file is automatically generated from cmake.toml - DO NOT EDIT +# See https://github.com/build-cpp/cmkr for more information + +# Create a configure-time dependency on cmake.toml to improve IDE support +if(CMKR_ROOT_PROJECT) + configure_file(cmake.toml cmake.toml COPYONLY) +endif() + +# Target linux-pe +set(CMKR_TARGET linux-pe) +set(linux-pe_SOURCES "") + +set(CMKR_SOURCES ${linux-pe_SOURCES}) +add_library(linux-pe INTERFACE) + +if(linux-pe_SOURCES) + target_sources(linux-pe INTERFACE ${linux-pe_SOURCES}) +endif() + +target_include_directories(linux-pe INTERFACE + "linux-pe/includes/" +) + +unset(CMKR_TARGET) +unset(CMKR_SOURCES) + diff --git a/include/comp/comp.hpp b/include/comp/comp.hpp new file mode 100644 index 0000000..308beb2 --- /dev/null +++ b/include/comp/comp.hpp @@ -0,0 +1,30 @@ +#pragma once +#include +#include + +namespace theo::comp { +using resolve_t = std::function; +using copy_t = std::function; +using alloc_t = std::function; + +class comp_t { + public: + explicit comp_t(decomp::decomp_t& dcmp, comp::symbol_table_t syms); + explicit comp_t(decomp::decomp_t& dcmp, + comp::symbol_table_t syms, + alloc_t alloc, + copy_t copy, + resolve_t resolve); + + void allocator(alloc_t alloc); + void copier(copy_t copy); + void resolver(resolve_t resolve); + std::uintptr_t resolve(std::string&& sym); + + private: + resolve_t m_resolver; + copy_t m_copier; + alloc_t m_allocator; +}; +} // namespace theo::comp \ No newline at end of file diff --git a/include/comp/symbol_table.hpp b/include/comp/symbol_table.hpp new file mode 100644 index 0000000..584254f --- /dev/null +++ b/include/comp/symbol_table.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include + +#include + +namespace theo::comp { +class symbol_table_t { + public: + symbol_table_t(); + symbol_table_t(const std::vector&& syms); + + void add_symbol(decomp::symbol_t& sym); + void add_symbols(std::vector& syms); + + void update(std::string& name, decomp::symbol_t& sym); + void update(std::string& name, std::uintptr_t location); + + void for_each(std::function fn); + private: + std::map m_table; +}; +} // namespace theo::comp \ No newline at end of file diff --git a/include/decomp/decomp.hpp b/include/decomp/decomp.hpp new file mode 100644 index 0000000..a39badf --- /dev/null +++ b/include/decomp/decomp.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +#include + +#include +#include + +namespace theo::decomp { +class decomp_t { + public: + explicit decomp_t(std::vector& lib_data); + std::vector& rtns(); + std::vector& lib(); + std::vector& objs(); + + private: + void decompose(); + std::vector m_lib_data; + std::vector m_obj_imgs; + std::vector m_rtns; +}; +} // namespace theo::decomp \ No newline at end of file diff --git a/include/decomp/routine.hpp b/include/decomp/routine.hpp new file mode 100644 index 0000000..f72ac34 --- /dev/null +++ b/include/decomp/routine.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +#include "symbol.hpp" + +namespace theo::decomp { +class routine { + public: + explicit routine(coff::section_header_t scn_hdr, + std::vector& rtn_data); + + std::vector syms(); + coff::section_header_t scn_hdr(); + std::vector data(); + private: + void decompose(); + std::vector m_data; + std::vector m_orig_syms; + coff::section_header_t m_scn_hdr; +}; +} // namespace theo::decomp \ No newline at end of file diff --git a/include/decomp/symbol.hpp b/include/decomp/symbol.hpp new file mode 100644 index 0000000..02faf51 --- /dev/null +++ b/include/decomp/symbol.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include + +namespace theo::decomp { +class symbol_t { + public: + explicit symbol_t(const std::string&& name, + std::uintptr_t location, + const std::vector&& data, + coff::section_header_t scn_hdr); + + std::string name() const; + std::uintptr_t location() const; + std::uint32_t size() const; + std::vector data() const; + + void name(const std::string&& name); + void location(std::uintptr_t location); + void data(const std::vector&& data); + + private: + std::string m_name; + std::uintptr_t m_location; + std::vector m_data; + const coff::section_header_t m_scn_hdr; +}; +} // namespace theo::decomp \ No newline at end of file diff --git a/include/theo.hpp b/include/theo.hpp index e69de29..819e64a 100644 --- a/include/theo.hpp +++ b/include/theo.hpp @@ -0,0 +1,3 @@ +#pragma once +#include +#include \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..afb526c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,18 @@ +# This file is automatically generated from cmake.toml - DO NOT EDIT +# See https://github.com/build-cpp/cmkr for more information + +# Create a configure-time dependency on cmake.toml to improve IDE support +if(CMKR_ROOT_PROJECT) + configure_file(cmake.toml cmake.toml COPYONLY) +endif() + +# tests +set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) +if(CMAKE_FOLDER) + set(CMAKE_FOLDER "${CMAKE_FOLDER}/tests") +else() + set(CMAKE_FOLDER tests) +endif() +add_subdirectory(tests) +set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) + diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt new file mode 100644 index 0000000..c672f49 --- /dev/null +++ b/src/tests/CMakeLists.txt @@ -0,0 +1,18 @@ +# This file is automatically generated from cmake.toml - DO NOT EDIT +# See https://github.com/build-cpp/cmkr for more information + +# Create a configure-time dependency on cmake.toml to improve IDE support +if(CMKR_ROOT_PROJECT) + configure_file(cmake.toml cmake.toml COPYONLY) +endif() + +# demo +set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) +if(CMAKE_FOLDER) + set(CMAKE_FOLDER "${CMAKE_FOLDER}/demo") +else() + set(CMAKE_FOLDER demo) +endif() +add_subdirectory(demo) +set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) + diff --git a/src/tests/cmake.toml b/src/tests/cmake.toml index b19f65f..e0bf4cc 100644 --- a/src/tests/cmake.toml +++ b/src/tests/cmake.toml @@ -1 +1 @@ -[subdir.usermode-demo] \ No newline at end of file +[subdir.demo] \ No newline at end of file diff --git a/src/tests/demo/CMakeLists.txt b/src/tests/demo/CMakeLists.txt new file mode 100644 index 0000000..1389251 --- /dev/null +++ b/src/tests/demo/CMakeLists.txt @@ -0,0 +1,64 @@ +# 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() + +# Regenerate CMakeLists.txt automatically in the root project +set(CMKR_ROOT_PROJECT OFF) +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(CMKR_ROOT_PROJECT ON) + + # Bootstrap cmkr + 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) +endif() + +# Create a configure-time dependency on cmake.toml to improve IDE support +if(CMKR_ROOT_PROJECT) + configure_file(cmake.toml cmake.toml COPYONLY) +endif() + +project(usermode-demo) + +# Target usermode-demo +set(CMKR_TARGET usermode-demo) +set(usermode-demo_SOURCES "") + +list(APPEND usermode-demo_SOURCES + main.cpp +) + +list(APPEND usermode-demo_SOURCES + cmake.toml +) + +set(CMKR_SOURCES ${usermode-demo_SOURCES}) +add_executable(usermode-demo) + +if(usermode-demo_SOURCES) + target_sources(usermode-demo PRIVATE ${usermode-demo_SOURCES}) +endif() + +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 usermode-demo) +endif() + +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${usermode-demo_SOURCES}) + +target_link_libraries(usermode-demo PRIVATE + Theodosius +) + +unset(CMKR_TARGET) +unset(CMKR_SOURCES) + diff --git a/src/tests/usermode-demo/cmake.toml b/src/tests/demo/cmake.toml similarity index 60% rename from src/tests/usermode-demo/cmake.toml rename to src/tests/demo/cmake.toml index 0214073..bfb83b1 100644 --- a/src/tests/usermode-demo/cmake.toml +++ b/src/tests/demo/cmake.toml @@ -4,5 +4,5 @@ name = "usermode-demo" [target.usermode-demo] type = "executable" -sources = "**.cpp" +sources = ["*.cpp"] link-libraries = ["Theodosius"] \ No newline at end of file diff --git a/src/tests/demo/cmkr.cmake b/src/tests/demo/cmkr.cmake new file mode 100644 index 0000000..9af0802 --- /dev/null +++ b/src/tests/demo/cmkr.cmake @@ -0,0 +1,236 @@ +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.12" 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} AND EXISTS "$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}") + +# Handle upgrading logic +if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE) + if(CMKR_EXECUTABLE MATCHES "^${CMAKE_CURRENT_BINARY_DIR}/_cmkr") + if(DEFINED ENV{CMKR_CACHE} AND EXISTS "$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 EXISTS "$ENV{CMKR_CACHE}" AND CMKR_EXECUTABLE MATCHES "^${CMKR_DIRECTORY_PREFIX}") + 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() diff --git a/src/tests/usermode-demo/main.cpp b/src/tests/demo/main.cpp similarity index 100% rename from src/tests/usermode-demo/main.cpp rename to src/tests/demo/main.cpp diff --git a/src/theo/theo.cpp b/src/theo/theo.cpp new file mode 100644 index 0000000..e69de29