A static blog generator, written in C++17.

First things first: How can I get it?

  1. You can use SourceTree, just add this repository's URL, clone it and you're done.
  2. You can use SmartHg, just add this repository's URL, clone it and you're done.
  3. You can use TortoiseHg, just add this repository's URL, clone it and you're done.
  4. You can use the command-line Mercurial client: hg clone https://bitbucket.org/tux_/blogcpp.


Because there are not enough static site generators yet.

No, seriously, why?

  • Just like other static site generators, blogcpp is virtually unbreakable by intruders as your server is not required to host anything but static HTML files - even JavaScript and CSS are, depending on your theme, entirely optional.
  • Unlike other static site generators, blogcpp is written in modern C++, resulting in a fast build speed, reducing the need for workarounds like incremental builds or advanced caching mechanisms while compiling. Still, blogcpp tries to use as many CPU cores as possible to achieve the maximum speed on your machine.
  • blogcpp aims to provide a decent feature set without requiring too much configuration; in fact, it would work right out of the box if your website was example.com (which is, admittedly, rather unlikely).

Current version

The latest released version is version 5.


  • Markdown support: Write your articles and pages in Markdown, get HTML.
  • Theming support: You don't like the default theme? Well, nor do I. Go on and do it better!
  • OEmbed support: Just post an OEmbed-enabled link (e.g. Twitter or YouTube) and blogcpp will embed the media for you.
  • RSS feeds for new articles, tags and categories.
  • Configurable article permalinks.
  • Sticky articles: Just put Sticky: On on top of your article file.
  • Emoji support: Write :-) and get a real smiling face instead.
  • Commenting support: Even a static blog needs a community. ;-)
  • OpenGraph support if you feel like sharing stuff on Facebook or whatever.
  • Syntax highlighting via highlight.js.
  • Plug-in support: If anything's missing, just write a script.
  • much more is planned - see the roadmap for a clue.

Used libraries

blogcpp uses the following third-party libraries (in 3rdparty/):

Some code was added from other people's suggestions:

Not included in this repository (because of their size), but still required external libraries:


How can I use blogcpp?

The easier way:

Set up your blog.cfg file first, follow the documentation in the blog.cfg-example file in this repository. Then type blogcpp --new-article to start a new article or blogcpp --new-page to start a new page. When you're done, run blogcpp and everything will be there soon.

The nerd way:

Set up your blog.cfg file first, follow the documentation in the blog.cfg-example file in this repository. Then start to add Markdown-formatted posts (in /posts) and/or pages (in /pages) formatted like this:

Author: Your name here.
Date: 2016-01-01 12:00:00
Title: This is the title.
Tags: tag 1;tag 2;tag 3
Categories: some;random;categories


(Everything that follows will be a part of the contents.)

