Skip to content

Project Structure

Complete guide to CCGO project organization and directory structure.

Overview

CCGO projects follow a standardized structure:

  • Source code: src/ for implementation, include/ for headers
  • Tests: tests/ for unit tests
  • Benchmarks: benches/ for performance tests
  • Documentation: docs/ for Doxygen/Sphinx docs
  • Configuration: CCGO.toml for project settings
  • Build outputs: target/ for compiled binaries

Standard Project Layout

myproject/
├── CCGO.toml                    # Project configuration
├── CMakeLists.txt               # CMake configuration (generated)
├── build_config.py              # Build-specific settings (generated)
├── .ccgoignore                  # Files to exclude from CCGO operations
├── README.md                    # Project documentation
├── LICENSE                      # License file
├── .gitignore                   # Git ignore rules
├── include/                     # Public headers
│   └── myproject/
│       ├── myproject.h          # Main header
│       ├── version.h            # Version info (generated)
│       └── feature.h            # Feature-specific headers
├── src/                         # Implementation files
│   ├── myproject.cpp            # Main implementation
│   ├── feature.cpp              # Feature implementations
│   └── internal/                # Private implementation
│       └── utils.cpp
├── tests/                       # Unit tests
│   ├── test_main.cpp            # Test runner
│   ├── test_myproject.cpp       # Tests for main module
│   └── test_feature.cpp         # Tests for features
├── benches/                     # Benchmarks
│   ├── bench_main.cpp           # Benchmark runner
│   └── bench_performance.cpp    # Performance benchmarks
├── docs/                        # Documentation
│   ├── Doxyfile                 # Doxygen configuration
│   ├── api/                     # API documentation
│   └── guides/                  # User guides
├── examples/                    # Example applications (optional)
│   ├── basic/
│   │   └── main.cpp
│   └── advanced/
│       └── main.cpp
├── cmake_build/                 # CMake build directory (generated)
│   ├── android/
│   ├── ios/
│   ├── linux/
│   └── windows/
└── target/                      # Build outputs (generated)
    ├── android/
    ├── ios/
    ├── linux/
    └── windows/

Directory Details

Root Files

CCGO.toml

Purpose: Main project configuration file.

Content:

[package]
name = "myproject"
version = "1.0.0"
description = "My C++ project"

[library]
type = "both"

[build]
cpp_standard = "17"

[dependencies]
spdlog = { git = "https://github.com/gabime/spdlog.git", tag = "v1.12.0" }

See: Configuration Guide

CMakeLists.txt

Purpose: CMake configuration (auto-generated by CCGO).

Content:

cmake_minimum_required(VERSION 3.20)
project(myproject VERSION 1.0.0)

# CCGO cmake utilities
include(${CCGO_CMAKE_DIR}/CMakeUtils.cmake)

# Add subdirectories
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(benches)

Note: Do not edit manually - regenerated on each build.

build_config.py

Purpose: Build-specific settings (auto-generated).

Content:

PROJECT_NAME = "myproject"
PROJECT_VERSION = "1.0.0"
BUILD_TYPE = "release"
CPP_STANDARD = "17"

Usage: Used by build scripts internally.

.ccgoignore

Purpose: Exclude files from CCGO operations.

Content:

# Build directories
cmake_build/
target/
bin/

# IDE files
.vscode/
.idea/

# Generated files
*.pyc

See: Configuration Guide - .ccgoignore

include/

Purpose: Public header files that users of your library will include.

Structure:

include/
└── myproject/               # Namespace directory (required)
    ├── myproject.h          # Main header
    ├── version.h            # Version info (generated)
    ├── config.h             # Configuration (generated)
    ├── feature_a.h          # Feature headers
    ├── feature_b.h
    └── internal/            # Internal headers (not for public use)
        └── impl.h

Guidelines:

  1. Namespace directory: Always use a subdirectory matching your project name

    // Good
    #include <myproject/myproject.h>
    
    // Bad - no namespace
    #include <myproject.h>
    

  2. Header guards: Use #pragma once or traditional guards

    #pragma once
    
    namespace myproject {
    // ...
    }
    

  3. Version header: Auto-generated with version info

    // version.h (generated)
    #pragma once
    
    #define MYPROJECT_VERSION_MAJOR 1
    #define MYPROJECT_VERSION_MINOR 0
    #define MYPROJECT_VERSION_PATCH 0
    #define MYPROJECT_VERSION "1.0.0"
    

  4. Minimize includes: Only include what's necessary

    // Good - forward declare when possible
    class FeatureA;
    
    // Bad - include if not needed
    #include "feature_a.h"
    

src/

Purpose: Implementation files (.cpp, .cc, .cxx).

Structure:

src/
├── myproject.cpp            # Main implementation
├── feature_a.cpp            # Feature implementations
├── feature_b.cpp
├── internal/                # Private implementation
│   ├── utils.cpp
│   └── platform/            # Platform-specific code
│       ├── android.cpp
│       ├── ios.cpp
│       └── linux.cpp
└── CMakeLists.txt           # Generated by CCGO

