linux下使用Scons構建自己的項目程序

原來簡單介紹了一種項目自動編譯的工具cmake,不過它基本是針對與c++程序而設計的,我感覺cmake已經很方便了,比寫Makefile要舒服多了,最近又看到一個scons,瞬間感覺scons纔是真愛啊。

scons簡介

SCons 是一個開放源代碼、以 Python 語言編寫的下一代的程序建造工具。它最初的名字是 ScCons, 基於由 perl 語言編寫的 Cons 軟件開發而成,它在 2000 年 8 月獲得了由 Software Carpentry 舉辦的 SC 建造比賽的大獎。現在 ScCons 已經被改名爲 SCons,目的是爲了表示不再與 Software Carpentry 有聯繫,當然,還有一個目的,就是爲了更方便的輸入。

使用

先安裝:
最簡單粗暴

sudo apt-get install scons

當然你也可以去下載壓縮包再自己安裝。

一,SConstruct 文件

它是scons用來控制編譯的文件,類似MakeFile,是一個Python腳本,它告訴scons做什麼,而不是嚴格的規定scons做這件事的步驟。

二,scons 運行選項

運行:scons
1,-c 就是清理你創建的文件,就是make clean
2, -Q 就是省略自帶的一堆廢話,只顯示編譯過程

三,SConstrcut文件編寫基礎

1.scons支持的編譯類型

  • scons支持的編譯類型有
  • Program: 編譯成可執行程序
  • Object :只編譯成目標文件,使用這種類型,編譯結束後,只會產生目標文件,.o文件。
  • Library :編譯成庫文件,scons默認編譯的庫是指靜態鏈接庫
  • StaticLibrary :顯式的編譯成靜態鏈接庫,與上面的Library效果一樣
  • SharedLibrary :編譯成動態庫

    2.指定目標名,且編譯多個文件

Program('hello',['file.c','file2.c']),  //生成可執行文件hello

3,可以使用Glob編譯所有匹配的文件

Program('hello',Glob('*.c')),

4,使用Split,以空白字符爲分割符,將字符串分割。

Program('hello',Split("main.c file1.c file2.c")),

5,文件中的關鍵字

CCFLAGS 指定編譯選項
LINKFLAGS 指定鏈接選項
CPPDEFINES指定預編譯器
LIBS 指定所需要鏈接的庫文件
LIBPATH 指定庫文件(lib)的搜索路徑
CPPPATH 指定[.h,.c,.cpp]等文件的搜素路徑

Program('hello',['hellosons.c','file.c'],
        LIBS = 'pthread',
        LIBPATH = ['/usr/lib','/usr/local/lib'],
        CCFLAGS = ['-g ','-Wall'],
        CPPPATH = ['/usr/include','hello/src'])

6,使用Environments

一個environment是一個影響程序執行的值的集合。
1,外部環境 External Environment
外部環境是運行Scons時,用戶的環境變量,他們可以通過os.environ獲取

6.1構建環境

Construction Environment :它包含一些變量,這些變量會影響Scons構建目標的行爲。

env = Environment()   //創建,(name,value)集合
for item in env.Dictionary():
    print '(%s:%s)' %(item,env[item]) //查看內容
env['cc']  //查看變量
env.subst('$CC')  //查看變量,如果subset變量不存在時報告錯誤。
//修改環境變量
env.Clone   //拷貝一個環境變量
env.Replace  //替換一個已經存在的環境變量
env.SetDefault  //爲一個沒有被定義的變量設置默認值
env.Append(CCFLAGS = '-g')  //爲一個已存在的環境變量增加一個值
env.AppendUnique  //爲一個環境變量添加一個唯一的值
flags = {'CCFLAGS':'-option -O3 -O1'}
env.MergeFlags(flags)  //合併環境變量
6.2 執行環境

Execution Environment:用於Scons執行外部命令,以構建一個或多個目標。當Scons構建一個目標文件時,它說使用的外部環境和執行Scons 時的環境變量是不同的。scons 使用$ENV構建變量中存儲的目錄作爲它執行命令的外部環境變量

//在構建環境中顯示初始化PATH
path = ['usr/local/bin','/bin','/usr/bin']
env = Environment(ENV = {'PATH':path}) //只設置了ENV
env['ENV']['PATH'] = ['usr/local/bin','/bin','/usr/bin']
//從外部環境初始化PATH
import os
env = Environment(ENV = {'path':os.environ['PATH']})
//使用env.PrependENVPath 和env.AppendENVPath
env.PrependENVPath('PATH','/usr/local/bin') //插入到'$PAHT'第一個位置

7.控制目標文件的路徑

使用Install:

test = env.Program('test.cpp')
env.Install('bin',test)  //放入到bin目錄

在指定目標名的時候指定其目錄

env.Program('bin/test','test.cpp')

//將目標放到其他目錄下,並修改名字
test = env.Program('test.cpp')
env.InstallAs('bin/testapp',test)   //執行文件改爲testapp

8.一份代碼構建多個版本的Target

一份源碼,要構建它的debug版本,又要構建release版本

//需要爲不同的版本指定不同的obj名字,否則會衝突
opt = Environment(CCFLAGS ='-O2')
dbg = Environment(CCFLAGS = '-g')

o = opt.Object('foo-opt','foo.c')   //生成foo-opt.o
opt.Program(o)

d = dbg.Object('foo-dbg','foo.c'//生成foo-dbg
dbg.Program(d)

這只是一些簡單介紹,如果你熟悉Python,就可以隨心所欲的編寫你要的效果,以前學的python早忘光了。

9,範例參考

這裏我貼上實驗室大神的SConstruct文件,大家做個簡單參考,我也在學習。

#SConstuct file for Shelf

libs = Split("Ice IceUtil pthread boost_program_options boost_filesystem " +
             "boost_regex boost_system pqxx log4cxx dl ENM"),


env = Environment(CCFLAGS = ["-g", "-Wall"],
                  LINKFLAGS = ["-rdynamic"],
                  CPPPATH = ["#src", "/usr/local/include/coral"],
                  LIBS = libs,
                  SLICEPATH = ["/usr/share/Ice-3.5.1/slice"])

#check library
from SCons.SConf import *

def check_flags():
    e = Environment()
    conf = Configure(e)
    for lib in libs[0]:
        if not conf.CheckLib(lib):
            print "Can't find library ", lib, " exiting..."
            Exit(1)
    conf.Finish()

check_flags()

obj = env.Object(["src/ConfigLoader.cpp",
                  "src/Service.cpp",
                  "src/Template.cpp",
                  "src/Resource.cpp",
                  "src/Persistent.cpp",
                  "src/Plugin.cpp",
                  "src/Main.cpp"])


import os

def build_slice2cpp(target, source, env):

    cmd = "slice2cpp"
    for src in source:
        cmd += " " + str(src)

    tdir = str(source[0]).rpartition("/")[0]
    if tdir:
        cmd += " --output-dir " + tdir

    if "SLICEPATH" in env:
        for path in env["SLICEPATH"]:
            cmd += " -I" + path

    return os.system(cmd)

builder = Builder(action = build_slice2cpp, src_suffix = ".ice")

env.Append(BUILDERS = {"Slice": builder})
env.Slice(["src/Shelf.h", "src/Shelf.cpp"], "src/Shelf")
ice_obj = env.Object("src/Shelf.cpp")

env.Program("slf", [obj, ice_obj])

Export('env')
SConscript('src/plugins/SConscript')

Export('ice_obj')
SConscript('src/tests/SConscript')
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章