Templates: Building and Loading (v 1.x)
Overview
The process of building CppCMS templates is following:
- Compile all sources of specific view together into single C++ file using cppcms_tmpl_cc.
- Compile C++ file into object file.
- Link it together with program or create dynamically loadable object that can be loaded by CppCMS program.
Creation of C++ code
Can be done by invoking cppcms_tmpl_cc with a list of files, for example:
cppcms_tmpl_cc -o view.cpp main.tmpl page.tmpl article.tmpl
Note, when you derive classes from parents, you should compile them together in correct order.
For example for following hierarchy.
[master] / \ [page] [summary] / \ / \ [post] [info.] [archive] [recent_posts]
You should compile files as:
cppcms_tmpl_cc master.tmpl page.tmpl post.tmpl \ info.tmpl summary.tmpl archive.tmpl \ recent_posts.tmpl -o my_view.cpp
When you share some templates between various skins, and compile all then using empty skin name. You should specify parameter: -s skin_name
.
By default, templates compiler puts all translation strings in the domain that is named by skin name. So if you compile with -s skin1
all you strings would be taken from
skin1
domain. It can be overridden by specifying -d domain_name
switch.
Generally you want to put all skins to same domain as the main program.
How templates are loaded
Each C++ file that is generated from the template includes
static global constructor that registers all classes of specific view in libcppcms
.
When programmer wants to use some class from specific view
he calls render()
function of application
class that
seeks for registered skins and uses them.
Thus, everything you need to do is link this object with your library or load it dynamically.
Static Linking with Compiled Object
This is the simplest way to add the template, for example:
cppcms_tmpl_cc -o view.cpp master.tmpl ... g++ -O2 -Wall view.cpp -o view.o g++ application_objects.o view.o -lcppcms -o app
Using Libraries of Views
Sometimes, you may create a library of several views and try to link with them. For example:
g++ -fPIC -DPIC view1.cpp -o view1.o g++ -fPIC -DPIC view2.cpp -o view2.o g++ -shared view1.o view2.o -lcppcms -o libview.so
Now you link this library directly with your program:
g++ application_objects.o -L. -lview -lcppcms -o app
You can also create static library and link with it.
g++ view1.cpp -o view1.o g++ view2.cpp -o view2.o ar cru libview.a view1.o view2.o ranlib libview.a
Now, if you link static the library as is, it would not work!!! At least with GNU linker.
GNU linker "optimizes" the code and discovers that there is no symbols in application objects that refer to the symbols of libview.a and would not include it in link process.
In order to make everything work you should link as following:
g++ application_objects.o \ -Wl,--whole-archive libview.a -Wl,--no-whole-archive \ -lcppcms -o app
It would force the linker include all objects from libview.a and cause everything work correctly.
Note: You do not need this for dynamically loaded libraries like so or dll. Because, by default they include whole archive.
Dynamic Loading of Views
You have an option load all views dynamically from shared object or dll. This option have following restrictions:
- You should compile your program with
--export-dynamic
or-rdynamic
option, otherwise dynamic casting would not work and you'll get error "incorrect content type" trying to render your skins. Windows platform has strong restriction on undefined symbols in dll's. Thus you should not refer directly to any undefined member functions of your content objects, otherwise you would get linker errors trying to build dll.
In order to override this and still call functions placed in content class, you may define its members as virtual or just use
std
,std::tr1
,booster
orboost
function class for callbackWindows skin dlls require link to
booster
library along withcppcms
library as well.And the link must be dynamic, i.e. skin dll should be linked to cppcms.dll and booster.dll.
For example:
Build your loadable view:
cppcms_tmpl_cc -o view.cpp master.tmpl ... g++ -fPIC -DPIC view.cpp -o view.o g++ -shared view.o -lcppcms -o libview.so
Link your program
g++ --export-dynamic app_objects.o -lcppcms -o app
Now add to your configuration file path to directory where libview.so is placed.
views.paths
configuration should be an array of strings where each string represents the path to location of the views.views.skins
is an array strings - skins names that should be loadedviews.default_skin
allows you to specify the default skin that should be used, if not defined the first one inviews.skins
will be used.views.auto_reload
boolean variable allow you to enable auto-reloading skins for faster debugging, where the application would reload the dll or shared object if it was recompiled without restarting the application.Note: this may significantly reduce application performance. Use this only for debugging.
For example, a part of config.js:
"views" : { "paths" : [ "/usr/lib/app" , "/usr/local/lib/app" ], "skins" : [ "blue", "orange" , "green" ] }