Guidelines:

  1. One class per file: Keep files focused

    src/
    ├── feature_a.cpp         # FeatureA implementation
    └── feature_b.cpp         # FeatureB implementation
    

  2. Private headers: Use internal/ for private headers

    // src/internal/utils.h
    #pragma once
    // Internal utilities not for public use
    

  3. Platform-specific code: Use subdirectories or conditional compilation

    // Option 1: Separate files
    #ifdef __ANDROID__
    #include "platform/android.cpp"
    #elif defined(__APPLE__)
    #include "platform/ios.cpp"
    #endif
    
    // Option 2: Conditional blocks
    void platform_init() {
    #ifdef __ANDROID__
        // Android-specific
    #elif defined(__APPLE__)
        // iOS-specific
    #endif
    }
    

tests/

Purpose: Unit tests using Catch2 or Google Test.

Structure:

tests/
├── test_main.cpp            # Test runner
├── test_myproject.cpp       # Tests for main module
├── test_feature_a.cpp       # Feature-specific tests
├── test_feature_b.cpp
└── CMakeLists.txt           # Generated by CCGO

Example test file:

// test_myproject.cpp
#include <catch2/catch_test_macros.hpp>
#include <myproject/myproject.h>

TEST_CASE("Basic functionality", "[myproject]") {
    myproject::MyClass obj;
    REQUIRE(obj.get_value() == 42);
}

TEST_CASE("Feature A", "[feature_a]") {
    myproject::FeatureA feature;
    REQUIRE(feature.is_enabled());
}

Test runner:

// test_main.cpp
#define CATCH_CONFIG_MAIN
#include <catch2/catch_test_macros.hpp>

Running tests:

ccgo test                    # Run all tests
ccgo test --filter "Basic"   # Run specific test

benches/

Purpose: Performance benchmarks using Google Benchmark.

Structure:

benches/
├── bench_main.cpp           # Benchmark runner
├── bench_performance.cpp    # Performance benchmarks
├── bench_feature_a.cpp      # Feature-specific benchmarks
└── CMakeLists.txt           # Generated by CCGO

Example benchmark:

// bench_performance.cpp
#include <benchmark/benchmark.h>
#include <myproject/myproject.h>

static void BM_MyFunction(benchmark::State& state) {
    myproject::MyClass obj;
    for (auto _ : state) {
        obj.do_work();
    }
}
BENCHMARK(BM_MyFunction);

BENCHMARK_MAIN();

Running benchmarks:

ccgo bench                   # Run all benchmarks
ccgo bench --filter "MyFunc" # Run specific benchmark

docs/

Purpose: Documentation source files.

Structure:

docs/
├── Doxyfile                 # Doxygen configuration
├── README.md                # Documentation overview
├── api/                     # API documentation
│   └── reference.md
├── guides/                  # User guides
│   ├── getting-started.md
│   └── advanced.md
└── images/                  # Documentation images
    └── architecture.png

Generating docs:

ccgo doc                     # Generate documentation
ccgo doc --open              # Generate and open in browser

examples/

Purpose: Example applications showing how to use your library.

Structure:

examples/
├── basic/                   # Simple example
│   ├── main.cpp
│   └── CMakeLists.txt
├── advanced/                # Advanced usage
│   ├── main.cpp
│   └── CMakeLists.txt
└── README.md                # Examples documentation

Example application:

// examples/basic/main.cpp
#include <myproject/myproject.h>
#include <iostream>

int main() {
    myproject::MyClass obj;
    std::cout << "Value: " << obj.get_value() << std::endl;
    return 0;
}

Building examples:

# examples/basic/CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(basic_example)

find_package(myproject REQUIRED)

add_executable(basic main.cpp)
target_link_libraries(basic myproject::myproject)

cmake_build/

Purpose: CMake build artifacts (generated, not committed to git).

Structure:

cmake_build/
├── android/                 # Android build files
│   ├── armeabi-v7a/
│   ├── arm64-v8a/
│   └── x86_64/
├── ios/                     # iOS build files
│   ├── arm64/
│   └── x86_64/
├── linux/                   # Linux build files
├── windows/                 # Windows build files
└── macos/                   # macOS build files

Note: Add to .gitignore:

cmake_build/

target/

Purpose: Final build outputs (generated).

Structure:

target/
├── android/                             # Android outputs
│   └── MyProject_Android_SDK-1.0.0.zip
├── ios/                                 # iOS outputs
│   └── MyProject_iOS_SDK-1.0.0.zip
├── linux/                               # Linux outputs
│   └── MyProject_Linux_SDK-1.0.0.zip
├── windows/                             # Windows outputs
│   └── MyProject_Windows_SDK-1.0.0.zip
└── doc/                                 # Documentation
    └── html/

Note: Add to .gitignore:

target/

File Naming Conventions

Header Files

include/myproject/
├── myproject.h              # Main header (lowercase, matches project)
├── feature_a.h              # Feature headers (lowercase, underscores)
├── my_class.h               # Class headers (lowercase, underscores)
└── constants.h              # Utility headers

