Iva*_*aev 6 c c++ python cmake waf
我的 waf 项目有两个依赖项,使用 CMake 构建。
我想做的,是按照waf git repo 中找到的dynamic_build3示例,创建一个生成 CMake 的工具,并在成功构建后执行安装到 waf 的输出子目录中:
@extension('.txt')
def spawn_cmake(self, node):
if node.name == 'CMakeLists.txt':
self.cmake_task = self.create_task('CMake', node)
self.cmake_task.name = self.target
@feature('cmake')
@after_method('process_source')
def update_outputs(self):
self.cmake_task.add_target()
class CMake(Task.Task):
color = 'PINK'
def keyword(self):
return 'CMake'
def run(self):
lists_file = self.generator.source[0]
bld_dir = self.generator.bld.bldnode.make_node(self.name)
bld_dir.mkdir()
# process args and append install prefix
try:
cmake_args = self.generator.cmake_args
except AttributeError:
cmake_args = []
cmake_args.append(
'-DCMAKE_INSTALL_PREFIX={}'.format(bld_dir.abspath()))
# execute CMake
cmd = '{cmake} {args} {project_dir}'.format(
cmake=self.env.get_flat('CMAKE'),
args=' '.join(cmake_args),
project_dir=lists_file.parent.abspath())
try:
self.generator.bld.cmd_and_log(
cmd, cwd=bld_dir.abspath(), quiet=Context.BOTH)
except WafError as err:
return err.stderr
# execute make install
try:
self.generator.bld.cmd_and_log(
'make install', cwd=bld_dir.abspath(), quiet=Context.BOTH)
except WafError as err:
return err.stderr
try:
os.stat(self.outputs[0].abspath())
except:
return 'library {} does not exist'.format(self.outputs[0])
# store the signature of the generated library to avoid re-running the
# task without need
self.generator.bld.raw_deps[self.uid()] = [self.signature()] + self.outputs
def add_target(self):
# override the outputs with the library file name
name = self.name
bld_dir = self.generator.bld.bldnode.make_node(name)
lib_file = bld_dir.find_or_declare('lib/{}'.format(
(
self.env.cshlib_PATTERN
if self.generator.lib_type == 'shared' else self.env.cstlib_PATTERN
) % name))
self.set_outputs(lib_file)
def runnable_status(self):
ret = super(CMake, self).runnable_status()
try:
lst = self.generator.bld.raw_deps[self.uid()]
if lst[0] != self.signature():
raise Exception
os.stat(lst[1].abspath())
return Task.SKIP_ME
except:
return Task.RUN_ME
return ret
Run Code Online (Sandbox Code Playgroud)
我想生成该工具,然后将 waf 目标链接到已安装的库,我通过调用以下命令使用“假库”机制执行此操作bld.read_shlib():
def build(bld):
bld.post_mode = Build.POST_LAZY
# build 3rd-party CMake dependencies first
for lists_file in bld.env.CMAKE_LISTS:
if 'Chipmunk2D' in lists_file:
bld(
source=lists_file,
features='cmake',
target='chipmunk',
lib_type='shared',
cmake_args=[
'-DBUILD_DEMOS=OFF',
'-DINSTALL_DEMOS=OFF',
'-DBUILD_SHARED=ON',
'-DBUILD_STATIC=OFF',
'-DINSTALL_STATIC=OFF',
'-Wno-dev',
])
bld.add_group()
# after this, specifying `use=['chipmunk']` in the target does the job
out_dir = bld.bldnode.make_node('chipmunk')
bld.read_shlib(
'chipmunk',
paths=[out_dir.make_node('lib')],
export_includes=[out_dir.make_node('include')])
Run Code Online (Sandbox Code Playgroud)
我觉得这非常丑陋,因为:
Build.POST_LAZY模式和bld.add_group()),尽管解除阻止会read_shlib()失败。想象一下,如果在此之前还有某种git clone任务......read_shlib()在命令中调用build()意味着调用者知道该工具如何以及在何处安装文件。我希望该工具本身能够执行调用read_shlib()(如果有必要的话)。但我在run()和 中未能做到这一点runnable_status(),正如 Waf Book 部分关于自定义任务的第 11.4.2 段所建议的那样,似乎我必须以某种方式封装对read_shlib()另一个任务的调用并将其放入未记录的 more_tasks属性中。还有以下问题:
read_shlib()封装在由 CMake 任务生成的任务中?git远程存储库中获取)?事实上你已经完成了大部分工作:)
read_shlib只创建一个假任务假装构建一个已经存在的库。就您而言,您确实构建了库,因此您实际上不需要read_shlib. use只要您设置了正确的参数,您就可以将cmake 任务生成器放在某处。
该关键字use识别所使用的任务生成器中的一些参数:
如果使用的任务生成器具有link_task.
因此,您只需在 cmake 任务生成器中正确设置export_includes和,再加上设置引用您的属性的属性。您还必须正确设置 cmake_task 输出才能使其正常工作,即列表的第一个输出必须是 lib 节点(您在 add_target 中所做的操作似乎没问题)。就像是:export_defineslink_taskcmake_task
@feature('cmake')
@after_method('update_outputs')
def export_for_use(self):
self.link_task = self.cmake_task
out_dir = self.bld.bldnode.make_node(self.target)
self.export_includes = out_dir.make_node('include')
Run Code Online (Sandbox Code Playgroud)
完成后,您只需在主脚本中编写:
def build(bld):
for lists_file in bld.env.CMAKE_LISTS:
if 'Chipmunk2D' in lists_file:
bld(
source=lists_file,
features='cmake',
target='chipmunk',
lib_type='shared',
cmake_args=[
'-DBUILD_DEMOS=OFF',
'-DINSTALL_DEMOS=OFF',
'-DBUILD_SHARED=ON',
'-DBUILD_STATIC=OFF',
'-DINSTALL_STATIC=OFF',
'-Wno-dev',
])
bld.program(source="main.cpp", use="chipmunk")
Run Code Online (Sandbox Code Playgroud)
您当然可以简化/分解代码。我认为add_target不应该在任务中,它主要管理任务生成器属性。