CMake install takes destination dirs, often using GNUInstallDirs to load standard values for the destination names. For example:
include(GNUInstallDirs)
install(TARGETS Foo
EXPORT Foo
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
However it doesn't provide different paths built for different platforms, or architectures. I've been installing to a platform specific folder within my project via CMAKE_INSTALL_PREFIX
like this:
CMAKE_INSTALL_PREFIX=dist/${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}
This has some problems though:
I'm looking for a structure that works with find_package module mode and config mode; something like this:
<install_prefix>/
include/
foo/
foo.h
lib/
<PLAT x ARCH x CONFIG>/
cmake/
foo/
FooConfig.cmake
libFoo.a
Goal is:
Considering I'd be installing mostly 3rd party libraries here, if this can be done by overriding the vars from GNUInstallDirs, it'd probably work for many libraries. The rest I guess would either have to be edited or I just give up and use separate installation dirs that include platform and arch.
I'll post as far as I've gotten so far, and maybe it'll be useful. If someone has missing pieces I'll update this.
The documentation describing the search order is here: https://cmake.org/cmake/help/v3.12/command/find_package.html?highlight=%3Cprefix%3E
There are quite a few supported permutations, so I'll start by eliminating some:
.../cmake/<name>*/
style.That leaves (**extra space added to show similarity):
<prefix>/ (lib/<arch>|lib*|share)/cmake/<name>*/ (U)
<prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/ (W/U)
The docs state that certain search paths are meant for certain platforms, but technically I think all of the search paths are tried. It's just a matter of what's idiomatic for the platform. As such, however, you can't use the different styles as platform differentiator. In fact, this should mean the Unix option is also valid for Windows.
As you can see above the only difference for the Windows friendly Unix format is an extra prefix for the name. Either are valid choices, so for now I'll just refer to the Unix only style as it fits my preference. Finally, I don't really care about the "share" folder, because we're talking about C/C++ libraries.
So finally we're down to these 2 choices:
<prefix>/lib/<arch>/cmake/<name>*/
<prefix>/lib*/cmake/<name>*/
Paths with lib/<arch>
are enabled if the CMAKE_LIBRARY_ARCHITECTURE
variable is set. CMAKE_<LANG>_LIBRARY_ARCHITECTURE
states:
If the
<LANG>
compiler passes to the linker an architecture-specific system library search directory such as<prefix>/lib/<arch>
this variable contains the<arch>
name if/as detected by CMake.
I know this is more specifically for certain distros that support multiarch, and is meant to be set automatically. However, I can't quite figure out if this is something that can easily be leveraged with cmake to achieve the goal here; what would you set to control this in cmake? On a multiarch system, libraries Foo and Bar could look like:
<prefix>/lib/x86_64-linux-gnu/
foo-1.1/
cmake/FooConfig.cmake
bar/
cmake/BarConfig.cmake
foo-1.1.so
foo-1.1.lib
foo-1.1.dll
foo-1.1.dylib
bar.so
bar.lib
bar.dll
bar.dylib
If we can control what the multiarch value is, this option could easily be used for other platforms like: Darwin_x86_64, Windows_x86_64, etc. And it would probably be compatible with find_package module mode where the includes would all be found, without needing config mode to redirect to some non-standard dir.
A partial solution is to keep the platforms completely separate in the prefix, but at least the 64-bit and 32-bit architectures can be combined just splitting the libs.
lib*
includes one or more of the valueslib64
,lib32
,libx32
orlib
(searched in that order).
- Paths with lib64 are searched on 64 bit platforms if the
FIND_LIBRARY_USE_LIB64_PATHS
property is set to TRUE.- Paths with lib32 are searched on 32 bit platforms if the
FIND_LIBRARY_USE_LIB32_PATHS
property is set to TRUE.- Paths with libx32 are searched on platforms using the x32 ABI if the
FIND_LIBRARY_USE_LIBX32_PATHS
property is set to TRUE.- The lib path is always searched.
This at least partially helps. I'd continue to use lib as 64-bit, and then just use lib32 for 32-bit needs.
If you expect user to set some standard directory as CMAKE_PREFIX_PATH, like
/usr/local # installation prefix
but your project installs things into non-standard, platform-specific subdirectories, like
/usr/local/linux/x86/ # actual root directory where things are installed
you may place FooConfig.cmake
into standard subdirectory:
/usr/local/lib/FooConfig.cmake
but write it so it searches appropriate .cmake
from platform-specific directory:
# File: FooConfig.cmake
# Location: lib/
#
# This is platform-independent script.
#
# Redirect configuration to the platform-specific script <system>/<cpu>/lib/FooConfig.cmake.
include(${CMAKE_CURRENT_LIST_DIR}/../${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}/lib/FooConfig.cmake)
Platform-specific *Config.cmake
script can be written in a usual way.
So, if a user will write
find_package(Foo)
in an environment set for Linux/x86
, it will setup imported targets for that platform.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With