conan-io / conan

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

[question] How to use Ninja with `CMake` helper? #16583

Closed PauloCarvalhoRJ closed 3 hours ago

PauloCarvalhoRJ commented 3 days ago

Hello,

I have lots of recipe code like below:

   def build(self):
        cmake = CMake(self, generator='Ninja')
        cmake.configure()
        cmake.build()

This used to work in Conan 1, but in Conan 2 it throws an error (apparently the generator parameter no longer exists in CMake's constructor). The docs are not very clear about it (a usage example would be quite handy). So, the question is, how do I instruct CMake to generate a Ninja makefile using CMake helper?

thanks,

PC

Have you read the CONTRIBUTING guide?

memsharded commented 3 days ago

Generator belongs now to CMakeToolchain: https://docs.conan.io/2/reference/tools/cmake/cmaketoolchain.html#cmaketoolchain

Though in general it can be defined better by tools.cmake.cmaketoolchain:generator conf from the profiles without hardcoding it in recipes.

PauloCarvalhoRJ commented 2 days ago

Yes, I saw that, but, as previously stated, the docs are unclear re Ninja. Is there a working example of Ninja usage in Conan 2 (perhaps something in Conan Center)?

thanks,

PC

memsharded commented 2 days ago

Sure a new section about CMake generators was added recently: https://docs.conan.io/2/examples/tools/cmake/cmake_toolchain/use_different_toolchain_generator.html

PauloCarvalhoRJ commented 1 day ago

Hello,

That seemed to work. Nevertheless, using Ninja resulted in test package's binaries being placed outside a sub-directory called Release/Debug, which was the behavior sans Ninja. This change in beavior was unexpected. Is that a bug? To work, the recipe must be tailored so support both behaviors with, IMO, an ugly if statement. What do you think?

best,

PC

PauloCarvalhoRJ commented 1 day ago

BTW, how do I test whether Ninja is being used from inside the recipe?

memsharded commented 15 hours ago

I am not sure what you mean:

conan new cmake_lib -d name=mypkg -d version=0.1
conan create . -c tools.cmake.cmaketoolchain:generator=Ninja

And then in test_package I get the binaries inside folders like test_package\build\msvc-194-x86_64-14-release, so it is looking good.

BTW, how do I test whether Ninja is being used from inside the recipe?

Reading the self.conf.get("tools.cmake.cmaketoolchain:generator") value? This is something that shouldn't be necessary for most cases, why would you need to test for Ninja inside recipes?

PauloCarvalhoRJ commented 14 hours ago

I mean:

1) Sans Ninja: I get the binaries in C:\conan_tmp\msvc-194-x86_64-14-release\Release. This seems to be a redundancy, but this is where the test package binaries go in this case;

2) With Ninja: I get the binaries like you in the post above: C:\conan_tmp\msvc-194-x86_64-14-release.

Please, notice the different paths. If they are different, then I must test whether Ninja is being used to make the exec() call passing the correct path for each case, otherwise a path-not-found error ensues.

memsharded commented 13 hours ago

I am afraid that there is something missing there, I don't get that folder.

If I use the above steps with the default configuration in Windows/MSVC I don't get those folders. For example the conan_tmp folder is unexpected, that only happens if you have some special configuration. Can you please try to reproduce with the default configuration or provide the full steps, recipes, configuration and output logs of the conan create command?

Please, notice the different paths. If they are different, then I must test whether Ninja is being used to make the exec() call passing the correct path for each case, otherwise a path-not-found error ensues.

You shouldn't. You can use the self.cpp.build.bindir to get the location of the built binaries irrespective of the generator. The layout definition will contain those locations. Please check how the default implementation of the test() method works for different layouts and generators:

    def test(self):
        if can_run(self):
            cmd = os.path.join(self.cpp.build.bindir, "example")
            self.run(cmd, env="conanrun")
PauloCarvalhoRJ commented 3 hours ago

You shouldn't. You can use the self.cpp.build.bindir to get the location of the built binaries irrespective of the generator.

Ah... that's the catch. Good one. 👏