conan-io / conan

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

[question] How to use cmake interface library with target sources? #10413

Open werto87 opened 2 years ago

werto87 commented 2 years ago

In my CMakeLists.txt I create an interface library, add sources to it and then link it to an executable. When I try to consume it I get lots of undefined references. CMakeLists.txt example:

add_library(MyLib INTERFACE)
target_sources(MyLib INTERFACE util.cxx)
add_executable(SomeTarget main.cxx)
target_link_libraries(SomeTarget MyLib)

The project where I am creating the library and using it in the tests The conan recipe The project in which I try to use the library

I want conan to create a target like "MyLib" with the sources so I can link to it in the consuming project. I tried to use "self.cpp_info.srcdirs" but it did not work.

memsharded commented 2 years ago

Hi @werto87

I am a bit confused about your setup. Why aren't you putting your conanfile.py directly in your repo with your code? Is it that you intend to submit it to ConanCenter and are preparing the recipe for it?

In any case, it seems that you are using a non-conventional approach, and using the library as source only. When packaging the normal thing would be to package it as a library, typically a static library (simpler, more convenient). And that is also part of the advantage of using a package manager, you don't need every consumer of the library to rebuild it from sources again and again.

If you want to do it, you will need the consumer recipes to be explicit about it (as there is no standard mechanism to consume libraries or packages as source code to be compiled):

In general that is a lot of extra effort for consumers that should be avoided unless very exceptional situations. I would suggest reconsider and package a real library, not a sources/interface one.

werto87 commented 2 years ago

Hi @memsharded

Thank you for the fast reply.

I am a bit confused about your setup. Why aren't you putting your conanfile.py directly in your repo with your code? Is it that you intend to submit it to ConanCenter and are preparing the recipe for it?

I intend to submit it to ConanCenter and I have no experience with putting the conanfile directly in my project repo.

In any case, it seems that you are using a non-conventional approach, and using the library as source only. When packaging the normal thing would be to package it as a library

I do this because my library only compiles if the consumer defines a path to a file which contains some definitions. You can see this in the test CMakeLists.txt of the library. I know that I could use templates or inheritance and create a normal library but I want to try some new things.

memsharded commented 2 years ago

I do this because my library only compiles if the consumer defines a path to a file which contains some definitions. You can see this in the test CMakeLists.txt of the library. I know that I could use templates or inheritance and create a normal library but I want to try some new things.

Ok, good, then you will need to try the above approach (using generate() to get the information and inject in your consumer CMakeLists.txt, if you would like more details about this, please ask), you can implement it in your test_package/conanfile.py. Note that this will create some unusual friction to use your library, as it requires more explicit effort on the consumer side, but if it is necessary, then lets do it. I recommend to add some clear docstrings in your test_package/conanfile.py, and explain it a little bit in the PR if you do one to ConanCenter, so reviewers understand it.

werto87 commented 2 years ago

Correct me if I am wrong but this feels like I have to recreate the library target inside the test_package/CMakeLists.txt. I like to reuse the library target created inside my library/CMakeLists.txt. For me it looks like conan does not consider what I write inside library/CMakeLists.txt if I do not call "cmake.configure()" and "cmake.build()".

memsharded commented 2 years ago

Correct me if I am wrong but this feels like I have to recreate the library target inside the test_package/CMakeLists.txt. I like to reuse the library target created inside my library/CMakeLists.txt. For me it looks like conan does not consider what I write inside library/CMakeLists.txt if I do not call "cmake.configure()" and "cmake.build()".

Yes. Conan is build-system agnostic, the consumers of your package could be using Visual Studio, Meson or other build system, not CMake. So whatever you write in your library/CMakeLists.txt is completely isolated to the consumers. The definition of what goes in the package comes in the package_info() method, and the build system integrations manage to translate that to the consumer build system. In many/most cases, the dependencies build() method is not called at all, because the pre-compiled binary is fetched, and no build from source happens at all, the build scripts or the source don't even exist in the computer.

In the CMake case, the CMakeDeps generator is creating xxxx-config.cmake files for dependencies, but those can be header-only, static or shared libraries. If find_package() cmake interface can also do source-only targets, then that is something that CMakeDeps should implement, but to my understanding find_package() cannot provide this.

werto87 commented 2 years ago

If find_package() cmake interface can also do source-only targets, then that is something that CMakeDeps should implement, but to my understanding find_package() cannot provide this.

I think this is possible. I made a minimal example of 2 project one creates the library and one consumes it with find_package. Based on this stackoverflow post.

memsharded commented 2 years ago

I think this is possible. I made a minimal example of 2 project one creates the library and one consumes it with find_package. Based on this stackoverflow post.

Very interesting. I will asign it to 1.46 to investigate a bit further, and evaluate the implementation effort in CMakeDeps. Steps:

malachib commented 1 year ago

Any movement on this one? I'd like this capability for my own INTERFACE lib which targets a whole bunch of platforms.

memsharded commented 1 year ago

Hi @malachib

No, this didn't get enough priority, so it was moved to 2.X (which means the backlog of new features to be addressed after 2.0 becomes generally available).

If you could elaborate a bit more what is your use case for doing pure sources target, instead of a compiled library, that would help for the future potential implementation and testing of this feature.

malachib commented 1 year ago

Hi @memsharded sure I would be happy to share.

The library estdlib supports a few embedded platforms, namely esp32/esp-idf , Raspberry Pi Pico and historically Arduino. These usually use gcc, but with wildly different versions. The library itself is designed for extremely high portability between MPUs and also includes a few platform-specific helpers, in particular FreeRTOS.

For esp-idf, it's conceivable that compiling a static library on an older version of their GCC toolchain+SDK will be OK when linking against a newer GCC/LD, but that makes me nervous. More wise people than me probably could inform me one way or the other.

For Raspberry Pi Pico, INTERFACE is necessary because FreeRTOS may or may not be present - and if it is - additional include pathing supplied by the application must flow down into the library.

Finally, I'd like those with MPUs I haven't vetted recently, or ever, to be able to nab the library and use it. Historically it worked great on AVR and Blackfin, but those toolchains I don't even have installed now

malachib commented 1 year ago

@memsharded hello, it's been some time and it seems 2.x is released. I wasn't able to find this capability mentioned though. Any suggestions?

ottmar-zittlau commented 7 months ago

@memsharded - I have a similar problem as @malachib - I have a library that mostly provides headers, but also some source files via the INTERFACE_SOURCES (https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_SOURCES.html) mechanism. I don't fully understand why it is done this way, but before I start refactoring this mess, I wanted to know, if there is any chance to provide the sources in a conan-file with CMakeDeps-generator (so far we are using cmake_paths)?

Thanks a lot! oz

memsharded commented 7 months ago

Hi @ottmar-zittlau

There is indeed a chance, this is why it is assigned to 2.X milestone, meaning that we want to implement it at some point. We haven't manage to do it yet, but the plan is to do it. The only problem is that this hasn't really started yet, so it means it might still take some time. Some implementation hints:

ottmar-zittlau commented 6 months ago

Thanks again @memsharded for the explanation.

mokafolio commented 1 month ago

Just wanted to voice that I'd greatly appreciate the addition of this feature!