Skip to content
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

Equip hwloc with CMake build capabilities #565

Open
FunMiles opened this issue Jan 31, 2023 · 20 comments
Open

Equip hwloc with CMake build capabilities #565

FunMiles opened this issue Jan 31, 2023 · 20 comments

Comments

@FunMiles
Copy link

FunMiles commented Jan 31, 2023

CMake is now a very popular build automation system. It would be good to be able to build hwloc via CMake. One benefit is the ease of integration that it would bring in other CMake projects.
It does not need to totally replace autotools but add a way of building for those more familiar with CMake.

I have created a fork (https://github.com/FunMiles/hwloc.git) in which I've made a first version that is tailored to MacOS but could be extended to Linux and Windows. I am not able to test all cases but with others' help, I'd be happy to make improvements so that it is a reliable way to compile hwloc with all its capabilities.
Having a correct CMakeLists.txt allows to consume hwloc in CMake projects (with CMake >= 3.24) very easily:

    include(FetchContent)

    FetchContent_Declare(
            hwloc
            GIT_REPOSITORY https://github.com/FunMiles/hwloc.git
            GIT_TAG 6e47ca0d1f86fc14fbc5fef982618d5b5f48054c # based on release-2.8.0
            OVERRIDE_FIND_PACKAGE
    )
    find_package(hwloc REQUIRED)
    target_link_library(my_executable PRIVATE hwloc::hwloc)

Of course, one can compile and install hwloc and then only the last two lines would be required.

@FrankXie05
Copy link

@JackBoosY

@JackBoosY
Copy link

@FunMiles Can you please make a PR in this repo, then I can help you to complete it?

@dg0yt
Copy link

dg0yt commented Feb 1, 2023

Compare:
master...FunMiles:hwloc:master

what cannot be compared this way is the CMakeLists.txt which already exists in
contrib/windows-cmake/
from #484.

@JackBoosY
Copy link

I think CMakeLists should support all the platforms.

@JackBoosY
Copy link

Related issue: #88

@jsquyres
Copy link
Member

jsquyres commented Feb 1, 2023

Can you describe in a bit more detail about what the "win" is for adding CMake support to a code base with an already-existing Autotools build system?

You cited "One benefit is the ease of integration that it would bring in other CMake projects" -- can you clarify what exactly you mean by that? Is FetchContent_Declare() the main impetus?

  • Does CMake have support for fetching, building, and installing GNU Autotools-based projects, or does it only support that for CMake-built packages?
  • Are there other use cases (beyond FetchContent_Declare()) that are beneficial? (I think that the text in your proposal means that finding/building against an already-installed hwloc is the same use of find_package() and target_liink_library() regardless as to whether hwloc is built+installed by the Autotools or CMake -- is that correct?)

Additionally, is there a reason to download+build+install a new hwloc if hwloc is already installed / available on the system? You can get into really sticky situations if project A uses dependency B (e.g., hwloc) with version X, but then project A has another dependency C that uses the same dependency B (hwloc) with a different version Y. You can end up with an executable that dynamically loads two different versions of B (hwloc) at run time, which inevitably results in much wailing and gnashing of teeth. For this very reason, we changed policy in Open MPI: for the last few major releases, Open MPI's build system "prefers" the hwloc that is already available on the system over its own embedded source code copy of hwloc.


I also ask because it's generally a losing proposition to try to support two different sets of software that accomplish the same thing in a single code base. There's a few factors which tend to make this kind of thing difficult:

  1. Having to maintain feature parity between the two. This takes additional time, effort, and maintenance (especially over the long haul).
  2. Having to remember -- and have the expertise -- to update both whenever something else related changes in the code base.
  3. Having to keep testing both in all supported environments (especially over the long haul).
  4. Keeping those who are interested in supporting the 2nd feature active in the project to help with 1, 2, and 3.

I don't know @bgoglin's opinion here, but one possible scenario is that the Autotools-based build will remain the "primary" build system. After all, it's what Hwloc has used since 2009. I.e., any changes to the Autotools stuff will then require a reactionary change to the CMake build system -- especially if the CMake code is maintained by different people than the Autotools code. This takes time and effort, meaning that the CMake-based build system would perennially lag the Autotools build system. This is an unattractive scenario from an overall maintenance and support perspective.

Granted, there's some limited support for CMake here in hwloc already. But #88 was at least a little different because the GNU Autotools are not good at supporting Windows, and CMake is. Notice that it took 7 years from an initial "here's a Cmakefile that works" to actually finding another person willing to help get it up to speed and part of hwloc. It's also in the contrib area -- I don't know the actual level of support. @bgoglin Is it regularly tested and supported?

That being said, a) this is all just my $0.02 because @bgoglin is the maintainer, not me 😄, b) I absolutely do not mean to tamp down enthusiasm for contributing to open source -- PR's with new features are always welcome! 😃

