Open ComicSansMS opened 2 months ago
Hey @ComicSansMS, welcome and thanks for the issue!
Whether we want to support [installed libraries using multi-config generator] use cases and to what extent
This is important to support. Is there a "most common" layout for installed C++ libraries? Does it make sense to use the same layout on Windows and UNIX platforms?
What conventions for naming and directory structure to adopt to address this
I don't know, but we should prioritize ergonomics for the library's user. I think it is safe to assume consumers will be using CMake (with or without or a package manager) to consume the library so perhaps the layout won't be exposed to them.
This is important to support. Is there a "most common" layout for installed C++ libraries? Does it make sense to use the same layout on Windows and UNIX platforms?
In my experience, the most popular version is the d
suffix, which is also the one that has been around the longest. Traditionally CMake only distinguished between debug and optimised binaries for library find scripts. The one-subdirectory-per-config approach has only become possible with the modern introduction of packaged CMake config scripts, so it is not super popular.
Many libraries choose to ignore the issue altogether, requiring two different install trees for Debug and Release on MSVC. Here's a list of some popular libraries that do take measures to support this:
_debug
, separate subdirectories for x86/x64 and MSVC versionsd
d
and static
_a
and _dll
d
(static builds not supported)-d
and -s
d
(static builds not supported)d
and static
Also:
Regarding the trade-offs between the different options for accomodating debug and release builds on MSVC:
find_package
call and then target_link_libraries
to an imported target, so chances are they will never even look at the files.Debug
and Release
versions is enough - the three release configurations (Release
, MinSizeRel
and RelWithDebInfo
) all use the same release runtime. Providing just two binary forms is the most space-efficient deployment and will compile with all configurations.MinSizeRel
, you want the smallest binary. If your upstream dependencies only provide the binaries from their Release
configuration, you will not get the smallest binary. If you want to debug your release builds in RelWithDebInfo
, but your upstream dependencies don't ship with the debug info for the binaries, debugging into them is going to be a pain.What conventions for naming and directory structure to adopt to address this
I don't know, but we should prioritize ergonomics for the library's user. I think it is safe to assume consumers will be using CMake (with or without or a package manager) to consume the library so perhaps the layout won't be exposed to them.
This is correct, when using CMake or a package manager, you are unlikely to notice any difference. The biggest impact is that with per-config subdirectories, your binaries will take up disk space for up to three distinct release configurations, while with the debug suffix it will be at most one.
@bbrown105 @bretbrownjr , it would be great to get your opinion here.
Also @steve-downey
I've been giving this some thought for the last week. There are some competing priorities to balance when considering the use cases descried here:
I don't have a simple solution now. I was talking to @foonathan and some others and it seems probable that we will need to bite the bullet and have one or more Beman CMake modules that provide abstractions over these workflows that allow powerful but DRY CMakeLists.txt for each Beman repo.
I expect the next step is for someone to describe the concerns and a recommended approach in a more fully considered proposal. I hope to get to that myself at some point, but I would be happy to see someone else take a stab at coming up with a an approach and starting a discussion on the Beman discourse and/or in the weekly meeting.
@ComicSansMS, would it make sense to use multiple subdirectories for multi-config generators and place archive artifacts directly in lib/
for single-config generators?
@ComicSansMS, would it make sense to use multiple subdirectories for multi-config generators and place archive artifacts directly in
lib/
for single-config generators?
I guess the desire to put artifacts directly in lib
is so that it follows common GNU directory layout conventions?
That would be fine, I guess. It solves the multi-config issue in MSVC, which is probably the most important use case.
It would be a bit awkward in that a Ninja Multi-Config build will produce a different install tree than e.g. a single-config Ninja build. I'm personally not too worried about this. Also, installing from differently configurated build trees to the same install location will overwrite any previously installed configurations. This is not unusual on Unix, so I would be surprised if it raised any eyebrows.
I believe vcpkg has expectations or at least defaults for where to put the debug build of a library. I believe if you provide Debug
as a CMAKE_BUILD_TYPE
, your find_package(foobar)
will resolve to a CMake module that points you at ${libdir}/debug/libfoobar.lib
, etc. I also believe they remove share
and include
directories, assuming those are identical across Debug
and Release
builds.
Anyway, this function tends to be called in vcpkg portfile.cmake
files for each library:
https://github.com/microsoft/vcpkg/blob/master/ports/vcpkg-cmake-config/vcpkg_cmake_config_fixup.cmake#L3
It sounds like we have consensus here. @ComicSansMS would you be willing to put together a PR for this?
I created a simple PR that will mirror the vcpkg directory layout that @bretbrownjr described above:
I hope this is the right place for this, since the example project seems to be the only spot where we define conventions like this.
Currently the example always builds and installs the example library under the same name:
The library binary file will always be libexample.a, example.lib, or similar
The binary is always installed to the default directory as determined by GNUInstallDirs:
This is very inconvenient for multi-config generators, where you may want to provide multiple builds for different configurations at the same time. It is particularly problematic for MSVC builds, as the Debug runtime there is incompatible with the Release runtime, so you want to be able to provide at least two different sets of binaries.
Traditionally, libraries solved this by adding a Debug postfix to the binary name:
This would then cause Debug builds to produce a binary
exampled.lib
, which coexists alongside theexample.lib
in the install tree.Generator expressions allow for an alternative approach, where each configuration gets its own subdirectory in the install tree:
This will result in the following install tree on MSVC:
I personally prefer the second solution, but I would like to hear other opinions.
In addition to this, there is other potential conflicts for binary configurations. x86 vs x64 is an obvious example, but there is also the issue of incompatible static and dll runtimes on Windows. Boost solved this by using an elaborate naming convention for binaries (e.g.
boost_atomic-vc143-mt-gd-x64-1_86.lib
).I would like to start a discussion how to solve this: