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

CMake can't locate spdlogExports.cmake #2514

Closed
puneetmatharu opened this issue Oct 16, 2022 · 13 comments
Closed

CMake can't locate spdlogExports.cmake #2514

puneetmatharu opened this issue Oct 16, 2022 · 13 comments

Comments

@puneetmatharu
Copy link
Contributor

puneetmatharu commented Oct 16, 2022

I'm attempting to consume spdlog as a third-party library via FetchContent but I encounter the following error:

CMake Error at build/_deps/spdlog_project-build/spdlogConfig.cmake:42 (include):
  include could not find requested file:

    /.../build/_deps/spdlog_project-build/spdlogConfigTargets.cmake

I believe this is down to a missing exported targets file in your build directory at configure-time. At configure-time, I would typically expect an exported targets file to be placed in the build directory. At the moment this is not the case, as can be seen from the snippet below:

spdlog/CMakeLists.txt

Lines 284 to 288 in d011332

if(SPDLOG_INSTALL)
message(STATUS "Generating install")
set(project_config_in "${CMAKE_CURRENT_LIST_DIR}/cmake/spdlogConfig.cmake.in")
set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake")
set(config_targets_file "spdlogConfigTargets.cmake")

However, this was not the case up until v1.3.1 of the library. See e.g.

spdlog/CMakeLists.txt

Lines 147 to 151 in a7148b7

export(
EXPORT ${targets_export_name}
NAMESPACE "${namespace}"
FILE ${targets_config}
)

Keeping in line with the currently-used variables, you would simply need to add the following code:

export(
  EXPORT spdlog
  NAMESPACE spdlog::
  FILE "${CMAKE_CURRENT_BINARY_DIR}/${config_targets_file}")

I am happy to create a PR to this effect if you would like. Please let me know how you'd like to proceed.

@tt4g
Copy link
Contributor

tt4g commented Oct 17, 2022

spdlogConfigTargets.cmake should be installed with the install command.

https://github.com/gabime/spdlog/blob/v1.x/CMakeLists.txt#L332

And if you are using FetchContent for importing external libraries like googletest, then I don't believe that an error include could not find requested file: ... spdlogConfigTargets.cmake would be reported since the spdlog install command should not be called.

Are you trying to call find_package(spdlog) to import the spdlog installed on your system and failing?

@puneetmatharu
Copy link
Contributor Author

puneetmatharu commented Oct 17, 2022

spdlogConfigTargets.cmake should be installed with the install command.

Agreed, but I also believe that it also needs to be export-ed to the build directory so that it can be found at configure-time.

Are you trying to call find_package(spdlog) to import the spdlog...

Indeed. I am using spdlog internally but also want to allow the user to use spdlog with their code after my library has been installed. However, if I simply link to the library without first using find_package(), the library tried to export it as one of my targets (which I don't want). As far as I am aware, the recommended approach in this case is to install the third-party library at install-time alongside the library and locate spdlog internally using find_package() so that CMake will consider it an imported target (see e.g. 4. Installing a superbuild). However, this approach does not currently work at configure time -- I can find the spdlog config file, but not the exported targets file that it searches for inside that config file.

EDIT:

...installed on your system and failing?

It is not installed on my system, and I do not want to force the user to install it manually beforehand; I want to install it for them alongside my library at install-time, as mentioned above.

@tt4g
Copy link
Contributor

tt4g commented Oct 17, 2022

I don't know how your Cmake project is configured, but I have a feeling that simply removing find_package(spdlog) will solve the problem.

If you configure your CMake project as per the sample in FetchContent, you will import an external project with add_subdirectory().
The add_subdirectory() will include the external project as part of your project, thus not preventing spdlog from being added to the installation target.
However, as answered on Stack Overflow, you can exclude it from the project's ALL target by specifying the EXCLUDE_FROM_ALL option to add_subdirectory().

And you can then configure CMake target spdlog not to install by defining the CMake variable SPDLOG_INSTALL=OFF.

option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})

@tt4g
Copy link
Contributor

tt4g commented Oct 17, 2022

If you believe that the previous behavior is correct, you may create PR.
However, please note that the CMake documentation states the following

https://cmake.org/cmake/help/v3.25/command/export.html:

Export targets or packages for outside projects to use them directly from the current project's build tree, without installation.

See the install(EXPORT) command to export targets from an install tree.

The file created by this command is specific to the build tree and should never be installed. See the install(EXPORT) command to export targets from an install tree.

@puneetmatharu
Copy link
Contributor Author

puneetmatharu commented Oct 17, 2022

If you configure your CMake project as per the sample in FetchContent, you will import an external project with add_subdirectory().
The add_subdirectory() will include the external project as part of your project, thus not preventing spdlog from being added to the installation target.
However, as answered on Stack Overflow, you can exclude it from the project's ALL target by specifying the EXCLUDE_FROM_ALL option to add_subdirectory().

Unfortunately that does not address the issue, I still encounter the following issue:

CMake Error in CMakeLists.txt:
  export called with target "myLibrary" which requires target "spdlog" that is
  not in any export set.

and I also do want to install the spdlog library.

However, simply remembering to also export the targets using export(...) as I have done here:

puneetmatharu@7768c62

fixes the issue.

The file created by this command is specific to the build tree and should never be installed. See the install(EXPORT) command to export targets from an install tree.

Yep, that makes complete sense, e.g. after libraries have been installed, the IMPORTED_LOCATION property will be different, as files will be found in the installation location and not the source tree. Importantly, the export(...) command generates its own exported targets file and does not clash with install(...), and I am not proposing that the install(...) command be removed (as can be seen from the linked commit diff).

I'll open a PR.

@gabime
Copy link
Owner

gabime commented Oct 17, 2022

However, this was not the case up until v1.3.1 of the library. See e.g.

@puneetmatharu Could you please find out from the commit log what was the reason for the change? There was probably a good reason.

@tt4g
Copy link
Contributor

tt4g commented Oct 18, 2022

I noticed one workaround.
I write this because it may be useful if export()` cannot be restored.

If you have imported the CMake target spdlog into your project with add_subdirectory(/path/to/spdlog), you should be able to export(TARGETS spdlog NAMESPACE spdlog:: FILE "${spdlog_BINARY_DIR}/spdlogConfigTargets.cmake") from your project.

@tt4g
Copy link
Contributor

tt4g commented Oct 18, 2022

Could you please find out from the commit log what was the reason for the change? There was probably a good reason.

@gabime Changed by baefe0b (PR #1089).
Nothing was known from the commit message.

@puneetmatharu
Copy link
Contributor Author

puneetmatharu commented Oct 18, 2022

Yeah, I've just stumbled across this commit too. It looks like there was a bunch of refactoring going on and they simply forgot to export the targets at build time, which is completely reasonable if you only expect your project to be used after it has been installed...

EDIT: See e.g. the info at the bottom of this page.

@gabime
Copy link
Owner

gabime commented Oct 18, 2022

Got it. So PR #2515 would solve it I guess. Will merge.

@puneetmatharu
Copy link
Contributor Author

puneetmatharu commented Oct 18, 2022

Excellent, thanks all for helping resolve this so quickly

Out of curiosity, would it be okay to create a tag for the merged commit too? E.g. 1.10.0 -> 1.10.1; I think the patch might be useful for people that also want to import spdlog into their CMake projects via FetchContent (that also export/install their own project). Not a problem if not, I can simply update my repo to fetch spdlog from a specific commit ID.

@gabime
Copy link
Owner

gabime commented Oct 18, 2022

I try to tag only releases. So I prefer not to if not critical to release officialy.

@puneetmatharu
Copy link
Contributor Author

I completely understand. Thanks for letting me know :)

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

3 participants