CMAKE_FIND_LIBRARY_PREFIXES on Windows

This post was inspired by discussions in the Qt issue tracker here (it was a side-issue that emerged in the comments):

https://bugreports.qt.io/browse/QTBUG-96401

On most platforms, libraries typically have a prefix of lib, but on some (notably Windows), there is typically no prefix. We currently handle these differences through the CMAKE_FIND_LIBRARY_PREFIXES variable, which is typically set by the platform files like Modules/Platforms/Windows.cmake and so on. In a recent commit (not yet in any CMake release), the fallback for when this variable isn’t defined (e.g. when CMake is run in script mode) was changed to the following:

std::string const& get_prefixes(cmMakefile* mf)
{
#ifdef _WIN32
  static std::string defaultPrefix = ";lib";
#else
  static std::string defaultPrefix = "lib";
#endif
  cmValue prefixProp = mf->GetDefinition("CMAKE_FIND_LIBRARY_PREFIXES");
  return (prefixProp) ? *prefixProp : defaultPrefix;
}

That fallback now allows lib as a prefix on Windows where it didn’t before. But that fallback should never get used in project mode, since Modules/Platforms/Windows.cmake explicitly sets CMAKE_FIND_LIBRARY_PREFIXES to an empty string, which means prefixProp in the above will see that empty string and use it instead of the hard-coded defaultPrefix.

But as highlighted by the linked Qt issue, sometimes libraries will still have a lib prefix, even on Windows (it is libEGL in that case, which is hard-coded by the .gn files for that project’s build system). This raises the question of whether we should still consider a lib prefix, even on Windows. We already will be for script mode due to the above-mentioned change, so there’s also an issue of consistency here. So I’d like to raise the following questions for discussion:

  • Would it make sense to set CMAKE_FIND_LIBRARY_PREFIXES to ;lib or lib on Windows too?
  • Would that result in any danger or change in behavior which would need a policy?

CC: @robert.maynard

I would suggest lib; as the default on all platforms. It is the wild west out there regarding useless lib prefixes (because the subfolder/extension already defines the file type)

File list of x64-windows in vcpkg filtered by the regex lib/lib.+\.lib (Not all will probably follow upstream behavior but most of them will)

