Темплейты: Сборка и загрузка (v 1.x)
Общий обзор
Процесс сборки темлейтов CppCMS:
- Скомпилируйте все исходники указанных view вместе в один C++-файл, используя cppcms_tmpl_cc.
- Скомпилируйте C++-файл в объектный файл.
- Слинкуйте его вместе с программой или создайте динамически подгружаемый объект, который может подгружаться CppCMS-программой.
Создание C++-кода
Может быть призведен вызовом cppcms_tmpl_cc со списком файлов, например:
cppcms_tmpl_cc -o view.cpp main.tmpl page.tmpl article.tmpl
Заметьте, что когда Вы наследуете классы из родителей, необходимо компилировать их вместе в правильной очередности.
Например, для следующей иерархии:
[master] / \ [page] [summary] / \ / \ [post] [info.] [archive] [recent_posts]
Вам необходимо скомпилировать файлы так:
cppcms_tmpl_cc master.tmpl page.tmpl post.tmpl \ info.tmpl summary.tmpl archive.tmpl \ recent_posts.tmpl -o my_view.cpp
Когда вы разделяете какие-либо темплейты между несколькими skin'ами и затем их все компилируете, используя пустое имя skin'а, Вы должны указать параметр: -s skin_name
.
По-умолчанию, копилятор темплейтов кладет все строки перевода в домен, называемый именем skin'а. Поэтому, при компиляции с -s skin1
все Ваши строки должны будут браться из домена skin1
. Это может быть переопределено указанием ключа -d domain_name
.
В основном, старайтесь расположить все skin'ы в том-же домене, что и главная программа.
Как загружаются темплейты
Каждый C++-файл, генерируемый из темплейта включает статический глобальный конструктор, регистрирующий все классы определенного view в libcppcms
.
Когда программист хочет использовать какой-либо класс из определенного view, он вызывает функцию render()
класса application
, которая ищет зарегистрированные skin'ы и использует их.
Следовательно, все что Вам нужно сделать - это слинковать этот объект с Вашей библиотекой или подгрузить его динамически.
Статическая линковка со скомпилированным объектом
Это простейший способ добавить темплейт, например:
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
Использование библиотеки view
Возможно, Вам потребуется создать библиотеку нескольких view и нужно будет попытаться прилинковаться к ним. Например:
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
Теперь можете прилинковать эту библиотеку напрямую к Вашей программе:
g++ application_objects.o -L. -lview -lcppcms -o app
Вы можете, также, создать статическую библиотеку и прилинковать ее.
g++ view1.cpp -o view1.o g++ view2.cpp -o view2.o ar cru libview.a view1.o view2.o ranlib libview.a
Теперь, если Вы прилинкуете статическую библиотеку как-есть, она не будет работать!!! По крайней мере с GNU-линкером.
GNU-линкер "оптимизирует" код и обнаружит, что в объектах приложения нет символов, относящихся к символам libview.a и не включит их в процесс линковки.
Чтобы все заработало, нужно производить лннковку так:
g++ application_objects.o \ -Wl,--whole-archive libview.a -Wl,--no-whole-archive \ -lcppcms -o app
Это заставит линкер включить все объекты из libview.a и всё станет работать корректно.
Примечание: Это не потребуется для динамически подгружаемых библиотек, таких как so или dll. Потому, что по-умолчанию они включают весь архив полностью.
Динамическая зарузка view
У вас есть выбор - загружать все view динамически из разделяемого объекта или dll. У него есть следующие ограничения:
- Вам потребуется скомпилировать Вашу программу с опцией
--export-dynamic
или-rdynamic
, иначе динамическое приведение объектов (dynamic casting - прим. пер.) не будет работать и Вы получите ошибку "incorrect content type" ("некорректный тип содержимого" - прим. пер.) пытаясь отрендерить свои skin'ы. У платформы Windows строгие ограничения на неизвестные символы в dll'ах. Поэтому, Вы не должны ссылаться напрямую на какие-либо неизвестные функции-члены Ваших content-объектов, иначе получите ошибки линкера при попытке сборки dll.
Чтобы переопределить это и все же вызвать функции-члены, расположенные в content-классе, можно объявить его члены виртуальными или просто использовать функцию класса
std
,std::tr1
,booster
илиboost
для обратного вызова.dll'ы skin'ов в Windows'е также требуют линковки к библиотеке
booster
вместе с библиотекойcppcms
.И ссылка должна быть динамической, т.е. dll skin'а должен быть прилинкован к cppcms.dll и booster.dll.
Например:
Соберите подгружаемые 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
Прилинкуйте их к программе:
g++ --export-dynamic app_objects.o -lcppcms -o app
Добавьте в Ваш конфигурационный файл путь к директории с libview.so.
views.paths
должен быть массивом строк, представляющих собой путь к размещению view'ек.views.skins
- массив строк с именами skin'ов, которые должны быть подгружены.views.default_skin
позволяет указать skin, который должен использоваться по-умолчанию. Если он не определен - будет использоваться первый изviews.skins
.views.auto_reload
- булева переменная, позволяющая включить авто-перезагрузку skin'ов для более быстрой отладки. При этом, приложение должно перезагружать dll или разделяемый объект, в случае его перекомпиляции - без перезапуска приложения.Примечание: это может значительно снизить производительность приложения. Используйте это только для отладки.
Например, часть config.js:
"views" : { "paths" : [ "/usr/lib/app" , "/usr/local/lib/app" ], "skins" : [ "blue", "orange" , "green" ] }