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

[REVIEW] cmake: prefer locally installed thirdparty packages #572

Merged
merged 5 commits into from
Sep 23, 2020

Conversation

germasch
Copy link
Contributor

This PR essentially just changes CPMAddPackage to CPMFindPackage, except for thrust , which is currently still handled in a separate fashion (DOWNLOAD_ONLY). This makes CMake search for existing locally installed packages (at proper compatible versions) first, and if those don't exist, it falls back to fetching the packages, ie., to current behavior.

In theory, this shouldn't break anyone's workflow, since it falls back to current behavior. It does reduce the amount of duplicated libraries and potential resulting conflicts, and also should shorten build times when pre-installed local libraries can be used. In practice, I wouldn't be surprised to find some hiccups, though.

This is a step towards my goal to make RMM more easily packagable in a cmake-compatible fashion -- when using a package manager, RMM should use, e.g., the spdlog provided by the package manager, not pull in its own. This also applies to integration with conda -- currently the conda environment prescribes spdlog=1.7.0, but RMM will download and use its own (which is also 1.7.0).

Nevertheless, this PR isn't the only way to support locally installed packages -- one can also stick with the current default by keeping CPMAddPackage and setting a CMake variable to prefer locally installed packages when desired (e.g., when packaging).

The main thing here is that the file is now included, rather than
pulled in via add_subdirectory(). The intended consequence of that is
that it's not executed in a separate scope, so that `find_package()`,
or rather its wrapped form `CPMFindPackage()` will work properly.

The one change after the move is removing the `PARENT_SCOPE` from setting
`THRUST_INCLUDE_DIR`, since it's now running in the parent scope.
This will prefer using a locally installed version of spdlog -- only if that
cannot be found will it download its own copy.
This works relatively easily, since new googletest comes with its own
cmake config. In the case where CPM pulls it in via add_subdirectory,
we have to create appropriate aliases to the new namespaced names.
@germasch germasch requested a review from a team as a code owner September 22, 2020 16:41
@GPUtester
Copy link
Contributor

Can one of the admins verify this patch?

1 similar comment
@GPUtester
Copy link
Contributor

Can one of the admins verify this patch?

@kkraus14
Copy link
Contributor

ok to test

@kkraus14 kkraus14 added this to PR-WIP in v0.16 Release via automation Sep 22, 2020
@kkraus14 kkraus14 added 2 - In Progress Currently a work in progress CMake labels Sep 22, 2020
@germasch
Copy link
Contributor Author

In the CI, it picked up spdlog and gtest, so success so far ;)

-- CPM: using local package spdlog@1.7.0
-- CPM: adding package thrust@1.10.0 (1.10.0)
-- CPM: using local package GTest@1.10.0

@germasch germasch changed the title [WIP] cmake: prefer locally installed thirdparty packages [REVIEW] cmake: prefer locally installed thirdparty packages Sep 22, 2020
@kkraus14 kkraus14 added 3 - Ready for review Ready for review by team and removed 2 - In Progress Currently a work in progress labels Sep 22, 2020
@@ -27,7 +27,7 @@ function(ConfigureBench CMAKE_BENCH_NAME CMAKE_BENCH_SRC)
set_target_properties(${CMAKE_BENCH_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_include_directories(${CMAKE_BENCH_NAME} PRIVATE "$<BUILD_INTERFACE:${RMM_SOURCE_DIR}>")

target_link_libraries(${CMAKE_BENCH_NAME} benchmark pthread rmm)
target_link_libraries(${CMAKE_BENCH_NAME} benchmark::benchmark pthread rmm)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the benchmark::benchmark target consistent whether the package is found or added?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, both spdlog and benchmark provide namespaced targets when used via add_subdirectory. gtest does not, that's why I added the aliases myself.

But I guess it brings up a good point, that is, the CI will not catch if things don't work with downloaded packages. You could add more CI checks that run with CPM_DOWNLOAD_ALL=ON, that would catch errors on that end.

v0.16 Release automation moved this from PR-WIP to PR-Reviewer approved Sep 23, 2020
@kkraus14
Copy link
Contributor

@harrism can you take a look as well before we merge?

@harrism harrism merged commit afa7248 into rapidsai:branch-0.16 Sep 23, 2020
v0.16 Release automation moved this from PR-Reviewer approved to Done Sep 23, 2020
@harrism
Copy link
Member

harrism commented Sep 24, 2020

@germasch after this PR and after building multiple times, I see

-- CPM: using local package spdlog@1.7.0
-- CPM: adding package thrust@1.10.0 (1.10.0)
-- CPM: using local package GTest@1.10.0
-- CPM: adding package benchmark@1.5.2 (v1.5.2)

Why does it only find local packages for spdlog and gtest?

@germasch germasch deleted the pr/thirdparty-local branch September 24, 2020 01:56
@kkraus14
Copy link
Contributor

Why does it only find local packages for spdlog and gtest?

It will only say using local package if it found the package outside of the CPM cache, i.e. via a conda package.

@germasch
Copy link
Contributor Author

For benchmark, I suppose because it's not installed in the environment. I can add it to the conda.yml files to see whether that's enough (I haven't looked how the CI sets up its environment).

For thrust, I'm still working on how to best do handle an external thrust install in the first place, so it's not even trying yet.

@kkraus14
Copy link
Contributor

Benchmarks don't look like they're currently being built in CI so it's not trying to grab benchmark at all.

@harrism was that from your local dev in rapids-compose? What does conda list | grep benchmark give you?

@harrism
Copy link
Member

harrism commented Sep 24, 2020

benchmark doesn't need to be in conda. I am surprised gtest is there. I just thought these would get cached somewhere after the first time they are fetched. Thought that was an advantage of CPM.

@harrism
Copy link
Member

harrism commented Sep 24, 2020

(rapids) rapids@compose:~/rmm/build/release$ conda list | grep benchmark
benchmark                 1.5.1                he1b5a44_2    conda-forge
pytest-benchmark          3.2.3              pyh9f0ad1d_0    conda-forge
rapids-pytest-benchmark   0.0.12                     py_0    rapidsai

@kkraus14
Copy link
Contributor

They are cached, it will just only say using local package if it's found outside of CPM handling it: https://github.com/TheLartians/CPM.cmake/blob/master/cmake/CPM.cmake#L420-L431

It will say adding package ... before calling into FetchContent_Declare which is what handles caching the added package.

@kkraus14
Copy link
Contributor

Looks like our conda package has the wrong version of benchmark as compared to CPM which is why CPM isn't finding it locally.

@germasch
Copy link
Contributor Author

Well, so for one, we ask for 1.5.2. (Which should exist in conda). The other potential issue is that there's at least one bug in what benchmark itself thinks its version is: google/benchmark#1045. There may be something else off -- could you look where benchmark is installed, .../lib/cmake/benchmark/benchmarkConfigVersion.cmake what it says its version is?

@harrism
Copy link
Member

harrism commented Sep 24, 2020

They are cached,

Thrust takes significant time, so it doesn't seem cached...

@harrism
Copy link
Member

harrism commented Sep 24, 2020

.../lib/cmake/benchmark/benchmarkConfigVersion.cmake

Not sure where to find that path.

@germasch
Copy link
Contributor Author

If you set CPM_SOURCE_CACHE to some local directory, it'll cache the repos there.

@harrism
Copy link
Member

harrism commented Sep 24, 2020

Is that a cmake variable or an env variable?

@germasch
Copy link
Contributor Author

.../lib/cmake/benchmark/benchmarkConfigVersion.cmake

Not sure where to find that path.

Wherever conda installs its packages.

@harrism
Copy link
Member

harrism commented Sep 24, 2020

We should document this.

@germasch
Copy link
Contributor Author

Is that a cmake variable or an env variable?

Either works.

@harrism
Copy link
Member

harrism commented Sep 24, 2020

(rapids) rapids@compose:~$ more compose/etc/conda/envs/rapids/lib/cmake/benchmark/benchmarkConfigVersion.cmake 
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major version is the same as the current one.
# The variable CVF_VERSION must be set before calling configure_file().


set(PACKAGE_VERSION "0.0.0")

if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
  set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()

  if("0.0.0" MATCHES "^([0-9]+)\\.")
    set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
  else()
    set(CVF_VERSION_MAJOR "0.0.0")
  endif()

  if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
    set(PACKAGE_VERSION_COMPATIBLE TRUE)
  else()
    set(PACKAGE_VERSION_COMPATIBLE FALSE)
  endif()

  if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
      set(PACKAGE_VERSION_EXACT TRUE)
  endif()
endif()


# if the installed project requested no architecture check, don't perform the check
if("FALSE")
  return()
endif()

# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
  return()
endif()

# check that the installed version has the same 32/64bit-ness as the one which is currently searching
:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
  math(EXPR installedBits "8 * 8")
  set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
  set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()

@harrism
Copy link
Member

harrism commented Sep 24, 2020

0.0.0 apparently. :)

@germasch
Copy link
Contributor Author

0.0.0 apparently. :)

Yeah, that's what I was afraid of -- that's what happens in benchmark installed by my package manager. I'll work on getting that fixed in upstream benchmark, but that may take a little while. You can install your own benchmark locally (and add it to CMAKE_PREFIX_PATH if its not in a standard location), then RMM will pick it up (for me it does, anyway).

@germasch
Copy link
Contributor Author

FWIW, google benchmark releases will hopefully provide their actual version in their cmake config once this gets resolved: google/benchmark#1047

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3 - Ready for review Ready for review by team CMake
Projects
No open projects
v0.16 Release
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants