JH-Toolkit v1.4.1
An engineering-oriented C++20 toolkit with duck-typed concepts, static design, async coroutines, and semantic containers — header-only, RTTI-free, and concurrency-friendly.
Loading...
Searching...
No Matches
header_begin.h File Reference

Macro setup for dual-mode headers (header-only / static). More...

Go to the source code of this file.

Macros

#define JH_INTERNAL_SHOULD_DEFINE   1
#define JH_INLINE   inline

Detailed Description

Macro setup for dual-mode headers (header-only / static).

Author
JeongHan-Bae <mastropseudo@gmail.com>
Attention
This header is intended for multiple inclusions. Do NOT use include guards or #pragma once.

Overview

This header initializes macros that control whether a header emits inline definitions (header-only mode) or only declarations (linked static/shared mode). It allows one unified .h file to serve both build styles.

Build Modes

MacroDefinition BehaviorDescription
(none)Emit inline definitionsDefault header-only mode.
JH_HEADER_IMPL_BUILDEmit non-inline definitionsUsed by the single implementation TU.
JH_HEADER_NO_IMPLSuppress definitions (declarations only)Used when linking prebuilt objects.

Pseudocode Layout

#pragma once
// === Declarations ===
declare_classes_or_functions();
// === Implementations ===
// 1. Must-visible functions (depend on user macros)
must_be_visible_implementation(); // placed outside conditional
// 2. Conditionally defined implementations
#if JH_INTERNAL_SHOULD_DEFINE
JH_INLINE normal_or_inline_implementation();
#endif // JH_INTERNAL_SHOULD_DEFINE
Macro setup for dual-mode headers (header-only / static).
Cleanup header for jh/macros/header_begin.h.

Visibility Rules

  • Functions whose behavior depends on caller-side compile-time macros (e.g. platform, feature toggles, template specializations) must remain visible in every translation unit — therefore they belong outside the #if JH_INTERNAL_SHOULD_DEFINE block.
  • All other normal definitions should be wrapped inside #if JH_INTERNAL_SHOULD_DEFINE to avoid redefinition when linked from a static or shared object.
  • Always finish the header with #include <jh/macros/header_end.h>.

Usage Guide: Using Dual-Mode Headers

Once you have written a header using <jh/macros/header_begin.h> and <jh/macros/header_end.h>, you can control how that header behaves in each translation unit (TU) by defining specific macros before including it.

Basic Inclusion Modes

  • Header-only (default)
    #include "example.h"
    Emits inline definitions. Safe for multiple inclusion. Ideal for direct inclusion without linking any static library.

  • Implementation TU (static/shared build)
    #define JH_HEADER_IMPL_BUILD
    #include "example.h"
    Emits non-inline strong definitions. Only one TU should use this mode.

  • Interface-only (no definition)
    #define JH_HEADER_NO_IMPL
    #include "example.h"
    #undef JH_HEADER_NO_IMPL
    Suppresses all definitions and exposes only declarations. Useful when only type visibility is needed.

Dependency Example

Suppose other.h depends on example.h. When you want to strongly instantiate other but not example in the same TU:

#include "example.h" // header-only (inline) mode
#define JH_HEADER_IMPL_BUILD
#include "other.h" // strong definition for other

Because example.h has already been included once, its definitions are fixed for this TU. Any further includes (directly or indirectly) are guarded and will not re-instantiate.

Special Case (not recommended)

If you need to build other but not include any example implementation at all:

#define JH_HEADER_NO_IMPL
#include "example.h"
#undef JH_HEADER_NO_IMPL
#define JH_HEADER_IMPL_BUILD
#include "other.h"

This is valid only if another TU already provides the strong definition of example.

Key Principle

  • The first inclusion of a dual-mode header within a TU locks its behavior.
  • Later inclusions (even indirect ones) reuse that locked mode because of header guards or #pragma once.
  • This allows fine-grained per-TU control without breaking the One Definition Rule (ODR).

Summary Table

ModeMacroEffectTypical Use
Header-only(none)Emit inline definitionsDirect inclusion
Static/SharedJH_HEADER_IMPL_BUILDEmit non-inline strong definitionsLibrary implementation TU
Interface-onlyJH_HEADER_NO_IMPLSuppress definitions (declarations only)Type visibility only

Conceptual Summary

  • Each TU determines how a header behaves at compile time.
  • The first inclusion defines the mode for that TU.
  • Multiple TUs can coexist using different modes safely.
  • Macros are automatically cleaned by <jh/macros/header_end.h>, ensuring no cross-header contamination.

With this pattern, a single C++ header can flexibly serve as both a header-only and a static/shared library implementation — eliminating the traditional need to maintain duplicate .h / .cpp files.


Integration with CMake and Library Packaging

Dual-mode headers are designed for both in-library use and external reuse through CMake targets. This section explains how to apply them in practice.

  1. Inside your own library build
    Define JH_HEADER_IMPL_BUILD before including each dual-mode header in the single implementation translation unit (TU). This causes strong, non-inline definitions to be generated and linked into the static or shared library.
    Other headers or source files in the same project can simply include those headers normally (header-only mode); header guards prevent redefinition.

  2. When providing your library to external users
    In your CMake packaging, propagate JH_HEADER_NO_IMPL via target_compile_definitions(... INTERFACE JH_HEADER_NO_IMPL). This ensures that all consumers automatically include headers in declaration-only mode when they link your exported target.
    Consumers do not need to define any macros manually — simply linking to the correct target selects the right mode.

  3. Example CMake configuration

    
        add_library(jh-toolkit INTERFACE ${INCLUDE})
        
    
        add_library(jh-toolkit-static STATIC ${SRC})
        
    
        target_compile_definitions(jh-toolkit-static INTERFACE JH_HEADER_NO_IMPL)
        

  4. Resulting usage summary
    • jh::jh-toolkit → header-only mode (full inline)
    • jh::jh-toolkit-static → prebuilt static object (declarations only)
    This structure allows seamless interoperability between source inclusion and prebuilt linking, all from a single unified header source.

Important Note

  • These two helper headers (jh/macros/header_begin.h and jh/macros/header_end.h) are intended to be copied directly into your own project, rather than included from jh-toolkit.
  • If your project already depends on jh-toolkit, you should rename the macros (e.g. MYLIB_HEADER_NO_IMPL) to avoid namespace pollution or conflicts.
  • You may freely modify or rename them, as long as you keep the original license notice.
See also
jh/macros/header_end.h