dropshell-build/CLAUDE.md
Your Name 1ac00e83f8
Some checks failed
dropshell-build / build (push) Has been cancelled
'Generic Commit'
2025-06-14 22:07:46 +12:00

4.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This repository contains a Docker-based build system for creating statically-linked C++ executables using Alpine Linux and musl libc. It consists of:

  1. dropshell-build-base: A comprehensive C++ development base image with Drogon web framework and database support
  2. dropshell-build: A multi-stage Docker build system that uses the base image to compile C++ projects
  3. ipdemo: A sample application demonstrating the build system

Key Commands

Building the Base Image

For local testing (single architecture):

cd build-base
./build.sh

This creates the gitea.jde.nz/public/dropshell-build-base:latest Docker image for your current architecture and loads it into Docker.

Building a Project

./build.sh

This builds the project defined in build.sh (default: ipdemo) and outputs the binary to output/.

Testing the Built Binary

./test.sh

Runs the compiled binary from output/ directory.

Environment Variables

  • CMAKE_BUILD_TYPE: Set to "Debug" or "Release" (default: Debug)
  • PROJECT: The project name to build (default: ipdemo)

Architecture and Design

Build System Structure

The build system uses a two-stage approach:

  1. Base Image (dropshell-build-base): Contains all dependencies compiled from source with static linking:

    • C++ compiler toolchain with ccache and mold linker
    • Libraries: OpenSSL, jsoncpp, PostgreSQL, MariaDB, MySQL, SQLite3, cURL, c-ares
    • Drogon web framework with full database support
    • All libraries built with -fPIC for static linking
  2. Project Build (Dockerfile.dropshell-build): Multi-stage build that:

    • Uses build cache mounts for faster rebuilds
    • Runs cmake_prebuild.sh for custom pre-build steps
    • Generates version information dynamically
    • Produces a single static binary in a scratch container

CMake Configuration

The CMakeLists.txt enforces static linking through:

  • CMAKE_EXE_LINKER_FLAGS with -static flag
  • CMAKE_FIND_LIBRARY_SUFFIXES set to .a
  • BUILD_SHARED_LIBS forced to OFF
  • All libraries installed in standard /usr/local paths

Important: Projects should set CMAKE_PREFIX_PATH and may need to explicitly link PostgreSQL libraries:

# Set paths for libraries before finding Drogon
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} /usr/local)

# Additional PostgreSQL libraries needed for static linking
set(POSTGRESQL_EXTRA_LIBS
    /usr/local/lib/libpgcommon.a
    /usr/local/lib/libpgport.a
)

Project Structure for New Applications

New C++ projects should follow this structure:

project-name/
├── CMakeLists.txt      # Based on ipdemo example
├── cmake_prebuild.sh   # Optional pre-build script
└── src/
    ├── main.cpp        # Application entry point
    └── version.hpp.in  # Version template

Adding New Projects

To build a different project:

  1. Create a directory with the project structure above
  2. Modify build.sh to set PROJECT="your-project-name"
  3. Run ./build.sh to build

Static Linking Details

The system ensures complete static linking by:

  • Using Alpine Linux's musl libc
  • Building all dependencies with --enable-static --disable-shared
  • Setting -fPIC for position-independent code
  • Using mold linker with -static flag
  • Configuring CMake to prefer .a libraries

Database Support

Applications can use:

  • PostgreSQL via libpq
  • MySQL via MariaDB connector
  • SQLite3

All database libraries are installed in /usr/local and are statically linked into the final binary.

HTTP Client Utilities

The ipdemo includes a blocking HTTP client utility (src/http_utils.hpp) that wraps Drogon's asynchronous HttpClient:

#include "http_utils.hpp"

// Make a blocking HTTP GET request
auto response = http_get("example.com", "/api/endpoint", true, 10.0); // HTTPS with 10s timeout
if (response.success && response.status_code == 200) {
    std::cout << response.body << std::endl;
}

This utility handles the threading complexity and provides a simple synchronous interface for HTTP requests.