Bazel using cc_binary with custom providers

43 Views Asked by At

So I discovered Bazel recently and wanted to compile my projects with it (that are using Premake right now).

I want to create a provider for each project that will contain all information about it. Like it defines, dependencies, includes directories, ..., and if it's a binary or a library. To simplify my example I have reduced it to just a little info.

SolutionProjectInfo = provider("", fields = {
    'name': "",
    'project_type': "",
    'srcs': "",
    'defines': "",
    'include_dirs': ""
})

What I would like to do is to have a rule that will produce a SolutionProjectInfo and make a call to cc_binary.

solution_project = rule(
    implementation = _impl_solution_project,
    attrs = {
        'project_type': attr.string(default = ProjectType.ConsoleApp),
        'srcs': attr.label_list(default = [], allow_files = True),
        'defines': attr.string_list(default = []),
        'include_dirs': attr.string_list(default = [])
    },
    provides = [SolutionProjectInfo]
)

Right now the implementation of _impl_solution_project is meaningless, cause I can't call cc_binary in a rule.

def _impl_solution_project(ctx):
    return [SolutionProjectInfo(
        name = ctx.label.name,
        project_type = ctx.attr.project_type,
        defines = ctx.attr.defines,
        include_dirs = ctx.attr.include_dirs,
        srcs = ctx.attr.srcs
    )]

With that I could have just a BUILD file, in which I make a call to this rule solution_project. But I have a big problem, I can't make a call to cc_binary in a rule, aka in _impl_solution_project the implementation of my rule solution_project (native.cc_binary can't be called within a rule's implementation). It seems intended: How to create a rule from within another rule in Bazel

And if I don't make my call to cc_binary in the function _impl_solution_project, my rule solution_project only generates me an SolutionProjectInfo provider. But I don't understand how I can use this provider to make a call to cc_binary, because I can only access values of a provider in a rule, is that right ?

By having something like :

attrs = {
    'project': attr.label(providers = [SolutionProjectInfo])
}

So here is my questions

This questions are independant, I only need one to work

How could make a call to cc_binary in my rule

How could make a call to cc_binary in my rule implementation; Aka make a call to cc_binary in _impl_solution_project of my rule solution_project

What I would like to do is a little bit like the presentation of first-class Macros/Symbolic Macros of future Bazel versions which is not available now. Symbolic Macros

Symbolic Macros

def _impl_solution_project(ctx):
    if ctx.attr.project_type == "ConsoleApp":
        native.cc_binary(...)
    elif ctx.attr.project_type == "StaticLib":
        native.cc_library(...)
    ...
    return [SolutionProjectInfo(
        name = ctx.label.name,
        project_type = ctx.attr.project_type,
        defines = ctx.attr.defines,
        include_dirs = ctx.attr.include_dirs,
        srcs = ctx.attr.srcs
    )]

Here I get an error of:

native.cc_binary can't be called within a rule's implementation

Get values from my provider ouside a rule

How could I get values from my provider outside a rule.

Like doing something like:

solution_project(
    name = "EngineCore",
    type = "StaticLib"
    srcs = glob("/src/**/*.cpp"),
    defines = [ "USE_OPENGL" ],
    include_dirs = [ "EngineCore/src/" ]
    ...
)

And then I would have a macro (classic StarLark macro) that make a call to cc_binary or cc_library

# *.bzl
def solution_project_macro(info_provider):
    if info_provider.project_type == "ConsoleApp":
        native.cc_binary(
            name = info_provider.name
            ...
        )
    elif info_provider.project_type == "StaticLib":
        native.cc_library(...)

# BUILD
solution_project(
    name = "EngineCore",
    type = "StaticLib"
    srcs = glob("/src/**/*.cpp"),
    defines = [ "USE_OPENGL" ],
    include_dirs = [ "EngineCore/src/" ]
    ...
)
solution_project_macro(":EngineCore")

Why

The code shown previously is made up, that is why I don't have any repo using this.

But that is what I am aiming for. The goal is to avoid duplication of defines / dependencies / includes directories when working with multiple static libs. Like, for example I have a graphics engine that needs to have the define USE_OPENGL. I want when building the lib to create a provider that stores that define, among include directories and others so when I set this graphics engine as dependencies I don't have to make a duplication of all these defines and flags in generals. Thanks for any help or if you have any other way to do that.

0

There are 0 best solutions below