覆盖和调用数组

Premake的可扩展性围绕两种编码约定构建:覆盖(一种将函数替换为另一种函数的形式化方法)和调用数组(一种在运行时对一系列步骤进行排序的方法)。

您的第一次自定义

让我们直接看一个简单的例子。 假设我们计划将Premake生成的Visual Studio项目保留一段时间,以供历史参考,我们想知道使用哪个版本的Premake生成它们。 为此,我们想在生成的项目文件的顶部添加一个XML注释,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by Premake 5.0.0-alpha3 -->
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
  <!-- ... and so on... -->

我们不想修改Premake自己的源代码,因为这样我们的更改将被每个新更新覆盖,并且我们将不得不维护自己的代码分支。这也意味着生成我们项目的每个人都需要具有定制版本的Premake,否则,我们最终将获得不包含版本注释的生成项目。

相反,我们真的很想在我们的项目脚本中实现这种自定义。这样,我们可以与任何开发人员共享脚本,然后他们可以生成一个包含版本注释的新项目。

使用源代码!

在进行更改之前,我们首先需要知道Premake源代码中的哪个函数正在发出此特定标记。如代码概述中所述,Visual Studio导出器当前位于Premake源代码树的src / actions / vstudio文件夹中(继续查找,我们将等待!)。

我们正在寻找生成.vcxproj文件的代码,浏览文件名会将我们带到vs2010_vcxproj.lua。打开此文件,然后我们可以搜索在m.project()函数中找到的“ <Project”字符串:

function m.project(prj)
        local action = premake.action.current()
        p.push('<Project DefaultTargets="Build" ToolsVersion="%s" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">',
            action.vstudio.toolsVersion)
    end

(或者,如果使用支持它的工具,则可以更快地在Premake来源中对要覆盖的标记进行全文搜索。)

目前,我们真的不需要太担心此代码的工作原理,因为我们实际上根本就不会对其进行更改。 取而代之的是,我们将使用新函数覆盖它,该新函数输出我们的版本注释,然后调用原始函数以输出未经修改的Project元素。

在我们能够做到这一点之前,我们需要更多的信息:什么是m? 按照惯例,m是我们在文件顶部声明的模块名称空间(实际上只是Lua表)的快捷方式。 查看vs2010_vcxproj.lua的顶部,我们发现:

local p = premake
local m = p.vstudio.vc2010

扩展这一点,我们可以推断出我们要覆盖的函数的标准名称是premake.vstudio.vc2010.project()。

引入覆盖

现在,我们已经确定了发出我们希望更改的标记的函数,我们可以使用Premake的恰当命名的override()函数来覆盖它。

请注意,只有在实际使用动作之前,它们才会被拉进去,因此您需要对其进行操作才能访问它

require('vstudio')

然后(只有这样),您才能继续调用覆盖函数!

premake.override(premake.vstudio.vc2010, "project", function(base, prj)
    premake.w('<!-- Generated by Premake ' .. _PREMAKE_VERSION .. ' -->')
    base(prj)
end)

此代码段用我的新(匿名)函数替换了m.project()的原始实现。 从这一点开始,当有人调用m.project()时,Premake将调用我的新函数,并将原始实现作为第一个参数(基础)传递给它。 如果该函数需要任何其他参数(在这种情况下,它接收到要导出为prj的项目),它们将出现在后面。

在替换函数中,我们使用premake.w()(它是“ premake write”的缩写)和_PREMAKE_VERSION发出的注释标头,_PREMAKE_VERSION是一个全局变量,用于保存当前正在运行的Premake可执行文件的版本。

发出评论后,我们将调用m.project()的原始实现base(prj),为我们完成其余工作。 简单的!

要启用我们的覆盖,请将该代码放置在项目或系统脚本中的任何位置。 也许像这样:

workspace "MyWorkspace"
   configurations { "Debug", "Release" }

project "MyProject"
   kind "ConsoleApp"
   -- ... the rest of the project settings...

-- Write the current Premake version into our generated files, for reference
premake.override(premake.vstudio.vc2010, "project", function(base, prj)
    premake.w('<!-- Generated by Premake ' .. _PREMAKE_VERSION .. ' -->')
    base(prj)
end)

下次您从脚本生成Visual Studio项目时,注释标题将放置在Project元素之前。

调用数组简介

覆盖是拦截现有调用以修改其参数或返回值甚至完全替换它的一种好方法。 我们可以利用Premake的调用数组约定来实现定制,这是另一种更独立的方法。

如果您查看vs2010_vcxproj.lua的顶部,您会看到通过函数引用数组调用了m.project():

m.elements.project = function(prj)
    return {
        m.xmlDeclaration,
        m.project,
        m.projectConfigurations,
        m.globals,
        m.importDefaultProps,
        m.configurationPropertiesGroup,
        m.importExtensionSettings,
        m.propertySheetGroup,
        m.userMacros,
        m.outputPropertiesGroup,
        m.itemDefinitionGroups,
        m.assemblyReferences,
        m.files,
        m.projectReferences,
        m.importExtensionTargets,
    }
end

function m.generate(prj)
    io.utf8()
    p.callArray(m.elements.project, prj)
    p.out('</Project>')
end

Premake调用m.generate()导出项目,稍后再讨论。 m.generate()调用p.callArray()(记住p是premake的别名),它将调用m.elements.project()返回的列表中的所有函数,并传递提供的参数(在本例中为prj) 给他们每个人。 这种间接方式使像您一样的项目脚本作者有机会通过添加,删除或重新排序列表来修改该调用列表。

让我们将版本注释实现为对此特定调用数组的补充。 为此,我们将覆盖m.elements.project()函数(从前面的示例中记住,m是premake.vstudio.vc2010的缩写)。 我们将调用原始实现以获取调用数组,然后添加自己的实现,然后将其返回给m.generate()。

local function premakeVersionComment(prj)
    premake.w('<!-- Generated by Premake ' .. _PREMAKE_VERSION .. ' -->')
end

premake.override(premake.vstudio.vc2010.elements, "project", function(base, prj)
    local calls = base(prj)
    table.insertafter(calls, m.xmlDeclaration, premakeVersionComment)
    return calls
end)

如果您将该代码段添加到项目或系统脚本中,则将在m.xmlDeclaration()和m.project()之间调用新函数,并将注释放在我们想要的位置。

results matching ""

    No results matching ""