Skip to content

[question] Editable packages: Custom cpp_info properties with path #18340

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

Open
1 task done
aagor opened this issue May 22, 2025 · 5 comments
Open
1 task done

[question] Editable packages: Custom cpp_info properties with path #18340

aagor opened this issue May 22, 2025 · 5 comments
Assignees

Comments

@aagor
Copy link

aagor commented May 22, 2025

What is your question?

Hi,

inside a package, I need a custom property that contains a path, which is needed by consumers of the package.
This is easy for the cache workflow:

def package_info(self):
    # ...
    self.cpp_info.set_property("proto_dir", os.path.join(self.package_folder, "whatever", "foo"))

However this is difficult to get right, when the package is in editable mode.
The local path is different and is contained inside the build folder.

I guess self.cpp.build.set_property inside layout() is supposed to be used for that, but that's difficult as I can't access self.build_folder there.
Setting it inside package_info() does also not work, as I can't access self.build_folder there, too.

  • How can I set it properly?
  • What's the difference regarding self.cpp.source and self.cpp.build when it comes to properties? Which one has more precedence?
  • Why is specifying of information for editable packages supposed to happen in layout(), whereas it is inside package_info() for cache packages? This leads to similar logic at two different places.

Have you read the CONTRIBUTING guide?

  • I've read the CONTRIBUTING guide
@memsharded memsharded self-assigned this May 22, 2025
@memsharded
Copy link
Member

Hi @aagor

Thanks for your question.

The "properties" of cpp_info and the editable source/build are transmitted as-is, without any transformation.
Do you really need the self.build_folder. I mean, the layout() method is the method that defines such a folder, as relative path with self.folders.build, etc, but it should be able to define where are the different artifacts in the local development layout, that is its reponsibility. Doesn't the layout() method know where the proto_dir binary is?

What's the difference regarding self.cpp.source and self.cpp.build when it comes to properties? Which one has more precedence?

Those are composed, the idea is that they define different and not overlapping things, they shouldn't really overwrite, so precedence shouldn't matter much. They do almost the same, it is a minor semantic difference:

  • self.cpp.source.includedirs will point to the regular include headers in code
  • self.cpp.source.libdirs will usually be empty, unless the "source" contains pre-compiled libraries, like inside the git repo
  • self.cpp.build.includedirs will point to headers not belonging to source, like for example the typical headers generated by code generators, that is way more unusual than the source.includedirs
  • self.cpp.build.libdirs will point to the locally compiled libraries. This is extremely common, and together with self.cpp.source.includedirs is the normal definition for a compiled library in editable mode.

Why is specifying of information for editable packages supposed to happen in layout(), whereas it is inside package_info() for cache packages? This leads to similar logic at two different places.

Mostly historical reasons, and introduction as layout() as opt-in, while package_info() was always there and mandatory. Still, the logic can be very similar, but not exactly the same, as package_info() always refer to the packaged layout, which is rarely identical to the development layout.

@aagor
Copy link
Author

aagor commented May 23, 2025

Hi @memsharded,

Do you really need the self.build_folder.

No, but I need an absolute path (as otherwise the paths would be relative to the consumer paths, which obviously doesn't work) and getting that without self.build_folder is at least tricky.

# Does not work as it's relative to build_folder.
self.cpp.build.set_property("proto_dir", os.path.join("path", "to", "subdir_in_build_folder"))

# Does not work as it's relative to the base folder.
self.cpp.build.set_property("proto_dir", os.path.join(self.folders.build, "path", "to", "subdir_in_build_folder"))

# Works, but is there a better solution?
self.cpp.build.set_property("proto_dir", os.path.normpath(os.path.join(self.recipe_folder, self.folders.root or ".", self.folders.build, "path", "to", "subdir_in_build_folder")))

The last one works, but feels a little clunky.

For the default information like includedirs, libdirs etc. I see the difference between self.cpp.source and self.cpp.build, but (as you said) there is no logic for custom properties, this has no value for custom properties. From my tests, self.cpp.build.set_property seems to win if a custom property is defined for both source and build.
For the builtin ones, the path definition is also not a problem, as conan takes care of relative paths and parents that on the source or build folder.

@memsharded
Copy link
Member

memsharded commented May 23, 2025

Quick question: Have you tried propagating the information via a user.xxx conf?

self.layouts.build.conf_info.define_path("user:mydictconf2", {"c": "mypathc"})

Because the paths are made absolute for the consumers

Note, not necessary for the value to be a dict, it can be a string, directly, that is just from a test to show path confs can be complex python objects

@aagor
Copy link
Author

aagor commented May 23, 2025

No, I haven't tried that. But thanks for the hint. Maybe that becomes useful in the future.
The conf solution feels like a little hack for me. This is more general visible and not as scoped as custom properties are.

I think, for now, I will go with the third option from above.
For me it seems like that should work generally and is the easiest.

If you are interested in feedback, I think it could be useful to have a define_path equivalent for properties, like:

self.cpp.build.set_property_path("proto_dir", os.path.join("path", "to", "subdir_in_build_folder"))

This would allow similar logic like for the builtins (includedirs, bindirs etc.) for custom properties.

Thanks for your help!

@memsharded
Copy link
Member

self.cpp.build.set_property_path("proto_dir", os.path.join("path", "to", "subdir_in_build_folder"))

The thing is that this seems a bit contrary to the cpp_info.set_property() design, which has always been intended:

  • to propagate to the consumers generators such as CMakeDeps, build-system specific things that are not conveyed by the common cpp_info.xxxdirs and other fields, such as cmake_target_name.
  • to be specific for a specific build system, not "abstract"
  • It is a cpp_info -> generator mechanism, not a cpp_info -> recipe mechanims
  • The cpp_info mechanism is also mostly intended for propagating information of "host" library dependencies.

It is true that I lack details about:

self.cpp_info.set_property("proto_dir", os.path.join(self.package_folder, "whatever", "foo"))

What is the proto_dir? What is in there? How consumers use this property and for what? In which build systems? It is used from requires or from tool_requires?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants