Clean up cmkr bootstrapping

vcpkg-wip archive_84f6b39f
Duncan Ogilvie 4 years ago
parent 67ac9a4328
commit 84f6b39f35

@ -3,15 +3,21 @@
# Create a configure-time dependency on cmake.toml to improve IDE support # Create a configure-time dependency on cmake.toml to improve IDE support
configure_file(cmake.toml cmake.toml COPYONLY) configure_file(cmake.toml cmake.toml COPYONLY)
cmake_minimum_required(VERSION 2.8...3.8)
# Regenerate CMakeLists.txt file when necessary # Regenerate CMakeLists.txt file when necessary
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT) set(CMKR_ROOT_PROJECT OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CMKR_ROOT_PROJECT ON)
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
if(CMKR_INCLUDE_RESULT) if(CMKR_INCLUDE_RESULT)
cmkr() cmkr()
endif() endif()
cmake_minimum_required(VERSION 2.8...3.8) endif()
# Enable folder support
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Hack to hide a warning during cmkr bootstrapping on Windows # Hack to hide a warning during cmkr bootstrapping on Windows

@ -1,20 +1,41 @@
include_guard() include_guard()
# Change these defaults to point to your infrastructure if desired
set(CMKR_REPO "https://github.com/MoAlyousef/cmkr" CACHE STRING "cmkr git repository")
set(CMKR_TAG "archive_67ac9a43" CACHE STRING "cmkr git tag (this needs to be available forever)")
set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable")
set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation")
# Disable cmkr if generation is disabled
if(CMKR_SKIP_GENERATION)
message(STATUS "[cmkr] Skipping automatic cmkr generation")
macro(cmkr)
endmacro()
return()
endif()
# Disable cmkr if no cmake.toml file is found # Disable cmkr if no cmake.toml file is found
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml) if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml") message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
macro(cmkr) macro(cmkr)
endmacro() endmacro()
return() return()
endif() 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) # Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher)
macro(cmkr_exec) function(cmkr_exec)
execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT) execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT)
if(NOT CMKR_EXEC_RESULT EQUAL 0) if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})") message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})")
endif() endif()
endmacro() endfunction()
# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment) # Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment)
if(WIN32) if(WIN32)
@ -24,79 +45,103 @@ else()
endif() endif()
# Use cached cmkr if found # Use cached cmkr if found
if(DEFINED CACHE{CMKR_EXECUTABLE} AND EXISTS ${CMKR_EXECUTABLE}) set(CMKR_CACHED_EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/_cmkr/bin/${CMKR_EXECUTABLE_NAME}")
if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}")
message(VERBOSE "[cmkr] Found cmkr: '${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")
else() else()
if(DEFINED CACHE{CMKR_EXECUTABLE}) set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
message(VERBOSE "[cmkr] '${CMKR_EXECUTABLE}' not found")
endif()
set(CMKR_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_cmkr)
set(CMKR_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/_cmkr/bin/${CMKR_EXECUTABLE_NAME} CACHE INTERNAL "Full path to cmkr executable")
if(NOT EXISTS ${CMKR_EXECUTABLE})
message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'") message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'")
message(STATUS "[cmkr] Fetching cmkr...") message(STATUS "[cmkr] Fetching cmkr...")
if(EXISTS ${CMKR_DIRECTORY}) set(CMKR_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
cmkr_exec(${CMAKE_COMMAND} -E rm -rf ${CMKR_DIRECTORY}) if(EXISTS "${CMKR_DIRECTORY}")
cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}")
endif() endif()
find_package(Git QUIET REQUIRED) find_package(Git QUIET REQUIRED)
set(CMKR_REPO "https://github.com/moalyousef/cmkr") cmkr_exec("${GIT_EXECUTABLE}"
cmkr_exec(${GIT_EXECUTABLE} clone ${CMKR_REPO} ${CMKR_DIRECTORY}) clone
cmkr_exec(${CMAKE_COMMAND} ${CMKR_DIRECTORY} -B${CMKR_DIRECTORY}/build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}) --config advice.detachedHead=false
cmkr_exec(${CMAKE_COMMAND} --build ${CMKR_DIRECTORY}/build --config Release --parallel) --branch ${CMKR_TAG}
cmkr_exec(${CMAKE_COMMAND} --install ${CMKR_DIRECTORY}/build --config Release --prefix ${CMKR_DIRECTORY} --component cmkr) --depth 1
${CMKR_REPO}
"${CMKR_DIRECTORY}"
)
message(STATUS "[cmkr] Building cmkr...")
cmkr_exec("${CMAKE_COMMAND}"
"${CMKR_DIRECTORY}"
"-B${CMKR_DIRECTORY}/build"
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
)
cmkr_exec("${CMAKE_COMMAND}"
--build "${CMKR_DIRECTORY}/build"
--config Release
--parallel
)
cmkr_exec("${CMAKE_COMMAND}"
--install "${CMKR_DIRECTORY}/build"
--config Release
--prefix "${CMKR_DIRECTORY}"
--component cmkr
)
if(NOT EXISTS ${CMKR_EXECUTABLE}) if(NOT EXISTS ${CMKR_EXECUTABLE})
message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'") message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'")
endif() endif()
cmkr_exec(${CMKR_EXECUTABLE} version) cmkr_exec("${CMKR_EXECUTABLE}" version)
message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}") message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}")
else()
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
endif()
endif() endif()
execute_process(COMMAND ${CMKR_EXECUTABLE} version execute_process(COMMAND "${CMKR_EXECUTABLE}" version
RESULT_VARIABLE CMKR_EXEC_RESULT RESULT_VARIABLE CMKR_EXEC_RESULT
) )
if(NOT CMKR_EXEC_RESULT EQUAL 0) if(NOT CMKR_EXEC_RESULT EQUAL 0)
unset(CMKR_EXECUTABLE CACHE)
message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding") message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding")
endif() endif()
# This is the macro that contains black magic # This is the macro that contains black magic
macro(cmkr) macro(cmkr)
# When this macro is called from the generated file, fake some internal CMake variables # 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) get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE)
if(CMKR_CURRENT_LIST_FILE) if(CMKR_CURRENT_LIST_FILE)
set(CMAKE_CURRENT_LIST_FILE ${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) get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
endif() endif()
# File-based include guard (include_guard is not documented to work) # 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) get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD)
if(NOT CMKR_INCLUDE_GUARD) if(NOT CMKR_INCLUDE_GUARD)
set_source_files_properties(${CMAKE_CURRENT_LIST_FILE} PROPERTIES CMKR_INCLUDE_GUARD TRUE) 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 # Generate CMakeLists.txt
cmkr_exec(${CMKR_EXECUTABLE} gen cmkr_exec("${CMKR_EXECUTABLE}" gen
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
) )
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST)
if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST)
# Copy the now-generated CMakeLists.txt to CMakerLists.txt # Copy the now-generated CMakeLists.txt to CMakerLists.txt
# This is done because you cannot include() a file you are currently in # This is done because you cannot include() a file you are currently in
set(CMKR_TEMP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt) set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
configure_file(CMakeLists.txt ${CMKR_TEMP_FILE} COPYONLY) configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY)
# Add the macro required for the hack at the start of the cmkr macro # Add the macro required for the hack at the start of the cmkr macro
set_source_files_properties(${CMKR_TEMP_FILE} PROPERTIES set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES
CMKR_CURRENT_LIST_FILE ${CMAKE_CURRENT_LIST_FILE} CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}"
) )
# 'Execute' the newly-generated CMakeLists.txt # 'Execute' the newly-generated CMakeLists.txt
include(${CMKR_TEMP_FILE}) include("${CMKR_TEMP_FILE}")
# Delete the generated file # Delete the generated file
file(REMOVE ${CMKR_TEMP_FILE}) file(REMOVE "${CMKR_TEMP_FILE}")
# Do not execute the rest of the original CMakeLists.txt # Do not execute the rest of the original CMakeLists.txt
return() return()
endif() endif()
# Resume executing the unmodified CMakeLists.txt
endif()
endmacro() endmacro()

@ -177,7 +177,7 @@ struct Command {
return result; return result;
} }
std::string indent(int n) { static std::string indent(int n) {
std::string result; std::string result;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
result += '\t'; result += '\t';
@ -305,8 +305,8 @@ int generate_cmake(const char *path, bool root) {
} }
return Command(ss, indent, command); return Command(ss, indent, command);
}; };
auto comment = [&ss](const std::string &comment) { auto comment = [&ss, &indent](const std::string &comment) {
ss << "# " << comment << '\n'; ss << Command::indent(indent) << "# " << comment << '\n';
return CommandEndl(ss); return CommandEndl(ss);
}; };
auto endl = [&ss]() { ss << '\n'; }; auto endl = [&ss]() { ss << '\n'; };
@ -340,26 +340,36 @@ int generate_cmake(const char *path, bool root) {
// TODO: add link with proper documentation // TODO: add link with proper documentation
comment("This file was generated automatically by cmkr.").endl(); comment("This file was generated automatically by cmkr.").endl();
comment("Create a configure-time dependency on cmake.toml to improve IDE support");
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY").endl();
cmake::CMake cmake(path, false); cmake::CMake cmake(path, false);
if (root) { if (root) {
comment("Regenerate CMakeLists.txt file when necessary"); cmd("cmake_minimum_required")("VERSION", cmake.cmake_version).endl();
cmd("include")(cmake.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT").endl();
comment("Regenerate CMakeLists.txt automatically in the root project");
cmd("set")("CMKR_ROOT_PROJECT", "OFF");
// clang-format off // clang-format off
cmd("if")("CMAKE_CURRENT_SOURCE_DIR", "STREQUAL", "CMAKE_SOURCE_DIR");
cmd("set")("CMKR_ROOT_PROJECT", "ON").endl();
comment("Bootstrap cmkr");
cmd("include")(cmake.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT");
cmd("if")("CMKR_INCLUDE_RESULT"); cmd("if")("CMKR_INCLUDE_RESULT");
cmd("cmkr")(); cmd("cmkr")();
cmd("endif")().endl(); cmd("endif")().endl();
// clang-format on
cmd("cmake_minimum_required")("VERSION", cmake.cmake_version).endl();
cmd("set_property")("GLOBAL", "PROPERTY", "USE_FOLDERS", "ON").endl(); comment("Enable folder support");
cmd("set_property")("GLOBAL", "PROPERTY", "USE_FOLDERS", "ON");
cmd("endif")().endl();
// clang-format on
} }
// clang-format off
comment("Create a configure-time dependency on cmake.toml to improve IDE support");
cmd("if")("CMKR_ROOT_PROJECT");
cmd("configure_file")("cmake.toml", "cmake.toml", "COPYONLY");
cmd("endif")().endl();
// clang-format on
// TODO: remove support and replace with global compile-features // TODO: remove support and replace with global compile-features
if (!cmake.cppflags.empty()) { if (!cmake.cppflags.empty()) {
ss << "set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} \""; ss << "set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} \"";
@ -471,6 +481,7 @@ int generate_cmake(const char *path, bool root) {
if (!cmake.subdirs.empty()) { if (!cmake.subdirs.empty()) {
for (const auto &dir : cmake.subdirs) { for (const auto &dir : cmake.subdirs) {
// clang-format off // clang-format off
comment(dir);
cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}"); cmd("set")("CMKR_CMAKE_FOLDER", "${CMAKE_FOLDER}");
cmd("if")("CMAKE_FOLDER"); cmd("if")("CMAKE_FOLDER");
cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir); cmd("set")("CMAKE_FOLDER", "${CMAKE_FOLDER}/" + dir);

Loading…
Cancel
Save