conan-io / conan-center-index

Recipes for the ConanCenter repository
https://conan.io/center
MIT License
967 stars 1.78k forks source link

[package] swig/4.0.2: find_package(SWIG) doesn't set SWIG_EXECUTABLE #10404

Open eigenwhat opened 2 years ago

eigenwhat commented 2 years ago

Package and Environment Details (include every applicable attribute)

Conan profile (output of conan profile show default or conan profile show <profile> if custom profile is in use)

[settings]
os=Macos
os_build=Macos
arch=x86_64
arch_build=x86_64
compiler=apple-clang
compiler.version=12.0
compiler.libcxx=libc++
build_type=Release
[options]
[conf]
[build_requires]
[env]

Steps to reproduce (Include if Applicable)

conanfile.py ``` from conans import CMake, ConanFile, tools class TestPackageConan(ConanFile): settings = "os", "arch", "compiler", "build_type" generators = "cmake_find_package" requires = "swig/4.0.2" def build(self): cmake = CMake(self) cmake.verbose = True cmake.configure() cmake.build() ```
CMakeLists.txt ``` cmake_minimum_required(VERSION 3.1) project(Test) set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_MODULE_PATH}) set(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR} ${CMAKE_PREFIX_PATH}) find_package(SWIG REQUIRED) include(UseSWIG) message("SWIG_DIR: ${SWIG_DIR}") message("SWIG_EXECUTABLE: ${SWIG_EXECUTABLE}") if ("${SWIG_EXECUTABLE}" STREQUAL "" OR "${SWIG_EXECUTABLE}" STREQUAL "SWIG_EXECUTABLE-NOTFOUND") message(FATAL_ERROR "Didn't work.") else() message("It looks like it worked? Check variables above and see if they make sense.") endif() add_executable(test main.cpp) ```
main.cpp ``` int main() { return 0; } ```

If I build this the usual way, it's unable to find the SWIG executable. However, if I build it as if it were a test package, it correctly populates SWIG_DIR, SWIG_EXECUTABLE, etc. I've tried this with and without the cmake generator, tried it with cmake_find_package_multi, CMakeDeps, etc, and nothing works.

Logs (Include/Attach if Applicable)

conan test . swig/4.0.2@ ``` SWIG_DIR: /Users/developer/.conan/data/swig/4.0.2/_/_/package/099d7b9cd06e9bd11e92b9a2ddf3b29cd986fdcb/bin/swig/swiglib SWIG_EXECUTABLE: /Users/developer/.conan/data/swig/4.0.2/_/_/package/099d7b9cd06e9bd11e92b9a2ddf3b29cd986fdcb/bin/swig ```
mkdir build && cd build && conan install .. && cmake .. ``` SWIG_DIR: SWIG_EXECUTABLE: SWIG_EXECUTABLE-NOTFOUND ```
madebr commented 2 years ago
find_package(SWIG)

only works when the PATH is configured correctly. When you would run the following commands, it will build correctly:

mkdir build && cd build
conan install ..
conan build ..

If you don't want conan to drive the compilation, you need modify your environment. This can be done with the virtualrunenv generator. Modify you conanfile.py slightly:

from conans import CMake, ConanFile, tools

class TestPackageConan(ConanFile):
    settings = "os", "arch", "compiler", "build_type"
    generators = "cmake_find_package", "virtualrunenv"
    requires = "swig/4.0.2"

    def build(self):
        cmake = CMake(self)
        cmake.verbose = True
        cmake.configure()
        cmake.build()

Then, you can do the following:

mkdir build && cd build
conan install ..
. activate_run.sh
cmake ..
eigenwhat commented 2 years ago

Is this a peculiarity of SWIG's package or a limitation of Conan? It's very surprising to me to find that it can't prepare the search path for binaries the same way it can find libraries. In order to drive the build from Conan for our main project it would basically mandate switching to a conanfile.py, which would be nontrivial. Using virtualrunenv feels like more of a hack, but how well does it work when building with CLion?

madebr commented 2 years ago

Is this a peculiarity of SWIG's package or a limitation of Conan?

It's common behavior of operating systems: paths of binaries need to be added to the PATH environment variable.

On my Linux system, conan created the swig package at /home/maarten/.conan/data/swig/4.0.2/_/_/package/ecb2d71ae4bad3b51dade00ec89140273402b5d7.

So when I run the following, I can build your project without virtualenv and without using conan as driver:

export PATH=/home/maarten/.conan/data/swig/4.0.2/_/_/package/ecb2d71ae4bad3b51dade00ec89140273402b5d7:$PATH
cmake ..
make

Using virtualrunenv feels like more of a hack, but how well does it work when building with CLion?

