premake / premake/premake-core

Enable configuration reuse

Open
#1,346 11 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
C
Stars
3.6k
Forks
654
Avg merge
1d 1h
Merged PRs (30d)
13

Description

What problem will this solve?
Allow project authors to script reusable blocks of configuration, which can then be used for:

  • Providing all necessary configuration to consumers of a library or project. Just linking a library is often not enough: preprocessor symbols, include directories, and additional linker dependencies may also be required. This feature would allow project authors to specify all of this configuration, including the links() call, in a block that can be reused by consumers.

  • Specifying common configuration once, and reusing it across multiple projects and configurations. For instance, setting a standard for how a debug build should be configured, or the listing the settings necessary to use a third-party library.

We've also called this feature "usages", and have talked about them quite a lot (see "What other alternatives…" below).

What might be a solution?
After going through all of the discussions and my own notes over the years, the example below is how I think it should be implemented. Feel free to disagree with me in the comments; I'll update this write-up to summarize the discussion.

This is a contrived example to show the main points. Please use your imagination to scale it up to meaningful project sizes, with all the filters for platforms, etc. that you would normally need to script. All names are my proposals only and are open for discussion.

-- Projects are defined as before. Any configuration provided here is
-- "internal", and only used while building the project. To pull in
-- shared configuration, use the `uses` statement.
project "MyLibrary"
    kind "StaticLib"
    files { "**.h", "**.cpp" }
    uses { "MyLibrary:common" }

-- This shared block contains configuration that is used both to build
-- the library, and for consumers of the library. The name is arbitrary 
-- and assigned by the script author. Special characters are okay in 
-- block names.
block "MyLibrary:common"
    filter { "configurations:Debug" }
        defines { "MYLIBRARY_DEBUG" }
    filter { "configurations:Release" }
        defines { "MYLIBRARY_RELEASE" }

-- This shared block contains the configuration required only by 
-- consumers of the library, and not the library project itself.
-- It is okay to use the same name as the project.
block "MyLibrary"
    uses { "MyLibrary:common" }
    defines { "MYLIBRARY_API" }
    links { "MyLibrary", "Dependency1", "Dependency2" }

-- A project that wants to consume the library can pull in the shared
-- "public" configuration block.
project "MyExecutable"
    uses { "MyLibrary" }

Some usage points that might not be obvious, or would need to be considered during development:

  • A block only gets "used" once. If it appears again in a uses() list it will be ignored. For example, if you try to "use" two libraries which share a common dependency.

  • To maximize reuse, Premake should be smart enough not to link a project against itself. That way a project can "use" its own public configuration without creating a circular dependency.

  • If no shared block exists, uses "MyLibrary" simply links the project, i.e. it becomes links "MyLibrary".

What other alternatives have you already considered?
As mentioned, this has been discussed before. These are the most recent and relevant references:

  • PR #956 presents an alternative approach, and sparked quite a lengthy conversation of pros and cons. This comment summarizes the discussion points.

  • Issue #1215 expresses some other pain points that this feature potentially help solve.

  • moomalade/premake-usage and Meoo/premake-export are other attempts at an implementation.

Some advantages of the approach that I proposed here:

  • Works for any type of configuration reuse; not tied to any particular use case
  • Helps minimize the number of filter calls required
  • Fits into the existing container+filters approach that we're using for everything else
  • Doesn't require adding any special logic to support "building" vs. "using"

Feedback appreciated!
Feedback is welcome and appreciated in the comments. I'll keep this updated to summarize any key points or alternative approaches that get raised. When expressing a preference, it would be helpful if you could provide some explanation. And if you don't like these names, please try to provide some alternatives you do like.

(You can now support Premake on our OpenCollective. Your contributions help us get features like this shipped!)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing Premake's existing project, filter, links(), and uses() entry points, then read the linked discussion in PR #956 and issue #1215. Done should include reusable named blocks with nested uses(), filtering, deduplication, and self-link avoidance matching the proposed examples.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, lua
Domain
build-system, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.