Closed Todiq closed 9 months ago
Hi @Todiq
I'd need to have a closer look, but some quick hints:
folders.source
it should receive old style pathscpp_info
is discarded, and only components information is used. You might need to define self.cpp_info.components["comp"].xxxxdirs = ..
tooHi @memsharded,
Thank you for your time and patience.
Regarding your advices : I noted that I should use os.join.path instead of Pathlib. I also see that self.cpp_info.components["comp"].xxxxdirs
are not defined in my recipe (as you can see below), which can lead to the problem.
I can give you my package_info(self)
method (taken from poco), which has worked flawlessly until now for full fledged packages. I used to accompany it with cmake_layout, but since I have an unusual source tree, that would not work with editables.
I also tried with basic_layout(self)
, but no luck. That's why I am now trying to define my custom layout.
def package_info(self):
self.cpp_info.set_property("cmake_file_name", self.name)
self.cpp_info.set_property("cmake_target_name", f"{self.name}::{self.name}")
for compname, comp in self._parsing_component_tree.items():
conan_component = f"{self.name}_{compname.lower()}"
requires = [f"{self.name}_{dependency.lower()}" for dependency in comp.dependencies] + comp.external_dependencies
self.cpp_info.components[conan_component].set_property("cmake_target_name", f"{self.name}::{compname}")
self.cpp_info.components[conan_component].set_property("cmake_file_name", compname)
if comp.is_lib:
self.cpp_info.components[conan_component].libs = [f"{compname}"]
self.cpp_info.components[conan_component].requires = requires
Thanks for sharing. Then yes, I think definitely the first step is to add there the definition of xxxdirs
for all components (typically the includedirs
would be different, but the libdirs
could be common to all of them, but that depends on the project). Please try that and let us know.
Hello @memsharded,
Unfortunately, even with your advices, I could not make it work.
I had a look at the file mentionned in the error: build/Debug/generators/BBB-Target-debug.cmake:24 (conan_package_library_targets)
.
And I indeed noticed that the library cannot be found here:
set_property(TARGET BBB_DEPS_TARGET
PROPERTY INTERFACE_LINK_LIBRARIES
$<$<CONFIG:Debug>:${BBB_FRAMEWORKS_FOUND_DEBUG}>
$<$<CONFIG:Debug>:${BBB_SYSTEM_LIBS_DEBUG}>
$<$<CONFIG:Debug>:BBB::comp1;BBB::comp2;BBB::compX> --> Not in this line
APPEND)
Even though it is present further away in the file, just like all the libs mentionned in the list above (line 24):
########## COMPONENTS TARGET PROPERTIES Debug ########################################
########## COMPONENT BBB::culprit #############
set(BBB_BBB_culprit_FRAMEWORKS_FOUND_DEBUG "")
conan_find_apple_frameworks(BBB_BBB_culprit_FRAMEWORKS_FOUND_DEBUG "${BBB_BBB_culprit_FRAMEWORKS_DEBUG}" "${BBB_BBB_culprit_FRAMEWORK_DIRS_DEBUG}")
set(BBB_BBB_culprit_LIBRARIES_TARGETS "")
...
I probably made a mistake at some point, but I don't understand how it manages to work when packaged with conan create
but not as an editable one.
If you have any idea, that would be fond of you to share it. Thanks in advance.
Hi @Todiq
I think it was my mistake, I probably wasn't very clear, and it was an oversight from my side (I was responding issues while travelling):
The definition of components to be useful for editable
mode, need to happen in the layout()
method, not in the package_info()
method. There isn't many references yet in the docs, we need to complete https://docs.conan.io/2/reference/conanfile/methods/layout.html#self-cpp: Components can be defined for self.cpp.source.components[...]
and self.cpp.build.components[...]
to specify their editable information (typically includedirs
is self.cpp.source.components..
while libdirs
is self.cpp.build.components
.
Hello @memsharded,
Here is my layout()
now:
def layout(self):
self.folders.source = "."
self.folders.build = f"build/{self.settings.build_type}"
self.folders.generators = f"{self.folders.build}/generators"
for compname, comp in self._parsing_component_tree.items():
conan_component = f"{self.name}_{compname.lower()}"
if comp.is_lib is True:
self.cpp.source.components[conan_component].includedirs = ["."]
self.cpp.build.components[conan_component].libdirs = ["."]
Unfortunately, that still does not help. I must have made a mistake while following poco's recipe, but can't find where. As I mentionned in my previous message, the lib is not present in the list of components in build/Debug/generators/BBB-Target-debug.cmake:24
, even if this line is displayed:
Conan: Component target declared 'BBB::culprit'
Ok, I think at this point it would be good to setup a small repro case, with a package with a couple of components (dummy "hello world" libraries, with just 1 function), and a consumer, with a script that reproduce the issue. Do you think you could strip a copy of your project to create it, or would you like some help to set it up?
Hey @memsharded,
You made an effort to answer quickly, but I could not follow up because it took me a while to create a reproducible case. I apologise for that.
Anyway, I created a docker image containing it all: docker run -it --name todiq_test --rm todiq/conan
All you have to do is execute conan build -verror beta/ --build="missing"
to get the error.
The repository can be found here. Feel free to rebuild the image on your side if required.
While creating it, I noticed that, even though I never execute conan create
(only editable mode), removing package_info()
from package alpha raises an error. It makes me think that I should maybe use the self.cpp.package.components
within my layout()
method to hopefully fix the issue. Thank you again for your time.
Hi @Todiq
Thanks very much for setting up the project. I managed to reproduce with the docker image. However, I have started to play with it with my own Linux docker, to understand better some things, and I am struggling with a couple of things:
fPIC
(maybe not an issue in Rocky Linux, but it was failing in my ubuntu)conan create
is not working, so it is not only the editable
mode, but the regular conan create
doesn't work (I am adding a test_package
to validate it, very recommended). This is expected because the CMakeLists.txt
do not contain any installation code. I guess that you might have stripped that code, and the repro case covers exclusively the editable
case.While creating it, I noticed that, even though I never execute conan create (only editable mode), removing package_info() from package alpha raises an error. It makes me think that I should maybe use the self.cpp.package.components within my layout() method to hopefully fix the issue.
Yes, brilliant observation, I think that is probably the right approach.
I'll keep working on this later if possible, some quick hints:
Your configure()
method is probably missing this:
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC") self.options["zlib/*"].shared=True
Otherwise fPIC is disabled and it fails to link
Most likely, the package_info()
can be simplified:
def package_info(self):
self.cpp_info.set_property("cmake_file_name", self.name)
self.cpp_info.set_property("cmake_target_name", f"{self.name}::{self.name}")
for compname, comp in self._alpha_component_tree.items():
conan_component = f"{self.name}_{compname.lower()}"
requires = [f"{self.name}_{dependency.lower()}" for dependency in comp.dependencies] + comp.external_dependencies
self.cpp_info.components[conan_component].set_property("cmake_target_name", f"{self.name}::{compname}")
self.cpp_info.components[conan_component].set_property("cmake_file_name", compname)
self.cpp_info.components[conan_component].names["cmake_find_package"] = compname
self.cpp_info.components[conan_component].names["cmake_find_package_multi"] = compname if comp.is_lib: self.cpp_info.components[conan_component].libs = [f"{compname}"] self.cpp_info.components[conan_component].requires = requires
First you don't need to support legacy 1.X generators like ``cmake_find_package``. Then, also, the default for ``cmake_target_name`` is already that, no need to define it. And overwriting the ``cmake_file_name`` to the ``compname`` is not correct, because it is just 1 file per package, not per component, so it has to be the name of the package, not the component.
I'd also strongly recommend using the test_package
functionality, so a single conan create .
is good to create and test the package quickly. I will try to submit some changes later with it.
Hello @memsharded
Thanks a lot for your dedication. I reviewed your changes and merged them.
Indeed, I removed a lot of things to stick with my editable issue, as I didn't want to pollute the sources (hence the removal of self.options.rm_safe("fPIC")
for example).
I removed many lines in my package_info()
method, matching what you showed me, and it still works! (should I be surprised? :) )
However, editable mode still won't work for alpha. I tried replicating in layout()
what you wrote in package_info()
, but that would not fix the issue:
def layout(self):
self.folders.source = "."
self.folders.build = f"build/{self.settings.build_type}"
self.folders.generators = f"{self.folders.build}/generators"
for compname, comp in self._alpha_component_tree.items():
if comp.is_lib:
self.cpp.source.components[compname].includedirs = ["."] # I tried this line in and outside of the if condition
self.cpp.build.components[compname].libdirs = ["."]
After setting alpha in editable mode, I ran:
conan build -verror beta/ --options "&:shared=True" --build=missing
and got:
-- Using Conan toolchain: /workspace/test_conan/Test/beta/build/Release/generators/conan_toolchain.cmake
-- Conan toolchain: Setting CMAKE_POSITION_INDEPENDENT_CODE=OFF (options.fPIC)
-- Conan toolchain: C++ Standard 17 with extensions ON
-- Conan toolchain: Setting BUILD_SHARED_LIBS = ON
-- Conan: Component target declared 'alpha::alpha'
-- Conan: Component target declared 'alpha::alpha1_1'
-- Conan: Component target declared 'alpha::alpha1_2'
-- Conan: Component target declared 'alpha::alpha2'
CMake Error at build/Release/generators/cmakedeps_macros.cmake:66 (message):
Library 'alpha2' not found in package. If 'alpha2' is a system library,
declare it with 'cpp_info.system_libs' property
Call Stack (most recent call first):
build/Release/generators/alpha-Target-release.cmake:24 (conan_package_library_targets)
build/Release/generators/alphaTargets.cmake:26 (include)
build/Release/generators/alpha-config.cmake:16 (include)
CMakeLists.txt:5 (find_package)
-- Configuring incomplete, errors occurred!
ERROR: conanfile.py (beta/1.0): Error in build() method, line 50
cmake.configure()
ConanException: Error 1 while executing
Do you have some ideas? Thanks in advance
Hello @memsharded
You must be very busy. Would it be possible to have a quick look when you have a minute please? Thank you very much for your help so far, I appreciate it.
Hi @memsharded
Could you please give me a hand about this when you have a moment? Thanks in advance.
Thanks @Todiq for resurfacing this. Indeed, we are extremely busy, it is very complicated to follow up, specially tickets that require investing more time.
I am doing some further checking (ongoing wip https://github.com/memsharded/test_conan/pull/new/review2), and I am seeing some unexpected behaviors, so I am going to reproduce in a test in Conan test suite first, to make sure things work fine.
Submitting https://github.com/conan-io/conan/pull/13801, it seems editables + components work fine
Hello @memsharded,
I merged your PR, thank you. However, after running the build.py, I still have the following errors. Did I miss something?
I developed and tested it in Windows. It is very possible that some of the definitions of layouts are Windows-specific and fails in Linux system. Let me try to have a look and make it more portable.
This https://github.com/Todiq/test_conan/pull/3 works both in WIndows and Linux.
The key would be also to simplify the CMakeLists.txt to achieve a binary output in CMake that is simple and homogenous across platforms, that would simplify the definition of components in the conanfile.py
https://github.com/conan-io/conan/pull/13801 was merged, proving it works, and also https://github.com/Todiq/test_conan/pull/3 seems to finally fix this?
Hello @memsharded,
Thank you for your attention. Your fix indeed works. I copied it to simplify my own recipe :
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout
from conan.tools.files import copy
required_conan_version = ">=2.0.0"
class Pkg(ConanFile):
name = "castparsing"
version = "1.0"
# Binary configuration
settings = "os", "compiler", "build_type", "arch"
options = {
"shared": [True, False],
"fPIC": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
}
_parsing_components = {
"a3sqlu": "common/a3sqlu",
"memmng": "common/memmng",
"mngtree": "common/mngtree",
"noyau": "common/noyau",
"syntree": "common/syntree",
"tblsym": "common/tblsym",
"lexel": "components/jee/lexel",
"lexj11": "components/jee/lexj11",
"lexjsp11": "components/jee/lexjsp11",
"yacel": "components/jee/yacel",
"yacj11": "components/jee/yacj11",
"yacjsp11": "components/jee/yacjsp11",
"lexbms": "components/mainframe/lexbms",
"lexcics": "components/mainframe/lexcics",
"lexcob": "components/mainframe/lexcob",
"lexcsd": "components/mainframe/lexcsd",
"lexims": "components/mainframe/lexims",
"lexjcl": "components/mainframe/lexjcl",
"sqltiny": "components/sql",
"lexabap": "components/sap/lexabap",
"lexcdsview": "components/sap/lexcdsview",
"yacabap": "components/sap/yacabap"
}
def export_sources(self):
copy(self, "*.c*", src=self.recipe_folder, dst=self.export_sources_folder)
copy(self, "*.h*", src=self.recipe_folder, dst=self.export_sources_folder)
copy(self, "*.inl", src=self.recipe_folder, dst=self.export_sources_folder)
copy(self, "*.l", src=self.recipe_folder, dst=self.export_sources_folder)
copy(self, "*CMakeLists.txt", src=self.recipe_folder, dst=self.export_sources_folder)
def requirements(self):
self.requires("castcore/1.0")
self.requires("zlib/1.2.13")
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
self.options["castcore/*"].shared=True
self.options["zlib/*"].shared=True
def layout(self):
self.folders.source = "."
self.folders.build = f"build/{self.settings.build_type}"
self.folders.generators = f"{self.folders.build}/generators"
bt_folder = f"/{self.settings.build_type}" if self.settings.compiler == "msvc" else ""
for compname in self._parsing_components.items():
component = compname[0]
folder = compname[1]
self.cpp.source.components[component].includedirs = [f"{folder}/include"]
self.cpp.build.components[component].libdirs = [f"{folder}{bt_folder}"]
self.cpp.build.components[component].bindirs = [f"{folder}{bt_folder}"]
def generate(self):
ct = CMakeToolchain(self)
ct.generate()
cd = CMakeDeps(self)
cd.generate()
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()
def package_info(self):
for compname in self._parsing_components.items():
component = compname[0]
self.cpp_info.components[component].libs = [f"{component}"]
However, although it also fixed my initial error for my own case, I am now getting an include error (only in editable mode):
The layout of the include files is virtually the same than the test repo.
I wonder if I made a mistake within my CMakeLists.txt
for the lib called noyau
. However, once again, the file looks almost identical with the ones in the repo. Is my layout()
method wrong? Thanks in advance.
I have been reading your recipe several times, but I don't see anything that could be wrong at plain sight. Sometimes depending on the compiler doing #include "..."
, instead of #include <...>
solves some issues, but I don't think this is the case at the moment.
Maybe if you could try to replicate the error in the git project, that would really help.
Hello @memsharded,
I have been trying the whole day, but I can neither reproduce it, nor can I fix it on my side.
I tried manually entering the dependencies within the layout()
and package_info()
methods (like you did) but that didn't help. Plus, looping through the deps that have been stored beforehand within the namedtuple works on the test repo (I commited).
It looks like the links of the libs in my castparsing
package are ignored, thus leading to the include error. The dependencies are properly set in the configure()
method and I made sure to link publicly in the CMakeLists.txt
(with target_link_libraries
. The only difference is that casparsing
links with an external library of mine, called castcore
, but I doubt it is the cause of the issue, since linking the latter with alpha_1_1
does not break the compilation for beta
.
I can't be 100% sure, but at this point I must have a config error in my multiple CMakeLists.txt
in my project, but comparing it side by side with the test repo didn't reveal any difference. Here is one example:
project(mngtree LANGUAGES CXX)
find_package(castcore)
add_library(${PROJECT_NAME} SHARED)
#add_library(castparsing::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PRIVATE
src/mng_tree.cpp
src/SignaturesSearchCtx.cpp
src/stdafx.cpp
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
castcore::castcore
memmng
parsing
)
install(TARGETS ${PROJECT_NAME})
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CastParsing
TYPE INCLUDE
)
NB: mngtree
is the equivalent of alpha_1_2
. It links within the same project with memmng
(equivalent of alpha1_1
) and with parsing
(equivalent of myalpha
, a lib interface).
If I link locally (in the test repo) beta
with mngtree
, the error I am getting indicates that it can't find the includes from castcore
. Linking manually within beta
's CMakeLists.txt
fixes the error. However, it should automatically detect dependencies and link with them, just like it does between alpha
and beta
.
If you have any idea crossing your mind, I would gladly hear it. I am aware of the low quantity of information I am giving you. Not being able to reproduce is a nightmare. Thanks in advance.
There is something that could probably be checked:
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CastParsing
TYPE INCLUDE
This is typically an indicator that the targets are not fully defined at build time, otherwise the install(TARGETS
is enough to also deploy/install the right headers to the right location. This could be the reason why it works for regular packages, but not for editables, because in editables, the install(...
functionality is not called at all.
If you could share the generated xxx.cmake
files for the failing consumer, the one that is missing the includes, that would help. Also the full log before the error, not just the error, could contain some hints.
@memsharded
I understand what you are saying. However, I then don't get how it can work for the test repo, since I install the include dirs the same way and I can properly call the includes.
Please note that although castparsing
is in editable mode, castcore
is not.
To try everything out, I locally edited the beta
package on the test repo to add anything castparsing
related:
If I run conan build test_conan/Test/beta
, I get:
We can see that an include from castcore
is not detected. Now, here are its generated .cmake files, taken from test_conan/Test/beta/build/Release/generators
:
We can indeed see that castcore_castcore_castcore_INCLUDE_DIRS_RELEASE
& castcore_castcore_castcore_LIBS_RELEASE
are both empty, whereas, in the castcore-release-x86_64-data.cmake found in the parsing/build/Release/generators dir, they are not:
Here is the conanfile for castcore
if that can help:
Hope that helps. Thanks!
Hello @memsharded,
I supposed you were wrapping up release 1.60. Do you have more free time now to have a look at this? Thanks in advance.
Hello @memsharded,
Do you happen to have some time to look at this by any chance? Thanks in advance.
Finally figured it myself. Had to configure the layout method to better match my need. Thank you!
What is your question?
Hello,
I am trying to understand how to use conan editables with packages containing multiple shared libraries. I don't encounter any issue with a single-package library. I presume it comes from a misusage from my side of the
layout(self)
method, since it works if the package is fully create viaconan create
. I tried following the instructions here and here, but still got unlucky.I am using Rocky 8.7 with GCC 8.5.0 and Python 3.9.13 Here is my profile
and here is my layout method
with a small part of the _parsing_component_tree :
When set as editable and used by another recipe, I get the following error (small portion of the output), with AAA being the current recipe's name, BBB being the previous one (conanfile above) and XXX being the missing library:
Hopefully you can give me a hand. Please let me know if you need more context. Thanks in advance.
Have you read the CONTRIBUTING guide?