Source Files

src/
├── myproject.cpp            # Matches header name
├── feature_a.cpp
├── my_class.cpp
└── internal/
    └── utils.cpp            # Private utilities

Test Files

tests/
├── test_myproject.cpp       # Prefix with "test_"
├── test_feature_a.cpp
└── test_my_class.cpp

Benchmark Files

benches/
├── bench_performance.cpp    # Prefix with "bench_"
├── bench_feature_a.cpp
└── bench_algorithms.cpp

Multi-Module Projects

For projects with multiple libraries:

workspace/
├── CCGO.toml                # Workspace configuration (optional)
├── lib_core/                # Core library
│   ├── CCGO.toml
│   ├── include/
│   └── src/
├── lib_utils/               # Utilities library
│   ├── CCGO.toml
│   ├── include/
│   └── src/
└── app/                     # Application
    ├── CCGO.toml
    ├── src/
    └── main.cpp

Workspace CCGO.toml:

[workspace]
members = [
    "lib_core",
    "lib_utils",
    "app"
]

Module dependencies:

# app/CCGO.toml
[dependencies]
lib_core = { path = "../lib_core" }
lib_utils = { path = "../lib_utils" }

Platform-Specific Files

Android

project/
├── android/                 # Android-specific files (optional)
│   ├── gradle.properties
│   └── proguard-rules.pro
└── CCGO.toml
    [android]
    min_sdk_version = 21

iOS

project/
├── ios/                     # iOS-specific files (optional)
│   ├── Info.plist
│   └── Entitlements.plist
└── CCGO.toml
    [ios]
    deployment_target = "12.0"

Windows

project/
├── windows/                 # Windows-specific files (optional)
│   ├── resource.rc
│   └── app.manifest
└── CCGO.toml
    [windows]
    subsystem = "console"

Best Practices

1. Consistent Naming

Use consistent naming conventions:

# Good - consistent lowercase with underscores
include/mylib/my_feature.h
src/my_feature.cpp
tests/test_my_feature.cpp

# Bad - inconsistent casing
include/mylib/MyFeature.h
src/my_feature.cpp
tests/TestMyFeature.cpp

2. Organize by Feature

Group related files:

src/
├── networking/              # Networking feature
│   ├── client.cpp
│   ├── server.cpp
│   └── protocol.cpp
└── database/                # Database feature
    ├── connection.cpp
    └── query.cpp

3. Separate Public and Private

Keep API surface clean:

include/
└── mylib/
    ├── public_api.h         # Public API only
    └── internal/            # Internal details
        └── impl.h

4. Documentation Near Code

Keep documentation close to source:

src/
├── feature_a/
│   ├── feature_a.cpp
│   ├── feature_a.h
│   └── README.md            # Feature documentation

5. Examples Are Tests

Examples should compile and run:

examples/
└── basic/
    ├── main.cpp             # Working example
    ├── CMakeLists.txt       # Build configuration
    └── README.md            # How to run

.gitignore Template

Recommended .gitignore for CCGO projects:

# Build directories
cmake_build/
target/
bin/
build/

# IDE files
.vscode/
.idea/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db
desktop.ini

# Python
__pycache__/
*.pyc
*.pyo
*.egg-info/

# Generated files
*.autosave
*.user
*.log

# Dependencies
vendor/

Migration from Existing Projects

From CMake Project

  1. Create CCGO.toml:

    ccgo init
    

  2. Copy source files:

    mkdir -p include/mylib src
    cp src/*.h include/mylib/
    cp src/*.cpp src/
    

  3. Configure CCGO.toml:

    [package]
    name = "mylib"
    version = "1.0.0"
    
    [build]
    cpp_standard = "17"
    

  4. Build:

    ccgo build linux
    

From Header-Only Library

  1. Keep headers in include/:

    include/
    └── mylib/
        ├── mylib.h
        └── impl.h
    

  2. Configure as header-only:

    [library]
    type = "header-only"
    

From Multiple CMakeLists.txt

  1. Merge into CCGO structure:

    Old:
    project/
    ├── CMakeLists.txt
    ├── module1/
    │   └── CMakeLists.txt
    └── module2/
        └── CMakeLists.txt
    
    New:
    project/
    ├── CCGO.toml
    ├── module1/
    │   ├── CCGO.toml
    │   └── src/
    └── module2/
        ├── CCGO.toml
        └── src/
    

  2. Use workspace:

    # Root CCGO.toml
    [workspace]
    members = ["module1", "module2"]
    

Common Patterns

Library with Examples

mylib/
├── CCGO.toml
├── include/
├── src/
├── tests/
└── examples/
    ├── basic/
    ├── advanced/
    └── integration/

Library with Tools

mylib/
├── CCGO.toml
├── include/
├── src/
├── tests/
└── tools/
    ├── converter/
    └── analyzer/

Library with Plugins

mylib/
├── CCGO.toml
├── include/
├── src/
├── plugins/
│   ├── plugin_a/
│   └── plugin_b/
└── tests/

See Also