Update dependency management system

This commit is contained in:
Chase Sunstrom
2025-12-08 17:57:57 -06:00
parent dc3d79069a
commit 137891cff3
42 changed files with 1331 additions and 151 deletions
+13 -38
View File
@@ -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
+13 -1
View File
@@ -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:
+6 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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&#x27;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&#x27;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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -5,7 +5,7 @@
<meta name="generator" content="Docusaurus v3.7.0">
<title data-rh="true">One post tagged with &quot;beta&quot; | 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 &quot;beta&quot; | 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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -5,7 +5,7 @@
<meta name="generator" content="Docusaurus v3.7.0">
<title data-rh="true">One post tagged with &quot;release&quot; | 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 &quot;release&quot; | 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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -5,7 +5,7 @@
<meta name="generator" content="Docusaurus v3.7.0">
<title data-rh="true">Scripts &amp; 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 &amp; Hooks | CForge"><meta data-rh="true" name="description" content="📝 Scripts &amp; Hooks"><meta data-rh="true" property="og:description" content="📝 Scripts &amp; 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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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
View File
@@ -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 &amp; 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 &amp; 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">
+75
View File
@@ -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;
+57
View File
@@ -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
View File
@@ -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);
+67 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
+364
View File
@@ -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]