I can’t seem to find any information on how to do this.
Here’s a concrete example I have in mind. I would like to build {fmt}, from source, in my project, with some specific flags (specifically with -fPIC). I’m currently doing this with ExternalProject_Add (although this means fmt::fmt doesn’t end up being an imported target for… reasons?).
One of my dependencies also depends on {fmt}, and itself does a find_package(fmt REQUIRED). I would like to ensure that my entire build consistently uses the same fmt::fmt target, so I need this call to find_package(fmt) to pick up my built-from-source version of {fmt}.
Which I guess means that I have to provide a Findfmt.cmake for everyone to find consistently. What is the Correct Way to write Findfmt.cmake to handle this case?
But one of my other dependencies is calling find_package(fmt), so that needs to find… something, which needs to be the same thing that I’m building from source. There needs to be someFindfmt.cmake that gets found, and it’s not the one that ships with {fmt} - because I’m building {fmt} from source.
For your situation, I’d recommend using FetchContent and use CMake 3.24 or later. The FetchContent_Declare() function gained an OVERRIDE_FIND_PACKAGE option in CMake 3.24, enabling the workflow you describe. For example:
include(FetchContent)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG a0b8a92e3d1532361c2f7feb63babc5c18d00ef2 # 10.0.0
OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(fmt)
# somewhere later in your project...
find_package(fmt REQUIRED)
The above call to find_package() gets redirected to a fmt-config.cmake that FetchContent creates for you internally. This pattern works as long as the dependency you’re pulling in follows the recommended (and increasingly expected) pattern of providing the same <namespace>::<target> target names whether it is built-from-source or brought in via find_package(). I thinkfmt satisfies that constraint, but I’ll have to leave you to confirm it.
I would use this SYSTEM and version tag to be explicit and prevent warnings from fmt headers:
include(FetchContent)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.0.0
OVERRIDE_FIND_PACKAGE
SYSTEM
)
FetchContent_MakeAvailable(fmt)
# somewhere later in your project...
find_package(fmt 10.0 REQUIRED)
bash-3.2$ ninja
[0/1] Re-running CMake...
-- Version: 10.0.0
-- Build type: Debug
-- Performing Test HAS_NULLPTR_WARNING
-- Performing Test HAS_NULLPTR_WARNING - Success
CMake Warning (dev) at cmake-build-cxx-modules-sandbox-x86_64-Debug/install/_deps/fmt-src/CMakeLists.txt:379 (install):
CMake's C++ module support is experimental. It is meant only for
experimentation and feedback to CMake developers.
This warning is for project developers. Use -Wno-dev to suppress it.
-- Configuring done (5.8s)
CMake Warning (dev):
C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
experimental. It is meant only for compiler developers to try.
This warning is for project developers. Use -Wno-dev to suppress it.
-- Generating done (0.1s)
-- Build files have been written to: /Users/clausklein/Workspace/cpp/cxx20/cxx-modules-sandbox/cmake-build-cxx-modules-sandbox-x86_64-Debug/install
[3/3] Linking CXX static library lib/libfmtd.a
bash-3.2$
``
Most likely it was fixed by MR 7977, which was included in CMake 3.25.2.
No, it works for me. I assume you’re objecting to the use of git@... instead of https://..., but both should work. There are cases where you may want to use one over the other, but both are valid.
Using OVERRIDE_FIND_PACKAGE is definitely the way to go if you are not bound to lower versions of cmake!
For <3.24 you can make the fmt config available to other deps by adding the fmt_BINARY_DIR to the prefix path and setting FMT_INSTALL=ON before MakeAvailable.