virtualenv sets the environment variables for all dependencies. Because you also need to set-up the paths, you need to somehow inform clion where all applications can be found.

I just tested with this conan plugin for CLion 2022.1, and can confirm I can build your project just fine.

eigenwhat commented 2 years ago

...I know how the PATH environment variable works, thank you very much.

That doesn't answer why CMake needs it to be in the environment's PATH, and why the generated find configuration for SWIG can't tell CMake where to look, you know, the way it does so for libraries. Needing to set PATH makes sense if you're relying on the stock find modules (i.e. what cmake_paths was used for in the past), but this is a find module generated by Conan, so it knows exactly where everything should be. It could just set SWIG_EXECUTABLE to the proper path with no searching required, just like it would when generating library targets. Having to tamper with the environment just to get this to work seems at odds with the entire premise of cmake_find_package and descendant generators.

I just tested with this conan plugin for CLion 2022.1, and can confirm I can build your project just fine.

It can build with or without SWIG because the Conan-generated find module doesn't actually fail if the executable isn't found (because, and I repeat, it finds the library part just fine). If I add the following to the CMakeLists (above add_executable):

if ("${SWIG_EXECUTABLE}" STREQUAL "" OR "${SWIG_EXECUTABLE}" STREQUAL "SWIG_EXECUTABLE-NOTFOUND")
    message(FATAL_ERROR "Didn't work.")
else()
    message("It looks like it worked? Check variables above and see if they make sense.")
endif()

It, in fact, doesn't work for me. (I will edit my initial sample project with this included.)

I'm beginning to think that any easy solution I can roll out to the rest of my team is hopeless because while I don't mind using the terminal to build things, it'll be one hard sell to make everyone else change their workflow just so we can use Conan to manage our build tools. Best I can hope for it seems is to convince them to budget time to rework our build system to be driven by Conan (i.e. move to a conanfile.py and port over our build configuration), and maybe have a dummy CMakeLists.txt to bootstrap the process so it plays nicely with CLion. Or switch IDEs. Or give up.

madebr commented 2 years ago

...I know how the PATH environment variable works, thank you very much.

Yeah sorry, I just wanted to show that cmake needs extra information to find swig: conan does not store it in a location where cmake (or autotools) look for dependencies by default.

That doesn't answer why CMake needs it to be in the environment's PATH, and why the generated find configuration for SWIG can't tell CMake where to look, you know, the way it does so for libraries.

FindSWIG uses find_program to look for swig. Here is a link to the source.

As you can read from the find_program documentation, CMake looks in various locations. Running the following commands all work (after running conan install ..):

cmake .. -DCMAKE_PREFIX_PATH=/home/maarten/.conan/data/swig/4.0.2/_/_/package/ecb2d71ae4bad3b51dade00ec89140273402b5d7
export PATH=/home/maarten/.conan/data/swig/4.0.2/_/_/package/ecb2d71ae4bad3b51dade00ec89140273402b5d7/bin:$PATH
cmake ..

I hope that explains why CMake needs extra information where to find swig. Libraries need something similar. When you'ld add a requirement to e.g. libjpeg and do a find_package(JPEG REQUIRED), it won't find the conan libjpeg library automagically too.

Needing to set PATH makes sense if you're relying on the stock find modules (i.e. what cmake_paths was used for in the past), but this is a find module generated by Conan, so it knows exactly where everything should be. It could just set SWIG_EXECUTABLE to the proper path with no searching required, just like it would when generating library targets. Having to tamper with the environment just to get this to work seems at odds with the entire premise of cmake_find_package and descendant generators.

Use the cmake generator to configure cmake. Modify your CMakeLists.txt script to:

cmake_minimum_required(VERSION 3.1)
project(Test)
option(USE_CONAN "Use Conan for dependency management" ON)
if(USE_CONAN)
    include("${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
    conan_basic_setup(TARGETS)
endif()
find_package(SWIG REQUIRED)
...

and conanfile.py to:

from conans import ConanFile

class TestPackageConan(ConanFile):
    settings = "os", "arch", "compiler", "build_type"
    generators = "cmake_find_package", "cmake"
    build_requires = "swig/4.0.2"

This allows an out-of-the box experience. The USE_CONAN cmake option still allows to use your system packages. (conan 2.0 removed the cmake generator

I'm beginning to think that any easy solution I can roll out to the rest of my team is hopeless because while I don't mind using the terminal to build things, it'll be one hard sell to make everyone else change their workflow just so we can use Conan to manage our build tools. Best I can hope for it seems is to convince them to budget time to rework our build system to be driven by Conan (i.e. move to a conanfile.py and port over our build configuration), and maybe have a dummy CMakeLists.txt to bootstrap the process so it plays nicely with CLion. Or switch IDEs. Or give up.

With the CMakeLists.txt modification suggested above + the clion conan plugin, it should be able to build projects from within clion without touching the console.

eigenwhat commented 2 years ago

FindSWIG uses find_program to look for swig.

Not when you use cmake_find_package. Then it uses the generated find script, which in turn includes lib/cmake/conan-official-swig-targets.cmake, which is part of the Conan package. It so happens to call find_program(SWIG_EXECUTABLE swig) in the first line, but if it instead read find_program(SWIG_EXECUTABLE swig "${CMAKE_CURRENT_LIST_DIR}/../../bin") it would find it perfectly without any fuss. If you could access some of the Conan-produced variables it could be made even more explicit.

If that's unworkable for whatever reason, I suppose I can produce the right search path myself by fishing out the package path from some other variables.

Use the cmake generator to configure cmake [...] This allows an out-of-the box experience.

What? No it doesn't. That doesn't work at all.

madebr commented 2 years ago

Use the cmake generator to configure cmake [...] This allows an out-of-the box experience.

What? No it doesn't. That doesn't work at all.

You still need to use the Conan CLion plugin: https://blog.jetbrains.com/clion/2019/05/getting-started-with-the-conan-clion-plugin/

eigenwhat commented 2 years ago

I know how to use the Conan CLion plugin. I've only been using it for the past few years. The question is and remains about having the executable search paths be set correctly without forcing anyone to do additional manual steps. I was hoping that I'd get advice in getting virtualrunenv to work within CLion using the IDE's standard build commands, or some other solution that prepares the environment. The cmake generator does not help.

At this point I think I will just modify the SWIG package and fix the problem myself as I described earlier, because I'm tired of talking in circles.

steffenhk commented 2 years ago

I have recently run into the same issue.

I have a very similar setup as @eigenwhat described and I am wondering why PATHS ${CONAN_BIN_DIRS_SWIG} NO_DEFAULT_PATH was removed from find_program(SWIG_EXECUTABLE swig) in this commit.

If I add that back to the conan-official-swig-targets.cmake file (and if I use cmake generator and include conanbuildinfo.cmake in my CMakeLists.txt) then it seems to work for me.

I'm curious and maybe @madebr can shed some light on why that change was made to conan-official-swig-targets.cmake?

SSE4 commented 2 years ago

@steffenhk does it need to be re-opened?

eigenwhat commented 2 years ago

It’s an open problem that hasn’t been resolved. I closed the issue originally because I ran out of patience trying to get a straight answer, not because anything got fixed.

soerengustenhoff commented 2 years ago

So we have investigated this for more than a day.

Why does the swig/4.0.2 contain the conan-official-swig-targets.cmake in the first place ? if the package location root was added to the CMAKE_PREFIX_PATH, instead of the package/lib/cmake path, then it will work out of the box, since find_program will look in CMAKE_PREFIX_PATH before it looks in the PATH environment variable.

madebr commented 2 years ago

This was added in https://github.com/conan-io/conan-center-index/pull/4534 Note how that pr also adds cmake_find_package to the generators of the test package.

I think this was done because on Windows, cmake is not case sensitive and will match the conan generated Findswig.cmake. An alternative could be to let conan generate FindSWIGDoNotUsecmake instead of FindSWIG.cmake.

steffenhk commented 2 years ago

Would another alternative be to also append "" to the list of cpp_info.builddirs in the swig conanfile in order to add the swig package root to CMAKE_PREFIX_PATH? Then using find_package(SWIG) when using either cmake_paths or cmake_find_package generators should both work, since both the CMake provided and the conan generated FindSWIG.cmake will find the swig executable using find_program.

manuelnp commented 1 year ago

Any update on this regard? Comment by @soerengustenhoff seems to point in the right direction.

macdew commented 3 weeks ago

I think I'm suffering from the same problem here, using Conan v2 with the cmake-conan integration that relies on find_package and CMakeDeps. However, Conan's SWIGConfig.cmake "shadows" the official CMake find script which is required to pull in the CMake functions etc to create SWIG targets.

Perhaps one solution would be for Conan to not intercept find_package with the COMPONENTS parameter, but am I missing something here on how Conan and SWIG should be integrating when using Conan's find_package integration?

I agree with @madebr that Conan's SWIGConfig.cmake should get a different name so that we can use CMake's FindSwig script as usual. And if we're not supposed to use that, I couldn't find any documentation on what we should be using instead?

macdew commented 3 weeks ago

Update: having slept on it, I found the solution this morning, this syntax works to run the official CMake FindSWIG.cmake script and get the SWIG_USE_FILE variable set:

find_package(SWIG 
  COMPONENTS csharp
  REQUIRED
  MODULE
  BYPASS_PROVIDER
)