战魂小筑

讨论群:309800774 知乎关注:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxu

   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  257 随笔 :: 0 文章 :: 506 评论 :: 0 Trackbacks

#

最近从Qt4.7.0 升级到 Qt4.8.2, 装好了新的open sdk, 但是观察工程中的引用依旧是4.7.0

在Windows环境变量中没有找到$(QTDIR)

随即在Qt的Visual Studio 插件菜单中, Qt->Qt Options-> Qt Versions

设置Default Qt/Win version为新版本

选中原有的Qt工程, 在插件菜单中找到Qt Project Settings->Properties->Version中,将版本设置为最新版本

如果装有Visual AssitX, 此时这东西应该开始Parse新的Qt库了

have fun 微笑!

posted @ 2012-07-14 15:35 战魂小筑 阅读(12911) | 评论 (0)编辑 收藏

MySQL++在MySQL原始C接口上做了一些封装, 给操作带来很大便利.

最近遇到DB服务器中报出一个MySQL的错误:Commands out of sync; you can't run this command now,2014

查阅很多代码, 解决方法都是使用C接口的方式, 模仿其解决方法,在MySQL++中找到了比较好的解决方案:

方案A: 清空每次未使用的记录

for (int i = 1; DataQuery.more_results(); ++i)
{
   DataQuery.store_next();                
}

其中 DataQuery类型为mysqlpp::Query

 

方案B: 对于存储过程中,使用了多个select语句返回同样的列结果, 就需要使用以下语句

static void print_multiple_results(Query& query)
{
    // 执行查询并输出结果表
 StoreQueryResult res = query.store();
 print_result(res, 0);
 for (int i = 1; query.more_results(); ++i) {
  res = query.store_next();
  print_result(res, i);
 }
}
 
参考文章:http://hi.baidu.com/freeknight/item/ea9fd88e7d291f854514cf43
posted @ 2012-06-13 17:57 战魂小筑 阅读(6696) | 评论 (0)编辑 收藏

本文转自: http://coolshell.cn/articles/7526.html

 

Lisp之魅

长久以来,Lisp一直被许多人视为史上最非凡的编程语言。它不仅在50多年前诞生的时候带来了诸多革命性的创新并极大地影响了后来编程语言的发展,即使在一大批现代语言不断涌现的今天,Lisp的诸多特性仍然未被超越。当各式各样的编程语言摆在面前,我们可以从运行效率、学习曲线、社区活跃度、厂商支持等多种不同的角度进行评判和选择,但我特别看中的一点在于语言能否有效地表达编程者的设计思想。学习C意味着学习如何用过程来表达设计思想,学习Java意味着学习如何用对象来表达设计思想,而虽然Lisp与函数式编程有很大的关系,但学习Lisp绝不仅仅是学习如何用函数表达设计思想。实际上,函数式编程并非Lisp的本质,在已经掌握了lambda、高阶函数、闭包、惰性求值等函数式编程概念之后,学习Lisp仍然大大加深了我对编程的理解。学习Lisp所收获的是如何“自由地”表达你的思想,这正是Lisp最大的魅力所在,也是这门古老的语言仍然具有很强的生命力的根本原因。

Lisp之源

Lisp意为表处理(List Processing),源自设计者John McCarthy于1960年发表的一篇论文《符号表达式的递归函数及其机器计算》。McCarthy在这篇论文中向我们展示了用一种简单的数据结构S表达式(S-expression)来表示代码和数据,并在此基础上构建一种完整的语言。Lisp语言形式简单、内涵深刻,Paul Graham在《Lisp之根源》中将其对编程的贡献与欧几里德对几何的贡献相提并论。

Lisp之形

然而,与数学世界中简单易懂的欧氏几何形成鲜明对比,程序世界中的Lisp却一直是一种古老而又神秘的存在,真正理解其精妙的人还是少数。从表面上看,Lisp最明显的特征是它“古怪”的S表达式语法。S表达式是一个原子(atom),或者若干S表达式组成的列表(list),表达式之间用空格分开,放入一对括号中。“列表“这个术语可能会容易让人联想到数据结构中的链表之类的线形结构,实际上,Lisp的列表是一种可嵌套的树形结构。下面是一些S表达式的例子:

foo

()

(a b (c d) e)

(+ (* 2 3) 5)

(defun factorial (N)
    (if (= N 1)
        1
        (* N (factorial (- N 1)))
    )
)

据说,这个古怪的S表达式是McCarthy在发明Lisp时候所采用的一种临时语法,他实际上是准备为Lisp加上一种被称为M表达式(M-expression)的语法,然后再把M表达式编译为S表达式。用一个通俗的类比,S表达式相当于是JVM的字节码,而M表达式相当于Java语言,但是后来Lisp的使用者都熟悉并喜欢上了直接用S表达式编写程序,并且他们发现S表达式有许多独特的优点,所以M表达式的引入也就被无限期延迟了。

许多Lisp的入门文章都比较强调Lisp的函数式特性,而我认为这是一种误导。真正的Lisp之门不在函数式编程,而在S表达式本身,Lisp最大的奥秘就藏在S表达式后面。S表达式是Lisp的语法基础,语法是语义的载体,形式是实质的寄托。“S表达式”是程序的一种形,正如“七言”是诗的一种形,“微博”是信息的一种形。正是形的不同,让微博与博客有了质的差异,同样的道理,正是S表达式让Lisp与C、Java、SQL等语言有了天壤之别。

Lisp之道

一门语言能否有效地表达编程者的设计思想取决于其抽象机制的语义表达能力。根据抽象机制的不同,语言的抽象机制形成了面向过程、面向对象、函数式、并发式等不同的范式。当你采用某一种语言,基本上就表示你已经“面向XXX“了,你的思维方式和解决问题的手段就会依赖于语言所提供的抽象方式。比如,采用Java语言通常意味着采用面向对象分析设计;采用Erlang通常意味着按Actor模型对并发任务进行建模。

有经验的程序员都知道,无论是面向XXX编程,程序设计都有一条“抽象原则“:What与How解耦。但是,普通语言的问题就在于表达What的手段非常有限,无非是过程、类、接口、函数等几种方式,而诸多领域问题是无法直接抽象为函数或接口的。比如,你完全可以在C语言中定义若干函数来做到make file所做的事情,但C代码很难像make file那样声明式地体现出target、depends等语义,它们只会作为实现细节被淹没在一个个的C函数之中。采用OOP或是FP等其它范式也会遇到同样的困难,也就是说make file语言所代表的抽象维度与面向过程、OOP以及FP的抽象维度是正交的,使得各种范式无法直接表达出make file的语义。这就是普通语言的“刚性”特征,它要求我们必须以语言的抽象维度去分析和解决问题,把问题映射到语言的基本语法和语义。

更进一步,如果仔细探究这种刚性的根源,我们会发现正是由于普通语言语法和语义的紧耦合造成了这种刚性。比如,C语言中printf(“hello %s”, name)符合函数调用语法,它表达了函数调用语义,除此之外别无他义;Java中interface IRunnable { … }符合接口定义语法,它表达了接口定义语义,除此之外别无他义。如果你认为“语法和语义紧耦合“是理所当然的,看不出这有什么问题,那么理解Lisp就会让你对此产生更深的认识。

当你看到Lisp的(f a (b c))的时候,你会想到什么?会不会马上联想到函数求值或是宏扩展?就像在C语言里看到gcd(10, 15)马上想到函数调用,或者在Java里看到class A马上想到类定义一样。如果真是这样,那它就是你理解Lisp的一道障碍,因为你已经习惯了顺着语言去思考,总是在想这一句话机器怎么解释执行?那一句话又对应语言的哪个特性?理解Lisp要反过来,让语言顺着你,Lisp的(f a (b c))可以是任何语义,完全由你来定,它可以是函数定义、类定义、数据库查询、文件依赖关系,异步任务的执行关系,业务规则 …

下面我准备先通过几个具体的例子逐步展示Lisp的本质。需要说明的是,由于Lisp的S表达式和XML的语法形式都是一种树形结构,在语义表达方面二者并无本质的差别。所以,为了理解方便,下面我暂且用多数人更为熟悉的XML来写代码,请记住我们可以很轻易地把XML代码和Lisp代码相互转换。

首先,我们可以轻易地用XML来定义一个求两个数最大公约数的函数:

    <func name='gcd' return_type='int'>
        <params>
            <a type='int'/>
            <b type='int'/>
        </params>
        <body>
            <if>
               <equals>
                   <a/>
                   <int>0</int>
               </equals>
            </if>
            <then>
                <return><b/></return>
            </then>
            <else>
                <return>
                    <gcd>
                        <modulo><b/><a/></modulo>
                        <a/>
                    </gcd>
                </return>
            </else>
        </body>
    </func>

其次,我们可以用它来定义类:

    <class name="Computer">
        <field access="private" type="MainBoard" name="main-board" />
        <field access="private" type="CPU" name="cpu" />
        <field access="private" type="Memory" name="memory" />

        <method access="public" return_type="boolean" name="powerOn" />
            <params>...</params>
            <body>...</body>
        </method>

        <method access="public" return_type="boolean" name="powerOff" />
            <params>...</params>
            <body>...</body>
        </method>
    </class>

还可以轻易地用它来编写关系查询:

<sql>
    <select>
        <column name="employees.id" />
        <column name="bonus.amount" />
    </select>
    <from>
        <table name="employees" />
        <table name="bonus" />
    </from>
    <where>
        <equals>
            <column name="employees.id" />
            <column name="bonus.employee_id" />
        </equals>
    </where>
</sql>

还可以用它来实现类似make file的自动化构建(语法取自ant):

    <project name="MyProject" default="dist" basedir=".">
        <property name="src" location="src"/>
        <property name="build" location="build"/>
        <property name="dist"  location="dist"/>

        <target name="init">
            <mkdir dir="${build}"/>
        </target>

        <target name="compile" depends="init" description="compile the source " >
            <javac srcdir="${src}" destdir="${build}"/>
        </target>

        <target name="dist" depends="compile" description="generate the distribution" >
            <mkdir dir="${dist}/lib"/>
            <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
        </target>

        <target name="clean" description="clean up" >
            <delete dir="${build}"/>
            <delete dir="${dist}"/>
        </target>
    </project>

一口气举了这么多个例子,目的在于用XML这种树形结构来说明Lisp的S表达式所能够描述的语义。不知道你是否发现了S表达式和XML这种树形语法在语义构造方面有着特别的“柔性”?我们可以轻易地用它构造出函数、变量、条件判断语义;类、属性、方法语义;可以轻易地构造出关系模型的select、where语义;可以轻易地构造出make的target、depends语义,等等数不清的语义。在普通语言里,你可以定义一个函数、一个类,但你无法为C语言增加匿名函数特性,也没法给Java语言加上RAII语义,甚至连自己创造一个foreach循环都不行,而自定义语义意味着在Lisp之上你创造了一门语言!不管是面向过程,面向对象,函数式,还是关系模型,在Lisp里统统都变成了一种DSL,而Lisp本身也就成了一种定义语言的语言,即元语言(Meta Language)。

Lisp的柔性与S表达式有着密切的关系。Lisp并不限制你用S表达式来表达什么语义,同样的S表达式语法可以表达各种不同领域的语义,这就是语法和语义解耦。如果说普通语言的刚性源于“语法和语义紧耦合”,那么Lisp的柔性正是源于“语法和语义解耦”!“语法和语义解耦”使得Lisp可以随意地构造各种领域的DSL,而不强制用某一种范式或是领域视角去分析和解决问题。本质上,Lisp编程是一种超越了普通编程范式的范式,这就是Lisp之道:面向语言编程(LOP, Language Oriented Programming)。Wikipedia上是这样描述LOP的:

Language oriented programming (LOP) is a style of computer programming in which, rather than solving problems in general-purpose programming languages, the programmer creates one or more domain-specific languages for the problem first, and solves the problem in those languages … The concept of Language Oriented Programming takes the approach to capture requirements in the user’s terms, and then to try to create an implementation language as isomorphic as possible to the user’s descriptions, so that the mapping between requirements and implementation is as direct as possible.

LOP范式的基本思想是从问题出发,先创建一门描述领域模型的DSL,再用DSL去解决问题,它具有高度的声明性和抽象性。SQL、make file、CSS等DSL都可以被认为是LOP的具体实例,下面我们再通过两个常见的例子来理解LOP的优势。

例1:在股票交易系统中,交易协议定义若干二进制的消息格式,交易所和客户端需要对消息进行编码和解码。

消息格式是一种抽象的规范,本身不对语言做任何的限制,你可以用C,C++,Java,或者Python。普通的实现方式是按照消息格式规范,在相应的语言中定义消息结构,并编写相应的编解码函数。假设为一个消息定义结构和实现编解码函数的工作量为M,不同消息类型的数量为N,这种方式的工作量大致为M*N。也就是说每增加一种消息类型,就需要为该消息定义结构,实现编解码函数,引入bug的可能性当然也和M*N成正比。如果仔细观察不难发现,各个消息结构其实是高度类似的,编解码函数也大同小异,但是普通语言却找不到一种抽象机制能表达这种共性,比如,我们无法通过面向对象的方法定义一个基类把消息结构的共性抽象出来,然后让具体的消息去继承它,达到复用的目的。这正是由于普通语言的抽象维度限制所致,在普通语言中,你只能从函数、接口等维度对事物进行抽象,而恰好消息格式共性所在的维度与这些抽象维度并不匹配。

其实,不同消息类型的共性在于它们都具有相同的领域语义,比如:“某字段内容是另一个字段内容的md5码”就是一种消息格式的领域语义,这种领域语义是OOP的抽象机制无法描述的。LOP的思路是先创建一门消息定义DSL,比如,类似Google的Protocol Buffer,Android的AIDL。然后,通过DSL编写消息定义文件,直接声明式地描述消息的结构特征,比如,我们可以声明式地描述“某字段内容是另一个字段内容的md5码”。我们还需要为DSL开发编译器用于生成C、Java等通用语言的消息定义和编解码函数。

有了消息定义DSL和编译器之后,由于DSL编写消息定义是一种高度声明式的编程方法,每增加一种消息的只需要多编写一个消息定义文件而已,工作量几乎可以忽略不计。所有的工作量都集中在编译器的开发上,工作量是一个常数C,与消息的数量没有关系;质量保证方面也只需要关注编译器这一点,不会因为增加新的消息类型而引入bug。

例2:在图书管理系统中,需要支持在管理界面上对书籍、学生、班级等各种实体进行管理操作。

如果按传统的三层架构,一般需要在后端程序中为每一种实体定义一个类,并定义相应的方法实现CRUD操作,与之相应的,还需要在前端页面中为每一个实体编写相应的管理页面。这些实体类的CRUD操作都是大同小异的,但细节又各不相同,虽然我们很想复用某些共同的设计实现,但OOP所提供的封装、继承、多态等抽象机制不足以有效捕获实体之间的共性,大量的代码还是必须放在子类中来完成。比如,Student和Book实体类的实现非常相似,但是如果要通过OOP的方式去抽象它们的共性,得出的结果多半是Entity这样的大而空的基类,很难起到复用的效果。

其实,不同实体之间的共性还是在于它们具有相同的领域语义,比如:实体具有属性,属性具有类型,属性具有取值范围,属性具有可读取、可编辑等访问属性,实体之间有关联关系等。LOP方法正是直接面向这种领域语义的。采用LOP方法,我们并不需要为每一个实体类单独编写CRUD方法,也不需要单独编写管理页面,只需要定义一种DSL并实现其编译器;然后,用DSL声明式地编写实体描述文件,去描述实体的属性列表,属性的类型、取值范围,属性所支持的操作,属性之间的关系和约束条件等;最后,通过这个实体描述文件自动生成后端的实体类和前端管理页面。采用LOP,不论前后端采用何种技术,Java也好,C#也好,JSP也好,ASP.NET也好,都可以自动生成它们的代码。采用LOP的工作量和质量都集中在DSL的设计和编译器的开发,与实体的数量无关,也就是说,越是庞大的系统,实体类越多越是能体现LOP的优势。

通过上面两个小例子我们可以感受到,LOP是一种面向领域的,高度声明式的编程方式,它的抽象维度与领域模型的维度完全一致。LOP能让程序员从复杂的实现细节中解脱出来,把关注点集中在问题的本质上,从而提高编程的效率和质量。

接下来的问题是如果需要为某领域设计DSL,我们是应该发明一门类似SQL这样的专用DSL呢,还是用XML或S表达式去定义DSL呢?它们各有何优缺点呢?

我认为采用XML或S表达式定义DSL的优点主要有:1) SQL、make file、CSS等专用DSL都只能面向各自的领域,而一个实际的领域问题通常是跨越多个领域的,有时我们需要将不同领域融合在一起,但是由于普通语言的刚性,多语言融合通常会是一件非常困难的事情,而XML和S表达式语法结构的单一性和“代码及数据”的特点使得跨领域融合毫无障碍。2) 在为DSL开发编译器或解释器的方面,二者难度不同。对XML和S表达式定义的DSL进行语法分析非常简单,相比之下,对SQL这样的专用DSL进行语法分析,虽然可以借助Lex、Yacc、ANTLR等代码生成工具,但总的来讲复杂度还是要明显高一些。

当然,XML和S表达式的优点也正好是其缺点,由于XML和S表达式的语法形式是固定的,不能像专用DSL那样自由地设计语法。所以,一般来讲专用DSL的语法显得更加简洁。换句话说,XML和Lisp其实是在语法和语义间做了一个交换,用语法的限制换来了语义的灵活。

Lisp之器

接下来我们继续探讨DSL的解释执行问题。DSL代码的解释执行一般分为3种典型的方式:1) 通过专门的解释器解释执行;2) 编译生成其他语言的代码,再通过其他语言的解释器解释执行(或编译运行);3) 自解释。比如,第1类的代表是SQL,上一节举的两个例子都属于第2类,而第3类自解释正是Lisp的特色。

为了理解自解释,我们可以先从内部DSL的解释执行说起。内部DSL是指嵌入在宿主语言中的DSL,比如,Google Test单元测试框架定义了一套基于流畅接口(Fluent Interface)的C++单元测试DSL。从语义构造的角度看,内部DSL直接借用宿主语言的语法定义了自己的领域语义,是一种语法和语义解耦;从解释执行的角度看,内部DSL是随宿主语言的解释器而自动解释的,不需要像外部DSL一样开发专门的解释器,因而实现的代价很低。当然,并不是说设计内部DSL不用关心任何的解释实现,实际上,还是需要熟悉宿主语言的特性,并利用该特性使得DSL能随着宿主语言的解释器得到解释执行。

Lisp拥有强大的自解释特性,这得益于独一无二的Lisp之器:宏 (macro)。宏使得Lisp编写的DSL可以被Lisp解释器直接解释执行,这在原理上与内部DSL是相通的,只是内部DSL一般是利用宿主语言的链式调用等特性,通常形式简陋,功能有限,而Lisp的宏则要强大和灵活得多。

C语言中也有宏的概念,不过Lisp的宏与C语言的宏完全不同,C语言的宏是简单的字符串替换。比如,下面的宏定义:

#define square(x) (x*x)

square(1+1)的期望结果是4,而实际上它会被替换成(1+1*1+1),结果是3。这个例子说明,C语言的宏只在预编译阶段进行简单的字符串替换,对程序语法结构缺乏理解,非常脆弱。Lisp的宏不是简单的字符串替换,而是一套完整的代码生成系统,它是在语法解析的基础上把Lisp代码从一种形式转换为另一种形式,本质上起到了普通语言编译器的作用。不同的是,普通编译器是把一种语言的代码转换为另一种语言的代码,比如,Java编译器把Java代码转换成Java字节码;而Lisp宏的输入和输出都是S表达式,它本质上是把一种DSL转换为另一种DSL。下面的例子是宏的一个典型用法。

例3:假设Lisp解释器已经具备解释执行面向过程DSL的能力,需要实现类似ant的自动化构建工具。

我们可以基于宏构建一门类ant的DSL,宏的作用是把类ant DSL通过宏展开变成面向过程的DSL,最后被Lisp解释器所解释执行。这样用Lisp编写的ant DSL就不需要被编译为其他语言,也不需要像XML的ant一样依赖于专门的解释器了。

当然,和开发专门的解释器/编译器相比,Lisp的宏也并非没有缺点,宏难以理解,开发和调试更加困难。到底是开发专门的解释器/编译器还是直接采用宏应该视具体情况而定。

总结

Lisp采用单一的S表达式语法表达不同的语义,实现了语法和语义解耦。这使得Lisp具有强大的语义构造能力,擅长于构造DSL实现面向语言编程,而宏使得Lisp具有自解释能力,让不同DSL之间的转换游刃有余。进入Lisp的世界应当从理解面向语言编程入门,这是Lisp之道,而函数式编程和宏皆为Lisp之器,以道驭器方为正途。

后记

本文是我学习Lisp的一个总结,也是写给有兴趣学习Lisp的程序员的入门资料。必须说明,我还是一个标准的Lisp初学者,几乎没有写过像样的Lisp程序,文中的错误和不足在所难免,希望读者批评指正,感谢!

参考

The Roots of Lisp

The Nature of Lisp

Why Lisp macros are cool, a Perl perspective

Wikipedia: Language-oriented programming

《实用Common Lisp编程》

《冒号课堂 – 编程范式与OOP思想》

posted @ 2012-06-12 12:38 战魂小筑 阅读(1024) | 评论 (0)编辑 收藏

最近团队已经全面弃用SVN全面转移到HG(Mercurial)分布式代码管理

Visual Studio系编辑工具由于质量过硬, 兼容性超强,因此使用HG一直没有出现过问题

但是第三方开发的FlashDevelop对UNICODE兼容性不好, 出现了很多乱码问题, 特别是在HG合并代码后, 代码中的中文在FlashDevelop中的乱码现象更是严重. 经过验证, 同样代码在FlashBuilder中没有问题. 因此可以推断是FlashDevelop兼容性问题

为解决此问题, 需要调整HG的配置, 这里以Windows环境下的TortoiseHg为例

解决方案如下:

kdiff3是TortoiseHg的默认合并工具, 默认安装路径在c:\Program Files\TortoiseHg\kdiff3.exe, 找到并运行

在菜单中找到Settings->Configure KDiff3...

在Regional Settings选项卡中选择Unicode, 8 bit(UTF-8) 然后取消勾选右边的Auto Detect Unicode

image

注意, 如果需要混合开发UTF8保存的源码和UNICODE保存的源码, 需要准备两套合并方案, 可以选择兼容性比较好的BeyondCompare

posted @ 2012-05-12 10:17 战魂小筑 阅读(2304) | 评论 (0)编辑 收藏

传统发布现状

传统的服务器/客户端版本发布流程都需要经历以下流程:

1. 获取代码

2. 编译代码

3. 将配置,二进制文件, 资源打包

4. 挂接远程服务器磁盘拷贝打包文件

5. 远程操作解压打包文件

6. 修改设置,指向最新版本

7. 重启服务器

此流程繁琐,重复且无聊, 同时, 由于网络带宽,网速等约束, 每次若使用完整包发布,传输起来非常吃力

本文讨论的外网服务器由于安全性要求,禁止root登录,只能用普通帐号登录或传输后, 提权为root继续进行以上操作, 因此rsync的使用受到严重限制

即便使用Windows下的同步软件, 也几乎不可能.

HG特性及优势

HG作为一个优秀,小巧的跨平台代码管理软件的特性,正好能解决以上问题, 主要特性:

1. 安装简便, 可以使用代码直接安装

2. 利用本地映射版本可以对新版本做差异比较

3. 增量包传输, 100%同步, 本地文件删除后, 远程文件也会同步删除

4. 传输压缩

5. 增量包可以打包为patch进行离线更新

6. 可以恢复到任意版本, 提交版本有据可查

 

以下部署系统以CentOS为基础, 其他系统类似

本文来自战魂小筑的博客http://www.cppblog.com/sunicdavy 转载请注明来源

为远程服务器安装HG

安装依赖库

yum install python-devel

获取HG源码

wget http://mercurial.selenic.com/release/mercurial-2.1.tar.gz

tar zxvf ./mercurial-2.1.tar.gz

编译安装

make all

make install

hg debuginstall

 

使用HG同步数据

创建仓库

找到你需要同步的目录,进入目录

执行

hg init

vi .hg/hgrc

添加以下内容,让这个仓库支持外部push

[ui]

username=服务器提交后看到的用户名

[web]

push_ssl = false
allow_push=*

同步

vi /etc/sysconfig/iptables

添加HG服务的8000端口

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8000 -j ACCEPT

开启仓库同步服务

hg serve

本地机器同样找到文件夹,创建仓库

hg init

以后每次需要同步时,使用命令,或者乌龟HG的界面工具拉取服务器数据即可

hg pull http://服务器地址:8000

 

版本提交方法与HG日常使用类似, 这里不再阐述

离线更新

对于某些服务器深处防火墙或者安全登录后方,不能直接开启8000端口的情况

可以使用hg导出一个patch, 传输到远程服务器, 使用hg import PATCH 即可

posted @ 2012-04-26 11:11 战魂小筑 阅读(3015) | 评论 (0)编辑 收藏

BasicLayout.cpp:37:5: error: 'auto_ptr' in namespace 'std' does not name a type

在包含中添加#include <memory>即可

posted @ 2012-04-21 16:43 战魂小筑 阅读(2851) | 评论 (2)编辑 收藏

由于服务器需要静态链接所有库,但mysql++默认编译使用的是共享库, 因此使用ar手动生成一个

mysql++版本3.1.0

进入mysql++目录,执行以下指令生成libmysqlpp.a

ar rcu libmysqlpp.a mysqlpp_beemutex.o mysqlpp_cmdline.o mysqlpp_connection.o mysqlpp_cpool.o mysqlpp_datetime.o mysqlpp_dbdriver.o mysqlpp_field_names.o mysqlpp_field_types.o mysqlpp_manip.o mysqlpp_myset.o mysqlpp_mysql++.o mysqlpp_mystring.o mysqlpp_null.o mysqlpp_options.o mysqlpp_qparms.o mysqlpp_query.o mysqlpp_result.o mysqlpp_row.o mysqlpp_scopedconnection.o mysqlpp_sql_buffer.o mysqlpp_sqlstream.o mysqlpp_ssqls2.o mysqlpp_stadapter.o mysqlpp_tcp_connection.o mysqlpp_transaction.o mysqlpp_type_info.o mysqlpp_uds_connection.o mysqlpp_utility.o mysqlpp_vallist.o mysqlpp_wnp_connection.o ssqls2parse_parsev2.o

然后mv到usr/local/lib,重新链接服务器即可

posted @ 2012-04-20 14:48 战魂小筑 阅读(3436) | 评论 (1)编辑 收藏

最近页游开放平台比较多, 每个平台要求的Linux版本各不相同, 这给开发人员部署服务器带来了很大的困难. 在本机Linux编译的程序,发布时即便将依赖的so附带到目标Linux环境,仍然会碰到依赖及版本问题,例如:

[root@localhost bin]# ldd wkcenter
./wkcenter: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by ./wkcenter)
./wkcenter: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./wkcenter)
./wkcenter: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./wkcenter)
./wkcenter: /lib/libc.so.6: version `GLIBC_2.9' not found (required by ./wkcenter)
./wkcenter: /lib/libc.so.6: version `GLIBC_2.7' not found (required by ./wkcenter)
./wkcenter: /lib/libc.so.6: version `GLIBC_2.8' not found (required by ./wkcenter)
./wkcenter: /lib/libc.so.6: version `GLIBC_2.11' not found (required by ./wkcenter)

        linux-gate.so.1 =>  (0xffffe000)
        liblog4cpp.so.4 => not found
        libprotobuf.so.7 => not found
        libboost_filesystem.so.1.48.0 => not found
        libboost_system.so.1.48.0 => not found
        libboost_thread.so.1.48.0 => not found
        libboost_program_options.so.1.48.0 => not found
        libunwind-x86.so.7 => not found
        libluabind.so.0.9.0 => not found
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x008ae000)
        libm.so.6 => /lib/libm.so.6 (0x0044b000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00476000)
        libc.so.6 => /lib/libc.so.6 (0x002c1000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x0041d000)
        librt.so.1 => /lib/librt.so.1 (0x00440000)
        /lib/ld-linux.so.2 (0x002a2000)

上面红字部分表示glibc及glibcxx库依赖不正确. 本人使用的Linux编译版本为Mint 11(基于Ubuntu), 一般Ubuntu发行版的glibc配备非常高. 但是上文中的发布的Linux版本为CentOS 5.8

使用/lib/libc.so.6 查看libc版本为2.5, 远远低于开发环境的2.11

GNU C Library stable release version 2.5, by Roland McGrath et al.
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.1.2 20080704 (Red Hat 4.1.2-51).
Compiled on a Linux 2.6.9 system on 2012-02-21.
Available extensions:
        The C stubs add-on version 2.1.2.
        crypt add-on version 2.1 by Michael Glad and others
        GNU Libidn by Simon Josefsson
        GNU libio by Per Bothner
        NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk
        Native POSIX Threads Library by Ulrich Drepper et al
        BIND-8.2.3-T5B
        RT using linux kernel aio
Thread-local storage support included.
For bug reporting instructions, please see:
<
http://www.gnu.org/software/libc/bugs.html>.

由于Linux操作系统的特有elf加载顺序. (可以参考此文). 虽然可以很大程度上解决Windows早期版本的dll hell问题, 但是给部署带来了很大难度

一般常见的解决方法是, 找到一个与目标Linux版本及glibc版本一致的Linux, 将代码及依赖包放在之上编译, 完成后再发布.这种方法与Linux下常见软件安装方法类似. 但是对于商用服务器部署步骤来说未免繁琐, 安全性低.

还有一种方法,使用静态链接. 将所有可执行文件文件依赖的静态库, 系统库,全部静态链接到可执行文件中,可以一次性解决这个问题

步骤:

    1. 在gcc链接命令行中添加-static -static-libgcc -static-libstdc++

    2. 将第三方依赖库打开静态链接开关, 将原来链接.so的库,全改为链接.a

    3. gcc对链接库顺序很敏感, 链接库顺序需要按照从前至后为:  项目产生的静态库 > 第三方库静态库 > 系统静态库

    4. 链接时, 若有未解决的symbol, 可以尝试在最后添加-lpthread及-lrt解决

   

在发布版本Linux上运行可能遇到的问题:

terminate called after throwing an instance of 'std::runtime_error'

what(): locale::facet::_S_create_c_locale name not valid

解决方法: 执行之前运行export LC_ALL="C"

posted @ 2012-04-20 11:35 战魂小筑 阅读(7065) | 评论 (4)编辑 收藏

#!/bin/bash
# chkconfig: 3 3 1
# description: svclauncher
ServicePath=/usr/local/bin

ServiceList=(
"wkcenterd --toc /home/davy/dev/kaze/Config/CenterService.toc --logfile /tmp/centerd.log"
"wkagentd --toc /home/davy/dev/kaze/Config/AgentService.toc --logfile /tmp/agentd.log"
)

StartAll()
{
    for((i = 0;i<${#ServiceList[*]};i=i+1))
    do

     echo "start:" $ServicePath/${ServiceList[i]}
     $ServicePath/${ServiceList[i]} > /dev/null &

    done
}

StopAll()
{
    for((i = 0;i<${#ServiceList[*]};i=i+1))
    do

     echo "stop:" $ServicePath/${ServiceList[i]}
     svcname=`echo ${ServiceList[i]} | awk '{print $1}'`
     killall $svcname > /dev/null

    done
}

RestartAll()
{
    StopAll
    StartAll
}


InstallService()
{
    svcname=`basename $0`
    chmod +x $svcname
    cp $svcname /etc/init.d
    ln /etc/init.d/$svcname /etc/rc3.d/S03$svcname
    ln /etc/init.d/$svcname /etc/rc0.d/K03$svcname
    chkconfig --add $svcname
    chkconfig $svcname on
    chkconfig --list | grep $svcname
}

UninstallService()
{
    svcname=`basename $0`
    chkconfig --del $svcname
    rm -f /etc/init.d/$svcname
    rm -f /etc/rc3.d/S03$svcname
    rm -f /etc/rc3.d/K03$svcname
}



case "$1" in
    start)
    StartAll
    ;;
    stop)
    StopAll
    ;;
    restart)
    RestartAll
    ;;
    install)
    InstallService
    ;;
    uninstall)
    UninstallService
    ;;
    *)
           echo "Usage: service $EXEC {install|start|stop|restart|uninst}"
       exit 1
esac
 
exit $? 

posted @ 2012-04-12 09:33 战魂小筑 阅读(2045) | 评论 (0)编辑 收藏

用作团队编码标准很不错

 

态度篇
1. 做实事
不要抱怨,发牢骚,指责他人,找出问题所在,想办法解决。对问题和错误,要勇于承担。
2. 欲速则不达
用小聪明、权宜之计解决问题,求快而不顾代码质量,会给项目留下要命的死角。
3. 对事不对人
就事论事,明智、真诚、虚心地讨论问题,提出创新方案。
4. 排除万难,奋勇前进
勇气往往是克服困难的唯一方法。
学习篇
5. 跟踪变化
新技术层出不穷并不可怕。坚持学习新技术,读书,读技术杂志,参加技术活动,与人交流。要多理解新词背后的所以然,把握技术大趋势,将新技术用于产品开发要谨慎。
6. 对团队投资
打造学习型团队,不断提高兄弟们的平均水平。
7. 懂得丢弃
老的套路和技术,该丢,就得丢。不要固步自封。
8. 打破砂锅问到底
不断追问,真正搞懂问题的本质。为什么?应该成为你的口头禅。
9. 把握开发节奏
控制好时间,养成好习惯,不要加班。

开发流程篇
10. 让客户做决定
让用户在现场,倾听他们的声音,对业务最重要的决策应该让他们说了算。
11. 让设计指导而不是操纵开发
设计是前进的地图,它指引的是方向,而不是目的本身。设计的详略程度应该适当。
12. 合理地使用技术
根据需要而不是其他因素选择技术。对各种技术方案进行严格地追问,真诚面对各种问题。
13. 让应用随时都可以发布
通过善用持续集成和版本管理,你应该随时都能够编译、运行甚至部署应用。
14. 提早集成,频繁集成
集成有风险,要尽早尽量多地集成。
15. 提早实现自动化部署
16. 使用演示获得频繁反馈
17. 使用短迭代,增量发布
18. 固定价格就意味着背叛承诺
估算应该基于实际的工作不断变化。
用户篇
19. 守护天使
自动化单元测试是你的守护天使。
20. 先用它再实现它
测试驱动开发其实是一种设计工具。
21. 不同环境,就有不同问题
要重视多平台问题。
22. 自动验收测试
23. 度量真实的进度
在工作量估算上,不要自欺欺人。
24. 倾听用户的声音
每一声抱怨都隐藏着宝贵的真理。

编程篇
25. 代码要清晰地表达意图

代码是给人读的,不要耍小聪明。
26. 用代码沟通
注释的艺术。
27. 动态地进行取舍

记住,没有最佳解决方案。各种目标不可能面面俱到,关注对用户重要的需求。
28. 增量式编程
写一点代码就构建、测试、重构、休息。让代码干净利落。
29. 尽量简单
宁简勿繁。如果没有充足的理由,就不要使用什么模式、原则和特别的技术。
30. 编写内聚的代码
类和组件应该足够小,任务单一。
31. 告知,不要询问
多用消息传递,少用函数调用。
32. 根据契约进行替换
委托往往优于继承。

调试篇
33. 记录问题解决日志
不要在同一地方摔倒两次。错误是最宝贵的财富。
34. 警告就是错误
忽视编译器的警告可能铸成大错。
35. 对问题各个击破
分而治之是计算机科学中最重要的思想之一。但是,要从设计和原型阶段就考虑各部分应该能够很好地分离。
36. 报告所有的异常
37. 提供有用的错误信息
稍微多花一点心思,出错的时候,将给你带来极大便利。

团队协作篇
38. 定期安排会面时间
常开会,开短会。
39. 架构师必须写代码

不写代码的架构师不是好架构师。好的设计都来自实际编程。编程可以带来深入的理解。
40. 实行代码集体所有制
让开发人员在系统不同区域中不同的模块和任务之间轮岗。
41. 成为指导者
教学相长。分享能提高团队的总体能力。
42. 让大家自己想办法

指引方向,而不是直接提供解决方案。让每个人都有机会在干中学习。
43. 准备好后再共享代码
不要提交无法编译或者没有通过单元测试的代码!
44. 做代码复查
复查对提高代码质量、减少错误极为重要。
45. 及时通报进展与问题

主动通报,不要让别人来问你。

posted @ 2012-04-03 21:40 战魂小筑 阅读(1240) | 评论 (1)编辑 收藏

仅列出标题
共26页: First 5 6 7 8 9 10 11 12 13 Last