-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[projmgr] Using existing .cprj as lockfile #119
Comments
Same idea here thinking #82 cprj acting as lock file if end user resources. |
Agree, lock file should be designed on this level too.
Agree, but... I think decision whether certain change impact dependency resolution or not might be difficult. If we take in account configuration (which is currently not covered by scope of open cmsis pack), even the compiler flag could be in theory dependency of some component and could affect dependency resolution. I would postpone this and consider it as performance optimization task. I would personally design lock file in similar way as python package manager pip:
In open cmis pack ecosystem it could be something like:
I am using cfreeze.yml because clock.yml sounds confusing. |
High-level, there are a few main requirements of a lockfile:
In #171 we see that the cprj-format grows and grows to support the use-cases supported by the yml formats. I think this is a problem since it means that we will always have two different formats that always needs to support the same things. I would much prefer if we either go in the route of yml->CMakeLists directly as in #171 (comment) or improve and align on the Generator input file (*.cgen.json) format that could also possibly serve as a lockfile (https://github.com/Open-CMSIS-Pack/devtools/blob/main/tools/projmgr/docs/Manual/YML-Format.md#generator-proposal and Open-CMSIS-Pack/Open-CMSIS-Pack-Spec#104). So we need:
The nice thing about this is that then we no longer need a tool to understand the complete state of the project, since everything has been made explicit in the lockfile. |
The benefit I am seeing in the representation in the 'cprj' format is, that it only describes a single context in a "fully specified" way. |
@jkrech I agree about the To fullfil my needs, the current cprj-format would need to evolve abit, since it does not satisfy the Below is a small proposal of what a {
"device": "STM32F407IGHx",
"board": "NucleoF407",
"solution": "../MySolution.csolution.yml",
"project": "../Blinky.cproject.yml",
"build_type": "Debug",
"target_type": "Nucleo",
"packs": [
"Keil::[email protected]",
{ "pack": "Keil::[email protected]", "sha256": "..." },
{ "pack": "MyPack::[email protected]", "path": "../Some/Path/toMyPack" }
],
"components": [
{
"pack_id": "Keil::[email protected]",
"name": "Device:STM32Cube HAL:[email protected]",
"condition": "STM32F4 GCC",
"pack_files": [
"./path_inside_pack/file.c"
],
"project_files": [
"./path_inside_project/file.c"
]
},
{
"pack_id": "Keil::[email protected]",
"name": "Board:[email protected]",
"condition": "STM32F4 GCC",
"pack_files": [
"./path_inside_pack/file.c"
],
"project_files": [
"./path_inside_project/file.c"
]
},
{
"pack_id": "Keil::[email protected]",
"name": "Device:HAL:[email protected]",
"condition": "STM32F4 GCC",
"pack_files": [
"./path_inside_pack/file.c"
],
"project_files": [
"./path_inside_project/file.c"
],
"instances": {
"WiFi": {
"instance": 0,
"setup": "wifi-config.json",
"baudrate": 19200
},
"Debug": {
"instance": 2,
"baudrate": 57600
}
}
}
]
} This lockfile could also be described like this using TypeScript types as "schema" interface Lockfile {
device: string,
board: string,
solution: string, // Relative to lockfile directory
project: string, // Relative to lockfile directory
packs: PackType[],
build_type: string,
target_type: string,
components: ComponentType[],
}
type PackType = string | Pack;
interface Pack {
pack: string, // Full identifier of pack
path?: string // Optional path to where the pack is located, relative to the lockfile directory
sha256?: string // Optionally store sha256 of entire pack installation
}
interface ComponentType {
pack_id: string, // Identify which pack that brings this component
name: string, // Full name of the component
condition: string, // Condition used by the component
pack_files: string[], // Component files that stay in the pack installation location
project_files: string[], // Component files that end up in the project AKA "RTE files" AKA "attr=config" files
instances?: InstancesType,
}
interface InstancesType {
[instanceName: string]: InstancesType,
}
interface Instance {
instance: number,
setup?: string, // Path to setup file
baudrate: number,
} Some open discussion points about this proposal:
The If we think we should go for a more detailed lockfile including the above three points, then I think we should consider moving directly from YML to CMakeLists, one CMakeList per context. EDIT: To clarify, With the above proposed file I suggest that we have two separate flows for building the project:
For the For the |
@slhultgren regarding 1.2 I think the devil is in the detail. I like the idea of "minimal" changes compared to previous lockfile but I doubt that this will always create the desired "update" behavior. E.g. if a newer version of the pack got installed but the previous version is no longer present, do we have to install the previous version in order to achieve minimal changes? What if the previous version is still installed, do we let the user know that there is a newer version available? |
@jkrech I agree there will be finer details to hash out indeed. for the ones you mention I would be very conservative:
This would be the minimum, then we could indeed add some more "sugar" on top, like suggesting possibly to move to a newer pack version. But moving to a newer pack version may change a lot of things in terms of component resolve state, so it needs to be a conscious choice by the user when and why this happens. As you say, technically we could restrict the pack selection in the yml file, but this is a less nice user-experience IMO. Lastly however I also again want to highlight the value of having a file showing the complete state of the pack/component state of the project as the tools would understand it:
All of these features also fits perfectly IMO with the generator input file mentioned previously, which would simplify implementing generators, so having a file format to explicitly describe the exact project pack/component state is very attractive here. |
@ReinhardKeil I would like to get your feedback on this as well since my latest thoughts in #119 (comment) is basically a slightly expanded version of your cgen.json proposal. High-level idea is that we should have a format that can explain the exact pack+component state, and this same format can then fill the needs of both a generator input and a lockfile. |
@slhultgren the *.CPRJ file has most of this information. I suggest we start there and make a gap analysis. We can of course add missing information once we have understood the usage. For example it does currently not show the invocation line of the csolution tool so that a convert process is cannot be replicated. Likewise the Environment variables and inherent settings (for example cdefault assumptions) is missing. However, these gaps are minor, and we should just list them as requirements for further development. We should also discuss if some of the current information should be removed. For example
We should check the behavior of git systems, so that the *.CPRJ file can be committed, but effectively does not change when csolution recreates the same content.
|
Beside requirements described in
I would prefer yml format for lock file since it is already used for solution definition. |
As discussed yesterday, I got confused by the difference of:
With *.CPRJ I believe only the "log file" requirement can be fulfilled. Are we aligned in this view? I would then split this issue into two. |
We could discuss the format, (I have some changes in mind to what I've previously posted), but I think it is also interesting to align on what this could bring for the tooling. In my view, having a file that clearly both locks the state (by locking on packs) and describes the resolved state, it then means that the user no longer need any runtime tool to understand what and why something is part of the project. This would also help streamline I'll take a few use-cases to explain the flow: Add a component [YML] high level
Add a component [CPRJ] high level
Add a component [YML] detailed
Using a generated component [YML]
|
@slhultgren - in the meantime we have been discussing to disable the cbuildgen functionality regarding 'managing' RTE config files. Do you think that editing cprj files is still relevant? |
Perfect :) I very much agree with this. There should only be one point in the flow where files are added in the project and this should be well defined. Then the lockfile is used to describe what/how/where files where created in the project. So long term, if we add some flexibility in YML on how certain components are placed for example, this would not change anything for cbuildgen since it would still rely on the "string value path" of the files described in the lockfile.
Honestly no, I would like us to consider the CPRJ format as deprecated. I kept it in the use-cases since it is still part of the OpenCMSIS standard, so we need to think of a way to handle it, but ideally I would like to avoid double-implementation of features. In my view:
So for me the main build path (ideally only build path) is
In the case of CPRJ there would be a single |
Apologies for coming late to this conversation, but just recently I have been thinking about this issue from a slightly different perspective. Mostly due to the separation of concerns design principle, I have been thinking about how to manage CMSIS components in a project agnostic way. This project agnostic approach is followed by most package managers, so in principle it should be relatively simple to replicate. However, CMSIS gives us an extra dimension, that package managers do not normally have to handle. Normally the package dependency being managed is the same as the library or component being used. With CMSIS we allow loosely defined component references, which can be resolved to a number of components that can be delivered by different packs. This increases flexibility, but makes both reproducibility and dependency management more tricky. Another aspect that most package managers posses, is a separation between the "required" components (those that a developer explicitly wishes to use) and the dependencies of those components (e.g. Python's Conceptually we can used the
A lock file could look something like the following, where the component reference is keyed from those included in the
This results in a tree structure that makes it straight forward to manage component dependencies and packs. For reference the schema for this document is as follows:
|
@madchutney thanks for the input, very interesting
Very valid point, I agree totally with this. Dependencies are not always that interesting, and indeed, if you change the top-level component, you likely also want to change/remove the now unused dependencies. Q: Do we now then say that the list of the components in
On this I'm not sure I fully understand what you mean.
For For
With a purely package based package manager like pip or NPM, the granularity is on the module/package level. If you know which module you have, then you implicitly also know all the files. With CMSIS it is not that simple, since the file set is not static for a component (file-based conditions, RTE connection, Generated components). To summarize my comments:
|
@madchutney I forgot to add, your |
Differentiating between "user required" components and those being selected to satisfy dependencies resonates with me. Considering the situation that there maybe choices in resolving dependencies, these user decisions would be recorded in the lock file, which means that the lock file becomes a mandatory project file or am I missing something? I am wondering whether we could record such components as "secondary components". Meaning they could be "excluded" from build in case they are no longer showing in the dependency list. |
After reviewing this issue, there might be an intermix of different things:
My suggestion: introduce a "log" file that lists all important information about a csolution based application in one file. The information could include:
It should be also possible to list:
This "log" file could be in YAML format (using the standard naming conventions) so that it is user digestible, but also serves as data source for analysis tools. Over time we could develop it into a "lock" mechanism (but I suggest this is not the initial priority). After considering all feedback the *.CPRJ file seems not the right place to add above information, instead my proposal is a single "log" file per *.csolution.yml" that is generated by the csolution tool. |
@slhultgren Thanks for taking the time to review my suggestion.
That was my thinking, yes.
I trying to illustrate how the
That is what I was thinking. The
I agree, the lock file should be per Project Context ($BUILD_TYPE*$TARGET_TYPE*$PROJECT). The lock file format could be structured such that there was a "lock" per Project Context or an individual lock file per Project Context (my example takes the latter approach as this seemed simpler).
Great points, the lock file I was proposing is only for CMSIS Components and Packs. There is a lot of information missing that would need to be in Solution/ Project File and for that matter in the source files. I came at this from the perspective of what do we need for a Component Manager for CMSIS. I was hoping that breaking down the problem into the different concerns of Packaging and Project might make the tools more extensible and flexible. |
Yes, my suggestion was to record user decisions in the lock file and not in the
I think the "secondary components" is the same concept as the dependencies. If a component is being added to resolve a dependency then it would be a "secondary component", but there should also be an option to make it a "primary component" even if it happens to satisfy a dependency requirement. From a component management perspective I think it would be clearer if unused components and packs were removed from the definition. |
I think this information is very similar in content to the lock file format for components #119 (comment), although the organisation is different. Rather than using |
Yes and no for me, all information that is put in the file is also My ideal view of the future is a simplified flow where cbuildgen doesn't have to understand:
cbuildgen should simply by inspecting the lockfile be able to figure out which files it should pick and where they are located in the project. So I would like to also streamline the lifecycle of the devtools to avoid double-implementing every flexibility feature we will introduce in the future in the standard. Today the flow is
I would love it if it could be simplified to
Because this means that only one tool need to consider PLM and dealing with flexibility of file placement etc ( This streamlining is a bit of work I agree, but I would be happy to work in this direction. |
I my proposal the |
I believe this is somewhat a duplicate with #434 -> suggest to close it. |
I agree, lets close this one and continue in #434 , for me the |
With the recent advances to the .yml format and projmgr/csolution tools I'd like to reopen the discussion around lockfiles.
It seems that the source of truth for the projects are now likely to be the .yml files.
Use-case: User adds a compiler flag to the project
During step 2, if there is already a cprj file existing, we should preserve/reuse as much information from that as possible.
For example, the yml files may not specify any packs, or without any version ranges, but the .cprj may be strictly locked down to a specific pack+version.
Same for components.
For the above use-case, the user expects only the define to be added in the build. If the 2. would result in a full recompute/resolving of components+pack-versions it would make the .yml files impossible to use over time or between colleagues, since the contents of the .cprj would very likely be different due to changing CMSIS_PACK_ROOT contents.
This is a followup on the discussion from the build gap
Also, working in this way means that the user should put commit the .yml and the .cprj files in their git repository to make sure that colleagues/CI are building the same thing.
The text was updated successfully, but these errors were encountered: