scons123

1.SConstruct 文件是scons用来控制编译的文件
                 是python脚本
                 告诉scons做什么,而不是严格规定scons做这件事的步骤
    scons中可能出现的文件:SConstruct,Sconstruct,sconstruct,SConscript
    scons将在当前目录以下次序 SConstruct,Sconstruct,sconstruct 来搜索配置文件,从读取的第一个文件中读取相关配置
    在配置文件SConstruct中可以使用函数SConscript()函数来定附属的配置文件。按惯例,这些附属配置文件被命名为”SConscript”,当然也可以使用任意其它名字
    源文件的目录结构如下:
    src:
    |-SConstruct
    |-test.cpp
    |-mA(目录):
      |-SConscript
      |-func.cpp
    其中test.cpp为主文件,调用func.cpp中定义的函数
    SConstruct内容如下:
        subobj = SConscript(['mA/SConscript'])
        obj = subobj + Object(Glob("*.cpp"))
        Program("test",list(obj))
    SConscript内容 :
        obj = Object(Glob("*.cpp"))
        Return("obj")
    上例中,在主目录中执行 scons就可以编译整个"工程"。
    SConstruct编译主目录中的test.cpp,并通过SConscript编译mA目录下的源文件,并最终生成可执行文件;
    SConscript用于编译mA中的func.cpp并把生成的func.o传递给主目录的SConstruct。
    env:环境变量
        环境变量用于设置在编译过程中的各种参数,可以用下面的SConstruct打印环境变量的所有信息
        (实际上env就是一个python字典)
        可以使用如下的SConstruct查看环境变量的内容:
            env = Environment()
            dict = env.Dictionary()
            keys = dict.keys()
            keys.sort()
            for key in keys:
                print "construction variable = '%s', value = '%s'" % (key, dict[key])
        环境变量的使用:
            env = Environment()   #创建默认的环境变量,默认scons会按编译器的默认选项来进行编译
            import os
            env = Environment(CC = 'gcc',CCFLAGS = '-O2') #创建并设置环境 变量
            env.Program('foo.c')
        环境变量的复制:
            env = Environment(CC = 'gcc')
            opt = env.Clone(CCFLAGS = '-O2')
            dbg = env.Clone(CCFLAGS = '-g')
        环境变量的替换:
            env = Environment(CCFLAGS = '-DDEFINE1')
            env.Replace(CCFLAGS = '-DDEFINE2')
            env.Program('foo.c') 
        环境变量的输入输出:用于统一多目录源文件的编译选项,如:
            src:
            |-SConstruct
            |-libstlport.a
            |-test.cpp
            |-include(目录):
              |-foo.h
            |-mA(目录):
              |-SConscript
              |-func.cpp
        test.cpp和mA/func.cpp都引用了include/foo.h,test.cpp调用了mA/func.cpp的功能函数,
        其中include/foo.h中定义了一个包含string类型的类。
        SConstruct如下:
            env = Environment()
            flags = env.ParseFlags(['-pthread -I/usr/include/stlport ',' -L .'])
            env.MergeFlags(class_flags)
            subobj = SConscript(['mA/SConscript'])
            obj = subobj + env.Object(Glob("*.cpp"))
            env.Program("test",list(obj),LIBS = ['libstlport.a'])
        mA/SConscrip如下:
            obj = Object(Glob("*.cpp"))
            Return("obj")
        不出意外的话上边的工程编译可以通过,但是运行的时候会Aborted。因为test.cpp,mA/func.cpp都使用了包含string类型的那个类,但是由于编译环境的不同,test.cpp认为string变量的大小是24字节, 
        mA/func.cpp认为string变量的大小是4个字节(libstlport.a捣的鬼)。
        解决问题的办法就是环境变量输出,修改SConstruct和mA/SConscript如下:
        SConstruct:
            env = Environment()
            flags = env.ParseFlags(['-pthread -I/usr/include/stlport ',' -L .'])
            env.MergeFlags(class_flags)
            Export('env')
            subobj = SConscript(['mA/SConscript'],exports = 'env')
            obj = subobj + env.Object(Glob("*.cpp"))
        mA/SConscript:
            Import('env')
            obj = env.Object(Glob("*.cpp"))
            Return("obj")
env.Program("test",list(obj),LIBS = ['libstlport.a'])
2.scons 编译选项
    -c  编译之后清理中间文件
    -Q  使scons输出更整洁,只显示编译信息,去除多余的打印信息
