加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – 将Waf目标链接到由外部构建系统(CMake)生成的库

发布时间:2020-12-20 13:07:10 所属栏目:Python 来源:网络整理
导读:我的waf项目有两个依赖项,用CMake构建. 我正在尝试做的是遵循在waf git repo中找到的 dynamic_build3示例,创建一个生成CMake的工具,并在成功构建之后,执行安装到waf的输出子目录中: @extension('.txt')def spawn_cmake(self,node): if node.name == 'CMakeL
我的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',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

我想生成该工具,然后将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')])

我觉得这很*非常*因为:

>只有在最终目标的链接阶段才需要使用chipmunk库,没有理由阻止整个构建(通过使用Build.POST_LAZY模式和bld.add_group()),尽管解锁它会使read_shlib()失败.想象一下,如果之前还有某种git clone任务……
>在build()命令中调用read_shlib()意味着调用者知道工具安装文件的方式和位置.我希望工具本身能够执行对read_shlib()的调用(如果需要的话).但是我在run()和runnable_status()中没有这样做,正如Waf Book部分关于Custom tasks的第11.4.2段建议的那样,似乎我必须以某种方式封装在另一个任务中调用read_shlib()并将其放入未记录的more_tasks属性.

还有一些问题:

>如何在任务中封装read_shlib()调用,由CMake任务生成?
>是否有可能让任务以非阻塞的方式并行执行其他任务(假设一个项目有2个或3个这些CMake依赖项,这些将由远程repos中的git获取)?

解决方法

事实上,你已经完成了大部分工作:)

read_shlib只创建一个虚假的任务,假装构建一个已经存在的lib.在你的情况下,你真的构建了lib,所以你真的不需要read_shlib.你可以在某个地方使用你的cmake任务生成器,因为你已经设置了正确的参数.

关键字use可识别使用的任务生成器中的一些参数:

> export_includes
> export_defines

如果使用的任务生成器具有link_task,它还管理库和任务顺序.

因此,您只需在cmake任务生成器中正确设置export_includes和export_defines,并设置引用cmake_task属性的link_task属性.您还必须正确设置cmake_task输出才能使其正常工作,即列表的第一个输出必须是lib节点(您在add_target中执行的操作似乎没问题).就像是:

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

完成后,您只需在主wscript中写下:

def build(bld):
    for lists_file in bld.env.CMAKE_LISTS:
        if 'Chipmunk2D' in lists_file:
            bld(
                source=lists_file,])

    bld.program(source="main.cpp",use="chipmunk")

您当然可以简化/分解代码.我认为add_target不应该在任务中,它主要管理任务生成器属性.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读