alac-decoder:/debug/lib/libalac_decoder.lib
alac-decoder:/lib/libalac_decoder.lib
alac:/debug/lib/libalac.lib
alac:/lib/libalac.lib
angle:/debug/lib/libANGLE.lib
angle:/debug/lib/libEGL.lib
angle:/debug/lib/libGLESv2.lib
angle:/lib/libANGLE.lib
angle:/lib/libEGL.lib
angle:/lib/libGLESv2.lib
apr-util:/debug/lib/libaprutil-1.lib
apr-util:/lib/libaprutil-1.lib
apr:/debug/lib/libapr-1.lib
apr:/debug/lib/libaprapp-1.lib
apr:/lib/libapr-1.lib
apr:/lib/libaprapp-1.lib
berkeleydb:/debug/lib/libdb48.lib
berkeleydb:/lib/libdb48.lib
boinc:/debug/lib/libboinc.lib
boinc:/debug/lib/libboincapi.lib
boinc:/lib/libboinc.lib
boinc:/lib/libboincapi.lib
breakpad:/debug/lib/libbreakpad_clientd.lib
breakpad:/debug/lib/libbreakpadd.lib
breakpad:/lib/libbreakpad.lib
breakpad:/lib/libbreakpad_client.lib
calceph:/debug/lib/libcalceph.lib
calceph:/lib/libcalceph.lib
cppcms:/debug/lib/libbooster-d.lib
cppcms:/debug/lib/libcppcms-d.lib
cppcms:/lib/libbooster.lib
cppcms:/lib/libcppcms.lib
ctemplate:/debug/lib/libctemplate.lib
ctemplate:/lib/libctemplate.lib
cunit:/debug/lib/libcunit.lib
cunit:/lib/libcunit.lib
curl:/debug/lib/libcurl-d.lib
curl:/lib/libcurl.lib
expat:/debug/lib/libexpatd.lib
expat:/lib/libexpat.lib
fastcgi:/debug/lib/libfcgi.lib
fastcgi:/lib/libfcgi.lib
freetds:/debug/lib/libct.lib
freetds:/lib/libct.lib
gperftools:/debug/lib/libtcmalloc_minimal.lib
gperftools:/lib/libtcmalloc_minimal.lib
hunspell:/debug/lib/libhunspell.lib
hunspell:/lib/libhunspell.lib
hwloc:/debug/lib/libhwloc.lib
hwloc:/lib/libhwloc.lib
jbigkit:/debug/lib/libjbig.lib
jbigkit:/lib/libjbig.lib
kealib:/debug/lib/libkea.lib
kealib:/lib/libkea.lib
libaiff:/debug/lib/libaiff.lib
libaiff:/lib/libaiff.lib
libbson:/debug/lib/libbson-1.0.lib
libbson:/lib/libbson-1.0.lib
libconfig:/debug/lib/libconfig++.lib
libconfig:/debug/lib/libconfig.lib
libconfig:/lib/libconfig++.lib
libconfig:/lib/libconfig.lib
libconfuse:/debug/lib/libconfuse.lib
libconfuse:/lib/libconfuse.lib
libdatrie:/debug/lib/libdatried.lib
libdatrie:/lib/libdatrie.lib
libde265:/debug/lib/libde265.lib
libde265:/lib/libde265.lib
libdisasm:/debug/lib/libdisasmd.lib
libdisasm:/lib/libdisasm.lib
libdshowcapture:/debug/lib/libdshowcapture.lib
libdshowcapture:/lib/libdshowcapture.lib
libexif:/debug/lib/libexif.lib
libexif:/lib/libexif.lib
libffi:/debug/lib/libffi.lib
libffi:/lib/libffi.lib
libgd:/debug/lib/libgd.lib
libgd:/lib/libgd.lib
libgo:/debug/lib/libgo.lib
libgo:/lib/libgo.lib
libharu:/debug/lib/libhpdfd.lib
libharu:/lib/libhpdf.lib
libics:/debug/lib/libics.lib
libics:/debug/lib/libics_cpp.lib
libics:/lib/libics.lib
libics:/lib/libics_cpp.lib
libideviceactivation:/debug/lib/libideviceactivation.lib
libideviceactivation:/lib/libideviceactivation.lib
libidn2:/debug/lib/libidn2.lib
libidn2:/lib/libidn2.lib
libimobiledevice:/debug/lib/libimobiledevice-1.0.lib
libimobiledevice:/lib/libimobiledevice-1.0.lib
liblas:/debug/lib/liblas.lib
liblas:/debug/lib/liblas_c.lib
liblas:/lib/liblas.lib
liblas:/lib/liblas_c.lib
liblinear:/debug/lib/liblinear.lib
liblinear:/lib/liblinear.lib
liblo:/debug/lib/liblo.lib
liblo:/lib/liblo.lib
libmaxminddb:/debug/lib/libmaxminddbd.lib
libmaxminddb:/lib/libmaxminddb.lib
libmicrohttpd:/debug/lib/libmicrohttpd-dll_d.lib
libmicrohttpd:/lib/libmicrohttpd-dll.lib
libmspack:/debug/lib/libmspack.lib
libmspack:/lib/libmspack.lib
libmupdf:/debug/lib/libmupdfd.lib
libmupdf:/lib/libmupdf.lib
libmysql:/debug/lib/libmysql.lib
libmysql:/lib/libmysql.lib
libodb-boost:/debug/lib/libodb-boost.lib
libodb-boost:/lib/libodb-boost.lib
libodb-mysql:/debug/lib/libodb-mysql.lib
libodb-mysql:/lib/libodb-mysql.lib
libodb-pgsql:/debug/lib/libodb-pgsql.lib
libodb-pgsql:/lib/libodb-pgsql.lib
libodb-sqlite:/debug/lib/libodb-sqlite.lib
libodb-sqlite:/lib/libodb-sqlite.lib
libodb:/debug/lib/libodb.lib
libodb:/lib/libodb.lib
libopenmpt:/debug/lib/libopenmpt.lib
libopenmpt:/lib/libopenmpt.lib
libpff:/debug/lib/libpff.lib
libpff:/lib/libpff.lib
libpng:/debug/lib/libpng16d.lib
libpng:/lib/libpng16.lib
libpq:/debug/lib/libecpg.lib
libpq:/debug/lib/libecpg_compat.lib
libpq:/debug/lib/libpgcommon.lib
libpq:/debug/lib/libpgport.lib
libpq:/debug/lib/libpgtypes.lib
libpq:/debug/lib/libpq.lib
libpq:/lib/libecpg.lib
libpq:/lib/libecpg_compat.lib
libpq:/lib/libpgcommon.lib
libpq:/lib/libpgport.lib
libpq:/lib/libpgtypes.lib
libpq:/lib/libpq.lib
libproxy:/debug/lib/libproxy.lib
libproxy:/lib/libproxy.lib
librabbitmq:/debug/lib/librabbitmq.4.lib
librabbitmq:/lib/librabbitmq.4.lib
librtmp:/debug/lib/librtmpd.lib
librtmp:/lib/librtmp.lib
librttopo:/debug/lib/librttopo.lib
librttopo:/lib/librttopo.lib
libsbml:/debug/lib/libsbml-static.lib
libsbml:/debug/lib/libsbml.lib
libsbml:/lib/libsbml-static.lib
libsbml:/lib/libsbml.lib
libsodium:/debug/lib/libsodium.lib
libsodium:/lib/libsodium.lib
libssh2:/debug/lib/libssh2.lib
libssh2:/lib/libssh2.lib
libstk:/debug/lib/libstk.lib
libstk:/lib/libstk.lib
libsvm:/debug/lib/libsvm.lib
libsvm:/lib/libsvm.lib
libtcod:/debug/lib/libtcod.lib
libtcod:/lib/libtcod.lib
libu2f-server:/debug/lib/libu2f-server.lib
libu2f-server:/lib/libu2f-server.lib
libudis86:/debug/lib/libudis86.lib
libudis86:/lib/libudis86.lib
libui:/debug/lib/libui.lib
libui:/lib/libui.lib
libunibreak:/debug/lib/libunibreak.lib
libunibreak:/lib/libunibreak.lib
libusb-win32:/debug/lib/libusb0.lib
libusb-win32:/lib/libusb0.lib
libusbmuxd:/debug/lib/libusbmuxd.lib
libusbmuxd:/lib/libusbmuxd.lib
libusb:/debug/lib/libusb-1.0.lib
libusb:/lib/libusb-1.0.lib
libuv:/debug/lib/libuv.lib
libuv:/lib/libuv.lib
libwebp:/debug/lib/libwebpmuxd.lib
libwebp:/lib/libwebpmux.lib
libxml2:/debug/lib/libxml2.lib
libxml2:/lib/libxml2.lib
libxmlmm:/debug/lib/libxmlmm.lib
libxmlmm:/lib/libxmlmm.lib
libxmp-lite:/debug/lib/libxmp-lite.lib
libxmp-lite:/lib/libxmp-lite.lib
libxslt:/debug/lib/libexslt.lib
libxslt:/debug/lib/libxslt.lib
libxslt:/lib/libexslt.lib
libxslt:/lib/libxslt.lib
libzippp:/debug/lib/libzippp.lib
libzippp:/lib/libzippp.lib
llvm:/debug/lib/libclangd.lib
llvm:/lib/libclang.lib
mapnik:/debug/lib/libmapnik-jsond.lib
mapnik:/debug/lib/libmapnik-wktd.lib
mapnik:/lib/libmapnik-json.lib
mapnik:/lib/libmapnik-wkt.lib
matio:/debug/lib/libmatio.lib
matio:/lib/libmatio.lib
mesa:/debug/lib/libGLESv1_CM_mesa.lib
mesa:/debug/lib/libGLESv2_mesa.lib
mesa:/debug/lib/libglapi.lib
mesa:/lib/libGLESv1_CM_mesa.lib
mesa:/lib/libGLESv2_mesa.lib
mesa:/lib/libglapi.lib
minizip-ng:/debug/lib/libminizip-ng.lib
minizip-ng:/lib/libminizip-ng.lib
modp-base64:/debug/lib/libmodpbase64.lib
modp-base64:/lib/libmodpbase64.lib
mongo-c-driver:/debug/lib/libmongoc-1.0.lib
mongo-c-driver:/lib/libmongoc-1.0.lib
mp3lame:/debug/lib/libmp3lame.lib
mp3lame:/lib/libmp3lame.lib
mujs:/debug/lib/libmujs.lib
mujs:/lib/libmujs.lib
openmama:/debug/lib/libmamabaseimplmd.lib
openmama:/debug/lib/libmamacmd.lib
openmama:/debug/lib/libmamacmt.lib
openmama:/debug/lib/libmamacppmd.lib
openmama:/debug/lib/libmamacppmt.lib
openmama:/debug/lib/libmamaentnoopmd.lib
openmama:/debug/lib/libmamaplugindqstrategymd.lib
openmama:/debug/lib/libmamaqpidimplmd.lib
openmama:/debug/lib/libmamaqpidmsgimplmd.lib
openmama:/debug/lib/libmamdabookmd.lib
openmama:/debug/lib/libmamdabookmt.lib
openmama:/debug/lib/libmamdamd.lib
openmama:/debug/lib/libmamdamt.lib
openmama:/debug/lib/libmamdanewsmd.lib
openmama:/debug/lib/libmamdanewsmt.lib
openmama:/debug/lib/libmamdaoptionsmd.lib
openmama:/debug/lib/libmamdaoptionsmt.lib
openmama:/debug/lib/libwombatcommoncppmd.lib
openmama:/debug/lib/libwombatcommoncppmt.lib
openmama:/debug/lib/libwombatcommonmd.lib
openmama:/debug/lib/libwombatcommonmt.lib
openmama:/lib/libmamabaseimplmd.lib
openmama:/lib/libmamacmd.lib
openmama:/lib/libmamacmt.lib
openmama:/lib/libmamacppmd.lib
openmama:/lib/libmamacppmt.lib
openmama:/lib/libmamaentnoopmd.lib
openmama:/lib/libmamaplugindqstrategymd.lib
openmama:/lib/libmamaqpidimplmd.lib
openmama:/lib/libmamaqpidmsgimplmd.lib
openmama:/lib/libmamdabookmd.lib
openmama:/lib/libmamdabookmt.lib
openmama:/lib/libmamdamd.lib
openmama:/lib/libmamdamt.lib
openmama:/lib/libmamdanewsmd.lib
openmama:/lib/libmamdanewsmt.lib
openmama:/lib/libmamdaoptionsmd.lib
openmama:/lib/libmamdaoptionsmt.lib
openmama:/lib/libwombatcommoncppmd.lib
openmama:/lib/libwombatcommoncppmt.lib
openmama:/lib/libwombatcommonmd.lib
openmama:/lib/libwombatcommonmt.lib
openssl:/debug/lib/libcrypto.lib
openssl:/debug/lib/libssl.lib
openssl:/lib/libcrypto.lib
openssl:/lib/libssl.lib
paraview:/debug/lib/libyaml_catalyst2.0.lib
paraview:/lib/libyaml_catalyst2.0.lib
pdal:/debug/lib/libpdal_plugin_reader_pgpointcloud.lib
pdal:/debug/lib/libpdal_plugin_writer_pgpointcloud.lib
pdal:/lib/libpdal_plugin_reader_pgpointcloud.lib
pdal:/lib/libpdal_plugin_writer_pgpointcloud.lib
pmdk:/debug/lib/libpmem.lib
pmdk:/debug/lib/libpmemblk.lib
pmdk:/debug/lib/libpmemlog.lib
pmdk:/debug/lib/libpmemobj.lib
pmdk:/debug/lib/libpmempool.lib
pmdk:/lib/libpmem.lib
pmdk:/lib/libpmemblk.lib
pmdk:/lib/libpmemlog.lib
pmdk:/lib/libpmemobj.lib
pmdk:/lib/libpmempool.lib
protobuf:/debug/lib/libprotobuf-lited.lib
protobuf:/debug/lib/libprotobufd.lib
protobuf:/debug/lib/libprotocd.lib
protobuf:/lib/libprotobuf-lite.lib
protobuf:/lib/libprotobuf.lib
protobuf:/lib/libprotoc.lib
speex:/debug/lib/libspeexd.lib
speex:/lib/libspeex.lib
suitesparse:/debug/lib/libamdd.lib
suitesparse:/debug/lib/libbtfd.lib
suitesparse:/debug/lib/libcamdd.lib
suitesparse:/debug/lib/libccolamdd.lib
suitesparse:/debug/lib/libcholmodd.lib
suitesparse:/debug/lib/libcolamdd.lib
suitesparse:/debug/lib/libcxsparsed.lib
suitesparse:/debug/lib/libklud.lib
suitesparse:/debug/lib/libldld.lib
suitesparse:/debug/lib/libspqrd.lib
suitesparse:/debug/lib/libumfpackd.lib
suitesparse:/lib/libamd.lib
suitesparse:/lib/libbtf.lib
suitesparse:/lib/libcamd.lib
suitesparse:/lib/libccolamd.lib
suitesparse:/lib/libcholmod.lib
suitesparse:/lib/libcolamd.lib
suitesparse:/lib/libcxsparse.lib
suitesparse:/lib/libklu.lib
suitesparse:/lib/libldl.lib
suitesparse:/lib/libspqr.lib
suitesparse:/lib/libumfpack.lib
tinyspline:/debug/lib/libtinysplinecppd.lib
tinyspline:/debug/lib/libtinysplined.lib
tinyspline:/lib/libtinyspline.lib
tinyspline:/lib/libtinysplinecpp.lib
wpilib:/debug/wpilib/lib/ntcored.lib
wpilib:/debug/wpilib/lib/wpiutild.lib
wpilib:/wpilib/lib/ntcore.lib
wpilib:/wpilib/lib/wpiutil.lib
x264:/debug/lib/libx264.lib
x264:/lib/libx264.lib
x265:/debug/lib/libx265.lib
x265:/lib/libx265.lib
xeus:/debug/lib/libxeus.lib
xeus:/lib/libxeus.lib
yara:/debug/lib/libyara.lib
yara:/lib/libyara.lib
z3:/debug/lib/libz3.lib
z3:/lib/libz3.lib
zeromq:/debug/lib/libzmq-mt-gd-4_3_4.lib
zeromq:/lib/libzmq-mt-4_3_4.lib
zxing-cpp:/debug/lib/libzxing-debug.lib
zxing-cpp:/lib/libzxing.lib
1 Like

The convention used on Windows often differs based on whether one is targeting the MSVC ABI or the GNU ABI (MinGW):

  • For the MSVC ABI, some projects use foo.{dll,lib} for shared libraries and libfoo.lib for the corresponding static library. CMake encodes only the shared library convention in Platform/Windows here. Using ;lib would preserve that historical preference, but may affect what gets found differently depending on whether NAMES_PER_DIR is used in the find_library call.

  • For the GNU ABI (MinGW), the convention is typically libfoo.{dll,dll.a} for shared libraries and libfoo.a for static libraries. CMake encodes the convention in Platform/Windows-GNU here.

libfoo.lib for the corresponding static library

source? Not even autotools with MSVC wrappers does that. Meson even does libfoo.a on windows for static libs (meson just decided to be incompatible with everything for static builds. )

some projects use foo.{dll,lib}

autotools even does .dll.lib. vcpkg patches this to .lib due to compatibility with cmake and not having to fix every pkg-config file by adding a .dll suffix into the -l flags.

It is also more what the compiler/linker vendors decided to be the default outputs instead of a “convention”. So libfoo.lib certainly doesn’t fall into that category (which also requires fixing pkg-config files to add the lib prefix into the -l flags…).

Using libfoo.lib for static libraries with the MSVC ABI is a boost convention. I’ve seen other projects follow the convention too, but I don’t know if any build system standardizes on it by default.

autotools even does .dll.lib.

For the GNU ABI we already use .dll.a, so I think equivalently searching for both .dll.lib and .lib extensions for the MSVC ABI would be fine.

The reason for such a “convention” is just justified by the fact that people commonly want to have every library type in the same folder. On linux this is taken care of by the suffixes e.g. .a vs .so. The same goes for configuration DEBUG (“d”) suffixes.
On windows this can be achieved by either adding add lib prefix to the static library or by using a .dll.lib. Syntactically only the later really makes sense since adding a lib prefix is simply a doubling of the suffix .lib while .dll.lib undoubtedly could be made the symbol for a shared library.
But really there is no “convention”. At least I don’t see one, its just all some random prefixes and suffixes for me ;).

The reason I selected this order was that -P mode could capture both GNU ABI and MSVC ABI with a measure of success. In this case anything that worked with MSVC ABI would continue to work as expected, and GNU ABI would potentially work.