3.SConstruct 脚本编写基础
    1)Program          生成的可执行文件
       Object           生成目标文件
       Library          生成静态库(可以使用StaticLibrary)
       SharedLibrary    生成动态库
       
       Program(['prog.c', 'file1.c', 'file2.c'])                # 生成 prog.exe
       Program('program', ['prog.c', 'file1.c', 'file2.c'])     # 生成program.exe
       Program('program', ['prog.c', 'file1.obj', 'file2.obj']) # 可以在文件列表中指定.obj文件
       Program('program', Glob('*.c'))                          # 使用Glob 编译所有匹配的文件
       Program('program', Split('main.c file1.c file2.c'))      # Split以空白字符为分隔符,将字符串分割
       Program('program', Split('main.c file1.c file2.c'))      # ,因此,你也可以这样写:
       Program('program', Split("""
                                main.c
                                file1.c
                                file2.c
                                """))
       Program(target = 'program', source = 'hello.c')          # 使用关键字参数
       Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')      # 链接库,不需加后缀或是前缀
       Library('foo', ['f1.c', 'f2.c', 'f3.c'])                 # 编译library
       SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])           # 编译 shared library
       StaticLibrary('bar', ['f4.c', 'f5.c', 'f6.c'])           # 编译 static library
       SourceSignatures:判断源文件是否修改
            SourceSignatures('MD5')         根据内容是否改变,默认方式
            SourceSignatures('timestamp')   根据修改时间
       TargetSignatures:判断目标文件是否改变
            TargetSignatures('build')   根据编译结果
            TargetSignatures('content')  根据文件内容,如果只是加了句注释,将不会被重新编译
       
    2)指定编译选项
       $CPPFLAGS            指定编译选项
       $LINKFLAGS           指定链接选项, 如 /DEBUG
       $CPPDEFINES          指定预编译器
       $LIBS                指定所需要链接的库文件
       $LIBPATH             指定库文件(.lib)的搜索目录
       $CPPPATH             指定[.h, .c, .cpp]等文件搜索路径
       eg: Library('foo', Split('f1.c f2.c f3.c'))
       Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')
       Ignore:忽略依赖关系
             Ignore(hello, 'hello.h')  忽略某个依赖关系
       Depends:明确依赖关系
             Depends(hello, 'other_file') 明确依赖关系
    3)Environments 环境变量
       外部环境是运行Scons时 用户的环境变量。它们可以通过os.environ获取
            
       构建环境 Construction Environment,包含一些变量,这些变量会影响Scons构建目标的行为
            > 创建 construction Environment:
              env = Environment()
              一个Environment是一个 (name,value)的集合,可以这样查看它的内容:
              for item in env.Dictionary():
                  print '(%s:%s)' % (item, env[item])
            > 查看变量
              env['CC']         # 查看 CC ,即C语言编译器
              env.subst('$CC')  # 功能同上
            > 修改环境变量
              拷贝一个环境变量,使用env.Clone
              替换一个已经存在的环境变量,env.Replace
              为一个没有被定义的变量设置默认值,env.SetDefault
              为一个已存在的环境变量增加一个值,env.Append, 例如:env.Append(CCFLAGS = '-option -O3 -O1')
                                                                  env.Append(CCFLAGS = ['-option', 'O3'])
              为一个环境变量增加一个唯一的值,env.AppendUnique
              在最前边添加一个值,env.Prepend
              在最前边添加一个唯一的值,env.PrependUnique
              合并环境变量,env.MergeFlags, 例如:flags = {'CCFLAGS':'-option -O3 -O1'}
                                                  env.MergeFlags(flags)
                                                  flags = {'CPPPATH' : ['/user/opt/include', 'user/local/include']}
                                                  env.MergeFlags(flags)
            > 一些实用的变量
              判断是否是windows: env['PLATFORM'] == 'win32'
              
              
       执行环境 Execution Environment,执行环境用于Scons执行外部命令(external command), 以构建一个或多个目标,注意:它与外部环境不相同
            当scons构建一个目标文件时,它所使用的外部环境和执行scons时的环境变量是不同的。
            scons使用$ENV 构建变量 中 存储的目录 作为它执行命令的外部环境变量
            > PATH 
              POSIX 系统中默认的PATH是 /user/local/bin:/user/bin
              Window系统中默认的PATH是 command interpreter在注册表中的值
              在构建环境中显示初始化PATH
                path = ['/user/local/bin', '/bin', '/user/bin']
                env = Environment(ENV = {'PATH':path})
                上面这种方式,只设置了ENV,如果你想保留其他的变量,可以这么做:env['ENV']['PATH'] = ['/user/local/bin', '/bin', '/user/bin']
              从 外部环境 初始化 PATH
                import os
                env = Environment(ENV = {'path' : os.environ['PATH']})
                你也可以将完整的外部变量传递给执行环境变量:
                    import os
                    env = Environment(ENV = os.environ)
                    这样做的缺点是:如果环境变量目录中,有多个目录包含编译器如gcc,那么,scons将执行第一个被找到的gcc
              使用env.PrependENVPath 和 env.AppendENVPath
                例如:将'/user/local/bin' 插入 $PATH中第一个位置,env.PrependENVPath('PATH', '/user/local/bin')
                例如:将'/user/local/bin' 插入 $LIB中最后一个位置,env.AppendENVPath('lib', '/user/local/lib')
    4)控制编译输出
       Help('this is a debug version'),在控制台上使用 scons -h 命令查看此帮助信息
       你可以在脚本中多次使用Help,帮助信息会被连接到一起
    5)scons 命令行参数
       用户可以为scons指定三种类型的参数:
            > Options    : 以 一个或两个(-) 开头 , 详细参考 User Guide 10.1
            > Variables  : 形式为:variable=value, 详细参考            10.2
            > Target     : 如果不是一个 Option 或 Variable ,那么就是一个Target , 详细参考 User Guide 10.3
       读取命令行的Variable参数
            命令行:scons debug=1
            SConstruct脚本如下:
            debug = ARGUMENTS.get('debug', 0)
            if int(debug) :
                pass # do something
       命令行Targets
            scons提供 COMMAND_LINE_TARGETS 供用户访问命令行参数中的 Targets列表,例如:
            if 'bar' in COMMAND_LINE_TARGETS:
                print "Don't forget to copy 'bar' to the archivel"
            Default(Program('foo.c'))
            Program('bar.c')
            使用 Default函数 定义 默认目标,当你没有在命令行参数中指定目标时,scons会编译每一个目标
                例子:
                env = Environment()
                hello = env.Program('hello.c')
                env.Program('goodbye.c')
                Default(hello)      #如果没有在命令行指定Target,则会编译hello
            使用DEFAULT_TARGETS获取 默认目标, 例如:
                prog1 = Program('prog1.c')
                Default(prog1)
                print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
            使用 BUILD_TARGETS 获取要编译的目标
    6)控制目标文件的路径
       1. BINDIR
            > 使用Install:如,
              test = env.Program('test.cpp')
              env.Install('bin', 'test.exe') #表示要将test.exe 放到bin目录下
              或
              env.Install('bin', test)
            > 在指定目标名的时候指定其目录,如:
              env.Program('bin/test', 'test.cpp')
            > 将目标放到其他目录下,并修改名字
              test = env.Program('test.cpp')
              env.InstallAs('bin/testapp.exe', 'test.exe') #表示将test.exe 拷贝到 bin/testapp.exe
              或
              env.InstallAs('bin/testapp', test)
            当 需要对多个目标做此操作时,可以这样做:
            env = Environment()
            hello = env.Program('hello.c')
            goodbye = env.Program('goodbye.c')
            env.InstallAs(['/usr/bin/hello-new', '/usr/bin/goodbye-new'], [hello, goodbye]) #多个目标
            env.Alias('install', '/usr/bin')
       2. obj文件路径
          使用VariantDir函数指定
       3. 一份代码构建多个版本的Target
          通常会有这样的需求,一份源码,既要构建它的debug版本,又要构建它的release版本,这种情况下,
          > 我们需要为不同版本指定不能的obj名字,否则就会产生冲突,导致scons不能工作。简单的示例如下:
            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.o
            dbg.Program(d)
          > 或者将不同版本的obj放到不同的路径下:
            o = opt.Object('opt/foo', 'foo.c')  // 生成 foo-opt.o
            opt.Program(o)
            
            d = dbg.Object('dbg/foo', 'foo.c')  // 生成 foo-dbg.o
            dbg.Program(d)
            
       
       

你可能感兴趣的:(Linux)