You can additionally set Markdown: Off to disable Markdown parsing for this specific post or page. Note that pages don't have categories, every category added to a page will be ignored.

  • If you want your newly created article (for logical reasons, only posts are supported) to be "sticked" to the top of your index page, just add Sticky: On into its header part.
  • Articles will always be sorted by their creation date; you can indicate the latest change (which will be displayed or not, depending on your theme) with Changed: yyyy-mm-dd hh:mm:ss somewhere above or below the Date: field.
  • If you don't want to have emojis on this post or page without removing them everywhere, just add Emojis: Off.
  • In case you want to have a specific OpenGraph image for this page or article, you can set OpenGraphImage: http://my/host/image.png or whatever you want it to show.
  • You can also disable comments per post (pages don't have comments): Comments: Off.
  • If you use Content plug-ins but you want to disable them for this item exclusively, you can set Plugins: Off.

When you're done, run blogcpp and everything will be there soon.

OK, but how can I compile blogcpp first?

If you're on Windows, you can just get a static binary. There are also precompiled builds for Debian GNU/Linux. It's not hard to compile blogcpp yourself though:

  • On Windows: You can refer to the build_windows.cmd file in this repository for details. Visual Studio 2015 or newer as well as Clang should work.
  • On Linux and Unix: Starting from version 3, CMake files are provided, tested on GNU/Linux and FreeBSD systems. (On other systems you might have to adjust the paths.) You'll need a C++17 compiler, blogcpp makes heavy use of the new <filesystem> header and other oddities.

blogcpp has been proven to compile on:

  • Windows 10 with Visual Studio 2015.
  • Windows 10 with Clang 4.0.0.
  • Debian GNU/Linux sid with g++ 6.3.0.

Also, the ICU libraries and headers as well as libcurl need to be in your include and library paths. (Visual Studio users can get the ICU libraries here.)

Manual compilation instructions:

  1. Compile 3rdparty/XML/tinyxml2.cpp, 3rdparty/NLTemplate/NLTemplate.cpp, 3rdparty/duktape/duktape/src/duktape.c, 3rdparty/curl/HTTPDownloader.cpp, EmojiParserClass.cpp, MediaEmbedderClass.cpp, MarkdownParserClass.cpp, ContentsGeneratorClass.cpp, ExcerptExtractorClass.cpp, CommentIntegrationClass.cpp, DebugClass.cpp, PluginClass.cpp, and blogcpp.cpp into one object file.
  2. Link to the libcurl_a, sicuin, sicuio, sicuuc and sicudt libraries. (Drop the leading "s" if you don't want to have a static linking.)
  3. On Windows, additionally link to shell32.lib and user32.lib.
  4. On POSIX systems, additionally link to pthread.

Optional preprocessor definitions while linking:

  • CURL_STATICLIB and U_STATIC_IMPLEMENTATION: Required for static linking of ICU and libcurl (highly recommended).
  • WITH_DEBUGLOG: Prints verbose debug output to /debuglog.txt.
  • WITH_PLUGINS: Actually supports loading and evaluating plug-ins.
  • WITH_OEMBED: blogcpp supports the OEmbed standard. This will - in some cases - affect the page generation speed. (If not used, blogcpp supports simple replacements for YouTube and Vimeo only.)

Which directories need to be there?

Here's a site's minimal directory structure:


Of course, the capital letters mean that the values are indeed variables. By default, TPLNAME is default, INDIR is site and OUTDIR is outdir. Please use the configuration file when building your site in order to change these values.

The name is stupid!

Well, I am a developer, not an economist. I do software, not shiny product names. However, blogcpp is path-agnostic (as long as it finds its usual path structure). You think blogcpp is a stupid name? mv blogcpp klaus and blog with klaus!

Also, please consider to ask a real question next time.

How does syntax highlighting work?

Four spaces at the beginning of a line mark the beginning of a code block. blogcpp tries to determine the language of the code automatically. If you want to set the language explicitly, you can use the Pelican syntax for code blocks; example:

print("This is Python code.")

Which parameters are supported?

You can call blogcpp with the following parameters:

  • -h / --help: Prints this list of parameters.
  • -v / --version: Prints the version number of blogcpp.
  • -q / --quiet: Generates your site and shuts up while doing so.
  • --new-article: Generates a new article stub and opens it in your default editor.
  • --new-page: Generates a new page stub and opens it in your default editor.
  • --config [filename]: Uses a different configuration file than blog.cfg. The file must exist.

If compiled with WITH_PLUGINS. three more parameters are supported:

  • --list-plugins: Shows a list of all available plug-ins with their enabled/disabled status.
  • --enable-plugin [name]: Enables the given plug-in (if found).
  • --disable-plugin [name]: Disables the given plug-in (if found).

Which emojis are supported?

Given that you have actually enabled Emoji support in your blog.cfg file and not disabled it for the page or article you want to process, the following smiley codes will automatically be replaced:

Code Emoji
;-) 😉
:-D 😀
:'( 😭
:-| 😐
>:) 😈
>:-) 😈
>:( 😠
>:-( 😠
:-* 😘
:-O 😮
:-o 😮
:-S 😕
:-s 😕
:-# 😶
0:-) 😇
:o) 🤡
<_< 😒
^^ 😊
^_^ 😊
m( 🤦

Which comment systems does blogcpp support?

While blogcpp does not have its own commenting system, you can easily integrate existing external commenting systems via your blog.cfg (please refer to the blog.cfg-example file in this repository). Currently supported are:

  • *Disqus* (comments = disqus, you need to set your commentdata to your Disqus shortname)
  • *isso* (comments = isso, you need to set your commentdata to your isso folder)
  • *Hashover* (comments = hashover, you need to set your commentdata to your Hashover folder) -- currently, version 2.0 only
  • Google Plus comments (comments = google, no additional settings required)
  • *Discourse* (comments = discourse, you need to set your commentdata to your Discourse domain)

How can I write a blogcpp plug-in? Is it hard?

Good news: blogcpp plug-ins are actually JavaScript scripts, meaning that it is rather easy to write one. Everyone can write JavaScript today, right?

The plug-in mechanisms are still in an early phase, they will probably be more extended in later releases. As of now, blogcpp only supports three kinds of plug-ins:

  • Content plug-ins: Will be searched under <plugindir>/contents. blogcpp will draw your contents (articles and pages) through all available scripts and spit out the results. Note that this happens during the initial reading stadium, so your scripts will see the raw Markdown text. The process() method is expected to take and return a string value.
  • Header plug-ins: Will be searched under <plugindir>/header. The process() method is expected to return a string value which will be attached to the {{ headscripts }} template variable (if applicable).
  • Footer plug-ins: Similar to header plug-ins, but they should be in <plugindir>/footer and fill the {{ footscripts }} variable.

The standard naming scheme is something.plugin.js, blogcpp will gladly ignore any files which do not have a name like this. You are also able to have a multi-part plug-in which affects multiple parts of the blog: Plug-ins with an identical file name are considered to belong together, blogcpp will handle them as one big plug-in which affects various parts of the software, e.g. <plugindir>/contents/moo.plugin.js for moo'ing in the contents part, <plugindir>/header/moo.plugin.js for moo'ing in the site header.

In order for this to work, you'll need to have blogcpp compiled with WITH_PLUGINS and the configuration variable plugins set to on. If you did so, blogcpp will read all files in the particular folder under your plug-in directory. If they are - more or less - valid JavaScript (ECMAScript 5.1 is mostly supported), blogcpp will try to find the process() method in them, fill it with the appropriate text and replace it by the results of the process() method before continuing as usual.

Plug-ins can also access certain parts of blogcpp itself from the BlogEngine object. By the time of writing, those are the following one:

  • getVersion(): Returns the current version of blogcpp as a number.

Please refer to the hello-world.plugin.js example plug-in in this repository for more or less information.

Can I use raw HTML in my Markdown-enabled article or page?

Yes, you can! Everything between <rawhtml> and </rawhtml> will be ignored by blogcpp's Markdown parser.

How can I disable Markdown parsing for a certain article or page?

Just add "Markdown: Off" to the meta part of your input file.

Which files does a template need to work?

blogcpp needs index.txt, post.txt, page.txt and archives.txt in order to be able to process your site correctly. All other template files are optional. CSS and image files can be put into a subfolder named static, blogcpp will automatically copy this folder to your output directory then.