mirror of
https://github.com/build-cpp/cmkr
synced 2026-06-08 13:22:55 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c7144b183 | |||
| 07797988b5 | |||
| 285614e4c2 | |||
| e725b10a9f | |||
| aafaf58c70 | |||
| 87db22f134 | |||
| 416a8365f9 | |||
| a718dfd675 | |||
| 25da3171f0 | |||
| 95907602b4 | |||
| 4b300df8d5 |
@@ -10,13 +10,17 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-2016, windows-2019, macos-10.15, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04]
|
||||
os: [windows-2019, macos-10.15, ubuntu-20.04]
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Tag cmkr.cmake
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
run: cmake -P "cmake/replace_tag.cmake"
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}
|
||||
@@ -26,7 +30,7 @@ jobs:
|
||||
- name: Check if cmkr was run
|
||||
run: |
|
||||
./install/bin/cmkr gen
|
||||
git diff --exit-code
|
||||
git diff --exit-code -- . ":(exclude)cmake/cmkr.cmake"
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
@@ -53,9 +57,9 @@ jobs:
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') && (matrix.os == 'windows-2019' || matrix.os == 'macos-10.15' || matrix.os == 'ubuntu-16.04') }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
with:
|
||||
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-pre') }}
|
||||
files: ${{ github.event.repository.name }}-${{ steps.osname.outputs.lowercase }}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
Generated
+8
-6
@@ -3,17 +3,15 @@
|
||||
|
||||
cmake_minimum_required(VERSION 2.8...3.8)
|
||||
|
||||
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()
|
||||
@@ -33,6 +31,7 @@ project(cmkr
|
||||
)
|
||||
|
||||
include("cmake/generate_documentation.cmake")
|
||||
include("cmake/generate_resources.cmake")
|
||||
|
||||
# third_party
|
||||
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
||||
@@ -93,6 +92,7 @@ list(APPEND cmkr_SOURCES
|
||||
"include/help.hpp"
|
||||
"include/literals.hpp"
|
||||
"include/project_parser.hpp"
|
||||
"cmake/cmkr.cmake"
|
||||
)
|
||||
|
||||
list(APPEND cmkr_SOURCES
|
||||
@@ -129,6 +129,8 @@ target_link_libraries(cmkr PRIVATE
|
||||
nlohmann_json
|
||||
)
|
||||
|
||||
generate_resources(${CMKR_TARGET})
|
||||
|
||||
unset(CMKR_TARGET)
|
||||
unset(CMKR_SOURCES)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# cmkr
|
||||
|
||||
`cmkr`, pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io). It was originally created by [Mohammed Alyousef](https://github.com/MoAlyousef).
|
||||
`cmkr`, pronounced "cmaker", is a modern build system based on [CMake](https://cmake.org/) and [TOML](https://toml.io).
|
||||
|
||||
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
|
||||
|
||||
|
||||
+23
-4
@@ -1,5 +1,6 @@
|
||||
[cmake]
|
||||
version = "2.8...3.8"
|
||||
cmkr-include = false
|
||||
|
||||
[project]
|
||||
name = "cmkr"
|
||||
@@ -7,7 +8,10 @@ version = "0.1.4"
|
||||
description = "CMakeLists generator from TOML"
|
||||
languages = ["CXX"]
|
||||
subdirs = ["third_party", "tests"]
|
||||
include-after = ["cmake/generate_documentation.cmake"]
|
||||
include-after = [
|
||||
"cmake/generate_documentation.cmake",
|
||||
"cmake/generate_resources.cmake"
|
||||
]
|
||||
|
||||
[target.cmkr_generate_documentation]
|
||||
type = "interface"
|
||||
@@ -17,10 +21,25 @@ generate_documentation()
|
||||
|
||||
[target.cmkr]
|
||||
type = "executable"
|
||||
sources = ["src/*.cpp", "include/*.hpp"]
|
||||
include-directories = ["include"]
|
||||
sources = [
|
||||
"src/*.cpp",
|
||||
"include/*.hpp",
|
||||
"cmake/cmkr.cmake",
|
||||
]
|
||||
include-directories = [
|
||||
"include",
|
||||
]
|
||||
compile-features = ["cxx_std_11"]
|
||||
link-libraries = ["toml11", "ghc_filesystem", "mpark_variant", "ordered_map", "nlohmann_json"]
|
||||
link-libraries = [
|
||||
"toml11",
|
||||
"ghc_filesystem",
|
||||
"mpark_variant",
|
||||
"ordered_map",
|
||||
"nlohmann_json"
|
||||
]
|
||||
cmake-after = """
|
||||
generate_resources(${CMKR_TARGET})
|
||||
"""
|
||||
|
||||
[[install]]
|
||||
targets = ["cmkr"]
|
||||
|
||||
Generated
-44
@@ -1,44 +0,0 @@
|
||||
# This file was generated automatically by cmkr.
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# 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(example
|
||||
VERSION
|
||||
0.1.0
|
||||
)
|
||||
|
||||
# Target example
|
||||
set(example_SOURCES
|
||||
"src/example.cpp"
|
||||
cmake.toml
|
||||
)
|
||||
|
||||
add_executable(example ${example_SOURCES})
|
||||
|
||||
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 example)
|
||||
endif()
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${example_SOURCES})
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# This is a minimal example project used for testing the cmkr bootstrapping process
|
||||
|
||||
[cmake]
|
||||
version = "3.15"
|
||||
|
||||
[project]
|
||||
name = "example"
|
||||
version = "0.1.0"
|
||||
|
||||
[target.example]
|
||||
type = "executable"
|
||||
sources = ["src/example.cpp"]
|
||||
+163
-162
@@ -1,162 +1,163 @@
|
||||
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 "archive_264e4ace" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
|
||||
# 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")
|
||||
|
||||
# Disable cmkr if generation is disabled
|
||||
if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION)
|
||||
message(STATUS "[cmkr] Skipping automatic cmkr generation")
|
||||
macro(cmkr)
|
||||
endmacro()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Disable cmkr if no cmake.toml file is found
|
||||
if(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
|
||||
set(CMKR_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_${CMKR_TAG}")
|
||||
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
|
||||
|
||||
if(NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE AND CMKR_EXECUTABLE MATCHES "^${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
|
||||
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
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")
|
||||
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}"
|
||||
)
|
||||
message(STATUS "[cmkr] Building cmkr...")
|
||||
cmkr_exec("${CMAKE_COMMAND}"
|
||||
--no-warn-unused-cli
|
||||
"${CMKR_DIRECTORY}"
|
||||
"-B${CMKR_DIRECTORY}/build"
|
||||
"-DCMAKE_BUILD_TYPE=Release"
|
||||
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
|
||||
"-DCMKR_GENERATE_DOCUMENTATION=OFF"
|
||||
)
|
||||
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})
|
||||
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()
|
||||
|
||||
# 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()
|
||||
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 "archive_a718dfd6" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
|
||||
# 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")
|
||||
|
||||
# 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 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
|
||||
set(CMKR_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_${CMKR_TAG}")
|
||||
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
|
||||
|
||||
if(NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE AND CMKR_EXECUTABLE MATCHES "^${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
|
||||
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
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")
|
||||
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}"
|
||||
)
|
||||
message(STATUS "[cmkr] Building cmkr...")
|
||||
cmkr_exec("${CMAKE_COMMAND}"
|
||||
--no-warn-unused-cli
|
||||
"${CMKR_DIRECTORY}"
|
||||
"-B${CMKR_DIRECTORY}/build"
|
||||
"-DCMAKE_BUILD_TYPE=Release"
|
||||
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
|
||||
"-DCMKR_GENERATE_DOCUMENTATION=OFF"
|
||||
)
|
||||
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})
|
||||
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()
|
||||
|
||||
# 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()
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
option(CMKR_GENERATE_DOCUMENTATION "Generate cmkr documentation" ${CMKR_ROOT_PROJECT})
|
||||
set(CMKR_TESTS "" CACHE INTERNAL "List of test directories in the order declared in tests/cmake.toml")
|
||||
|
||||
if(CMKR_GENERATE_DOCUMENTATION)
|
||||
# Hook the add_test function to capture the tests in the order declared in tests/cmake.toml
|
||||
function(add_test)
|
||||
cmake_parse_arguments(TEST "" "WORKING_DIRECTORY" "" ${ARGN})
|
||||
get_filename_component(TEST_WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}" NAME)
|
||||
list(APPEND CMKR_TESTS "${TEST_WORKING_DIRECTORY}")
|
||||
set(CMKR_TESTS "${CMKR_TESTS}" CACHE INTERNAL "")
|
||||
_add_test(${test} ${ARGN})
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
function(generate_documentation)
|
||||
if(CMKR_GENERATE_DOCUMENTATION)
|
||||
message(STATUS "[cmkr] Generating documentation...")
|
||||
|
||||
# Delete previously generated examples
|
||||
set(example_folder "${PROJECT_SOURCE_DIR}/docs/examples")
|
||||
file(GLOB example_files "${example_folder}/*.md")
|
||||
list(REMOVE_ITEM example_files "${example_folder}/index.md")
|
||||
if(example_files)
|
||||
file(REMOVE ${example_files})
|
||||
endif()
|
||||
|
||||
message(DEBUG "[cmkr] Test directories: ${CMKR_TESTS}")
|
||||
set(test_index 0)
|
||||
foreach(test_dir ${CMKR_TESTS})
|
||||
set(test_name "${test_dir}")
|
||||
set(test_dir "${PROJECT_SOURCE_DIR}/tests/${test_dir}")
|
||||
set(test_toml "${test_dir}/cmake.toml")
|
||||
if(IS_DIRECTORY "${test_dir}" AND EXISTS "${test_toml}")
|
||||
message(DEBUG "[cmkr] Generating documentation for: ${test_toml} (index: ${test_index})")
|
||||
|
||||
# Set template variables
|
||||
set(EXAMPLE_PERMALINK "${test_name}")
|
||||
set(EXAMPLE_INDEX ${test_index})
|
||||
math(EXPR test_index "${test_index}+1")
|
||||
|
||||
# Read cmake.toml file
|
||||
file(READ "${test_toml}" test_contents NO_HEX_CONVERSION)
|
||||
string(LENGTH "${test_contents}" toml_length)
|
||||
|
||||
# Extract header text
|
||||
string(REGEX MATCH "^(\n*(#[^\n]+\n)+\n*)" EXAMPLE_HEADER "${test_contents}")
|
||||
string(LENGTH "${EXAMPLE_HEADER}" header_length)
|
||||
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
||||
string(REGEX REPLACE "\n# ?" "\n" EXAMPLE_HEADER "\n${EXAMPLE_HEADER}")
|
||||
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
||||
|
||||
# Extract footer text
|
||||
string(REGEX MATCH "(((#[^\n]+)(\n+|$))+)$" EXAMPLE_FOOTER "${test_contents}")
|
||||
string(LENGTH "${EXAMPLE_FOOTER}" footer_length)
|
||||
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
||||
string(REGEX REPLACE "\n# ?" "\n" EXAMPLE_FOOTER "\n${EXAMPLE_FOOTER}")
|
||||
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
||||
|
||||
# Extract toml body
|
||||
math(EXPR toml_length "${toml_length}-${header_length}-${footer_length}")
|
||||
string(SUBSTRING "${test_contents}" ${header_length} ${toml_length} EXAMPLE_TOML)
|
||||
string(STRIP "${EXAMPLE_TOML}" EXAMPLE_TOML)
|
||||
|
||||
# Extract title from description
|
||||
if("${EXAMPLE_TOML}" MATCHES "description *= *\"([^\"]+)\"")
|
||||
set(EXAMPLE_TITLE "${CMAKE_MATCH_1}")
|
||||
|
||||
# Generate documentation markdown page
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/example.md.in" "${example_folder}/${EXAMPLE_PERMALINK}.md" @ONLY NEWLINE_STYLE LF)
|
||||
else()
|
||||
message(DEBUG "[cmkr] Skipping documentation generation for ${test_name} because description is missing")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
option(CMKR_GENERATE_DOCUMENTATION "Generate cmkr documentation" ${CMKR_ROOT_PROJECT})
|
||||
set(CMKR_TESTS "" CACHE INTERNAL "List of test directories in the order declared in tests/cmake.toml")
|
||||
|
||||
if(CMKR_GENERATE_DOCUMENTATION)
|
||||
# Hook the add_test function to capture the tests in the order declared in tests/cmake.toml
|
||||
function(add_test)
|
||||
cmake_parse_arguments(TEST "" "WORKING_DIRECTORY" "" ${ARGN})
|
||||
get_filename_component(TEST_WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}" NAME)
|
||||
list(APPEND CMKR_TESTS "${TEST_WORKING_DIRECTORY}")
|
||||
set(CMKR_TESTS "${CMKR_TESTS}" CACHE INTERNAL "")
|
||||
_add_test(${test} ${ARGN})
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
function(generate_documentation)
|
||||
if(CMKR_GENERATE_DOCUMENTATION)
|
||||
message(STATUS "[cmkr] Generating documentation...")
|
||||
|
||||
# Delete previously generated examples
|
||||
set(example_folder "${PROJECT_SOURCE_DIR}/docs/examples")
|
||||
file(GLOB example_files "${example_folder}/*.md")
|
||||
list(REMOVE_ITEM example_files "${example_folder}/index.md")
|
||||
if(example_files)
|
||||
file(REMOVE ${example_files})
|
||||
endif()
|
||||
|
||||
message(DEBUG "[cmkr] Test directories: ${CMKR_TESTS}")
|
||||
set(test_index 0)
|
||||
foreach(test_dir ${CMKR_TESTS})
|
||||
set(test_name "${test_dir}")
|
||||
set(test_dir "${PROJECT_SOURCE_DIR}/tests/${test_dir}")
|
||||
set(test_toml "${test_dir}/cmake.toml")
|
||||
if(IS_DIRECTORY "${test_dir}" AND EXISTS "${test_toml}")
|
||||
message(DEBUG "[cmkr] Generating documentation for: ${test_toml} (index: ${test_index})")
|
||||
|
||||
# Set template variables
|
||||
set(EXAMPLE_PERMALINK "${test_name}")
|
||||
set(EXAMPLE_INDEX ${test_index})
|
||||
math(EXPR test_index "${test_index}+1")
|
||||
|
||||
# Read cmake.toml file
|
||||
file(READ "${test_toml}" test_contents NO_HEX_CONVERSION)
|
||||
string(LENGTH "${test_contents}" toml_length)
|
||||
|
||||
# Extract header text
|
||||
string(REGEX MATCH "^(\n*(#[^\n]+\n)+\n*)" EXAMPLE_HEADER "${test_contents}")
|
||||
string(LENGTH "${EXAMPLE_HEADER}" header_length)
|
||||
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
||||
string(REGEX REPLACE "\n# ?" "\n" EXAMPLE_HEADER "\n${EXAMPLE_HEADER}")
|
||||
string(STRIP "${EXAMPLE_HEADER}" EXAMPLE_HEADER)
|
||||
|
||||
# Extract footer text
|
||||
string(REGEX MATCH "(((#[^\n]+)(\n+|$))+)$" EXAMPLE_FOOTER "${test_contents}")
|
||||
string(LENGTH "${EXAMPLE_FOOTER}" footer_length)
|
||||
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
||||
string(REGEX REPLACE "\n# ?" "\n" EXAMPLE_FOOTER "\n${EXAMPLE_FOOTER}")
|
||||
string(STRIP "${EXAMPLE_FOOTER}" EXAMPLE_FOOTER)
|
||||
|
||||
# Extract toml body
|
||||
math(EXPR toml_length "${toml_length}-${header_length}-${footer_length}")
|
||||
string(SUBSTRING "${test_contents}" ${header_length} ${toml_length} EXAMPLE_TOML)
|
||||
string(STRIP "${EXAMPLE_TOML}" EXAMPLE_TOML)
|
||||
|
||||
# Extract title from description
|
||||
if("${EXAMPLE_TOML}" MATCHES "description *= *\"([^\"]+)\"")
|
||||
set(EXAMPLE_TITLE "${CMAKE_MATCH_1}")
|
||||
|
||||
# Generate documentation markdown page
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/example.md.in" "${example_folder}/${EXAMPLE_PERMALINK}.md" @ONLY NEWLINE_STYLE LF)
|
||||
else()
|
||||
message(DEBUG "[cmkr] Skipping documentation generation for ${test_name} because description is missing")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Enumerates the target sources and automatically generates include/resources/${RESOURCE_NAME}.h from all .cmake files
|
||||
function(generate_resources target)
|
||||
get_property(TARGET_SOURCES
|
||||
TARGET ${target}
|
||||
PROPERTY SOURCES
|
||||
)
|
||||
foreach(SOURCE ${TARGET_SOURCES})
|
||||
if(SOURCE MATCHES ".cmake$")
|
||||
get_filename_component(RESOURCE_NAME "${SOURCE}" NAME_WE)
|
||||
set(RESOURCE_HEADER "include/resources/${RESOURCE_NAME}.hpp")
|
||||
# Add configure-time dependency on the source file
|
||||
configure_file("${SOURCE}" "${RESOURCE_HEADER}" COPYONLY)
|
||||
# Generate the actual resource into the header
|
||||
file(READ "${SOURCE}" RESOURCE_CONTENTS)
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/resource.hpp.in" "${RESOURCE_HEADER}" @ONLY)
|
||||
message(STATUS "[cmkr] Generated ${RESOURCE_HEADER}")
|
||||
endif()
|
||||
endforeach()
|
||||
target_include_directories(${target} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
endfunction()
|
||||
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
find_package(Git REQUIRED)
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}" name-rev --tags --name-only HEAD
|
||||
OUTPUT_VARIABLE GIT_TAG
|
||||
)
|
||||
|
||||
string(FIND "${GIT_TAG}" "\n" NEWLINE_POS)
|
||||
string(SUBSTRING "${GIT_TAG}" 0 ${NEWLINE_POS} GIT_TAG)
|
||||
string(STRIP "${GIT_TAG}" GIT_TAG)
|
||||
|
||||
if("${GIT_TAG}" STREQUAL "")
|
||||
message(FATAL_ERROR "Failed to retrieve git tag!")
|
||||
endif()
|
||||
|
||||
message(STATUS "CMKR_TAG: '${GIT_TAG}'")
|
||||
|
||||
file(READ "cmake/cmkr.cmake" CMKR_CMAKE)
|
||||
string(REGEX REPLACE "CMKR_TAG \"[^\"]+\"" "CMKR_TAG \"${GIT_TAG}\"" CMKR_CMAKE "${CMKR_CMAKE}")
|
||||
file(CONFIGURE
|
||||
OUTPUT "cmake/cmkr.cmake"
|
||||
CONTENT "${CMKR_CMAKE}"
|
||||
@ONLY
|
||||
NEWLINE_STYLE LF
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace cmkr {
|
||||
namespace resources {
|
||||
|
||||
static const char* @RESOURCE_NAME@ = R"RESOURCE(@RESOURCE_CONTENTS@)RESOURCE";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#include <cstdio>
|
||||
|
||||
int main()
|
||||
{
|
||||
puts("Hello from cmkr!");
|
||||
}
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
_site/
|
||||
.jekyll-metadata
|
||||
.jekyll-metadata
|
||||
|
||||
@@ -11,3 +11,5 @@ end
|
||||
|
||||
gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
|
||||
gem "just-the-docs"
|
||||
|
||||
gem "webrick", "~> 1.7"
|
||||
|
||||
+3
-1
@@ -262,6 +262,7 @@ GEM
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
webrick (1.7.0)
|
||||
zeitwerk (2.4.2)
|
||||
|
||||
PLATFORMS
|
||||
@@ -275,6 +276,7 @@ DEPENDENCIES
|
||||
tzinfo (~> 1.2)
|
||||
tzinfo-data
|
||||
wdm (~> 0.1.1)
|
||||
webrick (~> 1.7)
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.2
|
||||
2.2.26
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
---
|
||||
layout: page
|
||||
title: cmake.toml
|
||||
permalink: /cmake-toml/
|
||||
nav_order: 3
|
||||
---
|
||||
|
||||
# cmake.toml
|
||||
|
||||
This page is supposed to be a reference for the options in the `cmake.toml` file. If you think anything is missing or unclear, please [edit this page](https://github.com/build-cpp/cmkr/edit/main/docs/cmake-toml.md) or open an [issue](https://github.com/build-cpp/cmkr/issues).
|
||||
|
||||
See the [examples](/examples) section for more real-world examples.
|
||||
|
||||
## CMake configuration
|
||||
|
||||
```toml
|
||||
[cmake]
|
||||
version = "3.15"
|
||||
cmkr-include = "cmkr.cmake"
|
||||
```
|
||||
|
||||
## Project configuration
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "myproject"
|
||||
version = "1.0.0"
|
||||
description = "Description of the project"
|
||||
languages = ["C", "CXX"]
|
||||
cmake-before = """
|
||||
message(STATUS "CMake injected before the project() call")
|
||||
"""
|
||||
cmake-after = """
|
||||
message(STATUS "CMake injected after the project() call")
|
||||
"""
|
||||
include-before = ["cmake/before-project.cmake"]
|
||||
include-after = ["cmake/after-project.cmake"]
|
||||
```
|
||||
|
||||
## Conditions
|
||||
|
||||
```toml
|
||||
[conditions]
|
||||
arch64 = "CMAKE_SIZEOF_VOID_P EQUALS 8"
|
||||
arch32 = "CMAKE_SIZEOF_VOID_P EQUALS 4"
|
||||
```
|
||||
|
||||
## Subdirectories
|
||||
|
||||
```toml
|
||||
[subdir.mysubdir]
|
||||
condition = "linux"
|
||||
cmake-before = """
|
||||
message(STATUS "CMake injected before the add_subdirectory() call"
|
||||
"""
|
||||
cmake-after = """
|
||||
message(STATUS "CMake injected after the add_subdirectory() call")
|
||||
"""
|
||||
include-before = ["cmake/before-subdir.cmake"]
|
||||
include-after = ["cmake/after-subdir.cmake"]
|
||||
```
|
||||
|
||||
## Vcpkg
|
||||
|
||||
```toml
|
||||
[vcpkg]
|
||||
version = "2021.05.12"
|
||||
url = "https://github.com/microsoft/vcpkg/archive/refs/tags/2021.05.12.tar.gz"
|
||||
packages = ["fmt", "zlib"]
|
||||
```
|
||||
|
||||
The vcpkg `version` will automatically generate the `url` from the official repository. For a custom registry you can specify your own `url` (and omit the `version`).
|
||||
|
||||
## Packages
|
||||
|
||||
```toml
|
||||
[find-package]
|
||||
mypackage = { version = "1.0", required = true, config = true, components = ["mycomponent"] }
|
||||
|
||||
# Alternative syntax
|
||||
[find-package.mypackage]
|
||||
version = "1.0"
|
||||
required = true
|
||||
config = true
|
||||
components = ["mycomponent"]
|
||||
```
|
||||
|
||||
## FetchContent
|
||||
|
||||
**Note**: The `[fetch-content]` feature is unpolished and will likely change in a future release.
|
||||
|
||||
```toml
|
||||
[fetch-content]
|
||||
gitcontent = { git = "https://github.com/myuser/gitcontent", tag = "v0.1" }
|
||||
svncontent = { svn = "https://svn-host.com/url", rev = "svn_rev" }
|
||||
urlcontent = { url = "https://content-host.com/urlcontent.zip", hash = "123123123123" }
|
||||
|
||||
# Alternative syntax
|
||||
[fetch-content.gitcontent]
|
||||
git = "https://github.com/myuser/gitcontent"
|
||||
tag = "v0.1"
|
||||
```
|
||||
|
||||
## Targets
|
||||
|
||||
```toml
|
||||
[target.mytarget]
|
||||
condition = "linux"
|
||||
alias = "mytarget::mytarget"
|
||||
type = "static" # executable, library, shared, static, interface, custom
|
||||
headers = ["src/mytarget.h"]
|
||||
sources = ["src/mytarget.cpp"]
|
||||
|
||||
# The keys below match the target_xxx CMake commands
|
||||
# Keys prefixed with private- will get PRIVATE visibility
|
||||
compile-definitions = [""]
|
||||
private-compile-definitions = [""]
|
||||
compile-features = [""]
|
||||
private-compile-features = [""]
|
||||
compile-options = [""]
|
||||
private-compile-options = [""]
|
||||
include-directories = [""]
|
||||
private-include-directories = [""]
|
||||
link-directories = [""]
|
||||
private-link-directories = [""]
|
||||
link-libraries = [""]
|
||||
private-link-libraries = [""]
|
||||
link-options = [""]
|
||||
private-link-options = [""]
|
||||
precompile-headers = [""]
|
||||
private-precompile-headers = [""]
|
||||
|
||||
cmake-before = """
|
||||
message(STATUS "CMake injected before the target")
|
||||
"""
|
||||
cmake-after = """
|
||||
message(STATUS "CMake injected after the target")
|
||||
"""
|
||||
include-before = "cmake/target-before.cmake"
|
||||
include-after = "cmake/target-after.cmake"
|
||||
|
||||
# See https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets for a list of target properties
|
||||
[target.mytarget.properties]
|
||||
CXX_STANDARD = 17
|
||||
CXX_STANDARD_REQUIRED = true
|
||||
FOLDER = "MyFolder"
|
||||
```
|
||||
|
||||
## Tests and installation (unfinished)
|
||||
|
||||
**Note**: The `[[test]]` and `[[install]]` are unfinished features and will likely change in a future release.
|
||||
|
||||
```toml
|
||||
# You can declare as many as you want like this, but the name has to be unique
|
||||
[[test]]
|
||||
name = "mytest"
|
||||
command = "$<TARGET_FILE:mytest>"
|
||||
arguments = ["arg1", "arg2"]
|
||||
configurations = ["Debug", "Release", "RelWithDebInfo", "MinSizeRelease"]
|
||||
working-directory = "mytest-dir"
|
||||
```
|
||||
|
||||
```toml
|
||||
[[install]]
|
||||
targets = ["mytarget", "mytest"]
|
||||
destination = ["bin"]
|
||||
files = ["content/my.png"]
|
||||
dirs = [""]
|
||||
configs = [""]
|
||||
```
|
||||
@@ -5,7 +5,7 @@ permalink: /command-line/
|
||||
nav_order: 2
|
||||
---
|
||||
|
||||
## Command line
|
||||
# Command line
|
||||
|
||||
Optionally you can install `cmkr` in your `PATH` and use it as a utility from the command line:
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
# Automatically generated from tests/cxx-standard/cmake.toml - DO NOT EDIT
|
||||
layout: default
|
||||
title: Changing C++ standard
|
||||
permalink: /examples/cxx-standard
|
||||
parent: Examples
|
||||
nav_order: 5
|
||||
---
|
||||
|
||||
# Changing C++ standard
|
||||
|
||||
Require a C++11 compiler for the target `example`.
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "cxx-standard"
|
||||
description = "Changing C++ standard"
|
||||
|
||||
[target.example]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
compile-features = ["cxx_std_11"]
|
||||
```
|
||||
|
||||
This is equivalent to CMake's [target_compile_features](https://cmake.org/cmake/help/latest/command/target_compile_features.html)`(example PRIVATE cxx_std_11)`. For more information on available C/C++ standards and features see [cmake-compile-features(7)](https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html).
|
||||
|
||||
<sup><sub>This page was automatically generated from [tests/cxx-standard/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/cxx-standard/cmake.toml).</sub></sup>
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Automatically generated from tests/globbing/cmake.toml - DO NOT EDIT
|
||||
layout: default
|
||||
title: Globbing sources
|
||||
permalink: /examples/globbing
|
||||
parent: Examples
|
||||
nav_order: 6
|
||||
---
|
||||
|
||||
# Globbing sources
|
||||
|
||||
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "globbing"
|
||||
description = "Globbing sources"
|
||||
|
||||
# Recursively glob in the mylib/ folder
|
||||
[target.mylib]
|
||||
type = "static"
|
||||
alias = "mylib::mylib"
|
||||
sources = ["mylib/**.hpp", "mylib/**.cpp"]
|
||||
include-directories = ["mylib/include"]
|
||||
|
||||
# Single-folder glob in example/src/
|
||||
[target.example]
|
||||
type = "executable"
|
||||
sources = ["example/src/*.cpp"]
|
||||
link-libraries = ["mylib::mylib"]
|
||||
```
|
||||
|
||||
As you can see in the example above you can use `**.ext` to glob recursively and `*.ext` to glob non-recursively. This **does not** generate `file(GLOB ...)` commands, but instead globs when cmkr is run. Files are sorted to give deterministic results regardless of the platform used.
|
||||
|
||||
<sup><sub>This page was automatically generated from [tests/globbing/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/globbing/cmake.toml).</sub></sup>
|
||||
@@ -5,7 +5,7 @@ permalink: /getting-started/
|
||||
nav_order: 1
|
||||
---
|
||||
|
||||
## Getting started
|
||||
# Getting started
|
||||
|
||||
The easiest way to get started is to use the [cmkr_for_beginners](https://github.com/build-cpp/cmkr_for_beginners) template repository. Either open it in [Gitpod](https://gitpod.io/#https://github.com/build-cpp/cmkr_for_beginners), or clone the repository and run:
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "project_parser.hpp"
|
||||
|
||||
namespace cmkr {
|
||||
namespace gen {
|
||||
|
||||
int generate_project(const char *typ);
|
||||
|
||||
int generate_cmake(const char *path, bool root = true);
|
||||
int generate_cmake(const char *path, const parser::Project *parent_project = nullptr);
|
||||
|
||||
} // namespace gen
|
||||
} // namespace cmkr
|
||||
|
||||
@@ -126,6 +126,7 @@ struct Project {
|
||||
std::string build_dir = "build";
|
||||
std::string generator;
|
||||
std::string config;
|
||||
bool allow_in_tree = false;
|
||||
Condition<std::vector<std::string>> project_subdirs;
|
||||
std::vector<std::string> cppflags;
|
||||
std::vector<std::string> cflags;
|
||||
@@ -151,7 +152,7 @@ struct Project {
|
||||
tsl::ordered_map<std::string, std::string> conditions;
|
||||
std::vector<Subdir> subdirs;
|
||||
|
||||
Project(const std::string &path, bool build);
|
||||
Project(const Project *parent, const std::string &path, bool build);
|
||||
};
|
||||
|
||||
bool is_root_path(const std::string &path);
|
||||
|
||||
@@ -36,6 +36,9 @@ const char *handle_args(int argc, char **argv) {
|
||||
auto ret = cmkr::gen::generate_project(type.c_str());
|
||||
if (ret)
|
||||
return "Initialization failure!";
|
||||
ret = cmkr::gen::generate_cmake(fs::current_path().string().c_str());
|
||||
if (ret)
|
||||
return "CMake generation error!";
|
||||
return "Directory initialized!";
|
||||
} else if (main_arg == "build") {
|
||||
auto ret = build::run(argc, argv);
|
||||
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
#include "build.hpp"
|
||||
#include "project_parser.hpp"
|
||||
#include "error.hpp"
|
||||
#include "cmake_generator.hpp"
|
||||
#include "error.hpp"
|
||||
#include "project_parser.hpp"
|
||||
|
||||
#include "fs.hpp"
|
||||
#include <sstream>
|
||||
@@ -14,7 +14,7 @@ namespace cmkr {
|
||||
namespace build {
|
||||
|
||||
int run(int argc, char **argv) {
|
||||
parser::Project project(".", true);
|
||||
parser::Project project(nullptr, ".", true);
|
||||
if (argc > 2) {
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
project.build_args.push_back(argv[i]);
|
||||
@@ -25,7 +25,7 @@ int run(int argc, char **argv) {
|
||||
if (gen::generate_cmake(fs::current_path().string().c_str()))
|
||||
throw std::runtime_error("CMake generation failure!");
|
||||
|
||||
ss << "cmake -S. -B" << project.build_dir << " ";
|
||||
ss << "cmake -S. -DCMKR_BUILD_SKIP_GENERATION=ON -B" << project.build_dir << " ";
|
||||
|
||||
if (!project.generator.empty()) {
|
||||
ss << "-G \"" << project.generator << "\" ";
|
||||
@@ -50,7 +50,7 @@ int run(int argc, char **argv) {
|
||||
|
||||
int clean() {
|
||||
bool ret = false;
|
||||
parser::Project project(".", true);
|
||||
parser::Project project(nullptr, ".", true);
|
||||
if (fs::exists(project.build_dir)) {
|
||||
ret = fs::remove_all(project.build_dir);
|
||||
fs::create_directory(project.build_dir);
|
||||
@@ -59,7 +59,7 @@ int clean() {
|
||||
}
|
||||
|
||||
int install() {
|
||||
parser::Project project(".", false);
|
||||
parser::Project project(nullptr, ".", false);
|
||||
auto cmd = "cmake --install " + project.build_dir;
|
||||
return ::system(cmd.c_str());
|
||||
}
|
||||
|
||||
+32
-11
@@ -1,7 +1,7 @@
|
||||
#include "cmake_generator.hpp"
|
||||
#include "error.hpp"
|
||||
#include "literals.hpp"
|
||||
#include "project_parser.hpp"
|
||||
#include <resources/cmkr.hpp>
|
||||
|
||||
#include "fs.hpp"
|
||||
#include <cassert>
|
||||
@@ -440,12 +440,12 @@ static std::string vcpkg_escape_identifier(const std::string &name) {
|
||||
return escaped;
|
||||
}
|
||||
|
||||
int generate_cmake(const char *path, bool root) {
|
||||
int generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
if (!fs::exists(fs::path(path) / "cmake.toml")) {
|
||||
throw std::runtime_error("No cmake.toml found!");
|
||||
}
|
||||
|
||||
parser::Project project(path, false);
|
||||
parser::Project project(parent_project, path, false);
|
||||
Generator gen(project);
|
||||
|
||||
// Helper lambdas for more convenient CMake generation
|
||||
@@ -461,25 +461,46 @@ int generate_cmake(const char *path, bool root) {
|
||||
comment("See " + cmkr_url + " for more information");
|
||||
endl();
|
||||
|
||||
if (root) {
|
||||
// Root project doesn't have a parent
|
||||
if (parent_project == nullptr) {
|
||||
cmd("cmake_minimum_required")("VERSION", project.cmake_version).endl();
|
||||
|
||||
if (!project.allow_in_tree) {
|
||||
// clang-format off
|
||||
cmd("if")("CMAKE_SOURCE_DIR", "STREQUAL", "CMAKE_BINARY_DIR");
|
||||
cmd("message")("FATAL_ERROR", "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build");
|
||||
cmd("endif")().endl();
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
comment("Regenerate CMakeLists.txt automatically in the root project");
|
||||
cmd("set")("CMKR_ROOT_PROJECT", "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")(project.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT");
|
||||
cmd("if")("CMKR_INCLUDE_RESULT");
|
||||
cmd("cmkr")();
|
||||
cmd("endif")().endl();
|
||||
if (!project.cmkr_include.empty()) {
|
||||
comment("Bootstrap cmkr");
|
||||
cmd("include")(project.cmkr_include, "OPTIONAL", "RESULT_VARIABLE", "CMKR_INCLUDE_RESULT");
|
||||
cmd("if")("CMKR_INCLUDE_RESULT");
|
||||
cmd("cmkr")();
|
||||
cmd("endif")().endl();
|
||||
}
|
||||
|
||||
comment("Enable folder support");
|
||||
cmd("set_property")("GLOBAL", "PROPERTY", "USE_FOLDERS", "ON");
|
||||
cmd("endif")().endl();
|
||||
// clang-format on
|
||||
|
||||
fs::path cmkr_include(project.cmkr_include);
|
||||
if (!project.cmkr_include.empty() && !fs::exists(cmkr_include) && cmkr_include.is_relative()) {
|
||||
fs::create_directories(cmkr_include.parent_path());
|
||||
std::ofstream ofs(cmkr_include.string(), std::ios::binary);
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("Failed to create " + project.cmkr_include);
|
||||
}
|
||||
ofs.write(resources::cmkr, strlen(resources::cmkr));
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@@ -911,7 +932,7 @@ int generate_cmake(const char *path, bool root) {
|
||||
}
|
||||
}
|
||||
|
||||
auto generate_subdir = [path](const fs::path &sub) {
|
||||
auto generate_subdir = [path, &project](const fs::path &sub) {
|
||||
// Skip generating for subdirectories that have a cmake.toml with a [project] in it
|
||||
fs::path subpath;
|
||||
for (const auto &p : sub) {
|
||||
@@ -923,7 +944,7 @@ int generate_cmake(const char *path, bool root) {
|
||||
|
||||
subpath = path / sub;
|
||||
if (fs::exists(subpath / "cmake.toml")) {
|
||||
generate_cmake(subpath.string().c_str(), false);
|
||||
generate_cmake(subpath.string().c_str(), &project);
|
||||
}
|
||||
};
|
||||
for (const auto &itr : project.project_subdirs) {
|
||||
|
||||
+23
-7
@@ -61,7 +61,7 @@ static void get_optional(const TomlBasicValue &v, const toml::key &ky, T &destin
|
||||
}
|
||||
}
|
||||
|
||||
Project::Project(const std::string &path, bool build) {
|
||||
Project::Project(const Project *parent, const std::string &path, bool build) {
|
||||
const auto toml_path = fs::path(path) / "cmake.toml";
|
||||
if (!fs::exists(toml_path)) {
|
||||
throw std::runtime_error("No cmake.toml was found!");
|
||||
@@ -79,12 +79,21 @@ Project::Project(const std::string &path, bool build) {
|
||||
get_optional(cmake, "generator", generator);
|
||||
get_optional(cmake, "config", config);
|
||||
get_optional(cmake, "arguments", gen_args);
|
||||
get_optional(cmake, "allow-in-tree", allow_in_tree);
|
||||
}
|
||||
} else {
|
||||
if (toml.contains("cmake")) {
|
||||
const auto &cmake = toml::find(toml, "cmake");
|
||||
cmake_version = toml::find(cmake, "version").as_string();
|
||||
get_optional(cmake, "cmkr-include", cmkr_include);
|
||||
if (cmake.contains("cmkr-include")) {
|
||||
const auto &cmkr_include_kv = toml::find(cmake, "cmkr-include");
|
||||
if (cmkr_include_kv.is_string()) {
|
||||
cmkr_include = cmkr_include_kv.as_string();
|
||||
} else {
|
||||
// Allow disabling this feature with cmkr-include = false
|
||||
cmkr_include = "";
|
||||
}
|
||||
}
|
||||
get_optional(cmake, "cpp-flags", cppflags);
|
||||
get_optional(cmake, "c-flags", cflags);
|
||||
get_optional(cmake, "link-flags", linkflags);
|
||||
@@ -312,11 +321,18 @@ Project::Project(const std::string &path, bool build) {
|
||||
}
|
||||
|
||||
// Reasonable default conditions (you can override these if you desire)
|
||||
conditions["windows"] = R"cmake(WIN32)cmake";
|
||||
conditions["macos"] = R"cmake("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")cmake";
|
||||
conditions["unix"] = R"cmake(UNIX)cmake";
|
||||
conditions["bsd"] = R"cmake("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")cmake";
|
||||
conditions["linux"] = conditions["lunix"] = R"cmake("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")cmake";
|
||||
if (parent == nullptr) {
|
||||
conditions["windows"] = R"cmake(WIN32)cmake";
|
||||
conditions["macos"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "Darwin")cmake";
|
||||
conditions["unix"] = R"cmake(UNIX)cmake";
|
||||
conditions["bsd"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "BSD")cmake";
|
||||
conditions["linux"] = conditions["lunix"] = R"cmake(CMAKE_SYSTEM_NAME MATCHES "Linux")cmake";
|
||||
conditions["gcc"] = R"cmake(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "GNU")cmake";
|
||||
conditions["clang"] = R"cmake(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "Clang")cmake";
|
||||
conditions["msvc"] = R"cmake(MSVC)cmake";
|
||||
} else {
|
||||
conditions = parent->conditions;
|
||||
}
|
||||
|
||||
if (toml.contains("conditions")) {
|
||||
auto conds = toml::find<decltype(conditions)>(toml, "conditions");
|
||||
|
||||
+3
-2
@@ -1,2 +1,3 @@
|
||||
# These will be generated by cmkr, so no point in tracking them
|
||||
**/CMakeLists.txt
|
||||
# These will be generated by cmkr, so no point in tracking them
|
||||
**/CMakeLists.txt
|
||||
**/cmkr.cmake
|
||||
Generated
+20
@@ -58,3 +58,23 @@ add_test(
|
||||
build
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME
|
||||
cxx-standard
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/cxx-standard"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
build
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME
|
||||
globbing
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/globbing"
|
||||
COMMAND
|
||||
$<TARGET_FILE:cmkr>
|
||||
build
|
||||
)
|
||||
|
||||
|
||||
+13
-1
@@ -26,4 +26,16 @@ arguments = ["build"]
|
||||
name = "vcpkg"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
working-directory = "vcpkg"
|
||||
arguments = ["build"]
|
||||
arguments = ["build"]
|
||||
|
||||
[[test]]
|
||||
name = "cxx-standard"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
working-directory = "cxx-standard"
|
||||
arguments = ["build"]
|
||||
|
||||
[[test]]
|
||||
name = "globbing"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
working-directory = "globbing"
|
||||
arguments = ["build"]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Require a C++11 compiler for the target `example`.
|
||||
|
||||
[project]
|
||||
name = "cxx-standard"
|
||||
description = "Changing C++ standard"
|
||||
|
||||
[target.example]
|
||||
type = "executable"
|
||||
sources = ["src/main.cpp"]
|
||||
compile-features = ["cxx_std_11"]
|
||||
|
||||
# This is equivalent to CMake's [target_compile_features](https://cmake.org/cmake/help/latest/command/target_compile_features.html)`(example PRIVATE cxx_std_11)`. For more information on available C/C++ standards and features see [cmake-compile-features(7)](https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html).
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <cstdio>
|
||||
#include <tuple>
|
||||
|
||||
int main()
|
||||
{
|
||||
auto tpl = std::make_tuple(1, 2);
|
||||
printf("Hello from C++11 %d\n", std::get<0>(tpl));
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
[project]
|
||||
name = "globbing"
|
||||
description = "Globbing sources"
|
||||
|
||||
# Recursively glob in the mylib/ folder
|
||||
[target.mylib]
|
||||
type = "static"
|
||||
alias = "mylib::mylib"
|
||||
sources = ["mylib/**.hpp", "mylib/**.cpp"]
|
||||
include-directories = ["mylib/include"]
|
||||
|
||||
# Single-folder glob in example/src/
|
||||
[target.example]
|
||||
type = "executable"
|
||||
sources = ["example/src/*.cpp"]
|
||||
link-libraries = ["mylib::mylib"]
|
||||
|
||||
# As you can see in the example above you can use `**.ext` to glob recursively and `*.ext` to glob non-recursively. This **does not** generate `file(GLOB ...)` commands, but instead globs when cmkr is run. Files are sorted to give deterministic results regardless of the platform used.
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <mylib/mylib.hpp>
|
||||
|
||||
int main() {
|
||||
std::cout << mylib::message() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mylib
|
||||
{
|
||||
std::string message();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <mylib/mylib.hpp>
|
||||
|
||||
std::string mylib::message()
|
||||
{
|
||||
return "cmkr is awesome!";
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
"dependencies": [
|
||||
"fmt"
|
||||
],
|
||||
"description": "Example of using vcpkg",
|
||||
"description": "Dependencies from vcpkg",
|
||||
"name": "vcpkg",
|
||||
"version-string": ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user