Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

fengyuentau
Copy link
Member

@fengyuentau fengyuentau commented Jan 4, 2023

Fixes #23092
Fixes #18478

Helpful notes:

  1. OpenMP_CXX_INCLUDE_DIRS is defined since CMake >= 3.16.0.
  2. OpenMP_CXX_LIBRARIES is defined since CMake >= 3.9.0.
  3. For gnu openmp (libgomp, e.g. on Linux), OpenMP_CXX_INCLUDE_DIRS is null
    regardless CMake version. Passing flag -fopenmp is enough.
  4. For clang openmp (libomp, e.g. on macOS), OpenMP_CXX_INCLUDE_DIRS is not
    null and need to include header and link libomp in addition to passing flag.

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake
force_builders=Custom
build_image:Custom=openmp:20.04
buildworker:Custom=linux-4

@alalek
Copy link
Member

alalek commented Jan 9, 2023

There is the same problems like: #21427 (comment)
Need to support both old and new versions.

@fengyuentau
Copy link
Member Author

Need to support both old and new versions.

Sure, let me take a look into the old version. By the way, by "old version" do you mean versions <= 3.5?

@alalek
Copy link
Member

alalek commented Jan 9, 2023

OpenCV 4.0 has been released with CMake 3.5.1 support (version from Ubuntu 16.04).

BTW, we need to check for existence/definition of new variables (OpenMP_CXX_INCLUDE_DIRS), instead of CMake version.

@fengyuentau
Copy link
Member Author

we need to check for existence/definition of new variables (OpenMP_CXX_INCLUDE_DIRS), instead of CMake version.

Latest commit should fix this issue. Tested with cmake==3.5.0: If OpenMP_CXX_INCLUDE_DIRS is empty, OPENMP_FOUND is set to false and pthreads is used in place of openmp.

@alalek
Copy link
Member

alalek commented Jan 10, 2023

If OpenMP_CXX_INCLUDE_DIRS is empty, OPENMP_FOUND is set to false and pthreads is used in place of openmp.

This is a regression "by definition". Because you broke OpenMP on configurations similar to Ubuntu 16.04.
Check "Custom" builder with OpenMP:

@fengyuentau
Copy link
Member Author

fengyuentau commented Jan 10, 2023

I found that gnu gcc links libgomp by default on Linux, and the gnu openmp library is kind of integrated into the gnu gcc, so passing flag -fopenmp is enough and feasible for gnu gcc.

But this is not the case for clang on macOS. clang on macOS treats libomp (clang openmp library) as a third-party library and it needs the specified header and library. So does it make sense if I add condition if(APPLE) to make the change only valid for macOS?

@alalek
Copy link
Member

alalek commented Jan 10, 2023

if I add condition if(APPLE)

No.
Read above:

we need to check for existence/definition of new variables (OpenMP_CXX_INCLUDE_DIRS)

@fengyuentau
Copy link
Member Author

I need more information about the return of find_package(OpenMP) of different CMake versions. Do you know by any chance when OpenMP_CXX_INCLUDE_DIRS is empty? Does it relate only to CMake versions? Or relate to platforms as well?

@alalek
Copy link
Member

alalek commented Jan 10, 2023

In CMake 3.5.1 OpenMP_CXX_INCLUDE_DIRS is not defined at all (not used). E.g., see "vars" log of CMake output of Custom builder.

Again, refer to comments from previous PR: #21427 (comment)

To track behavior changes of CMake scripts you need to check history of CMake.

@fengyuentau
Copy link
Member Author

fengyuentau commented Jan 12, 2023

I found WITH_OPENMP is also broken with cmake==3.5.1 (maybe even cmake<=3.5.1) on Ubuntu 20.04. pthreads is used instead in this case without the changes in this pull request. Let me push a commit to see whether it works on Ubuntu 16.04 with cmake==3.5.1.

@fengyuentau
Copy link
Member Author

It shows OpenMP is used on openmp:16.04 with latest commit: https://pullrequest.opencv.org/buildbot/builders/precommit_custom_linux/builds/100176/steps/cmake/logs/stdio.

Let me take a look at cmake==3.5.1 on Ubuntu 20.04.

@fengyuentau
Copy link
Member Author

pthreads is used instead in this case without the changes in this pull request. Let me push a commit to see whether it works on Ubuntu 16.04 with cmake==3.5.1.

This is actually caused by a typo I made to the CMake option. It is good now. Feel free to review this pull request @alalek

ocv_target_link_libraries(${the_module} LINK_PRIVATE "${HPX_LIBRARIES}")
endif()

