Skip to content

Latest commit

 

History

History
480 lines (382 loc) · 15.5 KB

File metadata and controls

480 lines (382 loc) · 15.5 KB

Pack Generation Tool

The utility packgen assists the generation of a CMSIS-Pack from CMakeLists according to the standard format by reading a manifest YAML file with metadata and running the CMake generation step to retrieve CMake targets build information, namely source files, include paths and defines. It distributed as part of the CMSIS-Toolbox.

Requirements

NOTE: Make sure the CMake project has been previously configured and dependencies have been installed. It is a requirement to be able to successfully run the CMake generation step in the current environment.

For validating and compressing pack files, the packchk and 7-zip utilities shall be in the PATH system environment variable:

Usage

 packgen [-V] [--version] [-h] [--help]
          [OPTIONS...] manifest.yml

 packgen options:
  -s, --source arg   Source root folder
  -o, --output arg   Output folder
  -i, --include arg  PDSC file(s) for external dependency check
  -r, --regenerate   Regenerate CMake targets
  -v, --verbose      Verbose mode
  -c, --nocheck      Skip pack check
  -z, --nozip        Skip *.pack file creation
  -h, --help         Print usage
  -V, --version      Print version

Quick Start

The example CMakeTestProject provides an input manifest.yml describing components and their inter-dependencies to be generated from the CMakeLists.txt.

The demonstration pack can be generated by executing the packgen tool in the example directory:

packgen manifest.yml -o OutputFolder

The generated pack files will be stored in the OutputFolder folder. The generated PDSC file should be identical to ARM.TestPack.pdsc.

How it Works

The contents of a component are retrieved from the input manifest file and from the CMake targets associated with it. If several CMake targets are listed, the build information (source files, include paths and defines) will be merged. The build information of other components or CMake targets listed as dependencies will be filtered out.

External dependencies of a component can be added to the conditions list. When an internal component is listed as dependency, a require condition is automatically inserted. For checking the correctness of external dependencies the path of external PDSC files (absolute or relative to the working directory) can be specified with the command line option --include.

Files that are not among the build information such as config files can still join a component by adding them to the files list.

After changing CMakeLists and/or other included CMake files, use the tool option --regenerate to rerun the CMake generation step. When changing only the input YAML file there is no need to regenerate CMake targets.

Multiple sets of CMake options are supported and shall be inserted in the manifest file in the top level build mapping. The set(s) of options to be considered in the generation of a given component shall be inserted in the build field under the components mapping, while the operation to be applied to them can be chosen as intersection or difference.

The manifest.yml file shall be placed alongside the entry point CMakeLists.txt. The command line option --source shall be used to indicate the root (top-level) source folder when the CMakeLists.txt and manifest.yml are not located at the root folder. Paths inside the manifest.yml file shall be relative to the root folder.

The contents of include paths to be recursively copied into the pack can be filtered by setting allowed file extensions in the extensions tag, the default are .h and .hpp. These extensions are also used for handling file categories of source files coming from CMake targets.

CMSIS Manifest File

The YAML structure is described below.

build:
  - name: <value>
    options: <value>

packs:
  - name: <value>
    description: <value>
    vendor: <value>
    license: <value>
    url: <value>
    releases:
      - version: <value>
        date: <value>
        description: <value>

    requirements:
      packages:
        - attributes: {<key:value list>}
      compilers:
        - attributes: {<key:value list>}
      languages:
        - attributes: {<key:value list>}

    taxonomy:
      - attributes: {<key:value list>}
        description: <value>

    apis:
      - name: <value>
        attributes: {<key:value list>}
        description: <value>
        files:
          - name: <value>
            attributes: {<key:value list>}
        extensions: [<list>]

    components:
      - name: <value>
        target: [<list>]
        build: [<list>]
        operation: [<intersection|difference>]
        attributes: {<key:value list>}
        description: <value>
        dependencies: [<list>]
        conditions:
          - <require|accept|deny>: {<key:value list>}
        files:
          - name: <value>
            attributes: {<key:value list>}
            conditions:
              - <require|accept|deny>: {<key:value list>}
        extensions: [<list>]

build

Argument Description
name Name of a set of CMake options. Multiple sets are supported
options List of CMake options

packs

Argument Description
name Unique name of the Software Pack
description Description of the Software Pack
vendor Name of the supplier or vendor of the Software Pack
license Path to license document
url HTTP URL or file URI location of the Software Pack
requirements Lists of requirements
releases List of Software Pack releases
components List of Software Pack components

requirements

Argument Description
packages List of required package attributes
compilers List of required compiler attributes
languages List of required language attributes

releases

Argument Description
version Semantic version number, see Version Type
date Release date in the format YYYY-MM-DD
description Release notes

taxonomy

Argument Description
attributes Typically Cclass and Cgroup, see taxonomy
description Taxonomy entry brief description

apis

Argument Description
name Unique name of the API
description API brief description
attributes List of API attributes
files List of API files
extensions List of header file extensions for recursive copy

components

Argument Description
name Unique name of the component
target List of CMake targets associated with the component
build List of build options sets associated with the component
operation Obtain the intersection or the difference of build options sets
description Component brief description
dependencies List of component dependencies. Other components or CMake targets are accepted.
attributes List of component attributes
conditions List of component conditions
files List of component files
extensions List of header file extensions for categorization and recursive copy

attributes

Argument Description
Cclass Component class
Cgroup Component group
Csubgroup Component subgroup
Cvariant Component variant
Cversion Component version

files

