完全用python编写的类似make的构建实用程序。

python-pake的Python项目详细描述


关于巴基斯坦

Master Documentation Statuscodecov

pake是一个类似make的python构建实用程序,其中任务、依赖项和 构建命令可以完全用python表示,类似于ruby 耙子。

pake在处理文件/目录更改时支持自动检测 任务输入和输出,以及并行构建。

帕克需要Python3.5+

这个自述文件只包含一些关于如何使用pake的信息 在上面的链接中查看最新的文档 关于pake如何工作以及pakefiles应该如何编写的概述。

安装

注意:pake是alpha,可能会改变一些。

要安装最新版本,请使用:

sudo pip3 install python-pake--upgrade

如果要安装开发分支,可以使用:

sudo pip3 install git+git://github.com/Teriks/pake@develop

使用pake的示例项目

我正在使用libasm_io帮助测试pake,并包含了一个pakefile 在项目中生成生成文件。

https://github.com/Teriks/libasm_io

请参阅libasm_io/build readme.md的build with pake部分。

编写基本任务

这是一个精心设计的pake演示:

importpake# Tasks are registered the the pake.Pake object# returned by pake's initialization call, using the task decorator.pk=pake.init()# Try to grab a command line define.# In particular the value of -D CC=..# CC will default to 'gcc' in this case if# it was not specified.CC=pk.get_define('CC','gcc')# you can also use the syntax: pk["CC"] to# attempt to get the defines value, if it is not# defined then it will return None.# ===# If you just have a single input/output, there is no# need to pass a list to the tasks inputs/outputs@pk.task(i='foo/foo.c',o='foo/foo.o')deffoo(ctx):# Execute a program (gcc) and print its stdout/stderr to the tasks output.# ctx.call can be passed a command line as variadic arguments, an iterable, or# as a string.  It will automatically flatten out non string iterables in your variadic# arguments or iterable object, so you can pass an iterable such as ctx.inputs# as part of your full command line invocation instead of trying to create the command# line by concatenating lists or using the indexer on ctx.inputs/ctx.outputsctx.call(CC,'-c',ctx.inputs,'-o',ctx.outputs)# Pake can handle file change detection with multiple inputs# and outputs. If the amount of inputs is different from# the amount of outputs, the task is considered to be out# of date if any input file is newer than any output file.# When the amount of inputs is equal to the amount of outputs,# pake will compare each input to its corresponding output# and collect out of date input/outputs into ctx.outdated_inputs# and ctx.outdated_outputs respectively.  ctx.outdated_pairs# can be used to get a generator over (input, output) pairs,# it is shorthand for zip(ctx.outdated_inputs, ctx.outdated_outputs)@pk.task(i=pake.glob('bar/*.c'),o=pake.pattern('bar/%.o'))defbar(ctx):# zip together the outdated inputs and outputs, since they# correspond to each other, this iterates of a sequence of python# tuple objects in the form (input, output)fori,oinctx.outdated_pairs:ctx.call(CC,'-c',i,'-o',o)# This task depends on the 'foo' and 'bar' tasks, as# specified with the decorators leading parameters.# It outputs 'bin/baz' by taking the input 'main.c'# and linking it to the object files produced in the other tasks.@pk.task(foo,bar,o='bin/baz',i='main.c')defbaz(ctx):"""Use this to build baz"""# Documentation strings can be viewed by running 'pake -ti' in# the directory the pakefile exists in, it will list all documented# tasks with their python doc strings.# The pake.FileHelper class can be used to preform basic file# system operations while printing information about the operations# it has completed to the tasks output.file_helper=pake.FileHelper(ctx)# Create a bin directory, this won't complain if it exists alreadyfile_helper.makedirs('bin')# ctx.dependency_outputs contains a list of all outputs that this# tasks immediate dependencies producectx.call(CC,'-o',ctx.outputs,ctx.inputs,ctx.dependency_outputs)@pk.taskdefclean(ctx):"""Clean binaries"""file_helper=pake.FileHelper(ctx)# Clean up using the FileHelper object.# Remove the bin directory, this wont complain if 'bin'# does not exist.file_helper.rmtree('bin')# Glob remove object files from the foo and bar directoriesfile_helper.glob_remove('foo/*.o')file_helper.glob_remove('bar/*.o')# Run pake; The default task that will be executed when# none are specified on the command line will be 'baz' in# this case.# The tasks parameter is optional, but if it is not specified# here, you will be required to specify a task or tasks on the# command line.pake.run(pk,tasks=baz)

