编译系统自动生成函数条件
一、概述
scons是一个Python写的自动化构建工具,和GNU make相比优点明显:
1、移植性:python能运行的地方,就能运行scons
2、扩展性:理论上scons只是提供了python的类,scons使用者可以在这个类的基础上做所有python能做的事情。比如想把一个已经使用了Makefile大型工程切换到scons,就可以保留原来的Makefile,并用python解析Makefile中的编译选项、源/目标文件等,作为参数传递给scons,完成编译。
3、智能:Scons继承了autoconf/automake的功能,自动解析系统的include路径、typedef等;“以全局的观点来看所有的依赖关系”
二、scons文件
scons中可能出现的文件:
SConstruct,Sconstruct,sconstruct,SConscript
scons将在当前目录以下次序 SConstruct,Sconstruct,sconstruct 来搜索配置文件,从读取的第一个文件中读取相关配置。
在配置文件SConstruct中可以使用函数SConscript()函数来定附属的配置文件。按惯例,这些附属配置文件被命名为”SConscript”,当然也可以使用任意其它名字。
三、scons的命令行参数
scons: 执行SConstruct中脚本
scons -c clean
scons -Q 只显示编译信息,去除多余的打印信息
scons -Q --implicit-cache hello 保存依赖关系
--implicit-deps-changed 强制更新依赖关系
--implicit-deps-unchanged 强制使用原先的依赖关系,即使已经改变
四、SConstruct提供的方法
1、Program:生成可执行文件
Program('hello.c') 编译hello.c可执行文件,根据系统自动生成(hello.exe on Windows; hello on POSIX)
Program('hello','hello.c') 指定Output文件名(hello.exe on Windows; hello on POSIX)
Program(['hello.c', 'file1.c', 'file2.c']) 编译多个文件,Output文件名以第一个文件命名
Program(source = "hello.c",target = "hello")
Program(target = "hello" , source = "hello.c")
Program('hello', Split('hello.c file1.c file2.c')) 编译多个文件
Program(Glob("*.c"))
src = ["hello.c","foo.c"];Program(src)
2、Object:生成目标文件
Object('hello.c') 编译hello.c目标文件,根据系统自动生成(hello.obj on Windows; hello.o on POSIX)
3、Library:生成静态/动态库文件
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
库的使用:
Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.') 连接库,不需加后缀或是前缀
4、SourceSignatures:判断源文件是否修改
SourceSignatures('MD5') 根据内容是否改变,默认方式
SourceSignatures('timestamp') 根据修改时间
5、TargetSignatures:判断目标文件是否改变
TargetSignatures('build') 根据编译结果
TargetSignatures('content') 根据文件内容,如果只是加了句注释,将不会被重新编译
6、Ignore:忽略依赖关系
Ignore(hello, 'hello.h') 忽略某个依赖关系
7、Depends:明确依赖关系
Depends(hello, 'other_file') 明确依赖关系
8、SConscript:scons的配置文件。
源文件的目录结构如下:
src:
| SConstruct
|test.cpp
| mA(目录):
| SConscript
| func.cpp
其中test.cpp为主文件,中调用func.cpp中定义的函数
SConstruct内容如下:
[cpp]view plain
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=Environment()
dict=env.Dictionary()
keys=dict.keys()
keys.sort()
forkeyinkeys:
print"constructionvariable='%s',value='%s'"%(key,dict[key])
- 环境变量的使用:
- env = Environment() #创建默认的环境变量,默认scons会按编译器的默认选项来进行编译
- import os
- env = Environment(CC = 'gcc',CCFLAGS = '-O2') #创建并设置环境 变量
- env.Program('foo.c')
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'])
obj=Object(Glob("*.cpp"))
Return("obj")
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"))
env.Program("test",list(obj),LIBS=['libstlport.a'])
- mA/SConscript:
[cpp]view plain
10.env:环境变量
环境变量用于设置在编译过程中的各种参数,可以用下面的SConstruct打印环境变量的所有信息(实际上env就是一个python字典)
可以使用如下的SConstruct查看环境变量的内容:
[cpp]view plain
环境变量的复制:
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如下:
[cpp]view plain
mA/SConscrip如下:
[cpp]view plain
不出意外的话上边的工程编译可以通过,但是运行的时候会Aborted。因为test.cpp,mA/func.cpp都使用了包含string类型的那个类,但是由于编译环境的不同,test.cpp认为string变量的大小是24字节, mA/func.cpp认为string变量的大小是4个字节(libstlport.a捣的鬼)。
解决问题的办法就是环境变量输出,修改SConstruct和mA/SConscript如下:
SConstruct:
[cpp]view plain
2. 编译程序与什么有关
编译程序与编程语言、编译器设计、计算机系统结构、操作系统以及计算机性能等多个方面有关。
首先,编译程序与编程语言密切相关。编译器是将高级编程语言编写的源代码转换为机器语言或低级语言的工具,因此不同的编程语言需要不同的编译器。例如,C语言编译器将C语言源代码转换为机器语言,而Java编译器将Java源代码转换为字节码。
其次,编译程序的设计和实现需要考虑计算机系统结构。不同的计算机体系结构有不同的指令集和寄存器集,因此编译器需要生成与特定体系结构兼容的机器代码。例如,x86架构的计算机使用不同的指令集和寄存器集,与ARM架构的计算机不同,因此针对这两种架构的编译器会生成不同的机器代码。
此外,编译程序还与操作系统密切相关。操作系统提供了许多系统调用和库函数,编译器需要将这些调用和函数与生成的机器代码链接起来,以便程序能够在特定的操作系统上运行。例如,Windows操作系统和Linux操作系统提供了不同的系统调用和库函数,因此针对这两个操作系统的编译器会生成不同的链接代码。
最后,编译程序还与计算机性能有关。编译器可以优化生成的机器代码,以提高程序的运行效率。例如,编译器可以使用不同的算法和技术来优化循环、减少内存访问、提高并行性等等。这些优化可以提高程序的性能,但也可能增加编译时间和生成的代码大小。
综上所述,编译程序与编程语言、编译器设计、计算机系统结构、操作系统以及计算机性能等多个方面有关。编译器是将高级编程语言转换为机器语言的重要工具,它的设计和实现需要考虑多个因素,包括语言特性、系统结构、操作系统和性能要求等等。
3. 析构函数的作用是什么
析构函数的作用是什么如下:
(3)编译系统自动生成函数条件扩展阅读:
函数介绍
与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统会自动执行析构函数。以C++语言为例:析构函数名也应与类名相同,只是在函数名前面加一个位取反符,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。
只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数。