conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
8.17k stars 974 forks source link

[question] Issues packaging a C++/CMake project that internally uses Conan for its own dependencies #7424

Open tjwrona opened 4 years ago

tjwrona commented 4 years ago

I'm trying to create a Conan package for this C++/CMake project: https://github.com/tnt-coders/cpp-dsp

The package recipe I have so far is checked in here: https://github.com/tnt-coders/cpp-dsp-conan

When I run conan create, it seems like it only executes a conan install for the top level "conanfile.py" but does not execute it for the internal "conanfile.txt" that is located inside the "cpp-dsp" project. This causes the build to fail because it can't find the "conanbuildinfo.cmake" file for the "cpp-dsp" project.

What approach am I supposed to take for packaging a project that uses Conan in itself?

I tried using export_sources but since the CMakeLists.txt file is at the top level and not all contained within a single "src/" folder like every example online, the project doesn't seem to lend itself cleanly to using export_sources... When I finally did wrestle with export_sources until I got it to compile, the test_package would fail because the "cpp-dsp" package requires C++17 and the PUBLIC C++17 compiler flag for the "dsp" library wasn't properly being propagated to the "CONAN_PKG::cpp-dsp" target.

memsharded commented 4 years ago

When I run conan create, it seems like it only executes a conan install for the top level "conanfile.py" but does not execute it for the internal "conanfile.txt" that is located inside the "cpp-dsp" project. This causes the build to fail because it can't find the "conanbuildinfo.cmake" file for the "cpp-dsp" project.

Yes, the conanfile.txt and conanfile.py are alternatives. If you are using conanfile.py, you shouldn't be using the conanfile.txt at all. You can use the conanfile.py for consuming only, and conan install will work correctly with it. conanfile.txt is only recommended for consumer-only simple cases, that do not need conditional requirements or other more complex logic.

tjwrona commented 4 years ago

Thanks @memsharded, that does clarify some things. But this does raise two points...

1

Let's say for the sake of discussion what if I did not own the code contained in https://github.com/tnt-coders/cpp-dsp and could not modify it? (I do own it, and can modify it, but the situation will surely come up someday where someone wants to create a Conan package from a library they do not own that was originally designed to be a simple "consumer only" project.)

How would I create a Conan package from this library if there is no way to have Conan grab the dependencies for that library because conan-create will only use the top level conanfile.py and ignores the internal conanfile.txt?

2

Alternatively, if the answer to point 1 is simply "It is not possible", then how would you suggest packaging this library?

I've tried using a conanfile.py within the project that uses exports_sources = ["CMakeLists.txt", "docs/*", "include/*", "src/*", "test/*"] and got the library to build using conan-create, but when I tried to link to that library in the test_package by using CONAN_PKG::cpp-dsp I got a compilation error because the "cpp-dsp" library requires C++17 and the CMake target for the library uses target_compile_features(dsp PUBLIC cxx_std_17) but this compile feature doesn't seem to get propagated to the target created by Conan: CONAN_PKG::cpp-dsp

I don't want to require users of my library to need to add that compilation flag on their own because that breaks the encapsulation of the package.

tjwrona commented 4 years ago

@memsharded, I am actively working on option 2 in my comment above (since I do own the source code and I can modify it directly option 2 is viable), but I am curious if there is any way for option 1 to be possible.

Someone may need to create a package from a project that they do not own the source code to that internally uses its own conanfile.txt to fetch its dependencies. How would someone go about doing this since the internal conanfile for the project would be ignored when trying to create a package with conan create?

memsharded commented 4 years ago

Hi @tjwrona1992

I don't see how scenario 1) would be possible. The gap between a "consumer-only" conanfile.txt and a full package recipe conanfile.py is too large to expect that any package manager could do anything. There will be missing parts like the build(), package(), package_info() that are completely missing from a conanfile.txt and the necessary intelligence to get it is simply not there.

So if I understood the issue correctly, the only possibility to make a package from an existing library that does not provide a full conanfile.py recipe, is to write yourself such full conanfile.py recipe. It doesn't need to be in the original source repo if you don't own it, but such recipe would still be necessary. Does this make sense or am I missing something?

tjwrona commented 4 years ago

@memsharded I think I get what you are saying. So the external conanfile.py would have to specify all of the dependencies that are in the internal conanfile.txt and the internal conanfile.txt would not be used. It's a bit unfortunate that it can't recurse through all conanfiles within a folder hierarchy and grab all of the dependencies but I guess it is what it is.

memsharded commented 4 years ago

It's a bit unfortunate that it can't recurse through all conanfiles within a folder hierarchy and grab all of the dependencies but I guess it is what it is.

yeah, that would be a doable feature, can be even done in the conanfile.py recipe itself: exports the conanfile.txt, load it in the requirements() method and dynamically set self.requires() for each entry. Also it could be kind of automated by Conan, the thing is that in practice, it takes 15 seconds to just copy and paste them into the conanfile.py, and it can take much longer to craft a working build() method, because typically building other projects code is not straightforward. So is the kind of feature that takes a while to implement, might still fail sometimes, and delivers little value, because the actual pain is elsewhere, not in the list of requirements.