您的位置:首页 > 编程语言 > Python开发

makefile太难了,学不会,自己用Python写个简单的构建工具

2015-10-16 16:24 501 查看
makefile 太复杂了,学的不精。自己用Python写一个构建工具,经过简单测试,可用

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import argparse
import os
import commands
import re

# .c对应的.o文件
def obj_file_path(srcpath):
return srcpath[:-1] + 'o'

# 检测.[hc]是否比.o文件新
def is_newer_than(src, obj):
srcmtime = os.stat(src).st_mtime
if os.path.exists(obj):
objmtime = os.stat(obj).st_mtime
else:
objmtime = 0
return srcmtime > objmtime

# 检查是否需要重新编译.c文件
def need_compile_src(srcpath):
output = commands.getoutput('{} -MM {}'.format(cc, srcpath))
hlist = output.split(':')[1].strip().split(' ')
hfiles = [h for h in hlist if h.endswith('.h')]
objpath = obj_file_path(srcpath)

# 检查依赖的头文件是否更新了
for h in hfiles:
if is_newer_than(h, objpath):
return True

# 检查源文件是否更新了
if is_newer_than(srcpath, objpath):
return True

# 检查配置文件是否更新了
cfgpath = os.path.abspath('buildconfig')
execpath = os.path.abspath(execname)
if is_newer_than(cfgpath, execpath):
return True

return False

# target build
def build():
# compile
needlink = False
objfiles = []
for srcfile in srcfiles:
objfile = obj_file_path(srcfile)
objfiles.append(objfile)
if need_compile_src(srcfile):
needlink = True
cccmd = '{} {} -c {} -o {}'.format(cc, cflags, srcfile, objfile)
if not quiet:
print(cccmd)
if os.system(cccmd):
sys.exit(1)

# link
if needlink:
dependency = ''
for objfile in objfiles:
dependency += (' ' + objfile)
execpath = os.path.abspath(execname);
ldcmd = '{} {} {} -o {}'.format(cc, ldflags, dependency, execpath)
if not quiet:
print(ldcmd)
os.system(ldcmd)

def remove_file(filepath):
if os.path.exists(filepath):
if not quiet:
print('rm {}'.format(filepath))
os.remove(filepath)

# target clean
def clean():
# remove obj files
for srcfile in srcfiles:
objfile = obj_file_path(srcfile)
remove_file(objfile)

# remove exec file
execpath = os.path.abspath(execname);
remove_file(execpath)

# generate the buildconfig file
def gen_buildconfig():
with open('buildconfig', 'w') as cfgfile:
cfgfile.writelines('''######## buildconfig ########

CC=cc                   # eg. cc/gcc/clang
CFLAGS=-g
LDFLAGS=
EXECNAME=main

''')

# parse command line opthons
def args_parser():
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--config', action='store_true', help='create the buildconfig file')
parser.add_argument('-q', '--quiet', action='store_true', help='quiet')
parser.add_argument('target', nargs='?', choices=['build', 'clean'], default='build', help='build or clean.')
return parser

# parse buildconfig file
def parse_build_config():
variables = dict()
cfgpath = os.path.abspath('buildconfig');
if not os.path.exists(cfgpath):
print('先创建一个buildconfig文件')
parser.print_help()
sys.exit(2)

with open(cfgpath) as cfgfile:
pattern = re.compile(r'#.*$')
for line in cfgfile:
line = pattern.sub('', line)
line = line.strip()
pair = line.split('=')
if len(pair) == 2:
variables[pair[0].strip()] = pair[1].strip()
return variables

# find all src files
def src_file_list(srcdir, ext):
srcfiles = []
for dirpath, dirnames, filenames in os.walk(srcdir):
for filename in filenames:
fileext = os.path.splitext(filename)[1]
if fileext == '.' + ext:
srcpath = os.path.join(dirpath, filename)
srcfiles.append(srcpath)
return srcfiles

# main entry
if __name__ == '__main__':
parser = args_parser()

# parse args
args = parser.parse_args()
quiet = args.quiet
config = args.config
if config:
gen_buildconfig()
sys.exit(0)

# parse variables
variables = parse_build_config();
cc = variables.setdefault('CC', 'cc')
cflags = variables.setdefault('CFLAGS', '-g')
ldflags = variables.setdefault('LDFLAGS', '')
execname = variables.setdefault('EXECNAME', 'main')

# src files
srcfiles = src_file_list(os.getcwd(), 'c')

# make target
if args.target == 'build':
build()
elif args.target == 'clean':
clean()


使用演示











开启树莓派探索模式


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: