<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6" -->

---
title: Writing a C preprocessor for bgfx shader compiler
description: For over 14 years, bgfx&#x27;s shader compiler relied on fcpp, a C preprocessor descended from 1984 Amiga-era code, to translate a single GLSL-inspired shader...
canonical: https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Writing a C preprocessor for bgfx shader compiler | daily.dev
og:description: For over 14 years, bgfx&#x27;s shader compiler relied on fcpp, a C preprocessor descended from 1984 Amiga-era code, to translate a single GLSL-inspired shader...
og:url: https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6
og:image: https://api.daily.dev/og/posts/PX6OAFGu6.png
og:image:alt: Writing a C preprocessor for bgfx shader compiler
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing a C preprocessor for bgfx shader compiler

**[Overview — bgfx 1.146.9292 documentation](https://daily.dev/sources/bkaradzic)** · 14 min read · 2 upvotes · 0 comments

## Summary

For over 14 years, bgfx's shader compiler relied on fcpp, a C preprocessor descended from 1984 Amiga-era code, to translate a single GLSL-inspired shader source into HLSL, MSL, GLSL, SPIR-V and WGSL. Despite its age, fcpp worked well thanks to its clean, stateless, embeddable design. However, its codebase was crufty K&R-era C89 spread across unreadably named files, and upstream development had effectively frozen, with only janitorial commits. The author surveyed five alternative preprocessors (ucpp, mcpp, tinycpp, tcpp) and found each disqualified by global state, LGPL dependencies, STL bloat, or lack of injectable allocators. The conclusion was to write a new preprocessor from scratch: shaderc::Preprocessor, roughly 3,000 lines of C++ built on bx::Scanner, with a tiny callback-based API, no filesystem or exit() calls, an injectable arena allocator, and full reentrancy. It supports the C preprocessor features shaders actually need (recursive macro expansion, ##, variadics) while skipping irrelevant C99 conformance like trigraphs. fcpp was removed from the bgfx repository on 20 August 2026 after more than 14 years of service.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://bkaradzic.github.io/posts/preprocessor>

## Questions this post answers

### Why did bgfx replace the fcpp preprocessor in its shader compiler?

fcpp, despite working reliably for over 14 years, had frozen upstream development, K&R-era C89 code spread across poorly named files, no custom allocator support, and only partial virtual filesystem support. bgfx replaced it with shaderc::Preprocessor, a roughly 3,000-line C++ implementation with an injectable arena allocator, zero third-party dependencies beyond bx headers, full reentrancy, and no filesystem or exit() calls, while still supporting recursive macro expansion and token pasting.

_See how daily.dev surfaces real-world dependency replacement stories like this bgfx preprocessor rewrite._

### Why didn't bgfx just switch to tinycpp or tcpp instead of writing a new C preprocessor?

tinycpp, though small at 2,032 lines with a clean opaque-handle API and no globals, depends on tglist.h and hbmap.h from libulz, which is LGPL-2.1 licensed, making it unsuitable despite otherwise being the closest fit. tcpp targets shader preprocessing directly but is a single 2,331-line header that pulls in ten STL headers including vector, unordered_map, and functional, conflicting with the goal of avoiding STL and controlling memory allocation.

_Compare tradeoffs like this before picking a dependency, and follow evaluations like it on daily.dev._

### What programming languages does bgfx's shader compiler need to target with its preprocessor?

The bgfx shader compiler preprocesses a single GLSL-inspired source into HLSL for Direct3D, Metal Shading Language for Apple platforms, GLSL and its embedded variant for OpenGL, SPIR-V for Vulkan, and WGSL for WebGPU. A shared header included at the top of each shader contains a few hundred macros and conditional branches that reshape the source per target, selected by defines the compiler sets, making the preprocessor the actual cross-platform portability layer rather than a preliminary strip-comments pass.

_Track cross-platform shader tooling decisions like this on daily.dev as graphics API support evolves._

## Similar posts on daily.dev

- [The bgfx shader compiler, 14 years of not being a compiler](https://daily.dev/posts/the-bgfx-shader-compiler-14-years-of-not-being-a-compiler-bzzcsjzae) · Overview — bgfx 1.146.9292 documentation · 0 upvotes · 0 comments
- [compiler](https://daily.dev/posts/compiler-4h8jmmzmz) · Lobsters · 1 upvotes · 0 comments
- [On C extensions, portability, and alternative compilers](https://daily.dev/posts/on-c-extensions-portability-and-alternative-compilers-xh1x5m5qq) · Hacker News · 0 upvotes · 0 comments
- [GCC & The GNU Toolchain's Exciting 2025 With New Languages, More Optimizations](https://daily.dev/posts/gcc-the-gnu-toolchain-s-exciting-2025-with-new-languages-more-optimizations-nqa2he7af) · Phoronix · 0 upvotes · 0 comments

---

Tags: [#game-development](https://daily.dev/tags/game-development), [#architecture](https://daily.dev/tags/architecture), [#c](https://daily.dev/tags/c)

[View this post on daily.dev](https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Writing a C preprocessor for bgfx shader compiler","url":"https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6"},"datePublished":"2026-08-23T12:17:05.762Z","dateModified":"2026-09-14T08:07:47.001Z","description":"For over 14 years, bgfx's shader compiler relied on fcpp, a C preprocessor descended from 1984 Amiga-era code, to translate a single GLSL-inspired shader...","image":"https://media.daily.dev/image/upload/s--ZrL_HSsR--/f_auto/v1722860399/public/Placeholder%2006","thumbnailUrl":"https://media.daily.dev/image/upload/s--ZrL_HSsR--/f_auto/v1722860399/public/Placeholder%2006","isAccessibleForFree":true,"articleSection":"Overview — bgfx 1.146.9292 documentation","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Overview — bgfx 1.146.9292 documentation","logo":"https://media.daily.dev/image/upload/logos/placeholder.jpg","url":"https://daily.dev/sources/bkaradzic"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"game-development,architecture,c","timeRequired":"PT14M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Overview — bgfx 1.146.9292 documentation","item":"https://daily.dev/sources/bkaradzic"},{"@type":"ListItem","position":3,"name":"Writing a C preprocessor for bgfx shader compiler"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/writing-a-c-preprocessor-for-bgfx-shader-compiler-px6oafgu6#faq","mainEntity":[{"@type":"Question","name":"Why did bgfx replace the fcpp preprocessor in its shader compiler?","acceptedAnswer":{"@type":"Answer","text":"fcpp, despite working reliably for over 14 years, had frozen upstream development, K&R-era C89 code spread across poorly named files, no custom allocator support, and only partial virtual filesystem support. bgfx replaced it with shaderc::Preprocessor, a roughly 3,000-line C++ implementation with an injectable arena allocator, zero third-party dependencies beyond bx headers, full reentrancy, and no filesystem or exit() calls, while still supporting recursive macro expansion and token pasting. See how daily.dev surfaces real-world dependency replacement stories like this bgfx preprocessor rewrite."}},{"@type":"Question","name":"Why didn't bgfx just switch to tinycpp or tcpp instead of writing a new C preprocessor?","acceptedAnswer":{"@type":"Answer","text":"tinycpp, though small at 2,032 lines with a clean opaque-handle API and no globals, depends on tglist.h and hbmap.h from libulz, which is LGPL-2.1 licensed, making it unsuitable despite otherwise being the closest fit. tcpp targets shader preprocessing directly but is a single 2,331-line header that pulls in ten STL headers including vector, unordered_map, and functional, conflicting with the goal of avoiding STL and controlling memory allocation. Compare tradeoffs like this before picking a dependency, and follow evaluations like it on daily.dev."}},{"@type":"Question","name":"What programming languages does bgfx's shader compiler need to target with its preprocessor?","acceptedAnswer":{"@type":"Answer","text":"The bgfx shader compiler preprocesses a single GLSL-inspired source into HLSL for Direct3D, Metal Shading Language for Apple platforms, GLSL and its embedded variant for OpenGL, SPIR-V for Vulkan, and WGSL for WebGPU. A shared header included at the top of each shader contains a few hundred macros and conditional branches that reshape the source per target, selected by defines the compiler sets, making the preprocessor the actual cross-platform portability layer rather than a preliminary strip-comments pass. Track cross-platform shader tooling decisions like this on daily.dev as graphics API support evolves."}}]}
```