Please also note that I'm not trying to make any religious claims about the Autotools or CMake -- I'm solely talking about the inertia of the existing code base and the effort required to meaningfully maintain code over time. More specifically: I just wanted to set expectations that this is a difficult road to go down, even if the initial PR is "easy". It's the maintenance over time that makes supporting two equivalent-but-different pieces of code in the same code base difficult.

@FunMiles
Copy link
Author

FunMiles commented Feb 1, 2023

Can you describe in a bit more detail about what the "win" is for adding CMake support to a code base with an already-existing Autotools build system?

You cited "One benefit is the ease of integration that it would bring in other CMake projects" -- can you clarify what exactly you mean by that? Is FetchContent_Declare() the main impetus?

  • Does CMake have support for fetching, building, and installing GNU Autotools-based projects, or does it only support that for CMake-built packages?
  • Are there other use cases (beyond FetchContent_Declare()) that are beneficial? (I think that the text in your proposal means that finding/building against an already-installed hwloc is the same use of find_package() and target_liink_library() regardless as to whether hwloc is built+installed by the Autotools or CMake -- is that correct?)

Correct

Additionally, is there a reason to download+build+install a new hwloc if hwloc is already installed / available on the system? You can get into really sticky situations if project A uses dependency B (e.g., hwloc) with version X, but then project A has another dependency C that uses the same dependency B (hwloc) with a different version Y. You can end up with an executable that dynamically loads two different versions of B (hwloc) at run time, which inevitably results in much wailing and gnashing of teeth. For this very reason, we changed policy in Open MPI: for the last few major releases, Open MPI's build system "prefers" the hwloc that is already available on the system over its own embedded source code copy of hwloc.

CMake's FetchContent mechanism downloads a version in the build directory. The library will be built as part of your project. One side-effect is that if your project is compiled in debug mode, the downloaded library will also be in debug mode. There may be ways that I haven't explored yet to force the downloaded library to be in a different mode.

You can also manually do a compilation and installation of the library. I will make sure that the CMakeLists.txt that is created does a proper install so that any CMake based software can find it with find_package(hwloc). If you let it install in /usr/local/ then other non CMake based projects should be able to find it and link to it.

With CMake, you can, in your project, try to pick a system installed version first and if not, download and compile. You can also always use a downloaded version, independently of whether there is already an installed version. Finally you can make sure the static library is linked in. It requires only a line or two of logic in the CMakeLists file. Thus I think it fully adresses your A/B/C X/Y question. If you are going to rely on dynamic library, then prefer the system one. If you want a specific version, then force the download and compilation and use the static linking.

I do agree with most of your points with having to maintain two versions of the build tools. Technically, I would not have been forced to look into making a CMakeLists.txt file for hwloc if conan had not caused issue with my IDE. I had created a conan file to build hwloc and then I could use it in all my projects with find_package(hwloc) after the conan prologue. However I'll note that CMake is used by an increasing number of projects. Though I've used autotools build for about 3 decades, I am incapable of writing one and I think fewer and fewer people are able to put their hands to it.

I won't make any religious claims either, but maybe for the benefit of future users, making CMake the first citizen and autotools for, as @bgoglin mentioned in the issue of vcpkg, be there for older platforms, would be a good thing. It is not for me to decide. I just offer it as an option. If that does not come to be, either there is a CMakeLists.txt in the contrib directory to which I can contribute updates or I'll keep my fork with a CMakeLists.txt that I'll try to update as well to help those who want to use CMake.

