mirror of
https://github.com/ChaseSunstrom/cforge.git
synced 2026-05-22 06:08:23 -05:00
Update dependency management system
This commit is contained in:
+13
-38
@@ -67,44 +67,14 @@ else()
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
# Git dependencies
|
||||
include(FetchContent)
|
||||
# Ensure dependencies directory exists
|
||||
set(DEPS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor")
|
||||
file(MAKE_DIRECTORY ${DEPS_DIR})
|
||||
# Index dependencies (from cforge-index registry)
|
||||
# fmt (index package)
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/vendor/fmt/include")
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/vendor/fmt" "${CMAKE_BINARY_DIR}/_deps/fmt")
|
||||
|
||||
# Configure Git to prefer HTTPS but allow other protocols
|
||||
set(FETCHCONTENT_GIT_PROTOCOL "https")
|
||||
|
||||
# fmt dependency
|
||||
message(STATUS "Setting up fmt dependency from https://github.com/fmtlib/fmt.git")
|
||||
FetchContent_Declare(fmt
|
||||
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
|
||||
GIT_TAG 11.1.4
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/fmt
|
||||
)
|
||||
# Include directories for fmt
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/vendor/fmt/include)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/vendor/fmt/.)
|
||||
|
||||
# For fmt, configure options
|
||||
set(FMT_TEST OFF CACHE BOOL "" FORCE)
|
||||
set(FMT_DOC OFF CACHE BOOL "" FORCE)
|
||||
set(FMT_SYSTEM_HEADERS ON CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(fmt)
|
||||
|
||||
# tomlplusplus dependency
|
||||
message(STATUS "Setting up tomlplusplus dependency from https://github.com/marzer/tomlplusplus.git")
|
||||
FetchContent_Declare(tomlplusplus
|
||||
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
|
||||
GIT_TAG v3.4.0
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/tomlplusplus
|
||||
)
|
||||
# Include directories for tomlplusplus
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/vendor/tomlplusplus/include)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/vendor/tomlplusplus/.)
|
||||
|
||||
FetchContent_MakeAvailable(tomlplusplus)
|
||||
# tomlplusplus (index package)
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/vendor/tomlplusplus/include")
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/vendor/tomlplusplus" "${CMAKE_BINARY_DIR}/_deps/tomlplusplus")
|
||||
|
||||
# Add source files
|
||||
file(GLOB_RECURSE SOURCES
|
||||
@@ -132,6 +102,12 @@ target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${SOURCE_DIR}/include"
|
||||
)
|
||||
|
||||
# Link index dependencies
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||
fmt::fmt
|
||||
tomlplusplus::tomlplusplus
|
||||
)
|
||||
|
||||
# Definitions for config 'Debug'
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC DEBUG=1)
|
||||
@@ -141,7 +117,6 @@ endif()
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||
fmt
|
||||
)
|
||||
|
||||
# Compiler options
|
||||
|
||||
@@ -608,8 +608,9 @@ Registry dependencies in `cforge.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
# Simple version constraint
|
||||
# Simple version constraint - uses CMake FetchContent by default
|
||||
fmt = "11.1.4"
|
||||
tomlplusplus = "3.4.0"
|
||||
|
||||
# With features and options
|
||||
spdlog = { version = "1.15.0", features = ["async", "stdout"] }
|
||||
@@ -622,6 +623,17 @@ catch2 = "3.*" # Any 3.x version
|
||||
benchmark = "1.9.*" # Any 1.9.x version
|
||||
```
|
||||
|
||||
By default, index dependencies use CMake's FetchContent to download packages during the CMake configure step. This is the recommended approach as it integrates seamlessly with CMake's dependency management.
|
||||
|
||||
To disable FetchContent and pre-clone packages instead:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
fetch_content = false # Pre-clone packages to vendor/ directory
|
||||
directory = "vendor" # Where to clone packages (default: "deps")
|
||||
fmt = "11.1.4"
|
||||
```
|
||||
|
||||
### Git Dependencies
|
||||
|
||||
For packages not in the registry, use Git directly:
|
||||
|
||||
@@ -271,9 +271,9 @@
|
||||
"114": {
|
||||
"js": [
|
||||
{
|
||||
"file": "assets/js/7f85490b.36007da9.js",
|
||||
"hash": "17256aebf1020d46",
|
||||
"publicPath": "/cforge/assets/js/7f85490b.36007da9.js"
|
||||
"file": "assets/js/7f85490b.936614de.js",
|
||||
"hash": "e8a2c5c216f732bc",
|
||||
"publicPath": "/cforge/assets/js/7f85490b.936614de.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -334,9 +334,9 @@
|
||||
"354": {
|
||||
"js": [
|
||||
{
|
||||
"file": "assets/js/runtime~main.2af991c4.js",
|
||||
"hash": "c8d966849807175d",
|
||||
"publicPath": "/cforge/assets/js/runtime~main.2af991c4.js"
|
||||
"file": "assets/js/runtime~main.76be665e.js",
|
||||
"hash": "84860eeea74b6e98",
|
||||
"publicPath": "/cforge/assets/js/runtime~main.76be665e.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
+117
-18
@@ -5,28 +5,59 @@ title: Working with Dependencies
|
||||
|
||||
## Working with Dependencies
|
||||
|
||||
CForge supports multiple dependency management systems to make it easy to include external libraries in your projects.
|
||||
CForge supports a unified dependency configuration with multiple sources. Dependencies are consolidated under the `[dependencies]` section with source options: `index` (default), `git`, `vcpkg`, `system`, and `project`.
|
||||
|
||||
### vcpkg Integration
|
||||
### Package Registry (Index Dependencies)
|
||||
|
||||
[vcpkg](https://vcpkg.io/) is a C/C++ package manager from Microsoft. CForge integrates seamlessly with vcpkg:
|
||||
CForge has a built-in package registry similar to Cargo. Search and add packages easily:
|
||||
|
||||
```toml
|
||||
[dependencies.vcpkg]
|
||||
enabled = true
|
||||
path = "~/.vcpkg" # Optional: directory of vcpkg installation
|
||||
triplet = "x64-windows" # Optional: specify vcpkg target triplet
|
||||
packages = ["fmt", "boost", "nlohmann-json"]
|
||||
```bash
|
||||
# Search for packages
|
||||
cforge search json
|
||||
|
||||
# Get package info
|
||||
cforge info spdlog --versions
|
||||
|
||||
# Add a package (defaults to registry)
|
||||
cforge add fmt@11.1.4
|
||||
|
||||
# Add with specific features
|
||||
cforge add spdlog@1.15.0 --features async,stdout
|
||||
```
|
||||
|
||||
CForge will automatically:
|
||||
- Install vcpkg if not found
|
||||
- Install the specified packages
|
||||
- Configure CMake to use vcpkg's toolchain file
|
||||
Registry dependencies in `cforge.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
# Simple version constraint - uses CMake FetchContent by default
|
||||
fmt = "11.1.4"
|
||||
tomlplusplus = "3.4.0"
|
||||
|
||||
# With features and options
|
||||
spdlog = { version = "1.15.0", features = ["async", "stdout"] }
|
||||
|
||||
# Header-only library
|
||||
nlohmann-json = { version = "3.11.3", header_only = true }
|
||||
|
||||
# Wildcard versions (like Rust)
|
||||
catch2 = "3.*" # Any 3.x version
|
||||
benchmark = "1.9.*" # Any 1.9.x version
|
||||
```
|
||||
|
||||
By default, index dependencies use CMake's FetchContent to download packages during the CMake configure step. This is the recommended approach as it integrates seamlessly with CMake's dependency management.
|
||||
|
||||
To disable FetchContent and pre-clone packages instead:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
fetch_content = false # Pre-clone packages to vendor/ directory
|
||||
directory = "vendor" # Where to clone packages (default: "deps")
|
||||
fmt = "11.1.4"
|
||||
```
|
||||
|
||||
### Git Dependencies
|
||||
|
||||
Clone dependencies directly from Git repositories:
|
||||
For packages not in the registry, use Git directly:
|
||||
|
||||
```toml
|
||||
[dependencies.git.fmt]
|
||||
@@ -43,6 +74,12 @@ branch = "master"
|
||||
shallow = true
|
||||
```
|
||||
|
||||
Or use the CLI:
|
||||
|
||||
```bash
|
||||
cforge add fmt --git https://github.com/fmtlib/fmt.git --tag 11.1.4
|
||||
```
|
||||
|
||||
#### Git Dependency Options
|
||||
|
||||
| Option | Description |
|
||||
@@ -56,6 +93,33 @@ shallow = true
|
||||
|
||||
Git dependencies are automatically cloned into the `deps` directory and included as CMake subdirectories.
|
||||
|
||||
### vcpkg Integration
|
||||
|
||||
[vcpkg](https://vcpkg.io/) is a C/C++ package manager from Microsoft. CForge integrates seamlessly with vcpkg:
|
||||
|
||||
```toml
|
||||
[dependencies.vcpkg]
|
||||
enabled = true
|
||||
path = "~/.vcpkg" # Optional: directory of vcpkg installation
|
||||
triplet = "x64-windows" # Optional: specify vcpkg target triplet
|
||||
|
||||
[dependencies]
|
||||
boost = { vcpkg = true }
|
||||
openssl = { vcpkg = true, features = ["ssl", "crypto"] }
|
||||
```
|
||||
|
||||
Or use the CLI:
|
||||
|
||||
```bash
|
||||
cforge add boost --vcpkg
|
||||
cforge vcpkg install openssl
|
||||
```
|
||||
|
||||
CForge will automatically:
|
||||
- Install vcpkg if not found
|
||||
- Install the specified packages
|
||||
- Configure CMake to use vcpkg's toolchain file
|
||||
|
||||
### System Dependencies
|
||||
|
||||
System dependencies support three methods: `find_package`, `pkg_config`, and `manual`:
|
||||
@@ -149,6 +213,21 @@ link_type = "PRIVATE"
|
||||
|
||||
See [Workspaces](workspaces) for more details.
|
||||
|
||||
### Platform-Specific Dependencies
|
||||
|
||||
Add dependencies only for specific platforms:
|
||||
|
||||
```toml
|
||||
[platform.windows.dependencies]
|
||||
winapi = { vcpkg = true }
|
||||
|
||||
[platform.linux.dependencies]
|
||||
x11 = { system = true, method = "pkg_config", package = "x11" }
|
||||
|
||||
[platform.macos.dependencies]
|
||||
cocoa = { system = true, frameworks = ["Cocoa", "IOKit"] }
|
||||
```
|
||||
|
||||
### Dependency Lock File
|
||||
|
||||
Ensure reproducible builds with lock files:
|
||||
@@ -166,6 +245,16 @@ cforge lock --force
|
||||
|
||||
The lock file (`cforge.lock`) records the exact versions of all dependencies, ensuring consistent builds across different machines and times.
|
||||
|
||||
### Updating Dependencies
|
||||
|
||||
```bash
|
||||
# Update all packages from registry
|
||||
cforge update --packages
|
||||
|
||||
# Update cforge itself
|
||||
cforge update --self
|
||||
```
|
||||
|
||||
### Dependency Tree
|
||||
|
||||
Visualize your project's dependencies:
|
||||
@@ -174,20 +263,30 @@ Visualize your project's dependencies:
|
||||
cforge tree
|
||||
```
|
||||
|
||||
Output:
|
||||
Output (with colors):
|
||||
```
|
||||
myproject v1.0.0
|
||||
|-- fmt @ 11.1.4 (git)
|
||||
|-- nlohmann_json @ v3.11.3 (git)
|
||||
|-- fmt @ 11.1.4 (index)
|
||||
|-- tomlplusplus @ 3.4.0 (index)
|
||||
|-- boost (vcpkg)
|
||||
`-- OpenGL (system)
|
||||
|
||||
Dependencies: 2 git, 1 vcpkg, 1 system
|
||||
Dependencies: 2 index, 1 vcpkg, 1 system
|
||||
```
|
||||
|
||||
Dependencies are color-coded by type:
|
||||
- **Blue**: Index dependencies (from registry)
|
||||
- **Cyan**: Git dependencies
|
||||
- **Magenta**: vcpkg dependencies
|
||||
- **Yellow**: System dependencies
|
||||
- **Green**: Project dependencies (workspace)
|
||||
|
||||
### Managing Dependencies
|
||||
|
||||
```bash
|
||||
# Add a registry dependency
|
||||
cforge add fmt@11.1.4
|
||||
|
||||
# Add a git dependency
|
||||
cforge add fmt --git https://github.com/fmtlib/fmt.git --tag 11.1.4
|
||||
|
||||
|
||||
+7
-7
@@ -3,16 +3,16 @@
|
||||
# Do not commit to version control.
|
||||
|
||||
[metadata]
|
||||
generated = "2025-12-08T21:34:44Z"
|
||||
generated = "2025-12-08T23:57:23Z"
|
||||
|
||||
[config]
|
||||
hash = "6c58b1c81cf5b809"
|
||||
|
||||
[dependency.tomlplusplus]
|
||||
hash = "ee0d779c66a1ea01"
|
||||
version = "v3.4.0"
|
||||
hash = "7937ea90e387c7be"
|
||||
|
||||
[dependency.fmt]
|
||||
hash = "2e1bd4a6644e748e"
|
||||
hash = "1597a53385d75ae0"
|
||||
version = "11.1.4"
|
||||
|
||||
[dependency.tomlplusplus]
|
||||
hash = "dd811f31298761f9"
|
||||
version = "3.4.0"
|
||||
|
||||
|
||||
+4
-6
@@ -7,17 +7,15 @@
|
||||
|
||||
[metadata]
|
||||
version = "1"
|
||||
generated = "2025-12-01T21:06:52Z"
|
||||
generated = "2025-12-08T23:57:23Z"
|
||||
|
||||
[dependency.fmt]
|
||||
source = "git"
|
||||
url = "https://github.com/fmtlib/fmt.git"
|
||||
source = "index"
|
||||
version = "11.1.4"
|
||||
resolved = "123913715afeb8a437e6388b4473fcc4753e1c9a"
|
||||
|
||||
[dependency.tomlplusplus]
|
||||
source = "git"
|
||||
url = "https://github.com/marzer/tomlplusplus.git"
|
||||
version = "v3.4.0"
|
||||
source = "index"
|
||||
version = "3.4.0"
|
||||
resolved = "30172438cee64926dc41fdd9c11fb3ba5b2ba9de"
|
||||
|
||||
|
||||
+3
-9
@@ -23,9 +23,6 @@ flags = ["DEBUG_INFO", "NO_OPT"]
|
||||
defines = ["NDEBUG=1", "FMT_HEADER_ONLY=ON", "FMT_UNICODE=0"]
|
||||
flags = ["OPTIMIZE"]
|
||||
|
||||
[test]
|
||||
enabled = false
|
||||
|
||||
[package]
|
||||
enabled = true
|
||||
generators = ["ZIP", "TGZ", "DEB"]
|
||||
@@ -34,9 +31,6 @@ contact = "Chase Sunstrom <casunstrom@gmail.com>"
|
||||
|
||||
[dependencies]
|
||||
directory = "vendor"
|
||||
|
||||
[dependencies.git]
|
||||
# TOML parsing library - using latest main branch
|
||||
tomlplusplus = { url = "https://github.com/marzer/tomlplusplus.git", tag = "v3.4.0", link = false }
|
||||
# Formatting library - using latest main branch
|
||||
fmt = { url = "https://github.com/fmtlib/fmt.git", tag = "11.1.4" }
|
||||
tomlplusplus = "3.4.0"
|
||||
fetch_content = false
|
||||
fmt = "11.1.4"
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Page Not Found | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/404.html"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docusaurus_tag" content="default"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docsearch:docusaurus_tag" content="default"><meta data-rh="true" property="og:title" content="Page Not Found | CForge"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/404.html"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/404.html" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/404.html" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Announcing CForge Beta-v1.4.0 | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docusaurus_tag" content="default"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docsearch:docusaurus_tag" content="default"><meta data-rh="true" property="og:title" content="Announcing CForge Beta-v1.4.0 | CForge"><meta data-rh="true" name="description" content="Today we're excited to announce the beta release of CForge, a TOML-based build system for C/C++ projects!"><meta data-rh="true" property="og:description" content="Today we're excited to announce the beta release of CForge, a TOML-based build system for C/C++ projects!"><meta data-rh="true" property="og:type" content="article"><meta data-rh="true" property="article:published_time" content="2025-03-25T00:00:00.000Z"><meta data-rh="true" property="article:author" content="https://github.com/ChaseSunstrom"><meta data-rh="true" property="article:tag" content="cforge,release,beta"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0" hreflang="x-default"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"BlogPosting","@id":"https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0","mainEntityOfPage":"https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0","url":"https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0","headline":"Announcing CForge Beta-v1.4.0","name":"Announcing CForge Beta-v1.4.0","description":"Today we're excited to announce the beta release of CForge, a TOML-based build system for C/C++ projects!","datePublished":"2025-03-25T00:00:00.000Z","author":{"@type":"Person","name":"Chase Sunstrom","description":"CForge Creator","url":"https://github.com/ChaseSunstrom","image":"https://github.com/ChaseSunstrom.png"},"keywords":[],"isPartOf":{"@type":"Blog","@id":"https://chasesunstrom.github.io/cforge/blog","name":"Blog"}}</script><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Archive | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/blog/archive"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docusaurus_tag" content="default"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docsearch:docusaurus_tag" content="default"><meta data-rh="true" property="og:title" content="Archive | CForge"><meta data-rh="true" name="description" content="Archive"><meta data-rh="true" property="og:description" content="Archive"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/blog/archive"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/archive" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/archive" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Blog | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/blog"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" property="og:title" content="Blog | CForge"><meta data-rh="true" name="description" content="Blog"><meta data-rh="true" property="og:description" content="Blog"><meta data-rh="true" name="docusaurus_tag" content="blog_posts_list"><meta data-rh="true" name="docsearch:docusaurus_tag" content="blog_posts_list"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/blog"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog" hreflang="x-default"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"Blog","@id":"https://chasesunstrom.github.io/cforge/blog","mainEntityOfPage":"https://chasesunstrom.github.io/cforge/blog","headline":"Blog","description":"Blog","blogPost":[{"@type":"BlogPosting","@id":"https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0","mainEntityOfPage":"https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0","url":"https://chasesunstrom.github.io/cforge/blog/announcing-cforge-beta-v1-4-0","headline":"Announcing CForge Beta-v1.4.0","name":"Announcing CForge Beta-v1.4.0","description":"Today we're excited to announce the beta release of CForge, a TOML-based build system for C/C++ projects!","datePublished":"2025-03-25T00:00:00.000Z","author":{"@type":"Person","name":"Chase Sunstrom","description":"CForge Creator","url":"https://github.com/ChaseSunstrom","image":"https://github.com/ChaseSunstrom.png"},"keywords":[]}]}</script><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">One post tagged with "beta" | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/blog/tags/beta"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" property="og:title" content="One post tagged with "beta" | CForge"><meta data-rh="true" name="docusaurus_tag" content="blog_tags_posts"><meta data-rh="true" name="docsearch:docusaurus_tag" content="blog_tags_posts"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/blog/tags/beta"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/tags/beta" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/tags/beta" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Tags | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/blog/tags"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" property="og:title" content="Tags | CForge"><meta data-rh="true" name="docusaurus_tag" content="blog_tags_list"><meta data-rh="true" name="docsearch:docusaurus_tag" content="blog_tags_list"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/blog/tags"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/tags" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/tags" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">One post tagged with "release" | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/blog/tags/release"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" property="og:title" content="One post tagged with "release" | CForge"><meta data-rh="true" name="docusaurus_tag" content="blog_tags_posts"><meta data-rh="true" name="docsearch:docusaurus_tag" content="blog_tags_posts"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/blog/tags/release"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/tags/release" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/blog/tags/release" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Advanced Topics | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/advanced-topics"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Advanced Topics | CForge"><meta data-rh="true" name="description" content="🧩 Advanced Topics"><meta data-rh="true" property="og:description" content="🧩 Advanced Topics"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/advanced-topics"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/advanced-topics" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/advanced-topics" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Build Variants | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/build-variants"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Build Variants | CForge"><meta data-rh="true" name="description" content="🚩 Build Variants"><meta data-rh="true" property="og:description" content="🚩 Build Variants"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/build-variants"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/build-variants" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/build-variants" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Command Reference | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/command-reference"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Command Reference | CForge"><meta data-rh="true" name="description" content="CForge provides a comprehensive set of commands for building, testing, and managing C/C++ projects."><meta data-rh="true" property="og:description" content="CForge provides a comprehensive set of commands for building, testing, and managing C/C++ projects."><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/command-reference"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/command-reference" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/command-reference" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Contributing | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/contributing"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Contributing | CForge"><meta data-rh="true" name="description" content="🤝 Contributing"><meta data-rh="true" property="og:description" content="🤝 Contributing"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/contributing"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/contributing" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/contributing" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Cross-Compilation | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/cross-compilation"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Cross-Compilation | CForge"><meta data-rh="true" name="description" content="Cross-Compilation"><meta data-rh="true" property="og:description" content="Cross-Compilation"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/cross-compilation"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/cross-compilation" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/cross-compilation" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Examples | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/examples"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Examples | CForge"><meta data-rh="true" name="description" content="📚 Examples"><meta data-rh="true" property="og:description" content="📚 Examples"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/examples"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/examples" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/examples" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">IDE Integration | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/ide-integration"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="IDE Integration | CForge"><meta data-rh="true" name="description" content="🖥️ IDE Integration"><meta data-rh="true" property="og:description" content="🖥️ IDE Integration"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/ide-integration"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/ide-integration" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/ide-integration" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Installation | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/installation"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Installation | CForge"><meta data-rh="true" name="description" content="Install CForge on your system."><meta data-rh="true" property="og:description" content="Install CForge on your system."><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/installation"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/installation" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/installation" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Introduction | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/intro"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Introduction | CForge"><meta data-rh="true" name="description" content="Version"><meta data-rh="true" property="og:description" content="Version"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/intro"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/intro" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/intro" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">License | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/license"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="License | CForge"><meta data-rh="true" name="description" content="📄 License"><meta data-rh="true" property="og:description" content="📄 License"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/license"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/license" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/license" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Project Configuration | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/project-configuration"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Project Configuration | CForge"><meta data-rh="true" name="description" content="Project Configuration"><meta data-rh="true" property="og:description" content="Project Configuration"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/project-configuration"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/project-configuration" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/project-configuration" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Quick Start | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/quick-start"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Quick Start | CForge"><meta data-rh="true" name="description" content="Get up and running with CForge in minutes."><meta data-rh="true" property="og:description" content="Get up and running with CForge in minutes."><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/quick-start"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/quick-start" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/quick-start" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Scripts & Hooks | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/scripts-hooks"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Scripts & Hooks | CForge"><meta data-rh="true" name="description" content="📝 Scripts & Hooks"><meta data-rh="true" property="og:description" content="📝 Scripts & Hooks"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/scripts-hooks"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/scripts-hooks" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/scripts-hooks" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Testing | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/testing"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Testing | CForge"><meta data-rh="true" name="description" content="🧪 Testing"><meta data-rh="true" property="og:description" content="🧪 Testing"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/testing"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/testing" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/testing" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Troubleshooting | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/troubleshooting"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Troubleshooting | CForge"><meta data-rh="true" name="description" content="Common issues and their solutions."><meta data-rh="true" property="og:description" content="Common issues and their solutions."><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/troubleshooting"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/troubleshooting" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/troubleshooting" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">Workspaces | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/docs/workspaces"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Workspaces | CForge"><meta data-rh="true" name="description" content="Workspaces"><meta data-rh="true" property="og:description" content="Workspaces"><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/docs/workspaces"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/workspaces" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/docs/workspaces" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<meta name="generator" content="Docusaurus v3.7.0">
|
||||
<title data-rh="true">CForge - Modern C/C++ Build System | CForge</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" name="twitter:image" content="https://chasesunstrom.github.io/cforge/img/cforge.png"><meta data-rh="true" property="og:url" content="https://chasesunstrom.github.io/cforge/"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docusaurus_tag" content="default"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docsearch:docusaurus_tag" content="default"><meta data-rh="true" property="og:title" content="CForge - Modern C/C++ Build System | CForge"><meta data-rh="true" name="description" content="A modern TOML-based build system for C/C++ with CMake & vcpkg integration. Cargo-style output, dependency management, and developer tools."><meta data-rh="true" property="og:description" content="A modern TOML-based build system for C/C++ with CMake & vcpkg integration. Cargo-style output, dependency management, and developer tools."><link data-rh="true" rel="icon" href="/cforge/img/logo.svg"><link data-rh="true" rel="canonical" href="https://chasesunstrom.github.io/cforge/"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/" hreflang="en"><link data-rh="true" rel="alternate" href="https://chasesunstrom.github.io/cforge/" hreflang="x-default"><script data-rh="true">function insertBanner(){var n=document.createElement("div");n.id="__docusaurus-base-url-issue-banner-container";n.innerHTML='\n<div id="__docusaurus-base-url-issue-banner" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">/cforge/</span> </p>\n <p>We suggest trying baseUrl = <span id="__docusaurus-base-url-issue-banner-suggestion-container" style="font-weight: bold; color: green;"></span></p>\n</div>\n',document.body.prepend(n);var e=document.getElementById("__docusaurus-base-url-issue-banner-suggestion-container"),s=window.location.pathname,o="/"===s.substr(-1)?s:s+"/";e.innerHTML=o}document.addEventListener("DOMContentLoaded",(function(){void 0===window.docusaurus&&insertBanner()}))</script><link rel="alternate" type="application/rss+xml" href="/cforge/blog/rss.xml" title="CForge RSS Feed">
|
||||
<link rel="alternate" type="application/atom+xml" href="/cforge/blog/atom.xml" title="CForge Atom Feed"><link rel="stylesheet" href="/cforge/assets/css/styles.5a56e4b0.css">
|
||||
<script src="/cforge/assets/js/runtime~main.2af991c4.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/runtime~main.76be665e.js" defer="defer"></script>
|
||||
<script src="/cforge/assets/js/main.50450276.js" defer="defer"></script>
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
|
||||
@@ -253,6 +253,32 @@ public:
|
||||
dependencies_[name] = dep;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lock an index dependency (from cforge-index registry)
|
||||
*
|
||||
* @param name Package name
|
||||
* @param version Package version
|
||||
* @param repo_dir Local repository directory
|
||||
*/
|
||||
void lock_index_dependency(const std::string &name,
|
||||
const std::string &version,
|
||||
const std::filesystem::path &repo_dir) {
|
||||
locked_dependency dep;
|
||||
dep.name = name;
|
||||
dep.source_type = "index";
|
||||
dep.version = version;
|
||||
|
||||
// Get the actual commit hash
|
||||
std::string commit = git_get_head_commit(repo_dir, false);
|
||||
if (!commit.empty()) {
|
||||
dep.resolved = commit;
|
||||
} else {
|
||||
dep.resolved = version; // Fallback to requested version
|
||||
}
|
||||
|
||||
dependencies_[name] = dep;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a dependency from the lock file
|
||||
*
|
||||
@@ -384,6 +410,55 @@ inline bool update_lockfile(const std::filesystem::path &project_dir,
|
||||
}
|
||||
}
|
||||
|
||||
// Lock index dependencies (simple name = "version" format)
|
||||
// Skip if using FetchContent mode (CMake handles downloading, packages not in deps_dir)
|
||||
bool use_fetch_content = config.get_bool("dependencies.fetch_content", true);
|
||||
if (!use_fetch_content && config.has_key("dependencies")) {
|
||||
auto all_deps = config.get_table_keys("dependencies");
|
||||
|
||||
for (const auto &dep : all_deps) {
|
||||
// Skip known special sections
|
||||
if (dep == "directory" || dep == "git" || dep == "vcpkg" ||
|
||||
dep == "subdirectory" || dep == "system" || dep == "project" ||
|
||||
dep == "fetch_content") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this is a simple version string (index dependency)
|
||||
std::string dep_key = "dependencies." + dep;
|
||||
|
||||
// Skip if it's a table with source-specific keys
|
||||
if (config.has_key(dep_key + ".url") ||
|
||||
config.has_key(dep_key + ".vcpkg_name") ||
|
||||
config.has_key(dep_key + ".path") ||
|
||||
config.has_key(dep_key + ".system")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the version
|
||||
std::string version = config.get_string(dep_key, "");
|
||||
if (version.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::filesystem::path repo_dir = deps_dir / dep;
|
||||
|
||||
if (std::filesystem::exists(repo_dir)) {
|
||||
lock.lock_index_dependency(dep, version, repo_dir);
|
||||
|
||||
if (verbose) {
|
||||
auto locked = lock.get_dependency(dep);
|
||||
if (locked) {
|
||||
logger::print_verbose("Locked " + dep + " at " + locked->resolved);
|
||||
}
|
||||
}
|
||||
} else if (verbose) {
|
||||
logger::print_warning("Index dependency " + dep +
|
||||
" not found, skipping lock");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save lock file
|
||||
if (!lock.save(project_dir)) {
|
||||
return false;
|
||||
|
||||
@@ -49,6 +49,16 @@ struct package_version {
|
||||
std::string yanked_reason;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Git tag discovery configuration
|
||||
*/
|
||||
struct tag_config {
|
||||
std::string pattern = "{version}"; // Pattern like "v{version}", "{version}", "release-{version}"
|
||||
std::string version_regex; // Regex to extract version from tag (auto-generated from pattern)
|
||||
std::vector<std::string> exclude; // Tags to exclude (e.g., "nightly", "beta")
|
||||
int max_versions = 50; // Maximum versions to cache
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Package integration info
|
||||
*/
|
||||
@@ -81,6 +91,10 @@ struct package_info {
|
||||
std::vector<std::string> default_features;
|
||||
std::vector<package_version> versions;
|
||||
|
||||
// Git tag discovery
|
||||
tag_config tags;
|
||||
bool auto_discover_versions = true; // If true, fetch versions from Git tags
|
||||
|
||||
std::vector<std::string> maintainer_owners;
|
||||
std::vector<std::string> maintainer_authors;
|
||||
};
|
||||
@@ -236,6 +250,9 @@ private:
|
||||
std::filesystem::path cache_dir_;
|
||||
std::filesystem::path index_dir_;
|
||||
|
||||
// Cache for Git tags (repo_url -> versions)
|
||||
mutable std::map<std::string, std::vector<package_version>> version_cache_;
|
||||
|
||||
/**
|
||||
* @brief Load a package definition from the index
|
||||
* @param name Package name
|
||||
@@ -244,6 +261,46 @@ private:
|
||||
std::optional<package_info>
|
||||
load_package_file(const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Fetch Git tags from a remote repository
|
||||
* @param repo_url Repository URL
|
||||
* @param config Tag configuration (pattern, excludes)
|
||||
* @return Vector of discovered versions
|
||||
*/
|
||||
std::vector<package_version>
|
||||
fetch_git_tags(const std::string &repo_url, const tag_config &config) const;
|
||||
|
||||
/**
|
||||
* @brief Convert a tag pattern to a regex for version extraction
|
||||
* @param pattern Pattern like "v{version}" or "{version}"
|
||||
* @return Regex string to extract version from tag
|
||||
*/
|
||||
static std::string pattern_to_regex(const std::string &pattern);
|
||||
|
||||
/**
|
||||
* @brief Convert version to tag using pattern
|
||||
* @param version Version string (e.g., "1.2.3")
|
||||
* @param pattern Tag pattern (e.g., "v{version}")
|
||||
* @return Tag string (e.g., "v1.2.3")
|
||||
*/
|
||||
static std::string version_to_tag(const std::string &version,
|
||||
const std::string &pattern);
|
||||
|
||||
/**
|
||||
* @brief Load cached versions for a package
|
||||
* @param name Package name
|
||||
* @return Vector of cached versions, empty if not cached
|
||||
*/
|
||||
std::vector<package_version> load_version_cache(const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Save versions to cache
|
||||
* @param name Package name
|
||||
* @param versions Versions to cache
|
||||
*/
|
||||
void save_version_cache(const std::string &name,
|
||||
const std::vector<package_version> &versions) const;
|
||||
|
||||
/**
|
||||
* @brief Check if a version matches a version specification
|
||||
* @param version Actual version (e.g., "1.2.3")
|
||||
|
||||
+265
-1
@@ -11,7 +11,9 @@
|
||||
#include "core/error_format.hpp"
|
||||
#include "core/file_system.h"
|
||||
#include "core/git_utils.hpp"
|
||||
#include "core/lockfile.hpp"
|
||||
#include "core/process_utils.hpp"
|
||||
#include "core/registry.hpp"
|
||||
#include "core/script_runner.hpp"
|
||||
#include "core/toml_reader.hpp"
|
||||
#include "core/workspace.hpp"
|
||||
@@ -361,6 +363,225 @@ bool clone_git_dependencies(const std::filesystem::path &project_dir,
|
||||
return all_success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resolve and clone index (registry) dependencies for a project
|
||||
*
|
||||
* This function reads the [dependencies] section, identifies packages that
|
||||
* should come from the cforge-index registry, resolves them to git URLs/tags,
|
||||
* and clones them.
|
||||
*
|
||||
* @param project_dir Project directory
|
||||
* @param project_config Project configuration from cforge.toml
|
||||
* @param verbose Verbose output flag
|
||||
* @param skip_deps Skip dependencies flag
|
||||
* @return bool Success flag
|
||||
*/
|
||||
bool resolve_index_dependencies(const std::filesystem::path &project_dir,
|
||||
const toml_reader &project_config,
|
||||
bool verbose, bool skip_deps) {
|
||||
if (skip_deps) {
|
||||
logger::print_verbose("Skipping index dependency resolution (--skip-deps flag)");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we have a [dependencies] section
|
||||
if (!project_config.has_key("dependencies")) {
|
||||
logger::print_verbose("No dependencies section found");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get dependencies directory from configuration
|
||||
std::string deps_dir =
|
||||
project_config.get_string("dependencies.directory", "deps");
|
||||
std::filesystem::path deps_path = project_dir / deps_dir;
|
||||
|
||||
// Create dependencies directory if it doesn't exist
|
||||
if (!std::filesystem::exists(deps_path)) {
|
||||
std::filesystem::create_directories(deps_path);
|
||||
}
|
||||
|
||||
// Get all dependency keys - look for entries that are index dependencies
|
||||
// An index dependency is specified as: name = "version" or name = { version = "..." }
|
||||
// without git/vcpkg/system/project flags
|
||||
auto dep_keys = project_config.get_table_keys("dependencies");
|
||||
logger::print_verbose("resolve_index_dependencies: Found " + std::to_string(dep_keys.size()) + " keys in [dependencies]");
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> index_deps; // name -> version
|
||||
|
||||
for (const auto &dep : dep_keys) {
|
||||
logger::print_verbose(" Checking key: " + dep);
|
||||
|
||||
// Skip known non-package keys
|
||||
if (dep == "directory" || dep == "git" || dep == "vcpkg" ||
|
||||
dep == "system" || dep == "project" || dep == "subdirectory" ||
|
||||
dep == "fetch_content") {
|
||||
logger::print_verbose(" Skipping (special key)");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string dep_key = "dependencies." + dep;
|
||||
|
||||
// Check if this is a simple string version or a table
|
||||
std::string version = project_config.get_string(dep_key, "");
|
||||
if (!version.empty()) {
|
||||
// Simple format: dep = "version"
|
||||
logger::print_verbose(" Found index dep: " + dep + " = " + version);
|
||||
index_deps.push_back({dep, version});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if it's a table with version key
|
||||
std::string version_key = dep_key + ".version";
|
||||
version = project_config.get_string(version_key, "");
|
||||
|
||||
// Skip if it has explicit source indicators
|
||||
bool has_git = !project_config.get_string(dep_key + ".git", "").empty();
|
||||
bool has_vcpkg = project_config.get_bool(dep_key + ".vcpkg", false);
|
||||
bool has_system = project_config.get_bool(dep_key + ".system", false);
|
||||
bool has_project = project_config.get_bool(dep_key + ".project", false);
|
||||
|
||||
if (!has_git && !has_vcpkg && !has_system && !has_project && !version.empty()) {
|
||||
// This is an index dependency
|
||||
logger::print_verbose(" Found index dep (table): " + dep + " = " + version);
|
||||
index_deps.push_back({dep, version});
|
||||
} else {
|
||||
logger::print_verbose(" Skipping (no version or has source indicator)");
|
||||
}
|
||||
}
|
||||
|
||||
if (index_deps.empty()) {
|
||||
logger::print_verbose("No index dependencies found to resolve");
|
||||
return true;
|
||||
}
|
||||
|
||||
logger::print_verbose("Total index deps to resolve: " + std::to_string(index_deps.size()));
|
||||
|
||||
logger::print_action("Resolving", std::to_string(index_deps.size()) + " package(s) from registry");
|
||||
|
||||
// Initialize registry
|
||||
registry reg;
|
||||
|
||||
// Check if registry needs update
|
||||
if (reg.needs_update()) {
|
||||
logger::print_action("Updating", "package index");
|
||||
if (!reg.update()) {
|
||||
logger::print_warning("Failed to update package index, using cached version");
|
||||
}
|
||||
}
|
||||
|
||||
// Check if git is available
|
||||
if (!is_command_available("git", 20)) {
|
||||
logger::print_error("Git is not available. Please install Git.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load dependency hashes
|
||||
dependency_hash dep_hashes;
|
||||
dep_hashes.load(project_dir);
|
||||
|
||||
bool all_success = true;
|
||||
bool deps_changed = false; // Track if any deps were cloned/updated
|
||||
|
||||
for (const auto &[name, version_spec] : index_deps) {
|
||||
// Get package info from registry
|
||||
auto pkg_opt = reg.get_package(name);
|
||||
if (!pkg_opt) {
|
||||
logger::print_error("Package '" + name + "' not found in registry");
|
||||
all_success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &pkg = *pkg_opt;
|
||||
|
||||
// Resolve version
|
||||
std::string resolved_version = reg.resolve_version(name, version_spec);
|
||||
if (resolved_version.empty()) {
|
||||
logger::print_error("Could not resolve version '" + version_spec + "' for package '" + name + "'");
|
||||
all_success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the version entry to get the tag
|
||||
std::string git_tag;
|
||||
for (const auto &ver : pkg.versions) {
|
||||
if (ver.version == resolved_version) {
|
||||
git_tag = ver.tag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (git_tag.empty()) {
|
||||
logger::print_error("Could not find git tag for version " + resolved_version + " of " + name);
|
||||
all_success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::filesystem::path dep_path = deps_path / name;
|
||||
|
||||
// Check if already exists and up to date
|
||||
std::string stored_version = dep_hashes.get_version(name);
|
||||
bool version_changed = resolved_version != stored_version;
|
||||
|
||||
if (std::filesystem::exists(dep_path)) {
|
||||
if (version_changed) {
|
||||
logger::print_action("Updating", name + " from " + stored_version + " to " + resolved_version);
|
||||
try {
|
||||
std::filesystem::remove_all(dep_path);
|
||||
deps_changed = true; // Version update requires regeneration
|
||||
} catch (const std::exception &e) {
|
||||
logger::print_error("Failed to remove old version of '" + name + "': " + e.what());
|
||||
all_success = false;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
logger::print_verbose("Package '" + name + "' already at version " + resolved_version);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Clone the package
|
||||
logger::fetching(name + "@" + resolved_version);
|
||||
|
||||
std::vector<std::string> clone_args = {"clone", "--depth=1", pkg.repository,
|
||||
dep_path.string(), "--branch", git_tag};
|
||||
if (!verbose) {
|
||||
clone_args.push_back("--quiet");
|
||||
}
|
||||
|
||||
bool clone_result = execute_tool("git", clone_args, "",
|
||||
"Git Clone for " + name, verbose, 600);
|
||||
|
||||
if (!clone_result) {
|
||||
logger::print_error("Failed to clone package '" + name + "' from " + pkg.repository);
|
||||
all_success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store hash and version
|
||||
std::string current_hash = dependency_hash::calculate_directory_hash(dep_path);
|
||||
dep_hashes.set_hash(name, current_hash);
|
||||
dep_hashes.set_version(name, resolved_version);
|
||||
deps_changed = true; // Mark that deps changed
|
||||
|
||||
logger::print_action("Downloaded", name + "@" + resolved_version);
|
||||
}
|
||||
|
||||
// If any deps were cloned/updated, clear the cforge.toml hash to force CMakeLists.txt regeneration
|
||||
if (deps_changed) {
|
||||
logger::print_verbose("Dependencies changed - will force CMakeLists.txt regeneration");
|
||||
dep_hashes.set_hash("cforge.toml", ""); // Clear the hash to force regeneration
|
||||
}
|
||||
|
||||
// Save updated dependency hashes
|
||||
dep_hashes.save(project_dir);
|
||||
|
||||
if (all_success) {
|
||||
logger::print_action("Finished", "all packages resolved");
|
||||
}
|
||||
|
||||
return all_success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Run CMake configure step
|
||||
*
|
||||
@@ -562,6 +783,23 @@ static bool build_project(const std::filesystem::path &project_dir,
|
||||
// Handle project-level dependencies and CMakeLists generation (skip in
|
||||
// workspace build)
|
||||
if (!use_workspace_build && has_project_config) {
|
||||
// Resolve index/registry dependencies first (they get cloned to deps/)
|
||||
// Skip if using FetchContent mode (CMake will handle downloading)
|
||||
bool use_fetch_content = project_config.get_bool("dependencies.fetch_content", true);
|
||||
if (!use_fetch_content) {
|
||||
try {
|
||||
std::filesystem::current_path(project_dir);
|
||||
if (!resolve_index_dependencies(project_dir, project_config, verbose, skip_deps)) {
|
||||
logger::print_warning("Some index dependencies could not be resolved");
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
logger::print_warning("Exception while resolving index dependencies: " +
|
||||
std::string(ex.what()));
|
||||
}
|
||||
} else {
|
||||
logger::print_verbose("Using FetchContent mode - CMake will download index dependencies");
|
||||
}
|
||||
|
||||
// Clone Git dependencies before generating CMakeLists.txt
|
||||
if (project_config.has_key("dependencies.git")) {
|
||||
logger::print_action("Setting up", "Git dependencies");
|
||||
@@ -584,6 +822,16 @@ static bool build_project(const std::filesystem::path &project_dir,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate/update lock file after dependencies are resolved
|
||||
{
|
||||
std::string deps_dir_str =
|
||||
project_config.get_string("dependencies.directory", "deps");
|
||||
std::filesystem::path deps_path = project_dir / deps_dir_str;
|
||||
if (std::filesystem::exists(deps_path)) {
|
||||
update_lockfile(project_dir, deps_path, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate CMakeLists.txt in the build directory
|
||||
std::filesystem::path timestamp_file =
|
||||
build_dir / ".cforge_cmakefile_timestamp";
|
||||
@@ -1320,12 +1568,28 @@ cforge_int_t cforge_cmd_build(const cforge_context_t *ctx) {
|
||||
logger::building("entire workspace");
|
||||
}
|
||||
|
||||
// Handle Git dependencies for workspace projects if not skipped
|
||||
// Handle dependencies for workspace projects if not skipped
|
||||
if (!skip_deps) {
|
||||
for (const auto &proj : ws.get_projects()) {
|
||||
auto proj_toml = proj.path / CFORGE_FILE;
|
||||
if (std::filesystem::exists(proj_toml)) {
|
||||
toml_reader pcfg(toml::parse_file(proj_toml.string()));
|
||||
|
||||
// Resolve index/registry dependencies first (skip if using FetchContent)
|
||||
bool proj_use_fetch_content = pcfg.get_bool("dependencies.fetch_content", true);
|
||||
if (!proj_use_fetch_content) {
|
||||
try {
|
||||
std::filesystem::current_path(proj.path);
|
||||
if (!resolve_index_dependencies(proj.path, pcfg, verbose, skip_deps)) {
|
||||
logger::print_warning("Some index dependencies could not be resolved for project: " + proj.name);
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
logger::print_warning("Exception while resolving index dependencies for project " +
|
||||
proj.name + ": " + std::string(ex.what()));
|
||||
}
|
||||
}
|
||||
|
||||
// Then handle Git dependencies
|
||||
if (pcfg.has_key("dependencies.git")) {
|
||||
logger::print_action("Setting up",
|
||||
"Git dependencies for project: " + proj.name);
|
||||
|
||||
@@ -43,9 +43,11 @@ cforge_int_t cforge_cmd_help(const cforge_context_t *ctx) {
|
||||
logger::print_plain(" deps Manage Git dependencies");
|
||||
logger::print_plain(" vcpkg Manage vcpkg dependencies");
|
||||
logger::print_plain(" install Install a cforge project to the system");
|
||||
logger::print_plain(" search Search for packages in the registry");
|
||||
logger::print_plain(" info Show detailed package information");
|
||||
logger::print_plain(" add Add a dependency to the project");
|
||||
logger::print_plain(" remove Remove a dependency from the project");
|
||||
logger::print_plain(" update Update cforge");
|
||||
logger::print_plain(" update Update cforge or packages");
|
||||
logger::print_plain(" ide Generate IDE project files");
|
||||
logger::print_plain(" list List dependencies or projects");
|
||||
logger::print_plain(
|
||||
@@ -285,14 +287,30 @@ cforge_int_t cforge_cmd_help(const cforge_context_t *ctx) {
|
||||
} else if (specific_command == "add") {
|
||||
logger::print_plain("cforge add - Add a dependency");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Usage: cforge add <package> [options]");
|
||||
logger::print_plain("Usage: cforge add <package>[@version] [options]");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Arguments:");
|
||||
logger::print_plain(
|
||||
" package Package to add (format: name[:version])");
|
||||
logger::print_plain(" package Package name (e.g., fmt, spdlog)");
|
||||
logger::print_plain(" @version Optional version (e.g., @11.1.4, @1.*)");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Options:");
|
||||
logger::print_plain("Source Options (default: registry):");
|
||||
logger::print_plain(" --git <url> Add as Git dependency");
|
||||
logger::print_plain(" --tag <tag> Git tag (with --git)");
|
||||
logger::print_plain(" --branch <name> Git branch (with --git)");
|
||||
logger::print_plain(" --vcpkg Add as vcpkg package");
|
||||
logger::print_plain(" --index Add from registry (default)");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Other Options:");
|
||||
logger::print_plain(" --features <f> Comma-separated features to enable");
|
||||
logger::print_plain(" --header-only Mark as header-only library");
|
||||
logger::print_plain(" -v, --verbose Show verbose output");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Examples:");
|
||||
logger::print_plain(" cforge add fmt Add fmt from registry");
|
||||
logger::print_plain(" cforge add fmt@11.1.4 Add specific version");
|
||||
logger::print_plain(" cforge add spdlog --features async");
|
||||
logger::print_plain(" cforge add boost --vcpkg Add from vcpkg");
|
||||
logger::print_plain(" cforge add mylib --git https://github.com/user/mylib --tag v1.0");
|
||||
} else if (specific_command == "remove") {
|
||||
logger::print_plain("cforge remove - Remove a dependency");
|
||||
logger::print_plain("");
|
||||
@@ -303,13 +321,54 @@ cforge_int_t cforge_cmd_help(const cforge_context_t *ctx) {
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Options:");
|
||||
logger::print_plain(" -v, --verbose Show verbose output");
|
||||
} else if (specific_command == "update") {
|
||||
logger::print_plain("cforge update - Update cforge");
|
||||
} else if (specific_command == "search") {
|
||||
logger::print_plain("cforge search - Search for packages in the registry");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Usage: cforge update [options]");
|
||||
logger::print_plain("Usage: cforge search <query> [options]");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Arguments:");
|
||||
logger::print_plain(" query Search term to find packages");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Options:");
|
||||
logger::print_plain(" --limit <n> Maximum results to show (default: 20)");
|
||||
logger::print_plain(" --update Force update the package index first");
|
||||
logger::print_plain(" -v, --verbose Show verbose output");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Examples:");
|
||||
logger::print_plain(" cforge search json Find JSON-related packages");
|
||||
logger::print_plain(" cforge search logging Find logging libraries");
|
||||
logger::print_plain(" cforge search --limit 5 ui Show top 5 UI packages");
|
||||
} else if (specific_command == "info") {
|
||||
logger::print_plain("cforge info - Show detailed package information");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Usage: cforge info <package> [options]");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Arguments:");
|
||||
logger::print_plain(" package Name of package to get info for");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Options:");
|
||||
logger::print_plain(" --versions Show all available versions");
|
||||
logger::print_plain(" --update Force update the package index first");
|
||||
logger::print_plain(" -v, --verbose Show verbose output");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Examples:");
|
||||
logger::print_plain(" cforge info fmt Show fmt package details");
|
||||
logger::print_plain(" cforge info spdlog --versions Show all spdlog versions");
|
||||
} else if (specific_command == "update") {
|
||||
logger::print_plain("cforge update - Update cforge or packages");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Usage: cforge update <--self|--packages> [options]");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Options:");
|
||||
logger::print_plain(" -s, --self Update cforge itself to latest version");
|
||||
logger::print_plain(" -p, --packages Update the package registry index");
|
||||
logger::print_plain(" -v, --verbose Show verbose output");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Examples:");
|
||||
logger::print_plain(" cforge update --self Update cforge to latest");
|
||||
logger::print_plain(" cforge update --packages Refresh package registry");
|
||||
logger::print_plain("");
|
||||
logger::print_plain("Note: You must specify either --self or --packages");
|
||||
} else if (specific_command == "vcpkg") {
|
||||
logger::print_plain("cforge vcpkg - Run vcpkg commands");
|
||||
logger::print_plain("");
|
||||
|
||||
+36
-11
@@ -1182,13 +1182,19 @@ std::vector<diagnostic> parse_linker_errors(const std::string &error_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// LLD linker errors
|
||||
|
||||
|
||||
if (std::regex_search(line, matches, lld_error_regex)) {
|
||||
std::string message = matches[1].str();
|
||||
|
||||
// Skip if message is empty or only whitespace
|
||||
if (message.empty() || message.find_first_not_of(" \t\r\n") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
diagnostic diag;
|
||||
diag.level = diagnostic_level::ERROR;
|
||||
std::string message = matches[1].str();
|
||||
diag.message = message;
|
||||
diag.file_path = "";
|
||||
diag.line_number = 0;
|
||||
@@ -1269,14 +1275,21 @@ std::vector<diagnostic> parse_linker_errors(const std::string &error_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Clang linker wrapper errors
|
||||
|
||||
|
||||
if (std::regex_search(line, matches, clang_linker_error_regex)) {
|
||||
std::string message = matches[1].str();
|
||||
|
||||
// Skip if message is empty or only whitespace
|
||||
if (message.empty() || message.find_first_not_of(" \t\r\n") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
diagnostic diag;
|
||||
diag.level = diagnostic_level::ERROR;
|
||||
diag.code = "LNK-CLANG";
|
||||
diag.message = matches[1].str();
|
||||
diag.message = message;
|
||||
diag.file_path = "";
|
||||
diag.line_number = 0;
|
||||
diag.column_number = 0;
|
||||
@@ -1288,17 +1301,24 @@ std::vector<diagnostic> parse_linker_errors(const std::string &error_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// collect2 errors (GCC linker wrapper)
|
||||
|
||||
|
||||
if (std::regex_search(line, matches, collect2_error_regex)) {
|
||||
std::string message = matches[1].str();
|
||||
|
||||
// Skip if message is empty or only whitespace
|
||||
if (message.empty() || message.find_first_not_of(" \t\r\n") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// collect2 is a summary error; we prefer the more specific errors above
|
||||
// Only add if we haven't captured any linker errors yet
|
||||
if (diagnostics.empty()) {
|
||||
diagnostic diag;
|
||||
diag.level = diagnostic_level::ERROR;
|
||||
diag.code = "LNK-LD";
|
||||
diag.message = matches[1].str();
|
||||
diag.message = message;
|
||||
diag.file_path = "";
|
||||
diag.line_number = 0;
|
||||
diag.column_number = 0;
|
||||
@@ -1311,12 +1331,17 @@ std::vector<diagnostic> parse_linker_errors(const std::string &error_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ld linker errors
|
||||
|
||||
|
||||
if (std::regex_search(line, matches, ld_error_regex)) {
|
||||
std::string message = matches[1].str();
|
||||
|
||||
// Skip if message is empty or only whitespace
|
||||
if (message.empty() || message.find_first_not_of(" \t\r\n") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if it's just a warning or note
|
||||
if (message.find("warning") != std::string::npos &&
|
||||
message.find("error") == std::string::npos) {
|
||||
|
||||
+241
-8
@@ -236,6 +236,200 @@ std::optional<package_info> registry::get_package(const std::string &name) const
|
||||
return load_package_file(name);
|
||||
}
|
||||
|
||||
std::string registry::pattern_to_regex(const std::string &pattern) {
|
||||
// Convert pattern like "v{version}" to regex like "^v([0-9]+\\.[0-9]+\\.?[0-9]*)$"
|
||||
std::string regex_str = "^";
|
||||
size_t pos = 0;
|
||||
size_t version_pos = pattern.find("{version}");
|
||||
|
||||
if (version_pos == std::string::npos) {
|
||||
// No {version} placeholder, treat whole pattern as version
|
||||
return "^([0-9]+(?:\\.[0-9]+)*)$";
|
||||
}
|
||||
|
||||
// Escape everything before {version}
|
||||
for (size_t i = 0; i < version_pos; ++i) {
|
||||
char c = pattern[i];
|
||||
if (c == '.' || c == '*' || c == '+' || c == '?' || c == '^' ||
|
||||
c == '$' || c == '[' || c == ']' || c == '(' || c == ')' ||
|
||||
c == '{' || c == '}' || c == '|' || c == '\\') {
|
||||
regex_str += '\\';
|
||||
}
|
||||
regex_str += c;
|
||||
}
|
||||
|
||||
// Add version capture group - matches semver-like versions
|
||||
regex_str += "([0-9]+(?:\\.[0-9]+)*)";
|
||||
|
||||
// Escape everything after {version}
|
||||
for (size_t i = version_pos + 9; i < pattern.size(); ++i) {
|
||||
char c = pattern[i];
|
||||
if (c == '.' || c == '*' || c == '+' || c == '?' || c == '^' ||
|
||||
c == '$' || c == '[' || c == ']' || c == '(' || c == ')' ||
|
||||
c == '{' || c == '}' || c == '|' || c == '\\') {
|
||||
regex_str += '\\';
|
||||
}
|
||||
regex_str += c;
|
||||
}
|
||||
|
||||
regex_str += "$";
|
||||
return regex_str;
|
||||
}
|
||||
|
||||
std::string registry::version_to_tag(const std::string &version,
|
||||
const std::string &pattern) {
|
||||
std::string tag = pattern;
|
||||
size_t pos = tag.find("{version}");
|
||||
if (pos != std::string::npos) {
|
||||
tag.replace(pos, 9, version);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
std::vector<package_version>
|
||||
registry::fetch_git_tags(const std::string &repo_url,
|
||||
const tag_config &config) const {
|
||||
std::vector<package_version> versions;
|
||||
|
||||
// Check in-memory cache first
|
||||
auto cache_it = version_cache_.find(repo_url);
|
||||
if (cache_it != version_cache_.end()) {
|
||||
return cache_it->second;
|
||||
}
|
||||
|
||||
logger::print_verbose("Fetching tags from " + repo_url);
|
||||
|
||||
// Run git ls-remote --tags
|
||||
std::string stdout_output;
|
||||
auto result = execute_process(
|
||||
"git", {"ls-remote", "--tags", "--refs", repo_url}, "",
|
||||
[&stdout_output](const std::string &line) { stdout_output += line + "\n"; },
|
||||
[](const std::string &) {}, 30);
|
||||
|
||||
if (!result.success) {
|
||||
logger::print_verbose("Failed to fetch tags from " + repo_url);
|
||||
return versions;
|
||||
}
|
||||
|
||||
// Parse the output - format: "SHA\trefs/tags/tagname"
|
||||
std::string regex_str = pattern_to_regex(config.pattern);
|
||||
std::regex version_regex;
|
||||
try {
|
||||
version_regex = std::regex(regex_str);
|
||||
} catch (const std::regex_error &e) {
|
||||
logger::print_verbose("Invalid tag pattern regex: " + regex_str);
|
||||
return versions;
|
||||
}
|
||||
|
||||
std::istringstream iss(stdout_output);
|
||||
std::string line;
|
||||
|
||||
while (std::getline(iss, line)) {
|
||||
// Find the tag name after refs/tags/
|
||||
size_t tag_pos = line.find("refs/tags/");
|
||||
if (tag_pos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string tag = line.substr(tag_pos + 10);
|
||||
|
||||
// Trim whitespace
|
||||
tag.erase(tag.find_last_not_of(" \t\r\n") + 1);
|
||||
|
||||
// Check exclusions
|
||||
bool excluded = false;
|
||||
for (const auto &excl : config.exclude) {
|
||||
if (tag.find(excl) != std::string::npos) {
|
||||
excluded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (excluded) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract version using regex
|
||||
std::smatch match;
|
||||
if (std::regex_match(tag, match, version_regex) && match.size() >= 2) {
|
||||
package_version ver;
|
||||
ver.version = match[1].str();
|
||||
ver.tag = tag;
|
||||
versions.push_back(ver);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by version (newest first)
|
||||
std::sort(versions.begin(), versions.end(),
|
||||
[](const package_version &a, const package_version &b) {
|
||||
return compare_versions(a.version, b.version) > 0;
|
||||
});
|
||||
|
||||
// Limit number of versions
|
||||
if (versions.size() > static_cast<size_t>(config.max_versions)) {
|
||||
versions.resize(config.max_versions);
|
||||
}
|
||||
|
||||
// Cache the results
|
||||
version_cache_[repo_url] = versions;
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
std::vector<package_version>
|
||||
registry::load_version_cache(const std::string &name) const {
|
||||
std::vector<package_version> versions;
|
||||
// Always use global cache directory for version caching (not project-local)
|
||||
std::filesystem::path cache_file = get_default_cache_dir() / "versions" / (name + ".cache");
|
||||
|
||||
if (!std::filesystem::exists(cache_file)) {
|
||||
return versions;
|
||||
}
|
||||
|
||||
// Check if cache is still valid (1 hour)
|
||||
auto mod_time = std::filesystem::last_write_time(cache_file);
|
||||
auto now = std::filesystem::file_time_type::clock::now();
|
||||
auto age = std::chrono::duration_cast<std::chrono::hours>(now - mod_time);
|
||||
if (age.count() > 1) {
|
||||
return versions; // Cache expired
|
||||
}
|
||||
|
||||
std::ifstream file(cache_file);
|
||||
if (!file) {
|
||||
return versions;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
size_t tab_pos = line.find('\t');
|
||||
if (tab_pos != std::string::npos) {
|
||||
package_version ver;
|
||||
ver.version = line.substr(0, tab_pos);
|
||||
ver.tag = line.substr(tab_pos + 1);
|
||||
versions.push_back(ver);
|
||||
}
|
||||
}
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
void registry::save_version_cache(
|
||||
const std::string &name,
|
||||
const std::vector<package_version> &versions) const {
|
||||
// Always use global cache directory for version caching (not project-local)
|
||||
std::filesystem::path version_cache_dir = get_default_cache_dir() / "versions";
|
||||
std::filesystem::create_directories(version_cache_dir);
|
||||
|
||||
std::filesystem::path cache_file = version_cache_dir / (name + ".cache");
|
||||
std::ofstream file(cache_file);
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &ver : versions) {
|
||||
file << ver.version << "\t" << ver.tag << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<package_info>
|
||||
registry::load_package_file(const std::string &name) const {
|
||||
// Determine the package file path
|
||||
@@ -267,17 +461,34 @@ registry::load_package_file(const std::string &name) const {
|
||||
info.categories = reader.get_string_array("package.categories");
|
||||
info.verified = reader.get_bool("package.verified", false);
|
||||
|
||||
// Integration
|
||||
info.integration.type = reader.get_string("integration.type", "cmake");
|
||||
info.integration.cmake_target = reader.get_string("integration.cmake_target", "");
|
||||
info.integration.include_dir = reader.get_string("integration.include_dir", "");
|
||||
// Tag discovery configuration
|
||||
info.tags.pattern = reader.get_string("package.tag_pattern", "v{version}");
|
||||
info.tags.exclude = reader.get_string_array("package.tag_exclude");
|
||||
info.tags.max_versions = reader.get_int("package.max_versions", 50);
|
||||
info.auto_discover_versions = reader.get_bool("package.auto_versions", true);
|
||||
|
||||
// Integration - support both old [integration] and new [cmake] sections
|
||||
info.integration.type = reader.get_string("integration.type",
|
||||
reader.get_string("cmake.type", "cmake"));
|
||||
info.integration.cmake_target = reader.get_string("integration.cmake_target",
|
||||
reader.get_string("cmake.target", ""));
|
||||
info.integration.include_dir = reader.get_string("integration.include_dir",
|
||||
reader.get_string("cmake.include_dir", ""));
|
||||
info.integration.single_header = reader.get_string("integration.single_header", "");
|
||||
info.integration.cmake_subdir = reader.get_string("integration.cmake_subdir", "");
|
||||
info.integration.header_only_option =
|
||||
reader.get_string("integration.header_only_option", "");
|
||||
|
||||
// Check if header_only is set at cmake level
|
||||
if (reader.get_bool("cmake.header_only", false)) {
|
||||
info.integration.type = "header_only";
|
||||
}
|
||||
|
||||
// Default features
|
||||
info.default_features = reader.get_string_array("features.default");
|
||||
info.default_features = reader.get_string_array("package.features.default");
|
||||
if (info.default_features.empty()) {
|
||||
info.default_features = reader.get_string_array("features.default");
|
||||
}
|
||||
|
||||
// Features
|
||||
for (const auto &feature_name : reader.get_table_keys("features")) {
|
||||
@@ -290,18 +501,22 @@ registry::load_package_file(const std::string &name) const {
|
||||
std::string prefix = "features." + feature_name;
|
||||
feat.cmake_option = reader.get_string(prefix + ".option", "");
|
||||
feat.description = reader.get_string(prefix + ".description", "");
|
||||
feat.required_deps = reader.get_string_array(prefix + ".requires.dependencies");
|
||||
// Support both inline requires and nested requires.dependencies
|
||||
feat.required_deps = reader.get_string_array(prefix + ".requires");
|
||||
if (feat.required_deps.empty()) {
|
||||
feat.required_deps = reader.get_string_array(prefix + ".requires.dependencies");
|
||||
}
|
||||
|
||||
info.features[feature_name] = feat;
|
||||
}
|
||||
|
||||
// Versions - we need to handle the array of tables
|
||||
// For now, parse from raw file
|
||||
// First try to load explicit [[versions]] from file
|
||||
std::ifstream file(pkg_file);
|
||||
if (file) {
|
||||
std::string line;
|
||||
package_version current_ver;
|
||||
bool in_version = false;
|
||||
bool has_explicit_versions = false;
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
// Trim whitespace
|
||||
@@ -312,6 +527,7 @@ registry::load_package_file(const std::string &name) const {
|
||||
line = line.substr(start);
|
||||
|
||||
if (line.find("[[versions]]") == 0) {
|
||||
has_explicit_versions = true;
|
||||
if (in_version && !current_ver.version.empty()) {
|
||||
info.versions.push_back(current_ver);
|
||||
}
|
||||
@@ -362,6 +578,23 @@ registry::load_package_file(const std::string &name) const {
|
||||
if (in_version && !current_ver.version.empty()) {
|
||||
info.versions.push_back(current_ver);
|
||||
}
|
||||
|
||||
// If no explicit versions and auto-discover is enabled, fetch from Git
|
||||
if (info.versions.empty() && info.auto_discover_versions &&
|
||||
!info.repository.empty()) {
|
||||
// Try cache first
|
||||
info.versions = load_version_cache(name);
|
||||
|
||||
if (info.versions.empty()) {
|
||||
// Fetch from Git
|
||||
info.versions = fetch_git_tags(info.repository, info.tags);
|
||||
|
||||
// Cache the results
|
||||
if (!info.versions.empty()) {
|
||||
save_version_cache(name, info.versions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maintainers
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "core/constants.h"
|
||||
#include "core/dependency_hash.hpp"
|
||||
#include "core/process_utils.hpp"
|
||||
#include "core/registry.hpp"
|
||||
#include "core/toml_reader.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -619,6 +620,353 @@ void configure_git_dependencies_in_cmake(const toml_reader &project_config,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to get list of index dependencies (from cforge-index)
|
||||
*/
|
||||
/**
|
||||
* @brief Index dependency info for CMake generation
|
||||
*/
|
||||
struct index_dep_info {
|
||||
std::string name;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get list of index dependencies with their versions
|
||||
*/
|
||||
static std::vector<index_dep_info> get_index_dependencies_with_versions(
|
||||
const toml_reader &project_config) {
|
||||
std::vector<index_dep_info> index_deps;
|
||||
|
||||
if (!project_config.has_key("dependencies")) {
|
||||
logger::print_verbose("No [dependencies] section found");
|
||||
return index_deps;
|
||||
}
|
||||
|
||||
auto all_deps = project_config.get_table_keys("dependencies");
|
||||
logger::print_verbose("Found " + std::to_string(all_deps.size()) + " keys in [dependencies]");
|
||||
|
||||
for (const auto &dep : all_deps) {
|
||||
logger::print_verbose(" Checking dependency key: " + dep);
|
||||
|
||||
// Skip known special sections
|
||||
if (dep == "directory" || dep == "git" || dep == "vcpkg" ||
|
||||
dep == "subdirectory" || dep == "system" || dep == "project" ||
|
||||
dep == "fetch_content") {
|
||||
logger::print_verbose(" Skipping (special key)");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this is a simple version string (index dependency)
|
||||
std::string dep_key = "dependencies." + dep;
|
||||
|
||||
// Check if it's a table with source-specific keys
|
||||
if (project_config.has_key(dep_key + ".url") ||
|
||||
project_config.has_key(dep_key + ".vcpkg_name") ||
|
||||
project_config.has_key(dep_key + ".path") ||
|
||||
project_config.has_key(dep_key + ".system")) {
|
||||
logger::print_verbose(" Skipping (has source-specific keys)");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get version string
|
||||
std::string version = project_config.get_string(dep_key, "");
|
||||
if (version.empty()) {
|
||||
logger::print_verbose(" Skipping (no version string found)");
|
||||
continue;
|
||||
}
|
||||
|
||||
logger::print_verbose(" Found index dep: " + dep + " = " + version);
|
||||
index_deps.push_back({dep, version});
|
||||
}
|
||||
|
||||
logger::print_verbose("Total index dependencies found: " + std::to_string(index_deps.size()));
|
||||
return index_deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get list of index dependencies (names only, for backward compatibility)
|
||||
* Only returns deps that exist in the deps directory
|
||||
*/
|
||||
static std::vector<std::string> get_index_dependencies(
|
||||
const std::filesystem::path &project_dir,
|
||||
const toml_reader &project_config,
|
||||
const std::string &deps_dir) {
|
||||
std::vector<std::string> result;
|
||||
|
||||
auto deps = get_index_dependencies_with_versions(project_config);
|
||||
logger::print_verbose("Checking " + std::to_string(deps.size()) + " index deps for existence in " + deps_dir);
|
||||
|
||||
for (const auto &dep : deps) {
|
||||
// Check if the package directory exists in vendor
|
||||
std::filesystem::path pkg_path = project_dir / deps_dir / dep.name;
|
||||
logger::print_verbose(" Checking path: " + pkg_path.string());
|
||||
if (std::filesystem::exists(pkg_path)) {
|
||||
logger::print_verbose(" EXISTS - adding " + dep.name);
|
||||
result.push_back(dep.name);
|
||||
} else {
|
||||
logger::print_verbose(" NOT FOUND - skipping " + dep.name);
|
||||
}
|
||||
}
|
||||
|
||||
logger::print_verbose("Index dependencies with existing paths: " + std::to_string(result.size()));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure index dependencies - Phase 1: add_subdirectory and include_directories
|
||||
* This is called BEFORE the target is created
|
||||
*
|
||||
* @param project_dir Project directory
|
||||
* @param project_config Project configuration from cforge.toml
|
||||
* @param deps_dir Dependencies directory (e.g., "vendor")
|
||||
* @param cmakelists Output stream
|
||||
*/
|
||||
void configure_index_dependencies_phase1(const std::filesystem::path &project_dir,
|
||||
const toml_reader &project_config,
|
||||
const std::string &deps_dir,
|
||||
std::ofstream &cmakelists) {
|
||||
auto index_deps = get_index_dependencies(project_dir, project_config, deps_dir);
|
||||
if (index_deps.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize registry to get package info (use project_dir so index is at project_dir/cforge-index)
|
||||
registry reg(project_dir);
|
||||
|
||||
cmakelists << "# Index dependencies (from cforge-index registry)\n";
|
||||
|
||||
for (const auto &dep : index_deps) {
|
||||
std::filesystem::path pkg_path = project_dir / deps_dir / dep;
|
||||
|
||||
// Try to load package info from registry
|
||||
auto pkg_info = reg.get_package(dep);
|
||||
|
||||
std::string include_dir = "include";
|
||||
std::map<std::string, std::string> cmake_options;
|
||||
|
||||
if (pkg_info) {
|
||||
if (!pkg_info->integration.include_dir.empty()) {
|
||||
include_dir = pkg_info->integration.include_dir;
|
||||
}
|
||||
cmake_options = pkg_info->integration.cmake_options;
|
||||
}
|
||||
|
||||
cmakelists << "# " << dep << " (index package)\n";
|
||||
|
||||
// Add CMake options from package config
|
||||
for (const auto &[opt_key, opt_val] : cmake_options) {
|
||||
cmakelists << "set(" << opt_key << " " << opt_val << " CACHE BOOL \"\" FORCE)\n";
|
||||
}
|
||||
|
||||
// Add include directory (global, not target-specific)
|
||||
cmakelists << "include_directories(\"${CMAKE_CURRENT_SOURCE_DIR}/" << deps_dir << "/" << dep << "/" << include_dir << "\")\n";
|
||||
|
||||
// Check if package has CMakeLists.txt - if so, add_subdirectory
|
||||
if (std::filesystem::exists(pkg_path / "CMakeLists.txt")) {
|
||||
cmakelists << "add_subdirectory(\"${CMAKE_CURRENT_SOURCE_DIR}/" << deps_dir << "/" << dep << "\"";
|
||||
cmakelists << " \"${CMAKE_BINARY_DIR}/_deps/" << dep << "\")\n";
|
||||
}
|
||||
|
||||
cmakelists << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure index dependencies - Phase 2: target_link_libraries
|
||||
* This is called AFTER the target is created
|
||||
*
|
||||
* @param project_dir Project directory
|
||||
* @param project_config Project configuration from cforge.toml
|
||||
* @param deps_dir Dependencies directory (e.g., "vendor")
|
||||
* @param cmakelists Output stream
|
||||
*/
|
||||
void configure_index_dependencies_phase2(const std::filesystem::path &project_dir,
|
||||
const toml_reader &project_config,
|
||||
const std::string &deps_dir,
|
||||
std::ofstream &cmakelists) {
|
||||
auto index_deps = get_index_dependencies(project_dir, project_config, deps_dir);
|
||||
if (index_deps.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize registry to get package info (use project_dir so index is at project_dir/cforge-index)
|
||||
registry reg(project_dir);
|
||||
|
||||
// Collect targets to link
|
||||
std::vector<std::string> targets_to_link;
|
||||
|
||||
for (const auto &dep : index_deps) {
|
||||
std::filesystem::path pkg_path = project_dir / deps_dir / dep;
|
||||
|
||||
// Try to load package info from registry
|
||||
auto pkg_info = reg.get_package(dep);
|
||||
|
||||
std::string cmake_target;
|
||||
|
||||
if (pkg_info) {
|
||||
cmake_target = pkg_info->integration.cmake_target;
|
||||
}
|
||||
|
||||
if (cmake_target.empty()) {
|
||||
// Default: assume target is dep::dep
|
||||
cmake_target = dep + "::" + dep;
|
||||
}
|
||||
|
||||
// Link if package has CMakeLists.txt (even for header-only, target_link_libraries
|
||||
// propagates include directories for INTERFACE targets)
|
||||
if (std::filesystem::exists(pkg_path / "CMakeLists.txt") && !cmake_target.empty()) {
|
||||
targets_to_link.push_back(cmake_target);
|
||||
}
|
||||
}
|
||||
|
||||
if (!targets_to_link.empty()) {
|
||||
cmakelists << "# Link index dependencies\n";
|
||||
cmakelists << "target_link_libraries(${PROJECT_NAME} PUBLIC\n";
|
||||
for (const auto &target : targets_to_link) {
|
||||
cmakelists << " " << target << "\n";
|
||||
}
|
||||
cmakelists << ")\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure index dependencies using FetchContent - Phase 1
|
||||
* This generates FetchContent_Declare calls BEFORE the target is created
|
||||
*
|
||||
* @param project_dir Project directory (for registry lookup)
|
||||
* @param project_config Project configuration from cforge.toml
|
||||
* @param cmakelists Output stream
|
||||
*/
|
||||
void configure_index_dependencies_fetchcontent_phase1(
|
||||
const std::filesystem::path &project_dir,
|
||||
const toml_reader &project_config,
|
||||
std::ofstream &cmakelists) {
|
||||
auto index_deps = get_index_dependencies_with_versions(project_config);
|
||||
if (index_deps.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize registry to get package info
|
||||
registry reg(project_dir);
|
||||
|
||||
cmakelists << "# Index dependencies via FetchContent\n";
|
||||
cmakelists << "include(FetchContent)\n\n";
|
||||
|
||||
std::vector<std::string> deps_to_fetch;
|
||||
|
||||
for (const auto &dep : index_deps) {
|
||||
// Get package info from registry
|
||||
auto pkg_info = reg.get_package(dep.name);
|
||||
if (!pkg_info) {
|
||||
logger::print_warning("Package '" + dep.name + "' not found in registry, skipping FetchContent");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pkg_info->repository.empty()) {
|
||||
logger::print_warning("Package '" + dep.name + "' has no repository URL, skipping FetchContent");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Resolve version to a git tag
|
||||
std::string git_tag = dep.version;
|
||||
for (const auto &ver : pkg_info->versions) {
|
||||
if (ver.version == dep.version) {
|
||||
git_tag = ver.tag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If using tag_pattern, construct the tag
|
||||
if (git_tag == dep.version && !pkg_info->tags.pattern.empty()) {
|
||||
git_tag = pkg_info->tags.pattern;
|
||||
size_t pos = git_tag.find("{version}");
|
||||
if (pos != std::string::npos) {
|
||||
git_tag.replace(pos, 9, dep.version);
|
||||
}
|
||||
}
|
||||
|
||||
cmakelists << "# " << dep.name << " v" << dep.version << "\n";
|
||||
|
||||
// Add CMake options from package config
|
||||
for (const auto &[opt_key, opt_val] : pkg_info->integration.cmake_options) {
|
||||
cmakelists << "set(" << opt_key << " " << opt_val << " CACHE BOOL \"\" FORCE)\n";
|
||||
}
|
||||
|
||||
// FetchContent_Declare
|
||||
cmakelists << "FetchContent_Declare(\n";
|
||||
cmakelists << " " << dep.name << "\n";
|
||||
cmakelists << " GIT_REPOSITORY " << pkg_info->repository << "\n";
|
||||
cmakelists << " GIT_TAG " << git_tag << "\n";
|
||||
cmakelists << " GIT_SHALLOW TRUE\n";
|
||||
cmakelists << ")\n\n";
|
||||
|
||||
deps_to_fetch.push_back(dep.name);
|
||||
}
|
||||
|
||||
// FetchContent_MakeAvailable for all dependencies
|
||||
if (!deps_to_fetch.empty()) {
|
||||
cmakelists << "FetchContent_MakeAvailable(";
|
||||
for (size_t i = 0; i < deps_to_fetch.size(); ++i) {
|
||||
if (i > 0) cmakelists << " ";
|
||||
cmakelists << deps_to_fetch[i];
|
||||
}
|
||||
cmakelists << ")\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure index dependencies using FetchContent - Phase 2
|
||||
* This generates target_link_libraries calls AFTER the target is created
|
||||
*
|
||||
* @param project_dir Project directory (for registry lookup)
|
||||
* @param project_config Project configuration from cforge.toml
|
||||
* @param cmakelists Output stream
|
||||
*/
|
||||
void configure_index_dependencies_fetchcontent_phase2(
|
||||
const std::filesystem::path &project_dir,
|
||||
const toml_reader &project_config,
|
||||
std::ofstream &cmakelists) {
|
||||
auto index_deps = get_index_dependencies_with_versions(project_config);
|
||||
if (index_deps.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize registry to get package info
|
||||
registry reg(project_dir);
|
||||
|
||||
// Collect targets to link
|
||||
std::vector<std::string> targets_to_link;
|
||||
|
||||
for (const auto &dep : index_deps) {
|
||||
auto pkg_info = reg.get_package(dep.name);
|
||||
if (!pkg_info || pkg_info->repository.empty()) {
|
||||
// Fallback: assume target is dep::dep if package not in registry
|
||||
targets_to_link.push_back(dep.name + "::" + dep.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string cmake_target = pkg_info->integration.cmake_target;
|
||||
|
||||
if (cmake_target.empty()) {
|
||||
cmake_target = dep.name + "::" + dep.name;
|
||||
}
|
||||
|
||||
// Always link to the CMake target - even for header-only libraries,
|
||||
// target_link_libraries propagates include directories for INTERFACE targets
|
||||
targets_to_link.push_back(cmake_target);
|
||||
}
|
||||
|
||||
if (!targets_to_link.empty()) {
|
||||
cmakelists << "# Link FetchContent dependencies\n";
|
||||
cmakelists << "target_link_libraries(${PROJECT_NAME} PUBLIC\n";
|
||||
for (const auto &target : targets_to_link) {
|
||||
cmakelists << " " << target << "\n";
|
||||
}
|
||||
cmakelists << ")\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate a CMakeLists.txt file from cforge.toml configuration
|
||||
*
|
||||
@@ -897,6 +1245,15 @@ bool generate_cmakelists_from_toml(const std::filesystem::path &project_dir,
|
||||
// Handle Git dependencies
|
||||
configure_git_dependencies_in_cmake(project_config, deps_dir, cmakelists);
|
||||
|
||||
// Handle index dependencies phase 1 (before target)
|
||||
// Check if fetch_content mode is enabled (default: true)
|
||||
bool use_fetch_content = project_config.get_bool("dependencies.fetch_content", true);
|
||||
if (use_fetch_content) {
|
||||
configure_index_dependencies_fetchcontent_phase1(project_dir, project_config, cmakelists);
|
||||
} else {
|
||||
configure_index_dependencies_phase1(project_dir, project_config, deps_dir, cmakelists);
|
||||
}
|
||||
|
||||
// Source files - use the original project source directory
|
||||
cmakelists << "# Add source files\n";
|
||||
cmakelists << "file(GLOB_RECURSE SOURCES\n";
|
||||
@@ -983,6 +1340,13 @@ bool generate_cmakelists_from_toml(const std::filesystem::path &project_dir,
|
||||
cmakelists << ")\n\n";
|
||||
}
|
||||
|
||||
// Handle index dependencies phase 2 (target_link_libraries - after target)
|
||||
if (use_fetch_content) {
|
||||
configure_index_dependencies_fetchcontent_phase2(project_dir, project_config, cmakelists);
|
||||
} else {
|
||||
configure_index_dependencies_phase2(project_dir, project_config, deps_dir, cmakelists);
|
||||
}
|
||||
|
||||
// Handle workspace project dependencies includes
|
||||
{
|
||||
// Collect all keys under [dependencies]
|
||||
|
||||
Reference in New Issue
Block a user