-
Notifications
You must be signed in to change notification settings - Fork 997
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] packaging debug visualizers (natvis) #16916
Comments
Hi @vasama Thanks for your question.
At the moment there is not built-in direct way to do this. I think the best approach could be to generate a CMake build module that manages to add those extra files to the targets, see for example https://docs.conan.io/2/examples/graph/tool_requires/use_cmake_modules.html. These modules are automatically included at the end of |
Adding the cmake_minimum_required(VERSION 3.24)
project(test)
add_library(lib INTERFACE IMPORTED)
target_sources(lib INTERFACE lib.natvis)
add_executable(app app.cpp)
target_link_libraries(app PRIVATE lib) |
But what is exactly the usage of these files in the consumer project? Are they compiled automatically in any consumer target that does a |
The IDE uses them for debug visualisation and I believe may also embed them into .pdb files. |
Having tested it now, MSVC does indeed embed them in the |
Thanks for the feedback. Yes, I think the best approach could be to define a
|
Okay, I made it work using a CMake build module. During the CMake configuration of the package, I generate the build module script at |
Great, happy that you were able to make it work.
For the def layout(self):
...
self.cpp.source.builddirs = ["build/cmake_build_modules"] |
Shouldn't that instead be: def layout(self):
...
self.cpp.build.builddirs = ["cmake_build_modules"] In any case, that still leaves detecting the build modules. Currently I do this to find them in the package folder: def package_info(self):
...
# Find and add all scripts in package_folder/cmake_build_modules/
cmake_build_modules_dir = os.path.join(self.package_folder, "cmake_build_modules")
if os.path.isdir(cmake_build_modules_dir):
cmake_build_modules = self.cpp_info.get_property("cmake_build_modules") or []
for entry in os.scandir(cmake_build_modules_dir):
cmake_build_modules.append(os.path.join(cmake_build_modules_dir, entry.name))
if len(cmake_build_modules) > 0:
self.cpp_info.set_property("cmake_build_modules", cmake_build_modules) It's still not clear to me how I can make this work in editable mode. |
It depends. If the modules are generated at build time, it is I think the issue is that the folder is relative to the package folder, not to the build-folder, this is why I used
Not very clear why you are doing it, the
Maybe the best would be to try to put this in a full reproducible example, either a repo with some minimalistic code if you think you could easily provide it, or I can try to provide a test in the Conan test suite later. |
I have made a small example here: https://github.com/vasama/conan-issue-16916 cd ./lib
conan create .
cd ../app
conan install .
cmake --preset $PRESET # My Conan profile produces an MSBuild solution
cmake --open $BUILDDIR # Open the solution in Visual Studio |
Hi @vasama Thanks very much for putting together the code, that really helped. I'd like to apologize, because I was mistaken and I gave confusing information. I was mixing the I have done a PR in vasama/conan-issue-16916#1, I'll comment the details there |
I tested both flows, both with |
I made a related issue on the CMake issue tracker here, since the CMake support around Since you added this to the 2.8.0 milestone, are you planning some Conan changes to address this? |
No, I don't think it is needed any change in Conan client at the moment. I just wanted to make sure that this ticket wasn't buried, so assigning it to 2.8 was the way. I think we might close the ticket now? Thanks for the feedback! |
Actually, I still couldn't make it work. When the script is generated in the build directory, I'm not sure how I can specify it in the
|
This is expected, the Still I am not sure if I follow, maybe it is necessary to update the repo with the code? Because there I don't see the |
Yes, in the example it uses |
I had another look at your previous comments, and I see that I missed this part: def layout(self):
...
self.cpp.build.set_property("cmake_build_modules", ["my_cmake_build_module.cmake"]) This gets a little closer, but I can't do it unconditionally, because whether the file actually exists is never checked. It seems to me that I also cannot check in |
It seems to me that the CMake build module concept would be a lot more usable if
|
Hi @vasama I am resuming having a look to your suggestions while developing a new However, it is still not fully clear what would be the pain being solved. I think that what you are requesting can be easily solved with a one liner thanks to python: def package_info(self):
self.cpp_info.set_property("cmake_build_modules", glob.glob("myfolder/*.cmake")) That will pick all cmake modules in your specified folder, and it will not fail because of missing modules because it will only pick the modules that actually exist. Then, these files doesn't need to be |
I think the reason I couldn't do the glob as you suggest, was that the build modules are generated by CMake in the build directory, where they remain when the package is consumed in editable mode, and Conan didn't allow me to use the build directory during As for using package files from the build module, in this case I mean the |
To support what I want to do, I think we can simplify this to the following requirements:
Obviously I'm interested in more than just printing the contents, but I think that's a reasonable simplification for now. |
Regarding point 1 and the editable thing, I am still trying to figure out what are the issues and current possibilities. Wouldn't something like this work?: def layout(self):
self.cpp.source.set_property("cmake_build_modules", glob.glob(os.path.join(self.source_folder, "mysrcmodules/*.cmake"))
self.cpp.build.set_property("cmake_build_modules", glob.glob(os.path.join(self.build_folder, "mybuiltmodules/*.cmake"))
def package_info(self):
self.cpp_info.set_property("cmake_build_modules", glob.glob("myfolder/*.cmake")) Basically, there are 3 different sources that could contain build modules, in different states (editable, final package), so these 3 folders (mysrcmodules, mybuiltmodules, myfolder) needs to be specified to Conan somehow, I think the above might be a possibility to implement it, or am I still missing something? I am also not saying that this couldn't improve the UX, but it is important to understand if/why this is possible or not, and what are the reasons. Thanks for the feedback! |
It looks like |
Uhmm, good point. Let me try to come up with a working test. |
I am doing this test in this PR, please have a look: #17214 It is true that there is a small bug there that doesn't allow to use simultaneously If you could please have a look at the test, let me know if this would be capturing your needs or still something would be missing. |
To clarify, does that PR allow using |
No, it needs to compose the path with I think I can add some extra checks to the test to implement the case 2) |
Okay, I looked at the test more closely. How does this work with |
I am finding a limitation in CMake. It doesn't allow to read a .txt (or other) file relative to the current Conan can implement this with:
Doesn't seem trivial, but I don't see any other way that this can be done, unless you know some other way to overcome this CMake limitation. |
Did you try |
Yes, I did. But that will get the value of the Same with other CMAKE_ variables that I have checked, there is none that I have found that refers to the path where a |
# C:/Users/vasama/sandbox/conan-consumer/CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(conan-consumer)
include(cmake/test.cmake) # C:/Users/vasama/sandbox/conan-consumer/cmake/test.cmake
message(STATUS "CMAKE_CURRENT_LIST_DIR='${CMAKE_CURRENT_LIST_DIR}'") For me this produces:
|
Thanks for the hint. I realized what is happening. The variable seem to have different scope when evaluated inside a |
CMake 3.17 has |
Ok, even when using macros, the scope of the variable change. I managed to make it work with: set(MY_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}
macro(otherfunc)
file(READ "${MY_CMAKE_PATH}/my.txt" c)
message("Hello ${c}!!!!")
endmacro() It is included in the PR test now |
I still don't see how this is going to work though. |
Added |
Okay. That works for the case when the
I think this is not yet possible? I'm not sure how I could find the appropriate path from the build module script. You mentioned the What I suggested earlier was to specify some CMake variables before including the build module. Perhaps something like |
I have added a new test that uses some fake
also works, taking into account:
class Conan(ConanFile):
name = "myfunctions"
version = "1.0"
exports_sources = ["src/*.cmake", "src/vis/*.vis"]
settings = "build_type", "arch"
def build(self):
copy(self, "*.vis", src=self.source_folder, dst=self.build_folder, keep_path=False) And that will allow the local build-module to find the vis files too. |
I considered copying, but it somewhat defeats the point of using an editable layout, because changes in the source file are not immediately reflected in consumers. One might suggest using a symbolic link instead, but at least on Windows that's not a reasonable solution due to the administrative permissions required for creating one. |
That is fine, I am not very happy about the copy either. But it is important for us to analyze the alternatives to decide and prioritize, it is not the same something that cannot be implemented by any mean, that something that as some solution that something that doesn't have a great solution but has a reasonable workaround In this case, the changes in source, in most cases aren't directly visible to the consumers of the editable packages, editable packages still need to be "built" and build those sources into the form that the consumers can use. This is why the I have been trying to improve this, based on your suggestion of a variable such as set(MY_CMAKE_PATH ${myfunctions_PACKAGE_FOLDER_RELEASE})
macro(otherfunc)
file(READ "${MY_CMAKE_PATH}/src/vis/my.vis" c)
'message("Hello ${c}!!!!")\nendmacro() The But now, when this is in the real package, this path will no longer be valid. I can solve it by re-defining the module in the def package(self):
copy(self, "*.cmake", self.source_folder, os.path.join(self.package_folder, "mods"),
keep_path=False)
copy(self, "*.vis", self.source_folder, os.path.join(self.package_folder, "mods"),
keep_path=False)
cmake = 'set(MY_CMAKE_PATH ${myfunctions_PACKAGE_FOLDER_RELEASE})\n'\
'macro(otherfunc)\n'\
'file(READ "${MY_CMAKE_PATH}/mods/my.vis" c)\n'\
'message("Hello ${c}!!!!")\nendmacro()'
save(self, os.path.join(self.package_folder, "mods/otherfuncs.cmake"), cmake) I updated the test accordingly in commit: a79dc44 BUT THEN, I realized that these natvis files would probably be a good model for the
It seems to work nicely. Please have a look to the latest PR test (the second test), and let me know what you think. |
From looking at the files generated by |
Both the package name and config are available as config = str(self.settings.build_type).upper()
cmake = f'set(MY_CMAKE_PATH ${{{self.name}_RES_DIRS_{config}}})\n'\ The problem is that it is not the |
Hi @vasama This ticket has been closed by PR #17214 that contained the fix for the Please let us know if there is any further question or issue, feel free to re-open or create new ticket. As a side note, I have verified that the variable |
What is your question?
I want to package a library containing Visual Studio natvis debug visualizers for its interface types. I could not find any documentation on how to approach this with Conan. This requires adding the natvis files as sources on the CMake target generated by CMakeDeps. Is there an existing way to achieve this in the package recipe?
Have you read the CONTRIBUTING guide?
The text was updated successfully, but these errors were encountered: