Say bye to CMake and Makefile

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sheismylife/article/details/9635529

用了几年的CMake,最近想试着琢磨如何将C++应用的动态链接全部改成静态链接,发现还需要研究CMake的用法,进入CMake的文档,

http://www.cmake.org/cmake/help/syntax.html

看到这句:

In many ways writing a CMakeLists file is like a writing a program in a simple language. Like most languages CMake provides flow control structures to help you along your way. CMake provides three flow control structures:
再往下看,里面是什么条件语句,循环,定义过程等,一个简单的script语言用来控制CMake生成Makefile。

过去CMake帮助了我,因为我对写Makefile很厌烦,CMake让我能够设计良好的目录结构,不要再自己实现目录树递归的Makefile脚本。

但是时至今天,对于已经熟练掌握newlisp语言的我,还有什么比用newlisp来实现脚本更强大的工具,为什么我还用CMake?我并不需要考虑跨平台编译,我只是在实践Linux服务器上的C++编程。我仅仅使用GCC作为编译器。直接用newlisp来控制GCC,可以让我直接使用GCC,更深层次的理解编译器的行为。

说做就做,本着仍然不改变原有CMake工程的精神,创建了几个newlisp脚本实现递归目录树,编译文件,最后动态或者静态链接。

现在介绍一下使用。这个CppCMS程序目录结构是:

 tree -L 4
.
├── builder
│   ├── build_config.lsp
│   ├── compile.lsp
│   ├── compile.lsp~
│   ├── dlink.lsp
│   ├── dlink.lsp~
│   ├── g++.lsp
│   ├── link.lsp~
│   ├── rebuild.lsp
│   ├── slink.lsp
│   ├── slink.lsp~
│   └── tmpl.lsp
├── codes
│   ├── main
│   │   ├── build
│   │   ├── CMakeLists.txt
│   │   ├── conf.d
│   │   │   ├── ca-certs.crt
│   │   │   ├── site.crt
│   │   │   ├── ssl.key
│   │   │   ├── ssl-pwd.key
│   │   │   ├── site.conf
│   │   │   ├── default.conf_bk
│   │   │   ├── example_ssl.conf
│   │   │   ├── fastcgi.cml
│   │   │   ├── nginx_signing.key
│   │   │   ├── server.crt
│   │   │   ├── server.csr
│   │   │   ├── server.key
│   │   │   └── server.key.org
│   │   ├── config.js
│   │   ├── create_deploy.sh
│   │   ├── include
│   │   │   ├── bean
│   │   │   ├── configuration.h
│   │   │   ├── controller
│   │   │   ├── display.h
│   │   │   ├── displays.h
│   │   │   ├── exception
│   │   │   ├── group.h
│   │   │   ├── groups.h
│   │   │   ├── helper
│   │   │   ├── module
│   │   │   ├── my_application.h
│   │   │   ├── response.h
│   │   │   ├── service
│   │   │   └── web_user.h
│   │   ├── install.sh
│   │   ├── jscheck
│   │   │   ├── pom.xml
│   │   │   └── src
│   │   ├── proto
│   │   │   ├── build.sh
│   │   │   ├── input
│   │   │   └── output
│   │   ├── resources
│   │   │   ├── html
│   │   │   ├── images
│   │   │   ├── plugin
│   │   │   ├── script
│   │   │   └── style
│   │   ├── src
│   │   │   ├── bean
│   │   │   ├── CMakeLists.txt
│   │   │   ├── controller
│   │   │   ├── display.cpp
│   │   │   ├── displays.cpp
│   │   │   ├── group.cpp
│   │   │   ├── groups.cpp
│   │   │   ├── helper
│   │   │   ├── main.cpp
│   │   │   ├── module
│   │   │   ├── my_application.cpp
│   │   │   ├── service
│   │   │   ├── view
│   │   │   └── web_user.cc
│   │   ├── template
│   │   │   ├── accounts.tmpl
│   │   │   ├── default.tmpl
│   │   │   ├── deny.tmpl
│   │   │   ├── gprsConfig.tmpl
│   │   │   ├── gprsManager.tmpl
│   │   │   ├── groupManagement.tmpl
│   │   │   ├── home.tmpl
│   │   │   ├── login.tmpl
│   │   │   ├── log.tmpl
│   │   │   ├── message.tmpl
│   │   │   ├── register_client.tmpl
│   │   │   ├── updatePassword.tmpl
│   │   │   └── userTitle.tmpl
│   │   └── tool.sh
│   └── test
└── README

运行方式就是进入builder目录执行

./rebuild.lsp

首先将CppCMS的tmpl模板文件编译成C++类

然后将所有.cc和.cpp文件编译成.o文件

最后动态链接成可执行程序。

先看rebuild.lsp代码:

#!/usr/bin/newlisp 

;; init
(load "/opt/build_config.lsp")
(set 'armory-folder (env "NEWLISP_ARMORY_HOME"))
(println (append "newlisp armory home folder: " armory-folder))
(load (append armory-folder "/codes/file/file.lsp"))
(file:init)

;; clean files genereated by CMake
(set 'cmake-build-dir "../codes/main/build")
(file:clean-folder cmake-build-dir)

;; clean view/*.cpp files generated from cppcms_tmpl_cc
(set 'view-dir "../codes/main/src/view")
(file:clean-folder view-dir)

(set 'tmpl-dir "../codes/main/template")

;; generate .cc files in view folder
(load "tmpl.lsp")
(tmpl-to-cc tmpl-dir view-dir)

;; compile all c++ files to .o file in ./o folder
(load "g++.lsp")
(set 'include-paths 
     (list "../codes/main/include"
	    "../codes/main/src/../../loki-0.1.7/include"))
(set 'o-dir "./o")
(set 'src-paths 
     (list "../codes/main/src"
	   "../codes/main/src/bean"
	   "../codes/main/src/controller"
	   "../codes/main/src/helper"
	   "../codes/main/src/module"
	   "../codes/main/src/service"
	   "../codes/main/src/view"
	   ))

(compile include-paths src-paths o-dir)

;; link all .o files
(set 'libs 
     (list "pthread"
	   "cppcms"
	   "mongoclient"
	   "booster"
	   "loki"
	   "cryptopp"
	   "boost_system"
	   "boost_thread"
	   "boost_filesystem"
	   ))
(set 'binary-name "sports_lottery")
(set 'bin-dir "bin")
(dynamic-link o-dir bin-dir binary-name libs)


(exit)

该文件用到了newlisp armory模块,参考我的GitHub项目:https://github.com/csfreebird/newlisp_armory

tmpl.lsp文件专门负责处理CppCMS tmpl文件,代码如下:

(define (get-extension name)
  (first (regex "[^.]*$" name))
  )

;; @syntax (remove-extension name)
;; @return file name without extension
;; @note remove extension name e.g a.b .b is extension, it will be removed
(define (remove-extension name)
  ((regex "(.*)\\.(.*)$" name) 3)
  )

;; @syntax (tmpl-to-cc)
;; @note find all tmpl files in tmpl-folder, translate them into *.cc files
(define (tmpl-to-cc tmpl-folder cc-folder)
  (set 'tmpl-files (directory tmpl-folder "\\.tmpl"))
  (set 'cmd-tmpl (append "cppcms_tmpl_cc " tmpl-folder "/%s -o " cc-folder "/%s.cc"))
  (dolist (tmpl-file tmpl-files)
    (set 'cmd (format cmd-tmpl tmpl-file (remove-extension tmpl-file)))
    (println cmd)
    (exec cmd)
    )
)

g++.lsp专门生成g++命令,文件内容如下:

;; @syntax (compile include-dirs src-dirs o-dir)
;; @parameter include-dir a list contains one or more relative or absolute include directories
;; @parameter src-dirs a list contains one or more relative or absolute src dirs
(define (compile include-dirs src-dirs o-dir)
  (if (directory? o-dir)
      (file:clean-folder o-dir)
    (make-dir o-dir))
  (set 'path1 "")
  (dolist (path include-dirs)
    (set 'path1 (append path1 "-I" path " ")))

  (set 'cmd-template (format "/usr/bin/c++ -g %s -Wall -o %s/" path1 o-dir))
  
  (dolist (dir src-dirs)
    (compile-dir dir cmd-template)
    )
  )

;; @syntax (compile-dir dir cmd-template)
;; @parameter dir one folder which contains many .cc or .cpp files
;; @parameter cmd-template the command template that has -g, -Wall and -I args 
(define (compile-dir dir cmd-template)
  (set 'file-list (directory dir "\\.cc|\\.cpp"))
  (println "dir: " dir)
  (dolist (cc-path file-list)
    (set 'str (append cc-path ".o"))
    (set 'cmd (append cmd-template  str " -c "  dir "/" cc-path))
    (println cmd)
    (exec cmd))
  )

;; @syntax (dynamic-link o-dir bin-dir binary-name libs)
;; @parameter o-dir the direcotry includs all .o files
;; @parameter bin-dir the location of linked binary file
;; @libs the list of all dependencies
(define (dynamic-link o-dir bin-dir binary-name libs)
  (if (directory? bin-dir)
      (file:clean-folder bin-dir)
    (make-dir bin-dir))
  (set 'cmd "/usr/bin/c++ -g")
  (set 'o-files (directory o-dir "\\.o"))
  (dolist (o-file o-files)
    (set 'cmd (append cmd " " (real-path o-dir) "/" o-file)))
  (set 'cmd (append cmd " -o " bin-dir "/" binary-name " -rdynamic"))
  (dolist (lib libs)
    (set 'cmd (append cmd " -l" lib)))
  (println cmd)
  (exec cmd)
  )

;; @syntax (static-link o-dir bin-dir binary-name libs)
;; @parameter o-dir the direcotry includs all .o files
;; @parameter bin-dir the location of linked binary file
;; @libs the list of all dependencies
(define (static-link o-dir bin-dir binary-name libs)
  (if (directory? bin-dir)
      (file:clean-folder bin-dir)
    (make-dir bin-dir))
  (set 'cmd "/usr/bin/c++ -g ")
  (set 'o-files (directory o-dir "\\.o"))
  (dolist (o-file o-files)
    (set 'cmd (append cmd " " (real-path o-dir) "/" o-file)))
  (set 'cmd (append cmd " -o " bin-dir "/" binary-name " -static-libgcc -static-libstdc++ -static -L/usr/lib/x86_64-linux-gnu"))
  (dolist (lib libs)
    (set 'cmd (append cmd " -l" lib))
    (println cmd))
    (exec cmd)
  )

为了方便使用,还提供了专门用于编译的文件compile.lsp,可以直接运行。

;; compile all c++ files to .o file in ./o folder
(load "g++.lsp")
(set 'include-paths 
     (list "../codes/main/include"
	    "../codes/main/src/../../loki-0.1.7/include"))
(set 'o-dir "./o")
(set 'src-paths 
     (list "../codes/main/src"
	   "../codes/main/src/bean"
	   "../codes/main/src/controller"
	   "../codes/main/src/helper"
	   "../codes/main/src/module"
	   "../codes/main/src/service"
	   "../codes/main/src/view"
	   ))

(compile include-paths src-paths o-dir)

(exit)

专门动态链接的文件dlink.lsp

#!/usr/bin/newlisp 

;; init
(load "/opt/build_config.lsp")
(set 'armory-folder (env "NEWLISP_ARMORY_HOME"))
(println (append "newlisp armory home folder: " armory-folder))
(load (append armory-folder "/codes/file/file.lsp"))
(file:init)


;; compile all c++ files to .o file in ./o folder
(load "g++.lsp")
(set 'o-dir "./o")
;; link all .o files
(set 'libs 
     (list "pthread"
	   "cppcms"
	   "mongoclient"
	   "booster"
	   "loki"
	   "cryptopp"
	   "boost_system"
	   "boost_thread"
	   "boost_filesystem"
	   ))
(set 'binary-name "sports_lottery_d")
(set 'bin-dir "bin")
(dynamic-link o-dir bin-dir binary-name libs)


(exit)

专门静态链接的文件slink.lsp

#!/usr/bin/newlisp 

;; init
(load "/opt/build_config.lsp")
(set 'armory-folder (env "NEWLISP_ARMORY_HOME"))
(println (append "newlisp armory home folder: " armory-folder))
(load (append armory-folder "/codes/file/file.lsp"))
(file:init)


;; compile all c++ files to .o file in ./o folder
(load "g++.lsp")
(set 'o-dir "./o")
;; link all .o files
(set 'libs 
     (list "mongoclient"
	   "cppcms"
	   "booster"
	   "boost_system"
	   "loki"
	   "cryptopp"
	   "boost_thread"
	   "pthread"
	   "boost_filesystem"
	   "dl"
	   "gcrypt"
	   "z"
	   "pcre"
	   "icuuc"
	   "icui18n"
	   "gpg-error"
	   "icuuc"
	   "icudata"
	   ))
(set 'binary-name "sports_lottery_s")
(set 'bin-dir "bin")
(static-link o-dir bin-dir binary-name libs)


(exit)

注意,slink.lsp中这些静态库的名称和顺序是不断尝试出来的。我总结了一个好方法:

1. A依赖B,A必须出现在B前

2. 一开始只加一个库mongoclient,然后看连接器报错,看少什么库,然后通过ldd来查找正确的库名称,添加在后面。这样就能找全所有的静态库。


newlisp真是强大的脚本工具,不断改进我的生活。将来完善了,放到我自己的Github项目中。

展开阅读全文

Good Bye My Friend,Good Bye CSDN

09-04

Good Bye My Friend,Good Bye CSDNrn到CSDN也有一些年头了,但是,我不是经常来,断断续续的,经常是来了几个月,然后,几个月不见人影,抱歉,我的生活只能这样,希望大家原谅。rn在CSDN的日子是我很快乐的日子,也认识了很多朋友,更重要的是,学到了很多的知识,懂得了很多。各位也看得我起,让我担任了一个小版主,抱歉得是:我不称职,很少来,来,也是匆匆的。rn然而,今天,我是想和CSDN告别,离开CSDN,我将要告别我的梦想,而CSDN是我梦想起飞的地方,我从这里再倒退吧!rn说说我自己:rn我是一个中专生,而且,是一个和计算机相隔很远的专业,公安管理专业,也许有人说,当公安很好啊,可惜的是:因为身体的原因,以及政策的变化,我永远也不可能走向那个地方了,虽然,做一个网络刑警是我梦想之一rn98年,我拥有了自己的电脑,从此,开始了学习,直到2001年我毕业,时间过去很多,学到的却少,2001年初,我来到了CSDN,当时还很简陋,用的是asp写的系统,但是人很不错,我还记得“真我风采”和“无影石”的口水丈,playyuer的帮助,很平静的学习技术的站点,直到后来,bardo的出现,和dbcontrols的交锋,我开始对论坛失去了关注,去了水源,直到后来,日子就这么过去。rn再2002年,我认识了我的女友,就叫她G好了,一个很好的女孩子,虽然,我当时觉得我们在一起的可能不大,然而,我仍然执着,通过网络,我们相爱了,但是,世界不是听从你摆布的,它才是左右你的人,今年,她找到了一个不错的工作,在浙江,而我,第二次冲刺公务员失败,就失败在成功的门槛上,我想出去,想追逐我的梦想,然而,我被自己的使命压迫着,我是长子、长孙,我要支撑整个家族第三代的希望,而,对于父辈,我有个固定的本地的工作,才是希望的开端,我,不得不继续考试,直到,在进入教育系统,成为一名所谓的人类灵魂的工程师,可惜,我认为,我自己的灵魂就不知道在那里,我仅仅是为了家族而存在。我爱我的家,我爱我的家人,我只有屈服,也许没有屈服,因为,他们没有逼迫。是我主动弯腰的。既然,我在从事这个工作,就不可能去浙江了,而且,就很多的方面而言,和我,她只有苦,感情好,但是,人,不能不吃饭,我去,只有让她生活痛苦,与其她痛苦,不如我放弃,让她找到一个更好的伴侣,过更好的生活,我,原本就是为了家族而存在,也无所谓了,笑着说bye bye吧,我也许,会找一个谁都认为很般配的女人做妻子,过一个别人都认为幸福的生活。rnCSDN是我最初接触的论坛,也是给我帮助最大的论坛,既然,我已经不会再去从事编程相关的职业,那么也就无所谓再来这里了,向CSDN的朋友告别,希望后面来的朋友能够大胆的走出去,为自己而活!!!rnGood Bye, CSDNrnGood Bye, My DreamrnGood Bye, My Loverrnrn以后,CSDN就不会有Shawls,Good Byernrn9/3/2003 6:44:20 PMrnrnrn抱歉,说话很乱rn我还有不少可用分,如果要的,给我留言rn 论坛

Hello,Linux! Bye,Windows

03-23

终于决定投入到Linux下来了,windows下搞VC搞了这么多年,除了一些C++语言本身的东西, 剩下对于特定的平台的东西,随着microsoft的.net也几乎没有什么可以留下的. 简历是越来越拿不出手了. rnrn什么? 你会ATL, MFC,哦, 对不起,我们现在公司准备用C#了, 这些都不用了. 跟VB一样,拖个控件,改字体,方便. 哪像VC,修改个颜色都要拦截OnCtlColor消息,整个刷子.rn可是我还会COM+, 我还知道MTS, DCOM了? 哦, 我们现在的中间件都用J2EE了. 爽啊. 开发工具eclipse免费的,JDK免费的,J2EE的server也有免费的JBOSS. Microsoft的Visual Studio不便宜啊. 我们公司比较正规的,不敢用盗版,正版的买不起.rnrn可是我还在windows下写过多线程的网络程序啊? 哦, 这样啊,不过我们公司一般network server都是用linux的, TCP的效率还是比linux高,速度快,还是免费的.反正最终用户不直接接触,图形界面也就无所谓了. 也没有那么多黑客攻击.rnrnrn想多年,COM花了不少心血才稍微明白,现在也就是个概念了.实际工作中是没有用了.都是新东西, 我写了这么久的程序,和一个新手没有多大区别,那么意义何在? 还有什么可以留下?rnrn而Linux就不同了,10年前的程序和现在都没有什么太多差别.是一个可以学到老,用到老的. pthread, std, gcc, emacs, 10年前的tutorial, 现在照样指导着很多人.microsoft的10年前的技术资料,有多少可以留下? rnrn我不惧怕学习, 我只是问问, 我为什么不去学习一些可以用几十年的东西,而非要将大量的时间用在快餐式的严重依赖于厂家产品的那些所谓的技术上呢?rnrnrnrnrn 论坛

Accurately Say "CocaCola"! Again

02-17

In a party held by CocaCola company, several students stand in a circle and play a game.nnOne of them is selected as the first, and should say the number 1. Then they continue to count number from 1 one by one (clockwise). The game is interesting in that, once someone counts a number which is a multiple of 7 (e.g. 7, 14, 28, ...) or contains the digit '7' (e.g. 7, 17, 27, ...), he shall say "CocaCola" instead of the number itself.nnFor example, 4 students play this game. At some time, the first one says 25, then the second should say 26. The third should say "CocaCola" because 27 contains the digit '7'. The fourth one should say "CocaCola" too, because 28 is a multiple of 7. Then the first one says 29, and the game goes on. When someone makes a mistake, the game ends.nnDuring a game, you may hear a consecutive of p "CocaCola"s. So what is the minimum number that can make this situation happen?nnFor example p = 2, that means there are a consecutive of 2 "CocaCola"s. This situation happens in 27-28 as stated above. 27 is then the minimum number to make this situation happen.nnInputnnStandard input will contain multiple test cases. The first line of the input is a single integer T (1 <= T <= 1000) which is the number of test cases. And it will be followed by T consecutive test cases.nnThere is only one line for each case. The line contains only one integer p (1 <= p <= 12345678).nnOutputnnResults should be directed to standard output. The output of each test case should be a single integer in one line, which is the minimum possible number for the first of the p "CocaCola"s stands for.nnSample Inputnn2n2n3nSample Outputnn27n70 问答

没有更多推荐了,返回首页