<!--toc--> |
|
## Overview |
|
The process of building CppCMS templates is following: |
|
1. Compile all sources of specific view together into single C++ file using [cppcms\_tmpl\_cc](/wikipp/en/page/ref_utils#tmpl). |
2. Compile C++ file into object file. |
3. 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](/wikipp/en/page/ref_utils#tmpl) 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 in namespace `vary`. You should specify parameter: `-n view_name`. |
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 template name. So if you compile with `-n skin1` all you strings would be taken from |
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 templates to same domain as the main program. |
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 come class from specific view |
he calls `render()` function of `worker_thread` class that |
seeks for registered views and uses them. |
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 form 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: |
|
1. You should compile your program with `--export-dynamic` option, otherwise dynamic casting would not work and you'll get error "incorrect content type" trying to render your views. |
2. Windows/Cygwin has strong restriction on undefined symbols in dll's. Thus you should not refer directly to any non-virtual member functions of your content objects, otherwise you would get linker errors trying to build dll. |
1. 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. |
2. 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` or |
`boost` function class for callback |
|
3. Windows skin dlls require link to `booster` library along with `cppcms` 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](/wikipp/en/page/ref_utils#tmpl) path to directory where |
libview.so is placed: |
Now add to your configuration file path to directory where |
libview.so is placed. |
|
templates.dirs = { "/usr/local/lib/youapp" } |
1. `views.paths` configuration should be an array of strings where each string represents the path to location |
of the views. |
2. `views.skins` is an array strings - skins names that should be loaded |
3. `views.default_skin` allows you to specify the default skin that should be used, if not defined the first one in `views.skins` will be used. |
3. `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. |
|
When application starts, it would try to load **any** shared |
object that is placed in this path. Thus, it is not good |
idea to save put your views into directory with other |
non-related libraries. |
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" ] |
} |
|
|