Finally, and as a side note which probably should be a separate issue, making a conan file and putting hwloc on https://conan.io/center/ might also be helpful to many projects. it can be done with the autotools system, as I've done on my computers or with the CMakeLists based one.
Until there are really great very stable package managers for C/C++, the CMake FetchContent mechanism offers me a way to shield myself from difficulties when the package manager is crapping out.

@jsquyres
Copy link
Member

jsquyres commented Feb 1, 2023

There's no doubt that the GNU Autotools are "old skool", and feels a bit krufty these days. For what it is, it still works fine, but it's definitely not what the new kids are using these days. We (hwloc, Open MPI, ... lots of others ...) may definitely need to move to something else someday. No argument there.

@bgoglin can decide whether it's time to start thinking about moving to a new primary build system. That being said, adding CMake as the primary and keeping the Autotools as a secondary would have exactly the same kind of 2-packages-doing-the-same-thing-in-the-same-code-base problems. From that perspective, it would be better to be all-in on one or the other, not both.

Putting aside the challenges of simultaneously supporting 2 pieces of software that do generally the same thing in a single code base, I still have a question: does CMake have support for fetching, building, and installing GNU Autotools-based projects, or does it only support that for CMake-built packages? This seems to be a key question here. You answered "Correct" to this question, above, and I don't quite know how to interpret that.

Also, the multiple-versions-of-hwloc-in-a-binary issue is stickier than it appears. Even if your executable statically links hwloc, if your executable has a dependency that dynamically links to hwloc, then you still have the same problem. I.e., it's not just about your executable, it's also what all your dependencies do, too. Given that more and more packages are using hwloc these days, we've seen this exact scenario play out in real applications. It's almost always safer to either:

  1. Use the system-provided / inbox hwloc, or
  2. Build all the dependencies and your final application yourself, and ensure that only a single version of hwloc is used (a la Homebrew, Ports, Spack, EasyBuild, etc.).

I'm not trying to be argumentative here -- I agree that there are definitely applications that have no dependencies other than hwloc, and therefore using a locally-built hwloc is easy (vs. using the system-provided one). But there definitely are cases on the other side, too: where you're using multiple dependencies, and multiple of them are using hwloc. That gets tricky; the benefit of using a locally-built hwloc becomes more difficult.

@FunMiles
Copy link
Author

FunMiles commented Feb 1, 2023

Putting aside the challenges of simultaneously supporting 2 pieces of software that do generally the same thing in a single code base, I still have a question: does CMake have support for fetching, building, and installing GNU Autotools-based projects, or does it only support that for CMake-built packages? This seems to be a key question here. You answered "Correct" to this question, above, and I don't quite know how to interpret that.

The "Correct" was for your second question, not the first. For the one you restated, it can include autotools-based code with some additional work. My preferred way until I hit the issue I mentioned was to create a conan file to bring the libraries I want. The other way is to make a Find<LibraryName>.cmake file that will allow you to cleanly import an existing library on the system.

Also, the multiple-versions-of-hwloc-in-a-binary issue is stickier than it appears. Even if your executable statically links hwloc, if your executable has a dependency that dynamically links to hwloc, then you still have the same problem. I.e., it's not just about your executable, it's also what all your dependencies do, too. Given that more and more packages are using hwloc these days, we've seen this exact scenario play out in real applications. It's almost always safer to either:

  1. Use the system-provided / inbox hwloc, or
  2. Build all the dependencies and your final application yourself, and ensure that only a single version of hwloc is used (a la Homebrew, Ports, Spack, EasyBuild, etc.).

I'm not trying to be argumentative here -- I agree that there are definitely applications that have no dependencies other than hwloc, and therefore using a locally-built hwloc is easy (vs. using the system-provided one). But there definitely are cases on the other side, too: where you're using multiple dependencies, and multiple of them are using hwloc. That gets tricky; the benefit of using a locally-built hwloc becomes more difficult.

No argument here. This is an ongoing issue with any configure/build system. Nevertheless, as I mentioned earlier, with CMake, you can make your code compile and link against the system-installed library and only fall back to the download if nothing was found. You can even have CMake print a warning when configuring that a system-provided hwloc was not found and thus it was downloaded and compiled locally if that could be an issue that could affect your project.

