-
Notifications
You must be signed in to change notification settings - Fork 985
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
[question] CMakeDeps and inter-package dependencies when using shared libraries #16990
Comments
As a possible workaround target_link_libraries(engine_test
PRIVATE
engine
$<LINK_ONLY:log4cxx>
) That solves the linking problems, but something weird happens at the same time. Despite the
If I link Recipe of |
Hi @bukulin Thanks for your question and thanks specially for your detailed report. Can you please do a quick check? It would be in your test CMakeLists.txt: target_link_libraries(engine_test
PUBLIC engine ) This shouldn't have a bad impact, being the If this work, this is kind of a known issue, that happens in Linux like shared libraries (it doesn't happen in Windows shared libraries). It is kind of challenging to fix it in CMakeDeps at the moment with the current information we have, but we are working to improve and expand that information and planning an improved CMakeDeps generator (it will take some time, there are still other higher priorities) I think this was a very specific issue of the |
Hi @memsharded, Thank you for the quick reply! target_link_libraries(engine_test
PUBLIC engine ) Unfortunately the public dependency did not help here, I have got the same linker error and the same linker commandline. However, if target_link_libraries(engine PUBLIC log4cxx) , then the link step of
Thank you for the effort. We can live with a workaround that does not harm the required dependency chain. #16911 |
Maybe this is related to the Is the |
The from conan import ConanFile
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps
class engineRecipe(ConanFile):
name = "engine"
version = "1.0.0"
package_type = "library"
# Optional metadata
license = "MIT"
author = "Norbert Bukuli"
url = "-"
description = "middle engine library"
# Binary configuration
settings = "os", "compiler", "build_type", "arch"
options = {
"shared": [True, False],
"fPIC": [True, False]
}
default_options = {
"shared": False,
"fPIC": True
}
# Sources are located in the same place as this recipe, copy them to the recipe
exports_sources = "CMakeLists.txt", "src/*", "include/*"
def requirements(self):
self.requires("log4cxx/1.2.0")
def config_options(self):
if self.settings.os == "Windows":
self.options.rm_safe("fPIC")
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
def layout(self):
cmake_layout(self)
def generate(self):
deps = CMakeDeps(self)
deps.generate()
tc = CMakeToolchain(self)
tc.generate()
def build(self):
cmake = CMake(self)
cmake.configure(cli_args=["--graphviz", "deps.dot"])
cmake.build()
cmake.ctest(cli_args=["--output-on-failure"])
def package(self):
cmake = CMake(self)
cmake.install()
def package_info(self):
self.cpp_info.libs = ["engine"]
|
Hi @bukulin I am trying to fully reproduce your case, this is what I have done: engine.zip I am building it with either:
In both cases it works fine, because my actual test is empty. |
Hi @memsharded Thank you for spending the time with this. Here is the repository: https://github.com/bukulin/conan_cmakedeps In the meantime I also investigate your implementation. For the first try it also failed to link the test executable. |
The problem might be with the environment. On a more recently updated machine everything works well. The production machine and the new machine differs in many ways. The compiler, linker, cmake, make, everything is newer, only conan is the same: 2.7.1. As a quick check I've built So the differences are:
If there are other suspicious system packages please let me know. Comparing the build directories from the afformentioned
|
My environment:
This is an Ubuntu 22.04 on WSL When trying to build your project, the first thing I get is:
Note this is what was happening, the problem with your working scenario is that it is finding and using the
This can be fixed changing the CMakeLists to: -target_link_libraries(engine PRIVATE log4cxx)
+target_link_libraries(engine PUBLIC log4cxx) Note this shouldn't be an issue, because When changing that, I am able to get:
Which looks better, because the dependencies apr, apr-util, iconv are not found int he system, but provided by Conan. |
I have reviewed the CMake targets properties, but it seems correct, might be a CMake issue? Lets call the dependencies
I would expect that the |
I've checked with a clean virtual machine (lxd container), that does not have apr-utils installed in the system. The build failed there, as expected. If
I experienced the same behavior. Assuming your dependency chain I did the following workaround:
But that could go crazy if
We are right now in a transition from conan/1 to conan/2. With the former one we used In the long run, we would like to keep these CMake configuration files, not necessarily in the conan package but as part of the build. However this brings in some sort of duplication. All the required information must be set in our CMake system and in the conanfile.py, as well. Formerly Is there any chance to have best of both worlds? Is it feasible to have a generator, that uses the packaged CMake config files if they are present but behaves like CMakeDeps if the requirement package does not have a proper CMake config file? |
I am not sure, are you trying to move to
Yes, if the package that generates the |
In the long run, the goal would actually to use CPS information, we are working on this in the C++ tooling evolution group to try to standardize it, we already did some progress recently presented in CppCon: https://cppcon2024.sched.com/event/1gZew/common-package-specification-cps-in-practice-a-full-round-trip-implementation-in-conan-c-package-manager |
Yes, actually exactly that happened. Somehow I passed over this section of the documentation. Please let me point out, the documentation is invaluable. I have tried it and mostly works. The problem is again with
Exactly, thank you.
Great news, I will check it out. Thanks again. |
We are releasing in Conan 2.9 a completely new
Current known pending functionality (to be added soon):
The new Your feedback is very importantAs this is a major change, we will only remove the conf gate when we get confirmation from users that it works and solve the issues. Please try the new generator for your project, and let us know if it works. If it doesn't, please re-open this ticket and let us know what failed. Thanks very much! |
Great news! Thank you very much for all of your efforts. I have tested the new CMakeDeps2 generator and an error emerged: engine/1.0.0: WARN: Using the new CMakeDeps generator, behind the 'tools.cmake.cmakedeps:new' gate conf. This conf will changenext release, breaking, so use it only for testing and dev
ERROR: Traceback (most recent call last):
File "/home/user/conan2-venv/lib/python3.9/site-packages/conan/internal/errors.py", line 35, in conanfile_exception_formatter
yield
File "/home/user/conan2-venv/lib/python3.9/site-packages/conan/internal/api/install/generators.py", line 126, in write_generators
conanfile.generate()
File "/home/user/.conan2/p/engin4f0278febf2d5/e/conanfile.py", line 46, in generate
deps.generate()
File "/home/user/conan2-venv/lib/python3.9/site-packages/conan/tools/cmake/cmakedeps2/cmakedeps.py", line 41, in generate
generator_files = self._content()
File "/home/user/conan2-venv/lib/python3.9/site-packages/conan/tools/cmake/cmakedeps2/cmakedeps.py", line 68, in _content
ret[target_configuration.filename] = target_configuration.content()
File "/home/user/conan2-venv/lib/python3.9/site-packages/conan/tools/cmake/cmakedeps2/target_configuration.py", line 24, in content
return t.render(self._context)
File "/home/user/conan2-venv/lib/python3.9/site-packages/conan/tools/cmake/cmakedeps2/target_configuration.py", line 74, in _context
cpp_info = self._conanfile.cpp_info.deduce_full_cpp_info(self._conanfile)
File "/home/user/conan2-venv/lib/python3.9/site-packages/conans/model/build_info.py", line 750, in deduce_full_cpp_info
result._package.deduce_locations(pkg_type)
File "/home/user/conan2-venv/lib/python3.9/site-packages/conans/model/build_info.py", line 549, in deduce_locations
if self._type != pkg_type:
File "/home/user/conan2-venv/lib/python3.9/site-packages/conans/model/pkg_type.py", line 22, in __eq__
return super().__eq__(PackageType(other))
File "/usr/lib/python3.9/enum.py", line 384, in __call__
return cls.__new__(cls, value)
File "/usr/lib/python3.9/enum.py", line 702, in __new__
raise ve_exc
ValueError: None is not a valid PackageType
engine/1.0.0: Error in generate() method, line 46
deps.generate()
ValueError: None is not a valid PackageType I suppose that the problem lies in this function: https://github.com/conan-io/conan/blob/develop2/conans/model/build_info.py#L511-L517 In case of *nix, in the guts of def _find_matching(patterns, dirs):
matches = set()
for pattern in patterns:
for d in dirs:
matches.update(glob.glob(f"{d}/{pattern}"))
if len(matches) == 1:
return next(iter(matches))
if len(matches) > 1:
return min(matches, key=len) After that modification, conan successfully installed the requirements and generated everything, but CMake configuration fails with the following error message: engine/1.0.0: RUN: cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="generators/conan_toolchain.cmake" -DCMAKE_INSTALL_PREFIX="/home/user/.conan2/p/b/engine18a6ef5d1050/p" -DCMAKE_POLICY_DEFAULT_CMP0091="NEW" -DCMAKE_BUILD_TYPE="Release" "/home/user/.conan2/p/b/engine18a6ef5d1
050/b"
engine/1.0.0: Full command: . "/home/user/.conan2/p/b/engine18a6ef5d1050/b/build/Release/generators/conanbuild.sh" && cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="generators/conan_toolchain.cmake" -DCMAKE_INSTALL_PREFIX="/home/user/.conan2/p/b/engine18a6ef5d1050/p" -DCMAK
E_POLICY_DEFAULT_CMP0091="NEW" -DCMAKE_BUILD_TYPE="Release" "/home/user/.conan2/p/b/engine18a6ef5d1050/b"
-- Using Conan toolchain: /home/user/.conan2/p/b/engine18a6ef5d1050/b/build/Release/generators/conan_toolchain.cmake
-- Conan toolchain: Defining architecture flag: -m64
-- Conan toolchain: Including CMakeDeps generated conan_find_paths.cmake
-- Conan toolchain: Setting BUILD_SHARED_LIBS = ON
-- The CXX compiler identification is GNU 7.5.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring Targets for log4cxx/1.2.0
-- Configuring Targets for apr-util/1.6.1
-- Configuring Targets for apr/1.7.4
-- Conan: Target declared imported SHARED library 'apr::apr'
-- Configuring Targets for libiconv/1.17
-- Conan: Target declared imported SHARED library 'libiconv::_iconv'
-- Conan: Target declared imported SHARED library 'libiconv::_charset'
-- Conan: Target declared imported INTERFACE library 'libiconv::_common'
-- Conan: Target declared imported INTERFACE library 'Iconv::Iconv'
-- Configuring Targets for expat/2.6.3
-- Conan: Target declared imported SHARED library 'expat::expat'
-- Conan: Target declared imported SHARED library 'apr-util::apr-util'
-- Conan: Target declared imported SHARED library 'log4cxx'
-- Configuring done
CMake Error at CMakeLists.txt:10 (add_library):
Target "engine" links to target "libiconv::libiconv" but the target was not
found. Perhaps a find_package() call is missing for an IMPORTED target, or
an ALIAS target is missing?
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly. The dependency graph is the following: I suppose that the problem here might be that #################### Iconv::Iconv ####################
if(NOT TARGET Iconv::Iconv)
message(STATUS "Conan: Target declared imported INTERFACE library 'Iconv::Iconv'")
add_library(Iconv::Iconv INTERFACE IMPORTED)
endif()
target_link_libraries(Iconv::Iconv INTERFACE libiconv::_iconv libiconv::_charset libiconv::_common) but target_link_libraries(apr-util::apr-util INTERFACE apr::apr libiconv::libiconv expat::expat) I cannot figure out right now where this uppercase - lowercase problem comes from, but libiconv exports @memsharded what do you think, shall we reopen this ticket? |
Hi @bukulin Thanks for the extensive feedback! We are already aware of that error, the PR #17257 tries to fix it.
yes, definitely, we were also really looking forward this! :) It is just a matter of available time and resources, I am very happy that we are finally moving this forward. Let's re-open this and iterate it with that feedback, try to solve those issues for next release :) |
I have added a check for the "Iconv" failure in PR #17257, if you want to try things from that branch, otherwise I will keep you updated in this thread when it is merged I will be working with @franramirez688 to improve also the Thanks for your feedback, super useful, exactly the kind of feedback we need to improve the new CMakeDeps generator quickly. |
Great, thank you in advance! I'm looking forward for the new version!
|
What is your question?
Hi!
I ran into a problem with
CMakeDeps
generator when shared libraries are used and the consuming project has a unit-test-like application. Trying to describe the situation as briefly as I could, but I have to dive deep. This might be due to my misunderstanding of the advanced dependency handling, but I try to do my best.So let's consider the following things:
*:shared=True
)math
substituted withlog4cxx
to have some more dependencies.Everything works correctly as described in the aforementioned video until I add a unit test to the
engine
package, just like that:engine/CMakeLists.txt
:engine/test/CMakeLists.txt
:So,
engine
depends privately onlog4cxx
andengine_test
depends onengine
, in turn.At this point when I try to compile the whole engine package, the link step of
engine_test
fails:Interestingly
liblog4cxx.so.15
is found but its dependencies not. The linker command line lacks here the library paths (-L
) (and RPATH definitions (-Wl,--rpath
)) of the transitive dependencies ofengine
, however they were present whenengine
library was built:When
engine
is built its dependencies are all come from the config files generated byCMakeDeps
however dependencies ofengine_test
handled internally by CMake.Everything works well, if
*:shared=False
, because in that case every static library is listed in the linker commandline when linkingengine_test
.This issue might be related to this one: #16911
What do I wrong? If it is possible, I try to use modern CMake and rely on
target_link_libraries
with local targets in this case. I suppose a workaround could be written, where I query all the link-time dependencies ofengine
and apply them toengine_test
but I try to avoid that.Any guidance will be highly appreciated. Unfortunately I cannot find corresponding points in the documentation.
Thank you in advance!
Have you read the CONTRIBUTING guide?
The text was updated successfully, but these errors were encountered: