scons

scons  

2010-08-07 11:30:29|  分類:linux|  標籤:|字號 訂閱

介紹,scons用的是python語法。需要安裝python和scons後才能運行,能夠跨平臺。比較automake自動生成makefile文件,scons可以認爲直接是make的功能,因爲只需要執行scons命令就等於執行了make的功能。
現在有一個hello.c的文件。
新建一個SConstruct文件,是一個python腳本文件。
Program('hello.c')   編譯hello.c並生成.o文件和可執行文件
Object('hello.c')    編譯hello.c但只生成生成.o文件
這兩個方法都是python的method。
如果想執行clean操作,我們不需要再象makefile那樣指名make clean語句,而是直接執行scons -c 或者scons -clean就可以。程序會根據SConstruct文件內容自動清除。
SConstruct的讀取和執行順序是彼此獨立的,直接看以下例子。
SConstruct文件內容:
       print "Calling Program('hello.c')"     
       Program('hello.c')
       print "Calling Program('goodbye.c')"     
       Program('goodbye.c')
       print "Finished calling Program()"
執行結果:
 % scons
       scons: Reading SConscript files ...
       Calling Program('hello.c')    (1)
       Calling Program('goodbye.c')   (2)
       Finished calling Program()
       scons: done reading SConscript files.
       scons: Building targets ...
       cc -o goodbye.o -c goodbye.c    (2)
       cc -o goodbye goodbye.o          (1)
       cc -o hello.o -c hello.c
       cc -o hello hello.o
       scons: done building targets.
由於在執行scons時一些輸出信息反而會混淆我們,所以可以加參數  -Q來關閉一些輸出提示。
Program('new_hello', 'hello.c') #第一個參數可以指定目標文件名字,默認爲hello,第二個參數就是source files。
多源文件編譯指定:
Program('program', ['prog.c', 'file1.c', 'file2.c']) #如果沒有第一個參數,則以第二個參數(這是一個python list,用【】表示)的第一個元素爲program的名字。
如果你覺得列表裏面每個文件都需要帶一個引號太麻煩,可以利用
Program('program', Split('main.c file1.c file2.c')) #這裏的split函數是返回一個列表
也可以這麼用來提高可讀性
src_files = Split('main.c file1.c file2.c')    #中間多少個空格無所謂
Program('program', src_files)
也可利用Glob函數獲得名字列表,Golb('*.c')返回規則匹配的string列表,就是類似上面的'prog.c', 'file1.c', 'file2.c'。
Program('program', Glob('*.c'))

兩個關鍵字可以直接指明target和source,所以在Program

src_files = Split('main.c file1.c file2.c')
Program(target = 'program', source = src_files)
   
src_files = Split('main.c file1.c file2.c')
Program(source = src_files, target = 'program') #可以調換參數順序

多工程共享source files的話:
       common = ['common1.c', 'common2.c'] #把共同的文件列表單獨提取出來,以便維護
       foo_files = ['foo.c'] + common
       bar_files = ['bar1.c', 'bar2.c'] + common
       Program('foo', foo_files)
       Program('bar', bar_files)
building library:
Library('foo', ['f1.c', 'f2.c', 'f3.c'])    #文件列表   #靜態庫
Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o']) #文件列表喝object文件
StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])  #靜態library,其實跟Library調用沒區別,只是顯示強調是靜態庫
SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])  #共享庫,類似dll

The output on POSIX:

        % scons -Q
        cc -o f1.os -c f1.c
        cc -o f2.os -c f2.c
        cc -o f3.os -c f3.c
        cc -o libfoo.so -shared f1.os f2.os f3.os

link library:

     Library('foo', ['f1.c', 'f2.c', 'f3.c'])
     Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')  #指定庫,指定庫的路徑。
注意-l,-L,-i,-I的用法。
LIBPATH變量:
LIBPATH = '/usr/lib:/usr/local/lib'  #unix用:分開
 LIBPATH = 'C:\\lib;D:\\lib'   #windows用;分開
CPPPATH變量:類似 -I指定,指定編譯目錄     #聲明瞭這個選項是用於隱式依賴,比如某些cpp文件包含了h文件,當這些h文件更改時,就會重編這些cpp對應的對象。每次編譯的時候,會去搜索這些隱式依賴,所以會消耗一些時間
Program('hello.c', CPPPATH = '.')  #這裏會讓編譯器同時關注hello.c裏面include的h文件

Program('hello.c', CPPPATH = ['include', '/home/project/inc'])
編譯結果:
% scons -Q hello
  cc -o hello.o -c -Iinclude -I/home/project/inc hello.c
  cc -o hello hello.o
--implicit-cache參數可讓scons高速緩存哪些隱式依賴關係,這樣能減少搜索隱私依賴的時間。如:
% scons -Q --implicit-cache hello
       cc -o hello.o -c hello.c
       cc -o hello hello.o
       % scons -Q hello
       scons: `hello' is up to date.
當你不想每次都輸入這個參數時,可以在SConstruct文件中加入這個語句:SetOption('implicit_cache', 1)
有時scons掃描器檢查不出一些文件的依賴性,可以利用Depends函數顯示地的指明依賴性:
       hello = Program('hello.c')
       Depends(hello, 'other_file')
如果想讓某個依賴文件改變時不重編,可以用Ignore函數設置忽略這些依賴性:
      hello_obj=Object('hello.c')
      hello = Program(hello_obj)
      Ignore(hello_obj, 'hello.h')
每次都想重編一個目標,可用AlwaysBuild函數設置:
      hello = Program('hello.c')
      AlwaysBuild(hello)
環境變量:有三種,外部環境變量(外部環境信息),scons環境變量(控制scons行爲的變量),執行環境變量。變量是很多變量的集合,包括變量名和變量值。
env = Environment()   #創建默認的環境變量,默認scons會按編譯器的默認選項來進行編譯
import os

         env = Environment(CC = 'gcc',CCFLAGS = '-O2') #創建並設置環境 變量

         env.Program('foo.c')
 % scons -Q
         gcc -o foo.o -c -O2 foo.c
         gcc -o foo foo.o
環境變量訪問:env = Environment()
            print "CC is:", env['CC']
另一種訪問環境變量的方法,試用環境變量的subst方法,而且它還對下面的變量不斷展開直到無法繼續展開,例如下面兩個例子:
env = Environment(CCFLAGS = '-DFOO')
       print "CCCOM is:", env['CCCOM']          #輸出 CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINC                                                   FLAGS -c -o $TARGET $SOURCES
       print "CCCOM is:", env.subst('$CCCOM')  #輸出  CCCOM is: gcc -DFOO -c -o  #這裏將上面的變量值展開了
默認環境DefaultEnvironment(); 試用方法跟上面的環境變量一樣,不過控制範圍是默認的所有配置。在默認環境中設置好一些變量,可以提高編譯速度,比如在默認環境變量中制定了編譯器的位置,這樣的話可以省去搜索 默認編譯器位置的 消耗。如:
env = DefaultEnvironment(tools = ['gcc', 'gnulink'], CC = '/usr/local/bin/gcc') #顯式指定編譯器位置
多環境變量:  opt = Environment(CCFLAGS = '-O2')
           dbg = Environment(CCFLAGS = '-g')

           opt.Program('foo', 'foo.c')

           dbg.Program('bar', 'bar.c')
複製環境變量:env = Environment(CC = 'gcc')
         opt = env.Clone(CCFLAGS = '-O2')
         dbg = env.Clone(CCFLAGS = '-g')

         env.Program('foo', 'foo.c')

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

         d = dbg.Object('foo-dbg', 'foo.c')
         dbg.Program(d)
替換環境變量值:env = Environment(CCFLAGS = '-DDEFINE1')
            env.Replace(CCFLAGS = '-DDEFINE2')
            env.Program('foo.c')
替換注意事項: env = Environment(CCFLAGS = '-DDEFINE1')   #-DDEFINE1
         print "CCFLAGS =", env['CCFLAGS']    
         env.Program('foo.c')

         env.Replace(CCFLAGS = '-DDEFINE2')    #-DDEFINE2
         print "CCFLAGS =", env['CCFLAGS']
         env.Program('bar.c')
           #上面設置了兩次,但當程序開始編譯的時候,只會以最後一次配置的值爲準,所以請看下面的結果:
 % scons
         scons: Reading SConscript files ...
         CCFLAGS = -DDEFINE1
         CCFLAGS = -DDEFINE2
         scons: done reading SConscript files.
         scons: Building targets ...
         cc -o bar.o -c -DDEFINE2 bar.c
         cc -o bar bar.o
         cc -o foo.o -c -DDEFINE2 foo.c
         cc -o foo foo.o
         scons: done building targets.
env.SetDefault(SPECIAL_FLAG = '-extra-option')  #默認變量不存在時設置
  添加新的變量:  env = Environment()
               env.Append(NEW_VARIABLE = 'added')  #不存在時自動創建並賦值;存在時變量的值是append上去而不是assign的
               env.AppendUnique(CCFLAGS=['-g'])    #該變量不存在時才添加
              env.Prepend(CCFLAGS = ['-DFIRST'])  #在變量值前面插入,不存在則自動創建並賦值,跟append相似
              env.PrependUnique(CCFLAGS=['-g'])       #該變量不存在才前插

發佈了9 篇原創文章 · 獲贊 5 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章