if(WITH_OPENMP AND DEFINED OpenMP_CXX_INCLUDE_DIRS AND OpenMP_CXX_INCLUDE_DIRS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WITH_OPENMP

HAVE_OPENMP


OpenMP_CXX_INCLUDE_DIRS

Empty OpenMP_CXX_LIBRARIES would trigger CMake error below with missing argument, so check should use OpenMP_CXX_LIBRARIES instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, let me bake another commit for this.

Copy link
Member Author

@fengyuentau fengyuentau Jan 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty OpenMP_CXX_LIBRARIES would trigger CMake error below with missing argument, so check should use OpenMP_CXX_LIBRARIES instead.

I found that OpenMP_CXX_LIBRARIES is defined since CMake>=3.9.0, while OpenMP_CXX_INCLUDE_DIRS is defined since CMake>=3.16.0. So OpenMP_CXX_LIBRARIES is never empty when OpenMP_CXX_INCLUDE_DIRS has value. It actually behaves exactly like this in my experiences below:

Linux (Ubuntu 20.04)
cmake-3.5.1 inc: no def, lib: no def
cmake-3.9.6 inc: no def, lib: def +value
cmake-3.15.7 inc: no def, lib: def + value
cmake-3.16.0 inc: def (no value), lib: def + value

Update:

I use HAVE_OPENMP and OpenMP_CXX_LIBRARIES as condition for linking in the latest commit. Basically this patch of code is triggered when CMake >= 3.16.0 and it is on clang.

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
# NOTES:
# 1. For CMake <= 3.5.1, OpenMP_CXX_INCLUDE_DIRS is not defined.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.5.1

This is not correct.
This is a minimal CMake version on which we take a look look for OpenCV 4.x.

https://cmake.org/cmake/help/v3.6/module/FindOpenMP.html

  • still no _INCLUDE_DIRS too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked CMake docs and found _INCLUDE_DIRS is defined since CMake>=3.16.0. See https://cmake.org/cmake/help/v3.16/module/FindOpenMP.html#backward-compatibility.

# NOTES:
# 1. OpenMP_CXX_INCLUDE_DIRS is defined since CMake >= 3.16.0.
# 2. OpenMP_CXX_LIBRARIES is defined since CMake >= 3.9.0.
# 2. For gnu openmp (libgomp, e.g. on Linux), OpenMP_CXX_INCLUDE_DIRS is null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double 2.


Not sure if we really need such detailed comment here (especially not sure about its accuracy).

OpenMP_CXX_LIBRARIES and OpenMP_CXX_INCLUDE_DIRS are available with modern CMake scripts only. We use checks to detect that case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will copy-paste all the comments in the first comment of this PR and delete them from the code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

ocv_target_link_libraries(${the_module} LINK_PRIVATE "${HPX_LIBRARIES}")
endif()

if(HAVE_OPENMP AND DEFINED OpenMP_CXX_INCLUDE_DIRS AND OpenMP_CXX_LIBRARIES)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenMP_CXX_INCLUDE_DIRS AND OpenMP_CXX_LIBRARIES

mess of different variables

Copy link
Member Author

@fengyuentau fengyuentau Jan 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to my test above, there is a case when _LIBRARIES is defined and has value but _INCLUDE_DIRS is not defined at all (CMake >= 3.9, <= 3.15). This condition is basically ensuring the old behavior is not changed, which is OpenMP_CXX_LIBRARIES will not be linked until OpenMP_CXX_INCLUDE_DIRS is defined.

Do you suggest using OpenMP_CXX_LIBRARIES in replace of OpenMP_CXX_INCLUDE_DIRS for definition checking?

Update:

It is now using if(HAVE_OPENMP AND DEFINED OpenMP_CXX_INCLUDE_DIRS AND OpenMP_CXX_INCLUDE_DIRS AND OpenMP_CXX_LIBRARIES) as conditions for linking libomp.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to use other variables here.
Logic should protect usage from empty/non-defined values. No more, no less.

if(HAVE_OPENMP AND DEFINED OpenMP_CXX_LIBRARIES AND OpenMP_CXX_LIBRARIES)
  ocv_target_link_libraries(${the_module} LINK_PRIVATE "${OpenMP_CXX_LIBRARIES}")
endif()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, done with latest commit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, done with latest commit.

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@alalek alalek merged commit c63d79c into opencv:4.x Jan 16, 2023
@fengyuentau fengyuentau deleted the fix_omp_macos branch January 16, 2023 09:46
@alalek alalek mentioned this pull request Jan 18, 2023
a-sajjad72 pushed a commit to a-sajjad72/opencv that referenced this pull request Mar 30, 2023
* fix openmp include and link issue on macos

* turn off have_openmp if OpenMP_CXX_INCLUDE_DIRS is empty

* test commit

* use condition HAVE_OPENMP and OpenMP_CXX_LIBRARIES for linking

* remove trailing whitespace

* remove notes

* update conditions

* use OpenMP_CXX_LIBRARIES for linking
geversonsto pushed a commit to stodev-com-br/opencv that referenced this pull request Jun 3, 2023
* fix openmp include and link issue on macos

* turn off have_openmp if OpenMP_CXX_INCLUDE_DIRS is empty

* test commit

* use condition HAVE_OPENMP and OpenMP_CXX_LIBRARIES for linking

* remove trailing whitespace

* remove notes

* update conditions

* use OpenMP_CXX_LIBRARIES for linking
@themightyoarfish
Copy link
Contributor

On macos, i am getting

Undefined symbols for architecture arm64:
  "_omp_get_max_threads", referenced from:
      Eigen::internal::manage_multi_threading(Eigen::Action, int*) in dls.cpp.o
  "_omp_get_num_threads", referenced from:
      Eigen::internal::general_matrix_matrix_product<long, double, 1, false, double, 1, false, 0, 1>::run(long, long, long, double const*, long, double const*, long, double*, long, long, double, Eigen::internal::level3_blocking<double, double>&, Eigen::internal::GemmParallelInfo<long>*) in essential_solver.cpp.o
  "_omp_get_thread_num", referenced from:
      Eigen::internal::general_matrix_matrix_product<long, double, 1, false, double, 1, false, 0, 1>::run(long, long, long, double const*, long, double const*, long, double*, long, long, double, Eigen::internal::level3_blocking<double, double>&, Eigen::internal::GemmParallelInfo<long>*) in essential_solver.cpp.o
ld: symbol(s) not found for architecture arm64

when building the 4.12.0 tag

@themightyoarfish
Copy link
Contributor

specifically it fails linking calib3d, because the Openmp library is not getting linked, because the core module links it privately, but it has to be PUBLIC I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot find omp.h and link libomp on macOS with -DWITH_OPENMP=ON 4.1.1 (and master) does not compile on macOS with WITH_OPENMP

4 participants