C++
Dear %username%,

I would like to share with you my first-hand experience in creating a Website on CppCMS (library-template engine on C++). It can also be named as “help for beginners on CppCMS”.

Why Would You Write a Website with C++


There are different pros and cons against this solution. So in order not to provoke a “language war”, I will draw an analogy with cars: “I bought one. I like it and don’t want to sell it!”. As an additional argument I will use the fact that this language is filed-specific for my job.

High Time to Write Something


But before that

Before we write a website, CppCMS should be installed on the working machine. The library requires Boost c++, pcre, crypt, python, icu for its operation. Despite the cross-platform it's easier to set everything up under *nix systems.
Building is quite trite:

mkdir build  
cd build 
cmake ..  
make
make install


There should be no problems with it. Everything is built automatically and it has never let me down.

Looking ahead, I would like to say that development should desirably be able to execute user building steps and have a handily adjusted syntax analyzer. I use QtCreator. I am going to describe all my further steps with reference to the environment mentioned above, as the building by using the command line is well described at the library's website. I would also like to mention that some building actions will be automated by bash scripts (though it would be enough to write a “user step” at the setup stage).

It’s better to add the syntax highlight for QtCreator before we begin. It will help to identify special *.tmpl files which are used as templates. The given file tmpl.xml (slightly modified HTML highlight) should be allocated in the config folder “qtcreator/generic-highlighter/tmpl.xml”:



    
]>




  
    
  

  
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  

  
    
    
    
  

  
    
    
    
  

  
    
    
    
  

  
    
  


  
    
    
    
    
    
  
  
  
    
    
    
  

  
    
    
    
    
  

  
    
  

  
    
    
  

  
    
    
    
    
    
  

  
    
    
    
  

  
    
    
  

  
    
    
  

  
    
    
    
    
  

  
    
    
  

  
    
    
  

  
    
    
  

  
    
    
    
    
  

  
    
    
  

  
    
    
    
    
  

  
    
    
    
  

  
    
    
  

  
    
    
    
  

  
    
    
    
  

  
    
    
  

  
    
    
  



  
  
  
  
  
  
  
  
  
  
  
  
  




  
    
  




Now Let’s Start


Depending on the built, the following should be added:

LIBS += -L/usr/local/lib/ -lbooster -lcppcms
INCLUDEPATH += /usr/local/include
DEPENDPATH += /usr/local/include


Create main.cpp file and fill it with the following content:

#include 
#include 
#include 
#include 
#include 
#include 

//-------------------------------------------------------------------------------------
// Dsc: Our class for page rendering, when some address is requested by the user 
//      First of all he will get here 
//-------------------------------------------------------------------------------------
class WebSite : public cppcms::application{
public:
  //-------------------------------------------------------------------------------------
  // Constructor. Entry point.
  //-------------------------------------------------------------------------------------
  WebSite(cppcms::service &s) : cppcms::application(s)
  {}
  //-------------------------------------------------------------------------------------
  // Dsc: The function we’ll get into if it’s not indicated otherwise in the constructor.  
  //      (more about it later)
  //-------------------------------------------------------------------------------------
  virtual void main(std::string path)
  {
    response().out() << "Hello!";
  }
};

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
int main(int argc,char **argv)
{
 try {
    // create the service
    cppcms::service srv(argc,argv);
    // define the root
    srv.applications_pool().mount(cppcms::applications_factory());
    // run
    srv.run();
  }
  catch(std::exception const &e) {
    std::cerr << "Failed: " << e.what() << std::endl;
    std::cerr << booster::trace(e) << std::endl;
    return 1;
  }
  return 0;
}


If you have already tried to run it, you most likely failed. Configuration file for the server is lacking for full-fledged operation. Its location should be passed at start to the binary file.
WebApp.bin -c config.json
Here is an example of the config file:

{        
   "WebSite" : {
      "root" : "",
      "host" : "localhost:8080",
      "locdomain" : "localhost",
   },
   "service" : {
      "ip"  : "0.0.0.0",
      "api" : "http",
      "port" : 8080
   },
   "http" : {
      "script" : "/mb.fcgi" ,
      "rewrite" : [
         { "regex" : ".*" , "pattern" : "/mb.fcgi$0" }
      ],
   }
}


This should be enough.
You could also write startup options in “configs of the programming environment”.
So add it, then start.

Impressed? No?
Of course you aren’t as we haven’t used template mechanism for this example. We just put the string out. But the example lets us make sure that everything works.

Let's use templates

Let’s write the first template which will be “transformed” by the template engine of the library into *.cpp file.

First of all, we need to add a header file which contains the structure of dynamic data (template data). They will be located in the data folder within the project by default.
data/tmpl_master.h

#ifndef TMPL_MASTER_H
#define TMPL_MASTER_H
#include 

namespace Data {
  //-------------------------------------------------------------------------------------
  // Dsc: Basic page information  
  //-------------------------------------------------------------------------------------
  struct infoPage {
    std::string    title;                         // page title
    std::string    description;                   // page description
    std::string    keywords;                      // page key words
    std::map menuList;   // list of menu items  output (url,desc)
    //-------------------------------------------------------------------------------------
    // Dsc: Constructor 
    //-------------------------------------------------------------------------------------
    infoPage() :
      title      (""),
      description(""),
      keywords   (""),
      menuList   (  )
    {}
    //-------------------------------------------------------------------------------------
    // Dsc: Destructor, doing nothing
    //-------------------------------------------------------------------------------------
    ~infoPage(){}
  };
  //-------------------------------------------------------------------------------------
  // Dsc: Basic content which exists on every page  
  //-------------------------------------------------------------------------------------
  struct Master :public cppcms::base_content {
    infoPage    page;
    //-------------------------------------------------------------------------------------
    // Dsc: Page's constructor
    //-------------------------------------------------------------------------------------
    Master() :
      page()
    {}
    //-------------------------------------------------------------------------------------
    // Dsc: Lazy destructor
    //-------------------------------------------------------------------------------------
    ~Master(){}
  };
}
#endif


As a rule, the content of the given file isn’t notable for some smart code. They’re just containers for description of the variables, which are used in templates.

Let’s describe the template, then create templates folder and master.tmpl in it with the following content:

<% c++ #include "data/tmpl_master.h" %>
<% skin defskin %>
<% view Master uses Data::Master %>
<% template page_main() %>MAIN TEMPLATE<% end %>
<% template page_footer() %>Все права защищены<% end %>
<% template page_left_sidebar() %>Левая панелька<% end %>
<% template render() %>



  
  <%= page.title %>
  
  
  


<% include page_main() %>
<% include page_footer() %>
<% end template %> <% end view %> <% end skin %>


So what is written here?

In the very first line <% c++ #include «data/tmpl_master.h» %> the header file is written. Data structures will be declared in it.

<% skin defskin %> line defines the current skin name, so you can have different page skins.

<% view Master uses Data::Master %> line defines the current template name as “Master” (it will be further indicated for page filling mechanism) and also creates Data::Master structure inside the wrapper class. In C++ it will look like “Data::Master context;” (if you are interested in details, you can always look at the generated file).

<% template page_main() %>MAIN TEMPLATE<% end %> <% template page_footer() %>All rights reserved<% end %> <% template page_left_sidebar() %>Left panel<% end %> lines define default values which will be derived to the user unless we override them (i.e. they are
virtual const char* page_main(){ return "MAIN TEMPLATE"; }
)

Now let’s try to build. Of course C++ compiler won’t handle the entire tmpl file. That’s why we need a utility which will, together with the library, process the template to the needed state.
We’ll create “make_templates.sh” within the project. Inside the file the necessary operations will be located. The given file can be easily replaced either by manual call of this utility or by registering it at the “executed part” of the environment:

#!/bin/bash

INPUT=""
OUTPUT=""

while getopts ":i:o:" opt; do
  case $opt in
    i)
      INPUT=$OPTARG
      ;;
    o)
      OUTPUT=$OPTARG
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

# copy the configuration file to the build folder
cp $INPUT/config.json $OUTPUT

# write all templates here
TEMPLATES="$INPUT/templates/master.tmpl"

# process templates to срр
cppcms_tmpl_cc $TEMPLATES -o $INPUT/all_tmpl.cpp

# collect templates to the library  
g++ -shared -fPIC $INPUT/all_tmpl.cpp -o $OUTPUT/libcpp_defskin.so -lcppcms -lbooster


Now we should add a “user step” in the settings of QtCreator project
Command: "./make_templates.sh"
Working dir: "%{sourceDir}"
Command arguments: "-i %{sourceDir} -o %{buildDir}"
Don’t forget to add “execution” to the file (chmod +x make_template.sh)

If the build went well, libcpp_defskin.so library will appear at the building directory.
The library can be built either statically or dynamically. I made it dynamically and wouldn’t recommend you to do statically as TMPL files should be often changed. Recompiling the project because of that is quite a thankless task.

config.json file should be altered in order to tie templates to the project

