• 使用 SCons 建造程序


    介绍,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'])       #该变量不存在才前插
  • 相关阅读:
    winfrom 获取当前系统时间
    netcore3.1API+efcore快速搭建
    php
    php
    php
    php-array的相关函数使用
    php-正则表达式
    vim的复制与粘贴
    vim的多窗口和文件切换操作
    laravel教程中出现500问题
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318705.html
Copyright © 2020-2023  润新知