Adapt configs

Introduction

There are two major use cases:

  • Changing the configs from outside, e.g. injecting a toolchain.

  • Changing the configs depending on variables like the operating system.

Both is possible with the Adapt feature.

From command line

If you want to manipulate existing configs without changing them, you can “adapt” them via command line.

User@Host:~$ bake test --adapt abc/def

bake searches for abc/def in this priority:

  • <current directory>/abc/def

  • <main project directory>/abc/def

  • <workspace root>/abc/def (done for all roots)

  • abc/def/Adapt.meta recursively in all workspace roots (note, that /Adapt.meta is automatically appended here)

If found, the configs from the adapt file are parsed:

Adapt {
  ExecutableConfig ... # 0..n
  LibraryConfig ... # 0..n
  CustomConfig ... # 0..n
}

Here is an example to change the DefaultToolchain (details explained below):

Adapt {
  ExecutableConfig test, project: __MAIN__, type: replace {
    DefaultToolchain GCC
  }
}

–adapt can be used multiple times:

User@Host:~$ bake test --adapt abc --adapt xy

The values for adapt can be also comma separated:

User@Host:~$ bake test --adapt abc,xy

From Project.meta

You can do the same within the Project.meta:

Project {
  ...
}
Adapt {
  ...
}
Adapt {
  ...
}

Conditions and effectiveness

Be aware, these are two different things but look very similar.

Condition

An Adapt can have up to four attributes:

  • toolchain: e.g. GCC

  • os: can be Windows, Mac, Linux, Unix (which is != Linux)

  • mainConfig: name of the main config

  • mainProject: name of the main project

User defined conditions are specified in Scopes.

The Adapt configs will be only applied if all these conditions are true (“AND” operation). Example:

Adapt toolchain: GCC, os: Windows {
  Scope target, value: powerPC
  Scope somethingElse, value: "option1;option2"
  ...
}

Here the Adapt configs will be applied if toolchain is GCC on Windows and if target is powerPc and somethingElse either option1 or option2.

User defined scopes must be also specified in the config to be adapted or in main config:

LibraryConfig Lib {
  Scope target, value: powerPC
  Files "*.cpp"
  ...
}

Note

You can write “If” instead of “Adapt”:

If toolchain: GCC, os: Windows {
  ...
}

Note

It is possible to negate the conditions with “Unless”:

Unless toolchain: GCC, os: Windows {
  ...
}

The adapt block in the example above will be applied if the toolchain is not GCC AND if the OS is not Windows, e.g. for GCC on Linux or Diab Compiler on Mac.

Effectiveness

The Adapt configs can be applied to all configs from regular build. This can be controlled by the config names and the project attributes. Remember the example from the beginning?

Adapt {
  ExecutableConfig test, project: __MAIN__, type: replace {
    DefaultToolchain GCC
  }
}

This config is applied only to the config “test” of the main project.

__MAIN__, __ALL__ and __THIS__ are keywords:

  • __MAIN__ means the main project or main config

  • __ALL__ means all projects or configs

  • __THIS__ is only valid for project name, which can be used for Adapts within a Project.meta to restrict the adaption to the current project. This is the default for Adapts in Project.meta.

If you want to apply the changes only to the top level config, write:

ExecutableConfig __MAIN__, project: __MAIN__, ...

If you want to apply the changes to all configs, write:

ExecutableConfig __ALL__, project: __ALL__, ...

It is possible to mix the keywords with reals project or config names.

Config type

In most cases the type of the config does not matter. To adapt an attribute or element, the only important thing is that it’s valid in the config of the project AND in the config of the adapt file.

E.g. to adapt a Dependency, the config type is not relevant, Dependency is valid in both cases.

To adapt the ArtifactName, which is exclusively useable in ExecutableConfigs, you need in both cases an ExecutableConfig.

If you want to match the Adapt ONLY for the config type specified in the adapt file, use the strict attribute:

Adapt {
  ExecutableConfig ..., strict: true {
    ...
  }

Occurrences

You can specify more configs in one Adapt and you can specify more than one Adapt.meta file:

Adapt {
  ExecutableConfig ..., project: ..., type: ... {
    ...
  }
  ExecutableConfig ..., project: ..., type: ... {
    ...
  }
  LibraryConfig ..., project: ..., type: ... {
    ...
  }
  ...
}
User@Host:~$ bake test --adapt abc --adapt xy

Apply order

The Adapt configs will be applied in the order in which they were parsed. First the Adapt.metas referenced from the command line are read. Then the Project.metas are read one by one as usual. If an Adapt is found, it will be appended to the list of Adapts. Note, Adapts will be applied immediately when a Project.meta is read.

If you inject a Toolchain from outside, e.g. “–adapt gcc”, you can use the toolchain info for local Adapts:

Project {
  ...
}
Adapt toolchain: GCC {
  ...
}

Types

It is possible to specify the type of adaption:

ExecutableConfig ..., type: replace

The type can be

  • replace

  • remove

  • extend

  • push_front

Type: extend

This works exactly like for Derive configs.

Type: push_front

This works like extend, but elements which can be contained multiple times are pushed to front.

Example project config:

Project {
  LibraryConfig test {
    IncludeDir "abc"
    ...
  }
}

Adapt ... {
  LibraryConfig test, project: __THIS__, type: push_front {
    IncludeDir "mock"
  }
}

The resulting include path order will be “-Imock -Iabc”.

Type: remove

If parent elements can be found which matches to the child elements, they will be removed.

Example project config:

ExecutableConfig test {
  DefaultToolchain GCC
}

Example Adapt configs:

ExecutableConfig __ALL__, project: __ALL__, type: remove {
  DefaultToolchain # remove ok
}

ExecutableConfig __ALL__, project: __ALL__, type: remove {
  DefaultToolchain GCC # remove ok
}

ExecutableConfig __ALL__, project: __ALL__, type: remove {
  DefaultToolchain Diab # remove NOT ok
}

ExecutableConfig __ALL__, project: __ALL__, type: remove {
  DefaultToolchain GCC, eclipseOrder: true # remove NOT ok
}

Type: replace

This is for convenience. “replace” will remove all elements with the same type and extends the configs.

Example:

ExecutableConfig __ALL__, project: __ALL__, type: replace {
  Files "*.cpp"
  DefaultToolchain GCC {
    Linker command: "link.exe"
  }
}

This removes all “Files” and the “DefaultToolchain” from the original config regardless their attributes and replaces them by the elements of the Adapt config.

Wildcards

The “*” wildcard is allowed:

Adapt mainProject: HERE, mainConfig: HERE ... {
  Scope fasel, value: HERE
  SomeConfig HERE, project: HERE ... {
    ....
  }
}

Example (the configs of the Adapt are applied if the main config name starts with “UnitTest”):

Adapt mainConfig: "UnitTest*" {
  ...
}

Lists

Additionally to the wildcards, a list of projects/configs can be specified separated with “;”.

Example:

Adapt mainProject: "projA;projB", mainConfig: "UnitTest*;SomeOther" ... {
  Scope fasel, value: "option*;fasel"
  SomeConfig "libA;libX*", project: "can*;*lin" ... {
    ....
  }
}
LibraryConfig Lib {
  Scope target, value: "z4a;z4b"
    ....
  }
}

Command line filter

To apply adapt files to specific projects only, the usage can be restricted with square brackets:

--adapt abc[libraryA;libraryB]

In this case the Adapt.meta in abc is applied to libraryA and libraryB only. Note that further restrictions in the adapt file are still effective.

Lists and wildcards can be used as described above, e.g.:

--adapt abc[__MAIN__;*driver],xy/Adapt.meta[*can*;*lin*]