mirror of https://github.com/x64dbg/btparser
Port to cmkr and macos
This commit is contained in:
parent
8e19f7ce0d
commit
b24d73c7b7
|
@ -0,0 +1,3 @@
|
||||||
|
# cmkr
|
||||||
|
/**/CMakeLists.txt linguist-generated
|
||||||
|
/**/cmkr.cmake linguist-vendored
|
|
@ -10,3 +10,9 @@ expected.out
|
||||||
cmake-build*/
|
cmake-build*/
|
||||||
build*/
|
build*/
|
||||||
.idea/
|
.idea/
|
||||||
|
.cache/
|
||||||
|
*.pp.h
|
||||||
|
|
||||||
|
# cmkr
|
||||||
|
CMakerLists.txt
|
||||||
|
CMakeLists.txt.user
|
||||||
|
|
|
@ -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()
|
|
@ -2,9 +2,33 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <windows.h>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <intrin.h>
|
||||||
|
#elif defined(__clang__)
|
||||||
|
#define __debugbreak() __builtin_debugtrap()
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define __debugbreak() __builtin_trap()
|
||||||
|
#else
|
||||||
|
#warning Unsupported platform/compiler
|
||||||
|
#include <signal.h>
|
||||||
|
#define __debugbreak() raise(SIGTRAP)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
template<size_t Count, typename... Args>
|
||||||
|
static int sprintf_s(char (&dst)[Count], const char* fmt, Args&&... args)
|
||||||
|
{
|
||||||
|
return snprintf(dst, Count, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
namespace StringUtils
|
namespace StringUtils
|
||||||
{
|
{
|
||||||
inline std::string sprintf(const char* format, ...)
|
inline std::string sprintf(const char* format, ...)
|
||||||
|
@ -14,7 +38,11 @@ namespace StringUtils
|
||||||
std::vector<char> buffer(256, '\0');
|
std::vector<char> buffer(256, '\0');
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
int res = _vsnprintf_s(buffer.data(), buffer.size(), _TRUNCATE, format, args);
|
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)
|
if(res == -1)
|
||||||
{
|
{
|
||||||
buffer.resize(buffer.size() * 2);
|
buffer.resize(buffer.size() * 2);
|
||||||
|
@ -52,7 +80,9 @@ namespace StringUtils
|
||||||
return "\\\"";
|
return "\\\"";
|
||||||
default:
|
default:
|
||||||
if(!isprint(ch)) //unknown unprintable character
|
if(!isprint(ch)) //unknown unprintable character
|
||||||
|
{
|
||||||
sprintf_s(buf, "\\x%02X", ch);
|
sprintf_s(buf, "\\x%02X", ch);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
*buf = ch;
|
*buf = ch;
|
||||||
return buf;
|
return buf;
|
||||||
|
@ -65,19 +95,7 @@ namespace StringUtils
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string Utf16ToUtf8(const std::wstring & wstr)
|
#ifdef _WIN32
|
||||||
{
|
|
||||||
std::string convertedString;
|
|
||||||
auto requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
|
||||||
if(requiredSize > 0)
|
|
||||||
{
|
|
||||||
std::vector<char> buffer(requiredSize);
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &buffer[0], requiredSize, nullptr, nullptr);
|
|
||||||
convertedString.assign(buffer.begin(), buffer.end() - 1);
|
|
||||||
}
|
|
||||||
return convertedString;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::wstring Utf8ToUtf16(const std::string & str)
|
inline std::wstring Utf8ToUtf16(const std::string & str)
|
||||||
{
|
{
|
||||||
std::wstring convertedString;
|
std::wstring convertedString;
|
||||||
|
@ -90,6 +108,7 @@ namespace StringUtils
|
||||||
}
|
}
|
||||||
return convertedString;
|
return convertedString;
|
||||||
}
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
inline void Split(const std::string& s, char delim, std::vector<std::string>& elems)
|
inline void Split(const std::string& s, char delim, std::vector<std::string>& elems)
|
||||||
{
|
{
|
||||||
|
@ -119,42 +138,44 @@ namespace StringUtils
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
namespace FileHelper
|
namespace FileHelper
|
||||||
{
|
{
|
||||||
inline bool ReadAllData(const std::string & fileName, std::vector<uint8_t> & content)
|
inline bool ReadAllData(const std::string & fileName, std::vector<uint8_t> & content)
|
||||||
{
|
{
|
||||||
auto hFile = CreateFileW(StringUtils::Utf8ToUtf16(fileName).c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
std::ifstream file(fileName, std::ios::binary);
|
||||||
auto result = false;
|
|
||||||
if(hFile != INVALID_HANDLE_VALUE)
|
if (!file.is_open())
|
||||||
{
|
{
|
||||||
unsigned int filesize = GetFileSize(hFile, nullptr);
|
return false;
|
||||||
if(!filesize)
|
|
||||||
{
|
|
||||||
content.clear();
|
|
||||||
result = true;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
// Get the size of the file
|
||||||
content.resize(filesize);
|
file.seekg(0, std::ios::end);
|
||||||
DWORD read = 0;
|
std::streampos fileSize = file.tellg();
|
||||||
result = !!ReadFile(hFile, content.data(), filesize, &read, nullptr);
|
file.seekg(0, std::ios::beg);
|
||||||
}
|
|
||||||
CloseHandle(hFile);
|
// Resize the vector to fit the entire file
|
||||||
}
|
content.resize(static_cast<size_t>(fileSize));
|
||||||
return result;
|
|
||||||
|
// Read the file into the vector
|
||||||
|
file.read(reinterpret_cast<char*>(&content[0]), fileSize);
|
||||||
|
return !file.bad();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool WriteAllData(const std::string & fileName, const void* data, size_t size)
|
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);
|
std::ofstream file(fileName, std::ios::binary);
|
||||||
auto result = false;
|
|
||||||
if(hFile != INVALID_HANDLE_VALUE)
|
if (!file.is_open())
|
||||||
{
|
{
|
||||||
DWORD written = 0;
|
return false;
|
||||||
result = !!WriteFile(hFile, data, DWORD(size), &written, nullptr);
|
|
||||||
CloseHandle(hFile);
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
// Write the data to the file
|
||||||
|
file.write(static_cast<const char*>(data), size);
|
||||||
|
return !file.bad();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool ReadAllText(const std::string & fileName, std::string & content)
|
inline bool ReadAllText(const std::string & fileName, std::string & content)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include <cctype>
|
|
||||||
#include <windows.h>
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
#define MAKE_OP_TRIPLE(ch1, ch2, ch3) (ch3 << 16 | ch2 << 8 | ch1)
|
#define MAKE_OP_TRIPLE(ch1, ch2, ch3) (ch3 << 16 | ch2 << 8 | ch1)
|
||||||
#define MAKE_OP_DOUBLE(ch1, ch2) (ch2 << 8 | ch1)
|
#define MAKE_OP_DOUBLE(ch1, ch2) (ch2 << 8 | ch1)
|
||||||
#define MAKE_OP_SINGLE(ch1) (ch1)
|
#define MAKE_OP_SINGLE(ch1) (ch1)
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
#include <windows.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "testfiles.h"
|
#include "testfiles.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "parser.h"
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "preprocessor.h"
|
#include "preprocessor.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
bool TestLexer(Lexer& lexer, const std::string& filename)
|
bool TestLexer(Lexer& lexer, const std::string& filename)
|
||||||
|
@ -156,7 +155,7 @@ static void HandleVTable(Types::Model& model)
|
||||||
bool DebugParser(const std::string& filename)
|
bool DebugParser(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::string data;
|
std::string data;
|
||||||
if (!FileHelper::ReadAllText("tests\\" + filename, data))
|
if (!FileHelper::ReadAllText(filename, data))
|
||||||
{
|
{
|
||||||
printf("Failed to read: %s\n", filename.c_str());
|
printf("Failed to read: %s\n", filename.c_str());
|
||||||
return false;
|
return false;
|
||||||
|
@ -173,7 +172,14 @@ bool DebugParser(const std::string& filename)
|
||||||
return false;
|
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<std::string> errors;
|
std::vector<std::string> errors;
|
||||||
Types::Model model;
|
Types::Model model;
|
||||||
|
@ -191,15 +197,13 @@ bool DebugParser(const std::string& filename)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
//GenerateExpectedTests();
|
if(argc < 2)
|
||||||
auto ticks = GetTickCount();
|
{
|
||||||
DebugParser("cursor.hpp");
|
printf("Usage: test my.h\n");
|
||||||
//Lexer lexer;
|
return EXIT_FAILURE;
|
||||||
//DebugLexer(lexer, "AndroidManifestTemplate.bt", false);
|
}
|
||||||
//RunLexerTests();
|
DebugParser(argv[1]);
|
||||||
printf("finished in %ums\n", (unsigned int)(GetTickCount() - ticks));
|
return EXIT_SUCCESS;
|
||||||
system("pause");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
|
||||||
using namespace Types;
|
using namespace Types;
|
||||||
|
|
||||||
#define EXCLUSIVE_ACQUIRE(x)
|
#define EXCLUSIVE_ACQUIRE(x)
|
||||||
|
|
|
@ -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"]
|
|
@ -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()
|
Loading…
Reference in New Issue