If you have any example situation you would like to experiment with, I am definitely willing to help you do so.

@FunMiles
Copy link
Author

FunMiles commented Feb 1, 2023

@FunMiles Can you please make a PR in this repo, then I can help you to complete it?

Check out the PR #566

@tgamblin
Copy link

tgamblin commented Mar 4, 2023

If you end up accepting something like this, and if it uses FetchContent, PLEASE ensure that package managers can disable that so that we do not have to patch your build. Distro people and packaging people do NOT want hwloc to fetch its own dependencies -- they need a way to do that themselves.

Summoning @boegel.

@boegel
Copy link

boegel commented Mar 6, 2023

Very much +1 on what @tgamblin raised.

I would even suggest to make auto-downloading of required dependencies opt-in rather than opt-out.
It may seem like it's a nice way to make the installation less painful, but I can guarantee you it's going to lead to lots of confusing problem reports as well, for a variety of reasons.

@j-horner-c4x
Copy link

Adding CMake support would be very helpful. I was recommended this library and was ready to try it out.

After using a package manager (vcpkg), managing all my other dependencies is generally a breeze. Including them is generally as simple as e.g. find_package(hwloc). Adding CMake support greatly aids this.

This library looks pretty good and something I would consider using in the future. But for my current needs right now, it seems easier to parse /proc/cpuinfo.

@bgoglin
Copy link
Contributor

bgoglin commented Dec 12, 2023

@j-horner-c4x If you just need find_package(hwloc), there's some discussion about providing it even if hwloc isn't built with CMake.

@j-horner-c4x
Copy link

Yes that would definitely be sufficient for me. Thanks.

@bgoglin
Copy link
Contributor

bgoglin commented Dec 13, 2023

I was told that using pkg-config in cmake is actually very easy, here's an example:
https://gitlab.inria.fr/solverstack/distrib/-/tree/master/cmake/test/hwloc?ref_type=heads
Obviously, you need PKG_CONFIG_PATH to point to hwloc.pc, but you'll need an environment variable to point at findhwloc.cmake if it's installed in hwloc's directory anyway.

@j-horner-c4x
Copy link

@bgoglin Thanks that suggestion works for me. While I appreciate that it's more about CMake/pkgconfig than hwloc, putting this example in the docs and making it easier to find would be very helpful.

@bgoglin
Copy link
Contributor

bgoglin commented Dec 14, 2023

@j-horner-c4x Sure, I definitely want to include this in the doc but I didn't have time to find an appropriate location yet. There's a Makefile/pkg-config example in the API example but adding CMake to it may deserve a dedicated section somewhere later.

bgoglin added a commit to bgoglin/hwloc that referenced this issue Dec 20, 2023
The GNU Make stuff is moved from the API example,
and CMake is added thanks to Florent Pruvost's example at
https://gitlab.inria.fr/solverstack/distrib/-/tree/master/cmake/test/hwloc

Refs open-mpi#565

Signed-off-by: Brice Goglin <[email protected]>
bgoglin added a commit that referenced this issue Dec 20, 2023
The GNU Make stuff is moved from the API example,
and CMake is added thanks to Florent Pruvost's example at
https://gitlab.inria.fr/solverstack/distrib/-/tree/master/cmake/test/hwloc

Refs #565

Signed-off-by: Brice Goglin <[email protected]>
(cherry picked from commit cd3a1a7)
bgoglin added a commit that referenced this issue Dec 20, 2023
The GNU Make stuff is moved from the API example,
and CMake is added thanks to Florent Pruvost's example at
https://gitlab.inria.fr/solverstack/distrib/-/tree/master/cmake/test/hwloc

Refs #565

Signed-off-by: Brice Goglin <[email protected]>
(cherry picked from commit cd3a1a7)
@bgoglin
Copy link
Contributor

bgoglin commented Jun 17, 2024

I am posting 2.11rc1 right now with some doc updates about this.

@blozano-tt
Copy link

blozano-tt commented Dec 12, 2024

There is a handy new tool in the cmake world called CPM. It is built on top of FetchContent, and makes package integration very nice. Would love to see CMake support in this library.

https://github.com/cpm-cmake/CPM.cmake

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants