-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
[cmake] Some improvements to handling of OpenMP on macOS #6489
Conversation
@jameslamb we've repeatedly had issues with OpenMP on MacOS, I'm wondering whether we should just advertise a conda-based compilation process. I successfully compiled locally with the following environment: dependencies:
- python
- cxx-compiler
- llvm-openmp
- cmake
- make and by setting |
@borchero I think any default which you (upstream) prefer is fine, just do not hardcode it, otherwise everyone else is forced to patch the code to get around that. Compilation works perfectly fine in MacPorts, for example, but I have to throw away huge chunks from CMakeLists now, because we do not want rpaths, and certainly do not wait brewisms, and even less so hardcoded usage of incompatible libraries. That solves the problem for us, but it still exists elsewhere, since some thirdparty software borrow pre-built LightGBM, and that has hardcoded paths to Homebrew prefix, which of course cannot work in any other setup: ankane/lightgbm-ruby#7 |
Thanks for your interest in LightGBM. To start, please... don't come here and say that the current state is not "sane". We can discuss the relative benefits and disadvantages of different approaches without insulting each other.
Can you link us to the patches you're using to do that, so we can see specifically what you're referring to?
The hard-coded install name
The project should already support this without any need to add any other headers, and without adding any new how I tested that (click me)conda create \
--name delete-me \
-c conda-forge \
--yes \
python=3.10 \
cmake \
cxx-compiler \
llvm-openmp
source activate delete-me
cmake -B build -S .
cmake --build build --target _lightgbm -j4 That produces a library with the expected path entries. otool -L lib_lightgbm.dylib
# lib_lightgbm.dylib:
# @rpath/lib_lightgbm.dylib (compatibility version 0.0.0, current version 0.0.0)
# @rpath/libomp.dylib (compatibility version 5.0.0, current version 5.0.0)
# @rpath/libc++.1.dylib (compatibility version 1.0.0, current version 1.0.0)
# /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2) And an RPATH entry pointing to where otool -l lib_lightgbm.dylib
# Load command 15
# cmd LC_RPATH
# cmdsize 56
# path /Users/jlamb/miniforge3/envs/delete-me/lib (offset 12)
# Load command 16
# cmd LC_RPATH
# cmdsize 48
# path /opt/homebrew/opt/libomp/lib (offset 12) The Python package built in that way works without issue. source activate delete-me
sh build-python.sh bdist_wheel install
conda install -c conda-forge --yes pandas scikit-learn
python examples/python-guide/sklearn_example.py If you tried this and observed something different, please tell me.
Can you share an example where you ran into this issue? Because the install name LightGBM uses for the OpenMP it found at build time should be That's what I see (on my M2 Mac). brew install gcc
export CC=gcc-14
export CXX=g++-14
cmake -B build -S . build logs showing 'gcc -fopenmp' was used (click me)
cmake --build build --target _lightgbm -j4
otool -L lib_lightgbm.dylib
It would be a problem for relocation to have that absolute, Homebrew-specific install name for if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
INSTALL_RPATH "/opt/homebrew/opt/libomp/lib;/opt/local/lib/libomp;${OpenMP_LIBRARY_DIR}"
else()
INSTALL_RPATH "${OpenMP_LIBRARY_DIR}"
endif() I suspect
I'm not convinced that the case you've described justifies further complicating the API of project's Lines 164 to 167 in d56a7a3
will run only if Can you describe precisely, in a way that I could reproduce, a case where you saw different behavior? |
@jameslamb Thank you for responding in detail.
Absolutely. I apologize if my choice of words created such an impression, it was not intended. (I readily admit that my own code is not sane in some instances.)
Yes, you are right, of course. I just did not see any relevant condition on compiler here: Line 782 in 7cb1892
So my impression was that this will still be used regardless. Sorry, if I misread the code.
Any specific hardcoded path is problematic for general-case distribution, even without any concern for relocating a binary, since there are no standard paths for non-system libraries. I do not know a solution for a general case, as long as pre-built binaries/libraries are distributed. (Using rpaths is not perfect either, though preferable to baked in paths to any package manager.)
To be honest I would rather remove all package-specific code, since it is redundant at best: package managers handle install prefix etc. in their own build systems. But I think someone may get upset, whether now or at some point in a future, if such commit is merged, that somebody from MacPorts removed Homebrew code :) So I do not want to do that. However if the approach is to leave defaults as they are (there may be reasons for that which I did not think of, after all), then there is a case to allow disabling certain default behavior. It is conceivable that someone may have Homebrew and Macports both, or have Homebrew but trying to build without relying on a package manager etc.
MacPorts is placing it in
Sure, but this is our local patch, not a proposal for changes (I understand it may not fit the needs/preferences of others). |
@jameslamb Should I drop the second commit and leave only 26cc564 which should be uncontroversial? |
It may be a few days until I'm able to provide a thoughtful answer here, sorry. The state of these codepaths is very focused on building the library for redistribution (e.g. in Python wheels) and you've brought up some excellent points about how that might make other types of builds more difficult. I need to find a bit of time to think carefully about this. |
@jameslamb Sure, thank you. No hurry here. |
Thanks for this. We intentionally vendor sources of specific, fixed commits of But if you do want to propose that separately, we'd be happy to talk about it more on a separate issue.
Sure, and this is why
Yes I'd like to preserve the defaults. In short, we want to support the following:
In this project, we are producing shared libraries that are distributed in Python wheels installed with e.g. Given that, I strongly thing the project should continue to set the install name for its OpenMP dependency to
Ah sorry, my mistake. Thank you for explaining, that makes sense to me. Based on my read of the things you've written, and reviewing other OpenMP codepaths in LightGBM's CMake configuration, I'm open to adding a new CMake option as you've proposed. Here's what I'd like to propose, please let me know what you think:
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
INSTALL_RPATH "${OpenMP_LIBRARY_DIR};/opt/homebrew/opt/libomp/lib;/opt/local/lib/libomp"
else()
INSTALL_RPATH "${OpenMP_LIBRARY_DIR}"
endif() That should ensure that if you use the shared library on the same system where you built it, the location where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leaving a blocking review based on my last comment (meant to post that as a review not a regular comment)
@jameslamb Thank you for reviewing, sounds good to me. I will deal with this tomorrow and rebase the PR. P. S. As for supporting external dependencies, I do not think as a non-default option it is likely to increase maintenance burden. A notice can be added that such configuration is not tested / not guaranteed to work (or something to this effect). Maybe also use mark_as_advanced. |
@barracuda156 would it be ok if I push a commit to this PR with the changes recommended in #6489 (comment)? We are going to have to do a new release very soon to keep the R package on CRAN (#6522) and I'd love to get this fix into that release. |
@jameslamb Yes, please, and thank you very much. |
(I'll fix the @barracuda156 I've pushed some changes here, could you please take a look and let me know what you think? |
@jameslamb LGTM, thank you very much. |
Since I pushed some commits here, my approval probably shouldn't be enough for a merge. @borchero could you look again whenever you have time? |
I've updated this to latest I'll merge this once CI succeeds. @borchero if you come back and look later whenever you have time, please do comment here if you see anything problematic. We can always make follow-up changes. |
Thank you! |
Please review.
This is still hackish and makes assumptions which may not hold. However, it is arguably a bit more sane:
libomp
with GCC, which uses its ownlibgomp
(and which normally does not need specific paths at all).