{        
   "WebSite" : {
      "root" : "",
      "host" : "localhost:8080",
      "locdomain" : "localhost",
   },
   "service" : {
      "ip"  : "0.0.0.0",
      "api" : "http",
      "port" : 8080
   },
   "http" : {
      "script" : "/mb.fcgi" ,
      "rewrite" : [
         { "regex" : "/media(/.+)", "pattern" : "$1" },
         { "regex" : ".*" , "pattern" : "/mb.fcgi$0" }
      ],
   },
   "views" : {
      "default_skin" : "defskin" ,
      "paths" : [ "./" ],
      "skins" : [ "cpp_defskin" ],
   },
}


Appropriate changes should be made in main.cpp:

#include "data/tmpl_master.h"
...
WebSite::main(std::string path)
{
    Data::Master tmpl;
    tmpl.page.title = path;
    tmpl.page.description = "description";
    tmpl.page.keywords = "keywords";
    tmpl.page.menuList.insert(std::pair("/","MAIN"));
    tmpl.page.menuList.insert(std::pair("/else","ELSE"));
    render("Master",tmpl);
}


We should see the template output when we start the project. Oops, I forgot to say about css and images.
Add one more point to config.json

"file_server" : {
      "enable" : true,
      "listing" : true,
      "document_root" : "./media"
   },


I should explain that by the given point we allow the binary file to see the file system.
The rules according to which it performs it are described in http{ «regex»: "/media(/.+)", «pattern»: "$1" } section.
So any request beginning with /media/ should be addressed to the “file server”.
Let's create a «media» folder in our project and also add an appropriate change to make_templates.sh:

# copy the media data to the build folder 
cp -R $INPUT/media $OUTPUT


Inside the «media» folder (in the project's source codes directory) create css subfolder and style.css file in it.
/* Eric Meyer's CSS Reset */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}
/* End of Eric Meyer's CSS Reset */

html {
    height: 100%;
}
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary {
    display: block;
}
body {
    font: 12px/18px Arial, sans-serif;
    width: 100%;
    height: 100%;
}
.wrapper {
    width: 800px;
    margin: 0 auto;
    min-height: 100%;
    height: auto !important;
    height: 100%;
}


/* Header
-----------------------------------------------------------------------------*/
.header {
    height: 50px;
    background: #FFE680;
}


/* Middle
-----------------------------------------------------------------------------*/
.middle {
    width: 100%;
    padding: 0 0 50px;
    position: relative;
}
.middle:after {
    display: table;
    clear: both;
    content: '';
}
.container {
    width: 100%;
    float: left;
    overflow: hidden;
}
.content {
    padding: 0 270px 0 270px;
}


/* Left Sidebar
-----------------------------------------------------------------------------*/
.left-sidebar {
    float: left;
    width: 250px;
    margin-left: -100%;
    position: relative;
    background: #B5E3FF;
}


/* Footer
-----------------------------------------------------------------------------*/
.footer {
    width: 800px;
    margin: -50px auto 0;
    height: 50px;
    background: #BFF08E;
    position: relative;
}


Let’s try to build it one more time.
Now, when the website looks like a first work of a beginner – we can proceed to the most important part.

Template Inheritance


Template inheritance mechanism is quite simple.
Define from which template we inherit and add redefining of the content output function.
Create tmpl_news.h file in data folder.

#ifndef TMPL_NEWS_H
#define TMPL_NEWS_H
#include "tmpl_master.h"

namespace Data {
  //-------------------------------------------------------------------------------------
  // Dsc: News content
  //-------------------------------------------------------------------------------------
  struct News :public Master{
    //-------------------------------------------------------------------------------------
    // Dsc: Main News
    //-------------------------------------------------------------------------------------
    std::string mainNews;
    //-------------------------------------------------------------------------------------
    // Dsc: Page constructor
    //-------------------------------------------------------------------------------------
    News() :
      Master()
    {}
    //-------------------------------------------------------------------------------------
    // Dsc: Lazy destructor
    //-------------------------------------------------------------------------------------
    ~News(){}
  };
}


#endif // TMPL_NEWS_H


Also add news.tmpl file to templates folder.

<% c++ #include "data/tmpl_news.h" %>
<% skin defskin %>
<% view News uses Data::News extends Master %>
<% template page_main() %><%= mainNews %><% end %>
<% end view %>
<% end skin %>


Add a path to the file in the build script:

TEMPLATES="$INPUT/templates/master.tmpl"
TEMPLATES="$TEMPLATES $INPUT/templates/news.tmpl"


Change main.cpp file

#include 
#include 
#include 
#include 
#include 
#include 

#include "data/tmpl_master.h"
#include "data/tmpl_news.h"


//-------------------------------------------------------------------------------------
// Dsc: Our class for page rendering, when some address is requested by the user 
//      First of all he will get here 
//-------------------------------------------------------------------------------------
class WebSite : public cppcms::application{
public:
  //-------------------------------------------------------------------------------------
  // Dsc: Constructor. Entry point.
  //-------------------------------------------------------------------------------------
  WebSite(cppcms::service &s) : cppcms::application(s)
  {
    dispatcher().assign("/news(.*)",&WebSite::news,this,1);
    mapper().assign("news","/news");

    dispatcher().assign("(/?)",&WebSite::master,this,1);
    mapper().assign("master","/");
  }
  //-------------------------------------------------------------------------------------
  // Dsc: The function we’ll get into if it’s not indicated otherwise in the constructor.  
  //      (more about it later)
  //-------------------------------------------------------------------------------------
  virtual void main(std::string path)
  {
    cppcms::application::main(path);
  }
  //-------------------------------------------------------------------------------------
  // Dsc: Basic content rendering 
  //-------------------------------------------------------------------------------------
  virtual void master(std::string path)
  {
    Data::Master tmpl;
    tmpl.page.title = path;
    tmpl.page.description = "description";
    tmpl.page.keywords = "keywords";
    tmpl.page.menuList.insert(std::pair("/","MASTER"));
    tmpl.page.menuList.insert(std::pair("/news","NEWS"));
    render("Master",tmpl);
  }
  //-------------------------------------------------------------------------------------
  // Dsc: News rendering
  //-------------------------------------------------------------------------------------
  virtual void news(std::string path)
  {
    Data::News tmpl;
    tmpl.page.title = path;
    tmpl.page.description = "description";
    tmpl.page.keywords = "keywords";
    tmpl.page.menuList.insert(std::pair("/","MASTER"));
    tmpl.page.menuList.insert(std::pair("/news","NEWS"));
    tmpl.mainNews = "Sensation! Nothing happened at our website!";
    render("News",tmpl);
  }
};

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
int main(int argc,char **argv)
{
  try {
    // create the service
    cppcms::service srv(argc,argv);
    // define the root 
    srv.applications_pool().mount(cppcms::applications_factory());
    // start
    srv.run();
  }
  catch(std::exception const &e) {
    std::cerr << "Failed: " << e.what() << std::endl;
    std::cerr << booster::trace(e) << std::endl;
    return 1;
  }
  return 0;
}

}


Major changes of the file occurred in constructor, where we had indicated which function is in charge of which page.
Now these pages can display different templates.
A crucial pint is the order of files list delivery to the template engine (children files should go after parents, otherwise errors will occur.

That’s where I am going to end the first part. Comments are appreciated.

Write your own articles at Kukuruku Hub

13 comments

andrew
It's fun, they called it CppCMS, but then they say:

What is CppCMS? CppCMS is a Free High Performance Web Development Framework (not a CMS) aimed at Rapid Web Application Development.
Kukuruku Hub
I guess they have some plans for future.
skazka
For those who are interested in developing web applications, there is also Wt.
fishlabsoman
Where is a link to the original?
habrahabr.ru/post/219899/
MikeDRush
Also we need to copy all comments. and post them here. This will be international site of our native web site
Where all can read — what we write!
fishlabsoman
Обойдетесь без коментов, пиндосы. Коменты им подавай, ага!
MikeDRush
Чуть-чуть… самые интересные подойдут. ☻
Kukuruku Hub
We are not going to translate all the articles and don't want to be a clone. We are in process of building community and making the project unique. Users will have much more opportunities at Kukuruku Hub in future.
comment deleted
DenZurin
You MUST give link to source. Otherwise this is plagiarism, theft, crime. Authors can sue you.
BTW Habrahabr is russian version of Slashdot. Do you really want to compete with Slashdot? It will not be easy.
MikeDRush
So, this is a great news for me. It's seem that in future i can read two instead of one interesting website! Keep going!
Kukuruku Hub
Thank you, Mike! I personally really appreciate your input! As you can see, we don't have a lot of users right now, so any support from community helps us to move forward. We are currently working on design for email notifications, as they basically look like shit. Let me know if you have any ideas related to whole project in general.

Read Next

Hi Everyone! We are about to launch a new project very soon - CrowdMind.co. Sign up to get a private beta access!