diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9e02c3..89f9816 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,6 +32,8 @@ project(cmkr
"CMakeLists generator from TOML"
)
+include("cmake/generate_documentation.cmake")
+
# third_party
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER)
@@ -54,6 +56,21 @@ set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
+# Target cmkr_generate_documentation
+set(CMKR_TARGET cmkr_generate_documentation)
+set(cmkr_generate_documentation_SOURCES "")
+
+set(CMKR_SOURCES ${cmkr_generate_documentation_SOURCES})
+add_library(cmkr_generate_documentation INTERFACE)
+
+if(cmkr_generate_documentation_SOURCES)
+ target_sources(cmkr_generate_documentation INTERFACE ${cmkr_generate_documentation_SOURCES})
+endif()
+
+generate_documentation()
+
+unset(CMKR_TARGET)
+unset(CMKR_SOURCES)
# Target cmkr
set(CMKR_TARGET cmkr)
set(cmkr_SOURCES "")
diff --git a/cmake.toml b/cmake.toml
index 16307d0..1fb86f5 100644
--- a/cmake.toml
+++ b/cmake.toml
@@ -7,6 +7,13 @@ version = "0.1.4"
description = "CMakeLists generator from TOML"
languages = ["CXX"]
subdirs = ["third_party", "tests"]
+include-after = ["cmake/generate_documentation.cmake"]
+
+[target.cmkr_generate_documentation]
+type = "interface"
+cmake-after = """
+generate_documentation()
+"""
[target.cmkr]
type = "executable"
diff --git a/cmake/cmkr.cmake b/cmake/cmkr.cmake
index 61d8bbe..d4cbe7f 100644
--- a/cmake/cmkr.cmake
+++ b/cmake/cmkr.cmake
@@ -83,6 +83,7 @@ else()
"-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"
diff --git a/cmake/example.md.in b/cmake/example.md.in
new file mode 100644
index 0000000..e2c98e6
--- /dev/null
+++ b/cmake/example.md.in
@@ -0,0 +1,20 @@
+---
+# Automatically generated from tests/@EXAMPLE_PERMALINK@/cmake.toml - DO NOT EDIT
+layout: default
+title: @EXAMPLE_TITLE@
+permalink: /examples/@EXAMPLE_PERMALINK@
+parent: Examples
+nav_order: @EXAMPLE_INDEX@
+---
+
+# @EXAMPLE_TITLE@
+
+@EXAMPLE_HEADER@
+
+```toml
+@EXAMPLE_TOML@
+```
+
+@EXAMPLE_FOOTER@
+
+This page was automatically generated from [tests/@EXAMPLE_PERMALINK@/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/@EXAMPLE_PERMALINK@/cmake.toml).
\ No newline at end of file
diff --git a/cmake/generate_documentation.cmake b/cmake/generate_documentation.cmake
new file mode 100644
index 0000000..6c3990b
--- /dev/null
+++ b/cmake/generate_documentation.cmake
@@ -0,0 +1,73 @@
+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})
+ 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")
+ file(REMOVE ${example_files})
+
+ 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()
diff --git a/docs/.gitignore b/docs/.gitignore
index ca35be0..377c423 100644
--- a/docs/.gitignore
+++ b/docs/.gitignore
@@ -1 +1,2 @@
-_site
+_site/
+.jekyll-metadata
\ No newline at end of file
diff --git a/docs/examples/basic.md b/docs/examples/basic.md
new file mode 100644
index 0000000..7f1e416
--- /dev/null
+++ b/docs/examples/basic.md
@@ -0,0 +1,26 @@
+---
+# Automatically generated from tests/basic/cmake.toml - DO NOT EDIT
+layout: default
+title: Minimal example
+permalink: /examples/basic
+parent: Examples
+nav_order: 0
+---
+
+# Minimal example
+
+A minimal `cmake.toml` project:
+
+```toml
+[project]
+name = "basic"
+description = "Minimal example"
+
+[target.basic]
+type = "executable"
+sources = ["src/basic.cpp"]
+```
+
+Declares an executable target called `basic` with `src/basic.cpp` as a source file. Equivalent to CMake's [add_executable](https://cmake.org/cmake/help/latest/command/add_executable.html)`(basic src/basic.cpp)`.
+
+This page was automatically generated from [tests/basic/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/basic/cmake.toml).
diff --git a/docs/examples/cpp-version-change.markdown b/docs/examples/cpp-version-change.markdown
deleted file mode 100644
index 0b8bf85..0000000
--- a/docs/examples/cpp-version-change.markdown
+++ /dev/null
@@ -1,17 +0,0 @@
----
-layout: default
-title: Changing C/C++ version
-permalink: /examples/cpp-version-change
-parent: Examples
-nav_order: 3
----
-
-# Changing C/C++ version
-
-Simple example changing C++ to version 20 and C standard to the version 11
-
-```toml
-[target.example]
-type = "executable"
-compile-features = [ "cxx_std_20", "c_std_11" ]
-```
diff --git a/docs/examples/fetch-content.md b/docs/examples/fetch-content.md
new file mode 100644
index 0000000..c6c4358
--- /dev/null
+++ b/docs/examples/fetch-content.md
@@ -0,0 +1,30 @@
+---
+# Automatically generated from tests/fetch-content/cmake.toml - DO NOT EDIT
+layout: default
+title: Fetching from git
+permalink: /examples/fetch-content
+parent: Examples
+nav_order: 2
+---
+
+# Fetching from git
+
+Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) from [GitHub](https://github.com) and links an `example` target to it:
+
+```toml
+[project]
+name = "fetch-content"
+description = "Fetching from git"
+
+[fetch-content]
+fmt = { git = "https://github.com/fmtlib/fmt", tag = "7.1.3" }
+
+[target.example]
+type = "executable"
+sources = ["src/main.cpp"]
+link-libraries = ["fmt::fmt"]
+```
+
+This is equivalent to calling CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html).
+
+This page was automatically generated from [tests/fetch-content/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/fetch-content/cmake.toml).
diff --git a/docs/examples/import-from-git.markdown b/docs/examples/import-from-git.markdown
deleted file mode 100644
index e92e965..0000000
--- a/docs/examples/import-from-git.markdown
+++ /dev/null
@@ -1,22 +0,0 @@
----
-layout: default
-title: Import content from Github
-permalink: /examples/import-from-git
-parent: Examples
-nav_order: 2
----
-
-# Import content from Github
-
-Importing an existing project called Zydis to my project
-
-tag is optional but you can target any branch with it
-
-```toml
-[fetch-content]
-zydis = { git = "https://github.com/zyantific/zydis.git", tag = "v3.1.0" }
-
-[target.example]
-type = "executable"
-link-libraries = ["zydis"]
-```
diff --git a/docs/examples/index.markdown b/docs/examples/index.markdown
deleted file mode 100644
index e25f124..0000000
--- a/docs/examples/index.markdown
+++ /dev/null
@@ -1,10 +0,0 @@
----
-layout: default
-title: Examples
-permalink: /examples/
-nav_order: 4
-has_children: true
----
-
-# Examples
-
diff --git a/docs/examples/index.md b/docs/examples/index.md
new file mode 100644
index 0000000..9f27ce5
--- /dev/null
+++ b/docs/examples/index.md
@@ -0,0 +1,11 @@
+---
+layout: default
+title: Examples
+permalink: /examples/
+nav_order: 100
+has_children: true
+---
+
+# Examples
+
+The examples in this section are automatically generated from the [tests](https://github.com/build-cpp/cmkr/blob/main/tests/cmake.toml).
\ No newline at end of file
diff --git a/docs/examples/interface.md b/docs/examples/interface.md
new file mode 100644
index 0000000..3e27f87
--- /dev/null
+++ b/docs/examples/interface.md
@@ -0,0 +1,31 @@
+---
+# Automatically generated from tests/interface/cmake.toml - DO NOT EDIT
+layout: default
+title: Header-only library
+permalink: /examples/interface
+parent: Examples
+nav_order: 1
+---
+
+# Header-only library
+
+
+
+```toml
+[project]
+name = "interface"
+description = "Header-only library"
+
+[target.mylib]
+type = "interface"
+include-directories = ["include"]
+
+[target.example]
+type = "executable"
+sources = ["src/main.cpp"]
+link-libraries = ["mylib"]
+```
+
+
+
+This page was automatically generated from [tests/interface/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/interface/cmake.toml).
diff --git a/docs/examples/quickstart.markdown b/docs/examples/quickstart.markdown
deleted file mode 100644
index c6aa0a8..0000000
--- a/docs/examples/quickstart.markdown
+++ /dev/null
@@ -1,23 +0,0 @@
----
-layout: default
-title: Quickstart
-permalink: /examples/quickstart
-parent: Examples
-nav_order: 1
----
-
-# Quickstart
-
-Smallest possible start point you can have using cmkr
-
-```toml
-[cmake]
-version = "3.15"
-
-[project]
-name = "hello-world"
-
-[target.hello-world]
-type = "executable"
-sources = [ "src/*.cpp" ]
-```
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 5e5c957..4ee9fdc 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -6,7 +6,7 @@ nav_order: 0
# Index
-[cmkr](https://github.com/build-cpp/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). It was originally created by [Mohammed Alyousef](https://github.com/MoAlyousef).
`cmkr` parses `cmake.toml` files and generates a modern, idiomatic `CMakeLists.txt` for you. A minimal example:
diff --git a/docs/run-wsl.sh b/docs/run-wsl.sh
new file mode 100644
index 0000000..4cff5b8
--- /dev/null
+++ b/docs/run-wsl.sh
@@ -0,0 +1,2 @@
+bundle install
+bundle exec jekyll serve --force_polling --livereload --incremental
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 07a6b28..1467cd1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -12,7 +12,7 @@ add_test(
NAME
basic
WORKING_DIRECTORY
- "${CMAKE_CURRENT_LIST_DIR}/basic"
+ basic
COMMAND
$
build
@@ -20,9 +20,9 @@ add_test(
add_test(
NAME
- conditions
+ interface
WORKING_DIRECTORY
- "${CMAKE_CURRENT_LIST_DIR}/conditions"
+ interface
COMMAND
$
build
@@ -30,9 +30,19 @@ add_test(
add_test(
NAME
- interface
+ fetch-content
WORKING_DIRECTORY
- "${CMAKE_CURRENT_LIST_DIR}/interface"
+ fetch-content
+ COMMAND
+ $
+ build
+)
+
+add_test(
+ NAME
+ conditions
+ WORKING_DIRECTORY
+ conditions
COMMAND
$
build
diff --git a/tests/basic/cmake.toml b/tests/basic/cmake.toml
index 33aab4d..75ae8a1 100644
--- a/tests/basic/cmake.toml
+++ b/tests/basic/cmake.toml
@@ -1,9 +1,11 @@
-[cmake]
-version = "3.5"
+# A minimal `cmake.toml` project:
[project]
name = "basic"
+description = "Minimal example"
[target.basic]
type = "executable"
sources = ["src/basic.cpp"]
+
+# Declares an executable target called `basic` with `src/basic.cpp` as a source file. Equivalent to CMake's [add_executable](https://cmake.org/cmake/help/latest/command/add_executable.html)`(basic src/basic.cpp)`.
\ No newline at end of file
diff --git a/tests/cmake.toml b/tests/cmake.toml
index f5b57a7..b708184 100644
--- a/tests/cmake.toml
+++ b/tests/cmake.toml
@@ -1,17 +1,23 @@
[[test]]
name = "basic"
command = "$"
-working-directory = "${CMAKE_CURRENT_LIST_DIR}/basic"
+working-directory = "basic"
arguments = ["build"]
[[test]]
-name = "conditions"
+name = "interface"
command = "$"
-working-directory = "${CMAKE_CURRENT_LIST_DIR}/conditions"
+working-directory = "interface"
arguments = ["build"]
[[test]]
-name = "interface"
+name = "fetch-content"
+command = "$"
+working-directory = "fetch-content"
+arguments = ["build"]
+
+[[test]]
+name = "conditions"
command = "$"
-working-directory = "${CMAKE_CURRENT_LIST_DIR}/interface"
+working-directory = "conditions"
arguments = ["build"]
\ No newline at end of file
diff --git a/tests/fetch-content/cmake.toml b/tests/fetch-content/cmake.toml
new file mode 100644
index 0000000..ca5d912
--- /dev/null
+++ b/tests/fetch-content/cmake.toml
@@ -0,0 +1,15 @@
+# Downloads [fmt v7.1.3](https://fmt.dev/7.1.3/) from [GitHub](https://github.com) and links an `example` target to it:
+
+[project]
+name = "fetch-content"
+description = "Fetching from git"
+
+[fetch-content]
+fmt = { git = "https://github.com/fmtlib/fmt", tag = "7.1.3" }
+
+[target.example]
+type = "executable"
+sources = ["src/main.cpp"]
+link-libraries = ["fmt::fmt"]
+
+# This is equivalent to calling CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html).
\ No newline at end of file
diff --git a/tests/fetch-content/src/main.cpp b/tests/fetch-content/src/main.cpp
new file mode 100644
index 0000000..4a2fe7e
--- /dev/null
+++ b/tests/fetch-content/src/main.cpp
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ fmt::print("Hello, world!\n");
+}
\ No newline at end of file
diff --git a/tests/interface/cmake.toml b/tests/interface/cmake.toml
index 67de6cf..1f1c0c7 100644
--- a/tests/interface/cmake.toml
+++ b/tests/interface/cmake.toml
@@ -1,5 +1,6 @@
[project]
name = "interface"
+description = "Header-only library"
[target.mylib]
type = "interface"