Scons 五:完整的工程
工程的组织目录如下:
├── core
│ ├── inc
│ │ └── bsp.h
│ ├── SConscript
│ ├── src
│ │ ├── fsm.c
│ │ ├── fsm.h
│ │ ├── log.c
│ │ ├── log.h
│ │ └── SConscript
│ ├── test1.c
│ └── test1.h
├── main.c
├── phy
│ ├── inc
│ │ └── phy_inc.h
│ ├── SConscript
│ ├── src
│ │ └── Sconscript
│ ├── test2.c
│ └── test2.h
├── Sconstruct
└── wifi
├── inc
│ └── protol.h
├── SConscript
├── src
│ └── SConscript
├── test3.c
└── test3.h
分成3个模块core,phy,wifi。每个模块目录下都有inc和src两个文件夹。分别放.h和.c文件。首先来看core模块
Inc中包含bsp.h文件
内容如下。定义了x变量
#define x 1
Src下面分别有fsm.c, fsm.h,log.c,log.h,SConscript
Fsm.c
#include <stdio.h>
#include "fsm.h"
void fsm_print()
{
printf("fsm_log_level=%d\n",fsm_level);
printf("fsm_print\n");
}
Fsm.h
#define fsm_level 1
void fsm_print();
log.c
#include <stdio.h>
#include "log.h"
void log_print()
{
printf("log_print\n");
}
log.h
void log_print();
SConscript的内容。编译所有的.c文件并且返回所有的obj文件
from SCons.Script import *
from scons.SCons import *
Import('env')
source_file_list=[]
def find_source_file():
for file in os.listdir(os.getcwd()):
if file.endswith('.c'):
c_path=os.path.join(os.getcwd(),file)
source_file_list.append(c_path)
find_source_file()
fsm_object=env.Object(source_file_list)
Return('fsm_object')
在core目录下有test1.c,test1.h, SConscript
Tets1.c
#include <stdio.h>
#include "bsp.h"
void core_test()
{
printf("x=%d\n",x);
printf("core_test1\n");
}
Test1.h
void core_test();
SConscript
import sys
import os
import re
from SCons.Script import *
from scons.SCons import *
Import('env')
subdir = ''
subdir +='src '
source_file_list=[]
include_file_list=[]
incdir = ''
incdir +='inc '
object_list=[]
def find_source_file():
for file in os.listdir(os.getcwd()):
if file.endswith('.c'):
c_path=os.path.join(os.getcwd(),file)
source_file_list.append(c_path)
def scons_script_recursive():
print("scons_script_recursive,subdir=%s\n" % subdir)
subdir_list=subdir.split(' ')
print(subdir_list)
subdir_list.pop()
for dir in subdir_list:
dir_path=os.path.join(os.getcwd(),dir)
obj=SConscript(os.path.join(dir_path,'SConscript'))
object_list.append(obj)
def get_include_path():
dir_tmp=incdir.split(' ')
dir_tmp.pop()
for include_file in dir_tmp:
include_file_path=os.path.join(os.getcwd(),include_file)
include_file_path_env=include_file_path+' '
env.Append(include=include_file_path_env)
include_file_list.append(include_file_path)
scons_script_recursive()
get_include_path()
find_source_file()
core_object=env.Object(source_file_list,CPPPATH=include_file_list)
object_list.append(core_object)
env.Library('core',object_list)
1 首先递归的执行子目录下的SConscript,并且将返回的obj对象append到object_list
2 找到当前目录下所有的.c文件并编译成object文件append到object_list
3 将object_list中的所有.o文件打包成.a文件供后面连接使用
同样的步骤适合phy和wifi模块
Phy模块test2.c
#include <stdio.h>
#include "phy_inc.h"
void phy_test()
{
printf("phy=%d\n",phy);
printf("phy_test1\n");
}
Test2.h
void phy_test();
phy_inc.h
#define phy 3
wifi模块
test3.c
#include <stdio.h>
#include "protol.h"
void wifi_test()
{
printf("version=%d\n",version);
printf("wifi_test1\n");
}
Test3.h
void wifi_test();
protol.h
#define version 4
最后main.c的代码如下:
#include <stdio.h>
#include "test1.h"
#include "test2.h"
#include "test3.h"
#include "fsm.h"
#include "log.h"
void main()
{
printf("test1.c\n");
iot_core_test();
phy_test();
wifi_test();
fsm_print();
log_print();
}
SConscript:
import sys
import os
import re
from SCons.Script import *
from scons.SCons import *
from build_software import *
env = Environment()
env['subdir']='core '
env.Append(subdir='phy ')
env.Append(subdir='wifi ')
env['include']=''
Export('env')
print(env['subdir'])
source_file_list=[]
target='main'
link_path=['core','phy','wifi']
obj_list=[]
obj_path_list=[]
include_path_list=[]
inc_path = 'core/src '
def find_source_file():
for file in os.listdir(os.getcwd()):
if file.endswith('.c'):
source_file_list.append(file)
def find_all_object_file():
complete_path=[]
for link in link_path:
complete_path.append(os.path.join(os.getcwd(),link))
for path in complete_path:
for root,dir,files in os.walk(path):
for f in files:
if f.endswith('.o'):
print(f)
obj_path_list.append(root)
obj_list.append(f)
def find_all_include_path():
tmp_path_list=inc_path.split(' ')
for tmp_path in tmp_path_list:
tmp_path=os.path.join(os.getcwd(),tmp_path)+' '
env.Append(include=tmp_path)
include_path=env['include'].split(' ')
include_path.pop()
for path in include_path:
include_path_list.append(path)
for l in link_path:
include_path_list.append(os.path.join(os.getcwd(),l))
def get_target():
Progress("get_target")
main=env.Program('main.c',CPPPATH=include_path_list,LIBS=obj_list)
subdir_path=env['subdir'].split(' ')
subdir_path.pop()
def sub_scons():
path_list=[]
for scons_file in subdir_path:
path=os.path.join(os.getcwd(),scons_file)
path_list.append(os.path.join(path,'SConscript'))
SConscript(path_list)
complete_flag=True
sub_scons()
find_source_file()
find_all_include_path()
env.Append(LIBPATH=['./core','./phy','./wifi'])
env.Program('main.c',CPPPATH=include_path_list,LIBS=link_path)
1 执行子目录的SConscript文件
2 找到当前目录下的所有c文件
3 找到所有的include路径
4 设置外部链接library的路径和名称,最终编译main.c文件
最终执行结果:
scons: Reading SConscript files ...
scons_script_recursive,subdir=src
['src', '']
scons: done reading SConscript files.
scons: Building targets ...
gcc -o core/src/fsm.o -c core/src/fsm.c
gcc -o core/src/log.o -c core/src/log.c
gcc -o core/test1.o -c -Icore/inc core/test1.c
ar rc core/libcore.a iot_core/src/fsm.o iot_core/src/log.o core/test1.o
ranlib core/libiot_core.a
gcc -o main.o -c -Iiot_core/inc -Iphy/inc -Iwifi/inc -Iiot_core/src -I. -Iiot_core -Iphy -Iwifi main.c
gcc -o phy/test2.o -c -Iphy/inc phy/test2.c
ar rc phy/libphy.a phy/test2.o
ranlib phy/libphy.a
gcc -o wifi/test3.o -c -Iwifi/inc wifi/test3.c
ar rc wifi/libwifi.a wifi/test3.o
ranlib wifi/libwifi.a
gcc -o main main.o -Liot_core -Lphy -Lwifi -lcore -lphy -lwifi
scons: done building targets.
如果我们想将目标文件安装到系统路径中去,也就是可以运行命令的方式那样运行目标文件。可以用install的方式。
在Sconstruct的最后几行修改如下:将最终编译的文件安装到/usr/local/bin目录下
tar=env.Program('main.c',CPPPATH=include_path_list,LIBS=link_path)
env.Install('/usr/local/bin',tar)
env.Alias('install','/usr/local/bin')
执行命令sudo scons install
会增加如下的打印:表示main安装到了/usr/local/bin下
Install file: "main" as "/usr/local/bin/main"