命令pake:的输出

===== Executing task: "bar"
gcc -c bar/bar.c -o bar/bar.o
===== Executing task: "foo"
gcc -c foo/foo.c -o foo/foo.o
===== Executing task: "baz"
Created Directory(s): "bin"
gcc -o bin/baz main.c foo/foo.o bar/bar.o

命令输出pake clean

===== Executing task: "clean"
Removed Directory(s): "bin"
Glob Removed Files: "foo/*.o"
Glob Removed Files: "bar/*.o"

任务内部的并发性

工作可以提交给线程池pake正在运行其任务,以实现 受–jobs命令行参数限制的子任务的可预测并发级别, 或者pake.runpake.runjobs参数。

示例:

importpake# functools.partial is used for binding argument values to functionsfromfunctoolsimportpartialpk=pake.init()@pk.task(i=pake.glob('src/*.c'),o=pake.pattern('obj/%.o'))defbuild_c(ctx)file_helper=pake.FileHelper(ctx)# Make 'obj' directory if it does not exist.# This does not complain if it is already there.file_helper.makedirs('obj')# Start multitaskingwithctx.multitask()asmt:fori,oinctx.outdated_pairs:# Read the section 'Output synchronization with ctx.call & ctx.subpake'# in the 'Concurrency Inside Tasks` page on http://pake.readthedocs.io# for an explanation of 'sync_call' below, and how output# synchronization is achieved for ctx.call and ctx.subpakesync_call=partial(ctx.call,collect_output=pk.max_jobs>1)# Submit a work function with arguments to the threadpoolmt.submit(sync_call,['gcc','-c',i,'-o',o])@pk.task(build_c,i=pake.glob('obj/*.o'),o='main')defbuild(ctx):# Utilizing the automatic non string iterable# flattening here to pass ctx.inputs and ctx.outputsctx.call('gcc',ctx.inputs,'-o',ctx.outputs)pake.run(pk,tasks=build)

运行子包文件

pake能够通过使用pake.taskContext.subpake运行自己 以及pake.subpake

pake.subpake应该在任务之外使用,甚至可以是 在初始化pake之前调用。

pake.taskcontext.subpake首选用于任务内部,因为 它为您处理对任务输出队列的写入,而不必指定 要使其正常工作,pake.subpake的额外参数。

pake.taskcontext实例被传递到每个任务函数的单个参数中, 您可以依次从中调用subpake

可以使用pake.export将定义导出到使用pake的函数运行的pakefile。

pake.subpakepake.taskcontext.subpake使用–stdin定义的选项 pake将导出的define值传递到新的流程实例中,这意味着您可以覆盖 导出的define值带有-d/–如果需要,可以在subpake命令参数中定义

导出/子样本示例:

importpakepk=pake.init()# Try to get the CC define from the command line,# default to 'gcc'.CC=pk.get_define('CC','gcc')# Export the CC variable's value to all invocations# of pake.subpake or ctx.subpake as a define that can be# retrieved with pk.get_define()pake.export('CC',CC)# You can also export lists, dictionaries sets and tuples,# as long as they only contain literal values.# Literal values being: strings, integers, floats; and# other lists, dicts, sets and tuples.  Collections must only# contain literals, or objects that repr() into a parsable literal.pake.export('CC_FLAGS',['-Wextra','-Wall'])# Nesting works with composite literals,# as long as everything is a pure literal or something# that str()'s into a literal.pake.export('STUFF',['you',['might',('be',['a',{'bad':['person',['if',{'you','do'},('this',)]]}])]])# This export will be overrode in the next callpake.export('OVERRIDE_ME',False)# Execute outside of a task, by default the stdout/stderr# of the subscript goes to this scripts stdout.  The file# object to which stdout gets written to can be specified# with pake.subpake(..., stdout=(file))# This command also demonstrates that you can override# your exports using the -D/--define optionpake.subpake('sometasks/pakefile.py','dotasks','-D','OVERRIDE_ME=True')# This task does not depend on anything or have any inputs/outputs# it will basically only run if you explicitly specify it as a default# task in pake.run, or specify it on the command line@pk.taskdefmy_phony_task(ctx):# Arguments are passed in a variadic parameter...# Specify that the "foo" task is to be ran.# The scripts output is written to this tasks output queuectx.subpake('library/pakefile.py','foo')# Run this pake script, with a default task of 'my_phony_task'pake.run(pk,tasks=my_phony_task)

以上示例的输出:

*** enter subpake[1]:
pake[1]: Entering Directory "(REST OF PATH...)/paketest/sometasks"===== Executing Task: "dotasks"
Do Tasks
pake[1]: Exiting Directory "(REST OF PATH...)/paketest/sometasks"
*** exit subpake[1]:
===== Executing Task: "my_phony_task"
*** enter subpake[1]:
pake[1]: Entering Directory "(REST OF PATH...)/paketest/library"===== Executing Task: "foo"
Foo!
pake[1]: Exiting Directory "(REST OF PATH...)/paketest/library"
*** exit subpake[1]:

运行PAKE

cd your_pakefile_directory

# Run pake with up to 10 tasks running in parallel

pake -j 10

pake将在当前目录中查找“pakefile.py”或“pakefile” 运行它。

或者可以指定一个或多个要与-f/–file一起运行的文件。这个 开关没有多个参数,但可以使用多个参数 一次指定多个文件。

例如:

pake -f pakefile.py foo

pake -f your_pakefile_1.py -f your_pakefile_2.py foo

也可以指定多个任务,但不依赖于不相关的任务 以任何特定的顺序执行,因为它们不会被执行。如果有的话 需要执行任务的特定顺序 第一个应该声明为第二个的依赖项,然后 应指定要运行的第二个任务。

运行并行生成时,叶依赖项将开始执行 几乎是同时进行的,并且有依赖关系的非相关任务 链可以并行执行。

pake task unrelated_task order_independent_phony


热门话题
Java持久性和Foxpro   javajavax。命名。NameNotFoundException:com。javacodegeeks。实例服务AccountServiceRemote   java在不重复字符的情况下查找最长子字符串的长度   控制台Java runtine。执行官:不会改变路径   Java继承混乱,超类和子类成员变量同名   循环如何格式化在Java中循环的打印行   使用Jersey/Glassfish实现java正确的CDI注释   多线程Java创建一个连续线程数组   java根据特殊字符(逗号除外)验证字符串   安卓 JNI NewStringUTF调用了挂起的异常“java”。lang.NoSuchMethodError'   java在JSweet转换后运行脚本   java为什么$MockitoMock$实例没有被标识为mock?   用JavaJNA编写的密钥侦听器。无法停止线程   从Java代码创建的安卓视图包装在另一个视图中。为什么?   在另一个类中使用带有逻辑的JavaSwingGUI   java致命异常:Timer0?   java JavaFX在tableview中移动列   spring将jboss 6.0.0上的Hibernate 3.6升级为Hibernate 4.3.6,以获取java。lang.NoClassDefFoundError:org/hibernate/classic/Session   ImageView中的java图像是拉伸的   java我想扩展枚举和对象(通用)