Argument Description
name File path relative to the pack root directory
attributes List of file attributes
conditions List of file conditions

file attributes

Argument Description
category Defines the purpose of the file.
attr Defines the special use and handling of a file.
version File-specific version information.

conditions

Argument Description
<rule> It must be require, accept or deny
<key:value list> Typically external component attributes, but not limited to it.

For further info please consult the PDSC specification, for example:

Hints for Generating Packs

When starting the process of generating a new pack, the following workflow is recommended:

  1. In the project's root folder side by side with the CMakeLists.txt create an input YAML file with the minimal required fields, for instance:

    build:
      - name: "build1"
        options: "cmake -G Ninja"
    
    packs:
      - name: "TestPack"
        description: "TestPack description"
        vendor: "ARM"
        license: "LICENSE"
        url: "http://arm.com/"
        releases:
          - version: "1.0.0"
            date: "2021-08-10"
            description: "Initial release"
  2. Run packgen in verbose mode to obtain a list of CMake targets:

    packgen manifest.yml -o OutputFolder -v -c -z >log.txt

    In the example's case the following information will be printed:

    log.txt

    TARGET: lib1
    BUILD: build1
    src: lib1/src/lib1.cpp
    inc: lib1/inc
    
    TARGET: lib2
    BUILD: build1
    src: lib2/src/lib2.cpp
    inc: lib2/inc
    inc: lib3/inc
    inc: lib4/inc
    dep: lib3
    dep: lib4
    
    TARGET: lib3
    BUILD: build1
    src: lib3/src/lib3.cpp
    inc: lib3/inc
    
    TARGET: lib4
    BUILD: build1
    src: lib4/src/lib4.cpp
    inc: lib4/inc
    
    TARGET: lib5
    BUILD: build1
    src: lib5/src/lib5.cpp
    inc: lib5/inc
  3. Describe the components to be generated by assigning targets to be exposed or filtered out, respectively in the components target or dependencies fields.

    In the example below the content of the generated component3 is merged from lib4 and lib5:

    manifest.yml

      components:
        - name: component3
          target: [lib4, lib5]
          attributes: {Cclass: "Class3", Cgroup: "Group3", Csub: "Subgroup3", Cversion: "3.3.3"}
          description: "Component3"

    ARM.TestPack.pdsc

        <component Cclass="Class3" Cgroup="Group3" Csub="Subgroup3" Cversion="3.3.3">
          <description>Component3</description>
          <files>
            <file category="source" name="lib4/src/lib4.cpp"/>
            <file category="source" name="lib5/src/lib5.cpp"/>
            <file category="include" name="lib4/inc/"/>
            <file category="include" name="lib5/inc/"/>
          </files>
        </component>

Multiple Sets of CMake Options

The example CMakeTestMultipleBuilds has a CMakeLists.txt producing a library with different sources and include paths depending on the DEVICE option that can assume the values DEV1, DEV2 or DEV3:

CMakeLists.txt

if(DEVICE STREQUAL "DEV1")
  add_library(lib STATIC src/core.cpp
                         src/dev1.cpp)
  target_include_directories(lib PUBLIC inc
                                        inc1)
elseif(DEVICE STREQUAL "DEV2")
  add_library(lib STATIC src/core.cpp
                         src/dev2.cpp)
  target_include_directories(lib PUBLIC inc
                                        inc2)
elseif(DEVICE STREQUAL "DEV3")
  add_library(lib STATIC src/core.cpp
                         src/dev3.cpp)
  target_include_directories(lib PUBLIC inc
                                        inc3)
endif()

It means the CMake generation step has to be executed several times to cover all the possible results. To instruct the tool to run all the configurations, the manifest.yml has the following build options mapping:

manifest.yml

build:
  - name: build-dev1
    options: "cmake -G Ninja -DDEVICE=DEV1"
  - name: build-dev2
    options: "cmake -G Ninja -DDEVICE=DEV2"
  - name: build-dev3
    options: "cmake -G Ninja -DDEVICE=DEV3"

The description of every component indicates the sets of build options that will be associated and which operation will be applied to them, intersection or difference. Note in case of difference the order of sets is important:

manifest.yml (continued)

components:
  - name: core
    build: ["build-dev1", "build-dev2", "build-dev3"]
    operation: intersection

  - name: device1
    build: ["build-dev1", "build-dev2", "build-dev3"]
    operation: difference

  - name: device2
    build: ["build-dev2", "build-dev1", "build-dev3"]
    operation: difference

  - name: device3
    build: ["build-dev3", "build-dev1", "build-dev2"]
    operation: difference

Run packgen in verbose mode to print a list of CMake targets and the of generated components:

packgen manifest.yml -o OutputFolder -v -c -z > log.txt

The core component with common elements is generated by using the intersection operation, while each other device component is created with the difference operation:

log.txt

TARGET: lib
BUILD: build-dev1
src: src/core.cpp
src: src/dev1.cpp
inc: inc
inc: inc1

TARGET: lib
BUILD: build-dev2
src: src/core.cpp
src: src/dev2.cpp
inc: inc
inc: inc2

TARGET: lib
BUILD: build-dev3
src: src/core.cpp
src: src/dev3.cpp
inc: inc
inc: inc3

COMPONENT: core
src: src/core.cpp
inc: inc

COMPONENT: device1
src: src/dev1.cpp
inc: inc1

COMPONENT: device2
src: src/dev2.cpp
inc: inc2

COMPONENT: device3
src: src/dev3.cpp
inc: inc3