Scons入门指南 使用教程 笔记

Scons入门指南 使用教程 笔记

说明:本文为作者阅读scons官方手册之后编写的笔记,更详细内容可以自行查看官方文档

1. 介绍

Scons是一个开放源码、以Python语言编码的自动化构建工具,类似于makefile,但是他没有像makefile那样晦涩难懂的语法,更加友好。此外scons支持跨平台使用,编写好scons脚本,可以在windows和linux下随意切换使用!

2. 安装scons

先安装python3,之后使用python的pip安装工具安装scons,安装过程中的问题大家可以网上查查或者看错误提示,基本都能解决,以下是linux下安装关键指令

sudo apt install python
pip install scons

3. Scons初步使用

  首先记住,scons是以python语言编码的,所以支持python语法!当然没学过python也没关系,会几个指令也能玩

3.1 编译程序

源代码hello.c

int main()
{
printf("Hello, world!\n");
}

同级目录下创建名字为Sconstruct 的文件,内容如下

Program('hello.c')

然后在当前目录命令窗口输入scons即可编译工程

% scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o hello.o -c hello.c
cc -o hello hello.o
scons: done building targets.

在不同的系统下,scons会自动识别系统环境,采用对应系统下的指令进行编译,生成对应系统下可执行的文件,如windows下就会生成.exe文件

3.2 生成Object文件

修改Sconstruct 文件如下

Object('hello.c')

之后在当前目录命令窗口输入scons重新编译工程即可

3.3 清除工程

命令:scons -c

4. Sconstruct文件

  1. Sconstruct文件是一个python脚本,支持python语法,使用#注释
  2. 使用print 打印
  3. 屏蔽非必要的scons输出 scons -Q

5. 简单的编译工程示例

5.1 指定生成目标文件名字

修改Sconstruct文件为:

Program ('new_hello', 'hello.c')

重新编译工程

% scons -Q
cc -o hello.o -c hello.c
cc -o new_hello hello.o

5.2 编译多个源文件

  1. 在工程中往往有多个源文件一起组合生成一个目标文件,scons这样实现,修改Sconstruct文件如下:
Program(['prog.c', 'file1.c', 'file2.c'])

编译工程

% scons -Q
cc -o file1.o -c file1.c
cc -o file2.o -c file2.c
cc -o prog.o -c prog.c
cc -o prog prog.o file1.o file2.o
  1. 加上指定生成文件名,修改Sconstruct文件如下:
Program('program', ['prog.c', 'file1.c', 'file2.c'])

编译工程

% scons -Q
cc -o file1.o -c file1.c
cc -o file2.o -c file2.c
cc -o prog.o -c prog.c
cc -o program prog.o file1.o file2.o
  1. 如果文件比较多,可以采用Glob函数查找符合条件的文件制作一个文件列表,同时还支持使用shell模式匹配字符* ? [abc][!abc] ,修改Sconstruct如下:
Program('program', Glob('*.c'))

5.3 指定单个文件和指定多个文件

  1. 指定单个文件
    a) 采用字串方式:Program('hello', 'hello.c')
    b) 采用列表方式Program('hello', ['hello.c'])
  2. 指定多个文件Program('hello', ['file1.c', 'file2.c'])
  3. 尽管python支持采用字符串或者列表指定文件,但是注意不支持混合使用
common_sources = ['file1.c', 'file2.c']

# 以下操作错误,因为采用了 字符串+列表 方式
Program('program1', common_sources + 'program1.c')

# 以下操作正确,因为采用的是 列表+列表 方式
Program('program2', common_sources + ['program2.c'])

5.4 采用变量让文件列表方便阅读

对源文件使用python列表的一个缺点是,每个文件必须使用引号括起来,当文件名列表非常长的时候,这可能难以阅读,scons和python提供了许多方法使得Sconstruct易于阅读,scons提供了spilt函数,该函数受引用括号括起来的文件名列表,名称用空格或其他空白分隔符分隔,并将其转化为一个单独的文件名列表

Program('program', Split('main.c file1.c file2.c'))

加上变量

src_files = Split('main.c file1.c file2.c')
Program('program', src_files)

加上换行,方便编写

src_files = Split("""	main.c
						file1.c
						file2.c""")
Program('program', src_files)

注意这里可以使用"""或者 ""或者 " 都可以

5.5 采用关键字

scons允许你对于源文件和输出文件使用pyhton关键字targetsource定义,采用关键字之后传入参数的位置顺序可以随便放置

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')

5.6 同时编译多个程序

Program('foo.c')
Program('bar', ['bar1.c', 'bar2.c'])

输出

% scons -Q
cc -o bar1.o -c bar1.c
cc -o bar2.o -c bar2.c
cc -o bar bar1.o bar2.o
cc -o foo.o -c foo.c
cc -o foo foo.o

5.7 编译多个程序时的共享文件

如果不处理时会是这样

Program(Split('foo.c common1.c common2.c'))
Program('bar', Split('bar1.c bar2.c common1.c common2.c'))

这样有一个缺点,当需要增加公共文件时,会维护困难,容易遗漏,可以使用下面此方式

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)

6. 建立和链接库文件

6.1 生成库文件

Library('foo', ['f1.c', 'f2.c', 'f3.c'])

输出

% scons -Q
cc -o f1.o -c f1.c
cc -o f2.o -c f2.c
cc -o f3.o -c f3.c
ar rc libfoo.a f1.o f2.o f3.o
ranlib libfoo.a

默认生成静态库文件,同时scons会根据不同的系统生成对应的库文件,此外scons还会自动给库文件增加前缀和后缀

6.1.1 使用源文件+Object文件生成库文件
Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o'])

输出

% scons -Q
cc -o f1.o -c f1.c
cc -o f3.o -c f3.c
ar rc libfoo.a f1.o f2.o f3.o f4.o
ranlib libfoo.a
6.1.2 指定生成静态库文件StaticLibrary
StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])
6.1.3 指定生成动态库文件SharedLibrary
SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])

6.2 链接库文件

使用$LIBS指定库文件,使用$LIBPATH指定库文件路径

Library('foo', ['f1.c', 'f2.c', 'f3.c'])
Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')

注意,在使用库文件的时候,不用为其添加前缀和后缀,如lib .a .so,scons会根据当前的系统自动添加前缀和后缀

6.3 查找库文件:使用$LIBPATH构造变量

链接器默认只会从系统定义的目录中去查找库,scons知道如何在使用$LIBPAH构造变量指定的目录中查找库,$LIBPATH包含一个目录名列表,如下所示:

Program('prog.c', LIBS = 'm',
					LIBPATH = ['/usr/lib', '/usr/local/lib'])

使用python列表是首选,因为它可以跨系统移植,或者你可以把目录名放在一个字符串中,用系统特定的分隔符分隔,注意分隔符,linux里面使用:,windows里面使用;
linux:LIBPATH = '/usr/lib:/usr/local/lib'
windows:LIBPATH = 'C:\\lib;D:\\lib'
上述Sconstruct执行如下:

% scons -Q
cc -o prog.o -c prog.c
cc -o prog prog.o -L/usr/lib -L/usr/local/lib -lm
单链表是一种常见的数据结构,用于存储一系列的节点连接起来的数据。 在C语言中,我们可以使用结构体来定义一个节点,包含一个数据域和一个指向下一个节点的指针域。代码如下: ```c struct Node { int data; struct Node* next; }; ``` 然后,我们可以定义一个指向链表头部的指针,表示整个链表的起始位置。初始化链表时,这个指针可以指向NULL。 ```c struct Node* head = NULL; ``` 接下来,我们可以实现一些基本的操作,例如插入节点、删除节点、遍历链表等。 插入节点的过程包括创建一个新节点,并将其插入到链表中适当的位置。 ```c void insertNode(int value) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); newNode->data = value; newNode->next = NULL; if (head == NULL) { head = newNode; } else { struct Node* curr = head; while (curr->next != NULL) { curr = curr->next; } curr->next = newNode; } } ``` 删除节点的过程需要找到目标节点,并调整前后节点的指针。 ```c void deleteNode(int value) { if (head == NULL) { return; } if (head->data == value) { struct Node* temp = head; head = head->next; free(temp); return; } struct Node* prev = head; struct Node* curr = head->next; while (curr != NULL && curr->data != value) { prev = curr; curr = curr->next; } if (curr != NULL) { prev->next = curr->next; free(curr); } } ``` 遍历链表的过程是从头节点开始,依次打印每个节点的数据。 ```c void printList() { struct Node* curr = head; while (curr != NULL) { printf("%d ", curr->data); curr = curr->next; } printf("\n"); } ``` 这是一个简单的单链表的实现示例,你可以根据需要进一步扩展和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱出名的狗腿子

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值