瀏覽代碼

Added framework cppcms. (#3173)

Elgar 7 年之前
父節點
當前提交
9e6d303975

+ 1 - 0
.travis.yml

@@ -25,6 +25,7 @@ env:
     - "TESTDIR=CSharp/nancy"
     - "TESTDIR=CSharp/revenj"
     - "TESTDIR=CSharp/servicestack"
+    - "TESTDIR=C++/cppcms"
     - "TESTDIR=C++/ffead-cpp"
     - "TESTDIR=C++/cpoll_cppsp"
     - "TESTDIR=C++/cutelyst"

+ 4 - 0
frameworks/C++/cppcms/.gitignore

@@ -0,0 +1,4 @@
+mycppcms
+config.js
+fortunes_view.cpp
+

+ 22 - 0
frameworks/C++/cppcms/Makefile

@@ -0,0 +1,22 @@
+LIBS=-lcppcms -lbooster -lcppdb
+
+CXXFLAGS += -O3 -s -DNDEBUG -std=c++11 -I$(CPPCMS_HOME)/include -I$(CPPDB_HOME)/include -L$(CPPCMS_HOME)/lib -L$(CPPDB_HOME)/lib
+
+CSRC =  src/fortunes_view.cpp\
+	src/main.cpp\
+	src/test_db_base.cpp\
+	src/test_db.cpp\
+	src/test_fortunes.cpp\
+	src/test_simple.cpp
+
+all: clean main
+
+main: $(CSRC) src/fortunes_view.cpp
+	$(CXX) $(CXXFLAGS) -Wall $(CSRC) -o mycppcms $(LIBS)
+
+src/fortunes_view.cpp: src/fortunes.tmpl src/data.h
+	$(CPPCMS_HOME)/bin/cppcms_tmpl_cc src/fortunes.tmpl -o src/fortunes_view.cpp
+
+clean:
+	rm -fr mycppcms *.exe src/fortunes_view.cpp cppcms_rundir
+

+ 24 - 0
frameworks/C++/cppcms/README.md

@@ -0,0 +1,24 @@
+# CppCMS framework
+All Test are implemented. 
+
+
+## What is CppCMS
+CppCMS is a Free High-Performance Web Development Framework (not a CMS) aimed at Rapid Web Application Development. It differs from most other web development frameworks like Python Django, Java Servlets in the following ways:
+
+- It is designed and tuned to handle extremely high loads.
+- It uses modern C++ as the primary development language in order to achieve the first goal.
+- It is designed for developing both Web Sites and Web Services.
+
+It is available under open source LGPLv3 license and alternative Commercial License for users who need an alternative license for proprietary software development.
+(From homepage)
+
+
+## Problems/DOTO
+- Test PostgreSQL
+- Test 7 CachedWorld uses normal worlds table
+- Fix direct conection WARNING: Required response size header missing, please include either "Content-Length" or "Transfer-Encoding"
+
+
+
+## Links
+[Homepage](http://cppcms.com/wikipp/en/page/main)

+ 77 - 0
frameworks/C++/cppcms/benchmark_config.json

@@ -0,0 +1,77 @@
+{
+  "framework": "cppcms",
+  "tests": [{
+    "default": {
+      "setup_file": "setup-nginx-mysql",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "update_url": "/updates/",
+      "fortune_url": "/fortunes",
+      "plaintext_url": "/plaintext",
+      "cached_query_url": "/cached-worlds/",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "None",
+      "language": "C++",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "CppCMS-MySQL-nginx",
+      "notes": ""
+    },
+    "postgres": {
+      "setup_file": "setup-nginx-postgresql",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "update_url": "/updates/",
+      "fortune_url": "/fortunes",
+      "plaintext_url": "/plaintext",
+      "cached_query_url": "/cached-worlds/",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "postgres",
+      "framework": "None",
+      "language": "C++",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "CppCMS-PostgreSQL-nginx",
+      "notes": ""
+    },
+    "direct": {
+      "setup_file": "setup-direct-mysql",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "update_url": "/updates/",
+      "fortune_url": "/fortunes",
+      "plaintext_url": "/plaintext",
+      "cached_query_url": "/cached-worlds/",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "None",
+      "language": "C++",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "CppCMS-MySQL-NoFront",
+      "notes": "HTTP 1.0 and no Content-length header"
+    }
+  }]
+}

+ 19 - 0
frameworks/C++/cppcms/config.js.tpl

@@ -0,0 +1,19 @@
+{
+    "service": {
+        "api": "--api--",
+        --address--
+    },
+    "http": {
+        "script": "/"
+    },
+    "gzip": {
+        "enable": false
+    },
+    "app": {
+        "db_connection_string": "--db--"
+    },
+    "cache": {
+        "backend": "thread_shared",
+        "limit": 10000
+    }
+}

+ 50 - 0
frameworks/C++/cppcms/nginx.conf

@@ -0,0 +1,50 @@
+# This file is based on /usr/local/nginx/conf/nginx.conf.default.
+
+worker_processes auto;
+error_log stderr error;
+
+events {
+    # This needed to be increased because the nginx error log said so.
+    # http://nginx.org/en/docs/ngx_core_module.html#worker_connections
+    worker_connections  65535;
+    multi_accept on;
+}
+
+http {
+    default_type  application/octet-stream;
+    client_body_temp_path      /tmp;
+
+    # turn off request logging for performance
+    access_log off;
+
+    # I think these only options affect static file serving
+    sendfile        on;
+    tcp_nopush      on;
+
+    # Allow many HTTP Keep-Alive requests in a single TCP connection before
+    # closing it (the default is 100). This will minimize the total number
+    # of TCP connections opened/closed. The problem is that this may cause
+    # some worker processes to be handling too connections relative to the
+    # other workers based on an initial imbalance, so this is disabled for
+    # now.
+    keepalive_requests 1000;
+
+    #keepalive_timeout  0;
+    keepalive_timeout  65;
+
+    server {
+        # For information on deferred, see:
+        # http://nginx.org/en/docs/http/ngx_http_core_module.html#listen
+        # http://www.techrepublic.com/article/take-advantage-of-tcp-ip-options-to-optimize-data-transmission/
+        # The backlog argument to listen() is set to match net.ipv4.tcp_max_syn_backlog and net.core.somaxconn
+        listen       8080 default_server deferred backlog=65535 reuseport;
+        server_name  localhost;
+
+        location / {
+            fastcgi_pass unix:/var/tmp/cppcms.sock;
+            
+            fastcgi_split_path_info ^()((?:/.*))?$;  
+            fastcgi_param  PATH_INFO       $fastcgi_path_info;
+        }
+    }
+}

+ 6 - 0
frameworks/C++/cppcms/setup-direct-mysql.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+DRIVER=mysql
+NGINX=
+
+source ${TROOT}/setup.sh

+ 6 - 0
frameworks/C++/cppcms/setup-nginx-mysql.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+DRIVER=mysql
+NGINX=1
+
+source ${TROOT}/setup.sh

+ 6 - 0
frameworks/C++/cppcms/setup-nginx-postgresql.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+DRIVER=postgresql
+NGINX=1
+
+source ${TROOT}/setup.sh

+ 42 - 0
frameworks/C++/cppcms/setup.sh

@@ -0,0 +1,42 @@
+#!/bin/bash
+
+fw_depends mysql postgresql
+
+cp config.js.tpl config.js
+
+fw_depends cppcms cppcms-cppdb
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${CPPCMS_HOME}/lib:${CPPDB_HOME}/lib
+
+make
+
+
+#Database
+#http://cppcms.com/sql/cppdb/connstr.html
+#http://cppcms.com/sql/cppdb/backendref.html
+if [ "${DRIVER}" == "mysql" ]; then
+    dbstring="mysql:host="$DBHOST";database=hello_world;user=benchmarkdbuser;password=benchmarkdbpass;set_charset_name=utf8;@pool_size=10"
+else
+    dbstring="postgresql:host="$DBHOST";dbname=hello_world;user=benchmarkdbuser;password=benchmarkdbpass;@pool_size=10"
+fi
+sed -i 's|\(.*\)--db--\(.*\)|\1'"$dbstring"'\2|g' config.js
+
+
+#http://cppcms.com/wikipp/en/page/cppcms_1x_tut_web_server_config#Nginx
+#configure Nginx
+if [ -n "${NGINX}" ]; then
+    fw_depends nginx
+    nginx -c ${TROOT}/nginx.conf
+
+    sed -i 's|\(.*\)--api--\(.*\)|\1'"fastcgi"'\2|g' config.js
+    sed -i 's|\(.*\)--address--\(.*\)|\1"socket" : "/var/tmp/cppcms.sock"\2|g' config.js
+    #for ip based connection
+    #sed -i 's|\(.*\)--address--\(.*\)|\1"ip": "127.0.0.1" , "port" : 8081\2|g' config.js
+else
+    sed -i 's|\(.*\)--api--\(.*\)|\1'"http"'\2|g' config.js
+    sed -i 's|\(.*\)--address--\(.*\)|\1"port": 8080\2|g' config.js
+fi
+
+
+
+./mycppcms -c config.js
+

+ 1 - 0
frameworks/C++/cppcms/src/.gitignore

@@ -0,0 +1 @@
+fortunes_view.cpp

+ 25 - 0
frameworks/C++/cppcms/src/data.h

@@ -0,0 +1,25 @@
+#ifndef DATA_H
+#define DATA_H
+
+#include <cppcms/view.h>
+
+#include <string>
+#include <vector>
+
+class fortune {
+public:
+    int id;
+    std::string message;
+};
+
+typedef std::vector<fortune> fortune_vector;
+
+class data_holder : public cppcms::base_content {
+public:
+    fortune_vector fortunes;
+};
+
+
+
+#endif /* DATA_H */
+

+ 4 - 0
frameworks/C++/cppcms/src/fortunes.tmpl

@@ -0,0 +1,4 @@
+<% c++ #include "data.h" %>
+<% skin my_skin %>
+<% view message uses data_holder %>
+<% template render() %><!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><% foreach fortune_item in fortunes %><% item %><tr><td><%= fortune_item.id %></td><td><%= fortune_item.message %></td></tr><% end %><% end %></table></body></html><% end template %><% end view %><% end skin %>

+ 21 - 0
frameworks/C++/cppcms/src/fortunes_alt.tmpl

@@ -0,0 +1,21 @@
+<% c++ #include "data.h" %>
+<% skin my_skin %>
+<% view message uses data_holder %>
+<% template render() %>
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+<% foreach fortune_item in fortunes %>
+    <% item %>
+    <tr><td><%= fortune_item.id %></td><td><%= fortune_item.message %></td></tr>
+    <% end %>
+<% end %>
+</table>
+</body>
+</html>
+<% end template %>
+<% end view %>
+<% end skin %>

+ 40 - 0
frameworks/C++/cppcms/src/main.cpp

@@ -0,0 +1,40 @@
+#include <cppcms/service.h>
+#include <cppcms/applications_pool.h>
+
+#include <cppcms/http_response.h>
+#include <cppcms/url_dispatcher.h>
+
+#include <iostream>
+
+#include "test_simple.h"
+#include "test_fortunes.h"
+#include "test_db.h"
+
+class myapp : public cppcms::application {
+public:
+
+    myapp(cppcms::service &srv) : cppcms::application(srv) {
+
+        attach(new test_simple(srv), "/json()", 0);
+        attach(new test_simple(srv), "/plaintext()", 0);
+
+        attach(new test_fortunes(srv), "/fortunes()", 1);
+
+        attach(new test_db(srv), "/db()", 0);
+        attach(new test_db(srv), "/queries/.*", 0);
+        attach(new test_db(srv), "/updates/.*", 0);
+        attach(new test_db(srv), "/cached-worlds/.*", 0);
+
+    }
+
+};
+
+int main(int argc, char **argv) {
+    try {
+        cppcms::service app(argc, argv);
+        app.applications_pool().mount(cppcms::applications_factory<myapp>());
+        app.run();
+    } catch (std::exception const &e) {
+        std::cerr << e.what() << std::endl;
+    }
+}

+ 166 - 0
frameworks/C++/cppcms/src/test_db.cpp

@@ -0,0 +1,166 @@
+#include "test_db.h"
+#include <cppcms/http_response.h>
+#include <cppcms/url_dispatcher.h>
+#include <cppcms/json.h>
+#include <cppcms/cache_interface.h>
+#include <cppcms/serialization.h>
+
+#include  <ctime>
+
+class world_object : public cppcms::serializable {
+public:
+    int id;
+    int randomNumber;
+
+    void serialize(cppcms::archive &a) {
+        a & id & randomNumber;
+    }
+};
+
+test_db::test_db(cppcms::service &s) : test_db_base(s) {
+    srand(std::time(nullptr));
+    dispatcher().assign("/db", &test_db::servre_db, this);
+    dispatcher().assign("/queries/(.{0,3}).*", &test_db::servre_queries, this, 1);
+    dispatcher().assign("/updates/(.{0,3}).*", &test_db::servre_updates, this, 1);
+    dispatcher().assign("/cached-worlds/(.{0,3}).*", &test_db::servre_cached_worlds, this, 1);
+
+}
+
+void test_db::servre_db() {
+    int r = get_random_id();
+    world_object wo;
+    if (get_world_object_db(wo, r)) {
+        cppcms::json::value my_object;
+        my_object["id"] = wo.id;
+        my_object["randomNumber"] = wo.randomNumber;
+        send_json(my_object);
+    }
+}
+
+void test_db::servre_queries(const std::string val) {
+    int count = cinvert_constraint_count(val);
+    cppcms::json::array my_object;
+
+    for (int i = 0; i < count; ++i) {
+        cppcms::json::value my_val;
+        int r = get_random_id();
+
+        world_object wo;
+        if (get_world_object_db(wo, r)) {
+            my_val["id"] = wo.id;
+            my_val["randomNumber"] = wo.randomNumber;
+            my_object.push_back(my_val);
+        } else {
+            return;
+        }
+    }
+
+    send_json(my_object);
+}
+
+void test_db::servre_updates(const std::string val) {
+    int count = cinvert_constraint_count(val);
+    cppcms::json::array my_object;
+
+    for (int i = 0; i < count; ++i) {
+        cppcms::json::value my_val;
+        int r = get_random_id();
+
+        world_object wo;
+        if (get_world_object_db(wo, r)) {
+            my_val["id"] = wo.id;
+            my_val["randomNumber"] = wo.randomNumber;
+            int rv = get_random_value();
+            wo.randomNumber = rv;
+            if (!update_world_object_db(wo)) {
+                return;
+            }
+
+            my_object.push_back(my_val);
+        } else {
+            return;
+        }
+    }
+
+    send_json(my_object);
+}
+
+void test_db::servre_cached_worlds(const std::string val) {
+    int count = cinvert_constraint_count(val);
+    cppcms::json::array my_object;
+    for (int i = 0; i < count; ++i) {
+        cppcms::json::value my_val;
+        int r = get_random_id();
+        world_object wo;
+        if (!cache().fetch_data(std::to_string(r), wo)) {
+            if (get_world_object_db_ch(wo, r)) {
+                cache().store_data(std::to_string(r), wo);
+            } else {
+                return;
+            }
+        }
+        my_val["id"] = wo.id;
+        my_val["randomNumber"] = wo.randomNumber;
+        my_object.push_back(my_val);
+    }
+
+    send_json(my_object);
+
+
+}
+
+int test_db::get_random_id() {
+    return rand() % (MAX_WORLD_ID - 1) + 1;
+}
+
+int test_db::get_random_value() {
+    return rand() % (MAX_RANDOM_VALUE - 1) + 1;
+}
+
+int test_db::cinvert_constraint_count(const std::string & val) {
+    int count = 0;
+    count = atoi(val.c_str());
+    if (count < 1)count = 1;
+    if (count > MAX_QUERY_COUNT)count = MAX_QUERY_COUNT;
+    return count;
+}
+
+//For CachedWorld
+
+bool test_db::get_world_object_db_ch(world_object &c, int id) {
+    cppdb::result res;
+    res = sql << "SELECT id, randomNumber FROM world WHERE id = ?" << id << cppdb::row;
+    if (res.empty()) {
+        response().make_error_response(response().internal_server_error, "SQL result empty");
+        return false;
+    }
+    res >> c.id >> c.randomNumber;
+    return true;
+}
+
+bool test_db::get_world_object_db(world_object &c, int id) {
+    cppdb::result res;
+    res = sql << "SELECT id, randomNumber FROM world WHERE id = ?" << id << cppdb::row;
+    if (res.empty()) {
+        response().make_error_response(response().internal_server_error, "SQL result empty");
+        return false;
+    }
+    res >> c.id >> c.randomNumber;
+    return true;
+}
+
+bool test_db::update_world_object_db(const world_object &c) {
+    cppdb::statement st = sql
+            << "UPDATE world SET randomNumber = ? WHERE id = ?"
+            << c.randomNumber << c.id;
+    st.exec();
+    return true;
+}
+
+void test_db::send_json(const cppcms::json::value & json) {
+    response().content_type("application/json");
+    response().date(std::time(nullptr));
+    response().out() << json;
+}
+
+

+ 30 - 0
frameworks/C++/cppcms/src/test_db.h

@@ -0,0 +1,30 @@
+#ifndef TEST02_DB_H
+#define TEST02_DB_H
+#include "test_db_base.h"
+
+class world_object;
+
+class test_db : public test_db_base {
+    const int MAX_WORLD_ID = 10000;
+    const int MAX_RANDOM_VALUE = 10000;
+    const int MAX_QUERY_COUNT = 500;
+public:
+    test_db(cppcms::service &s);
+    void servre_db();
+    void servre_queries(const std::string a);
+    void servre_updates(const std::string a);
+    void servre_cached_worlds(const std::string a);
+private:
+    bool update_world_object_db(const world_object &c);
+    bool get_world_object_db(world_object &c, int id);
+    bool get_world_object_db_ch(world_object &c, int id);
+    int cinvert_constraint_count(const std::string & val);
+    int get_random_id();
+    int get_random_value();
+    void send_json(const cppcms::json::value & json);
+};
+
+
+
+#endif /* TEST02_DB_H */
+

+ 15 - 0
frameworks/C++/cppcms/src/test_db_base.cpp

@@ -0,0 +1,15 @@
+#include "test_db_base.h"
+
+#include <cppcms/json.h>
+
+test_db_base::test_db_base(cppcms::service &srv) : cppcms::application(srv) {
+    db_connection_str = settings().get<std::string>("app.db_connection_string");
+}
+
+void test_db_base::init() {
+    sql.open(db_connection_str);
+}
+
+void test_db_base::clear() {
+    sql.close();
+}

+ 21 - 0
frameworks/C++/cppcms/src/test_db_base.h

@@ -0,0 +1,21 @@
+#ifndef TEST_DB_BASE_H
+#define TEST_DB_BASE_H
+
+#include <cppcms/application.h>
+#include <cppdb/frontend.h>
+
+#include <string>
+
+class test_db_base : public cppcms::application {
+public:
+    test_db_base(cppcms::service &s);
+    virtual void init();
+    virtual void clear();
+protected:
+    cppdb::session sql;
+private:
+    std::string db_connection_str;
+};
+
+#endif /* TEST_DB_BASE_H */
+

+ 43 - 0
frameworks/C++/cppcms/src/test_fortunes.cpp

@@ -0,0 +1,43 @@
+#include "test_fortunes.h"
+
+#include "data.h"
+
+#include <cppcms/http_response.h>
+#include <cppcms/url_dispatcher.h>
+#include <cppcms/json.h>
+
+#include <algorithm>
+#include <ctime>
+
+test_fortunes::test_fortunes(cppcms::service &s) : test_db_base(s) {
+    dispatcher().assign("", &test_fortunes::servre, this);
+}
+
+void test_fortunes::servre() {
+    data_holder c;
+    get_fortunes_db(c);
+
+    fortune fortune_object;
+    fortune_object.id = 0;
+    fortune_object.message = "Additional fortune added at request time.";
+    c.fortunes.push_back(fortune_object);
+
+    std::sort(c.fortunes.begin(), c.fortunes.end(), [ ](const fortune& a, const fortune & b) {
+        return a.message.compare(b.message) < 0;
+    });
+
+    response().date(std::time(nullptr));
+    render("message", c);
+}
+
+bool test_fortunes::get_fortunes_db(data_holder &dh) {
+    fortune_vector &c = dh.fortunes;
+    cppdb::result res;
+    res = sql << "SELECT id, message FROM fortune";
+    while (res.next()) {
+        fortune f;
+        res >> f.id >> f.message;
+        c.push_back(f);
+    }
+    return true;
+}

+ 18 - 0
frameworks/C++/cppcms/src/test_fortunes.h

@@ -0,0 +1,18 @@
+#ifndef TEST04_FORTUNES_H
+#define TEST04_FORTUNES_H
+#include "test_db_base.h"
+
+
+class data_holder;
+
+class test_fortunes : public test_db_base {
+public:
+    test_fortunes(cppcms::service &s);
+    bool get_fortunes_db(data_holder &c);
+    void servre();
+private:
+
+};
+
+#endif /* TEST04_FORTUNES_H */
+

+ 26 - 0
frameworks/C++/cppcms/src/test_simple.cpp

@@ -0,0 +1,26 @@
+#include "test_simple.h"
+
+#include <cppcms/http_response.h>
+#include <cppcms/url_dispatcher.h>
+#include <cppcms/json.h>
+
+#include  <ctime>
+
+test_simple::test_simple(cppcms::service &s) : cppcms::application(s) {
+    dispatcher().assign("/json", &test_simple::servre_json, this);
+    dispatcher().assign("/plaintext", &test_simple::servre_plaintext, this);
+}
+
+void test_simple::servre_json() {
+    response().content_type("application/json");
+    cppcms::json::value my_object;
+    my_object["message"] = "Hello, World!";
+    response().date(std::time(nullptr));
+    response().out() << my_object;
+}
+
+void test_simple::servre_plaintext() {
+    response().content_type("text/plain");
+    response().date(std::time(nullptr));
+    response().out() << "Hello, World!";
+}

+ 15 - 0
frameworks/C++/cppcms/src/test_simple.h

@@ -0,0 +1,15 @@
+#ifndef TEST01_JSON_H
+#define TEST01_JSON_H
+#include <cppcms/application.h>
+
+class test_simple : public cppcms::application {
+public:
+    test_simple(cppcms::service &s);
+    void servre_json();
+    void servre_plaintext();
+private:
+
+};
+
+#endif /* TEST01_JSON_H */
+

+ 31 - 0
toolset/setup/linux/frameworks/cppcms-cppdb.sh

@@ -0,0 +1,31 @@
+#!/bin/bash
+
+fw_installed cppcms-cppdb && return 0
+fw_depends cppcms
+#libmysqld-dev
+fw_depends cmake libpq-dev
+
+#http://cppcms.com/sql/cppdb/build.html
+
+VERSION=0.3.1
+BACKNAME=cppdb
+CPPDB_HOME=$IROOT/$BACKNAME-$VERSION
+CPPDBROOT=${CPPDB_HOME}-install
+
+fw_get -o $BACKNAME-$VERSION.tar.bz2 https://download.sourceforge.net/project/cppcms/$BACKNAME/$VERSION/$BACKNAME-$VERSION.tar.bz2
+fw_untar $BACKNAME-$VERSION.tar.bz2
+
+cd $BACKNAME-$VERSION
+rm -rf build
+mkdir build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX=${CPPDBROOT} ..
+
+make
+#make test
+sudo make install
+#make clean
+
+
+echo "export CPPDB_HOME=${CPPDBROOT}" > $IROOT/cppcms-cppdb.installed
+source $IROOT/cppcms-cppdb.installed

+ 30 - 0
toolset/setup/linux/frameworks/cppcms.sh

@@ -0,0 +1,30 @@
+#!/bin/bash
+
+fw_installed cppcms && return 0
+fw_depends cmake libpcre3-dev zlib1g-dev libgcrypt11-dev libicu-dev
+
+#http://cppcms.com/wikipp/en/page/cppcms_1x_build
+
+#note '-rc1' in the url
+VERSION=1.1.1
+BACKNAME=cppcms
+CPPCMS_HOME=$IROOT/$BACKNAME-$VERSION
+CPPCMSROOT=${CPPCMS_HOME}-install
+
+
+fw_get -o $BACKNAME-$VERSION.tar.bz2 https://download.sourceforge.net/project/cppcms/$BACKNAME/$VERSION-rc1/$BACKNAME-$VERSION.tar.bz2
+fw_untar $BACKNAME-$VERSION.tar.bz2
+
+cd $BACKNAME-$VERSION
+rm -rf build
+mkdir build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX=${CPPCMSROOT} ..
+
+make
+#make test
+make install
+#make clean
+
+echo "export CPPCMS_HOME=${CPPCMSROOT}" > $IROOT/cppcms.installed
+source $IROOT/cppcms.installed